/ GUNRPG.Tests / DistanceSynchronizationTests.cs
DistanceSynchronizationTests.cs
  1  using GUNRPG.Core;
  2  using GUNRPG.Core.Combat;
  3  using GUNRPG.Core.Intents;
  4  using GUNRPG.Core.Operators;
  5  using Xunit;
  6  
  7  namespace GUNRPG.Tests;
  8  
  9  /// <summary>
 10  /// Tests to ensure distance between operators is synchronized at round boundaries.
 11  /// </summary>
 12  public class DistanceSynchronizationTests
 13  {
 14      [Fact]
 15      public void Distance_IsSynchronizedAtEndOfRound()
 16      {
 17          // Arrange - Create two operators at same distance
 18          var player = new Operator("Player")
 19          {
 20              EquippedWeapon = WeaponFactory.CreateM15Mod0(),
 21              DistanceToOpponent = 15f
 22          };
 23          player.CurrentAmmo = player.EquippedWeapon!.MagazineSize;
 24  
 25          var enemy = new Operator("Enemy")
 26          {
 27              EquippedWeapon = WeaponFactory.CreateM15Mod0(),
 28              DistanceToOpponent = 15f
 29          };
 30          enemy.CurrentAmmo = enemy.EquippedWeapon!.MagazineSize;
 31  
 32          var combat = new CombatSystemV2(player, enemy, seed: 42);
 33  
 34          // Act - Player moves forward, enemy stands still
 35          var playerIntents = new SimultaneousIntents(player.Id)
 36          {
 37              Movement = MovementAction.SprintToward,
 38              Primary = PrimaryAction.Fire
 39          };
 40          
 41          var enemyIntents = new SimultaneousIntents(enemy.Id)
 42          {
 43              Movement = MovementAction.Stand,
 44              Primary = PrimaryAction.Fire
 45          };
 46  
 47          combat.SubmitIntents(player, playerIntents);
 48          combat.SubmitIntents(enemy, enemyIntents);
 49  
 50          // Execute until round completes
 51          while (combat.Phase == CombatPhase.Executing)
 52          {
 53              combat.ExecuteUntilReactionWindow();
 54          }
 55  
 56          // Assert - Both operators should have the same distance after round completes
 57          Assert.Equal(player.DistanceToOpponent, enemy.DistanceToOpponent);
 58      }
 59  
 60      [Fact]
 61      public void Distance_IsSynchronizedWhenCombatEnds()
 62      {
 63          // Arrange - Create operators where one will die
 64          var player = new Operator("Player")
 65          {
 66              EquippedWeapon = WeaponFactory.CreateSokol545(),
 67              DistanceToOpponent = 10f,
 68              Health = 100f
 69          };
 70          player.CurrentAmmo = player.EquippedWeapon!.MagazineSize;
 71  
 72          var enemy = new Operator("Enemy")
 73          {
 74              EquippedWeapon = WeaponFactory.CreateSokol545(),
 75              DistanceToOpponent = 10f,
 76              Health = 1f // Very low health, likely to die
 77          };
 78          enemy.CurrentAmmo = enemy.EquippedWeapon!.MagazineSize;
 79  
 80          var combat = new CombatSystemV2(player, enemy, seed: 42);
 81  
 82          // Act - Both fire
 83          var playerIntents = new SimultaneousIntents(player.Id)
 84          {
 85              Primary = PrimaryAction.Fire
 86          };
 87          
 88          var enemyIntents = new SimultaneousIntents(enemy.Id)
 89          {
 90              Primary = PrimaryAction.Fire
 91          };
 92  
 93          combat.SubmitIntents(player, playerIntents);
 94          combat.SubmitIntents(enemy, enemyIntents);
 95          
 96          // Execute until round completes
 97          while (combat.Phase == CombatPhase.Executing)
 98          {
 99              combat.ExecuteUntilReactionWindow();
100          }
101  
102          // Assert - Even if combat ended, distances should be synchronized
103          Assert.Equal(player.DistanceToOpponent, enemy.DistanceToOpponent);
104      }
105  
106      [Fact]
107      public void Distance_RemainsConsistentAcrossMultipleRounds()
108      {
109          // Arrange
110          var player = new Operator("Player")
111          {
112              EquippedWeapon = WeaponFactory.CreateM15Mod0(),
113              DistanceToOpponent = 20f
114          };
115          player.CurrentAmmo = player.EquippedWeapon!.MagazineSize;
116  
117          var enemy = new Operator("Enemy")
118          {
119              EquippedWeapon = WeaponFactory.CreateM15Mod0(),
120              DistanceToOpponent = 20f
121          };
122          enemy.CurrentAmmo = enemy.EquippedWeapon!.MagazineSize;
123  
124          var combat = new CombatSystemV2(player, enemy, seed: 42);
125  
126          // Act - Execute multiple rounds with various movement
127          for (int i = 0; i < 5; i++)
128          {
129              var playerIntents = new SimultaneousIntents(player.Id)
130              {
131                  Movement = i % 2 == 0 ? MovementAction.WalkToward : MovementAction.WalkAway,
132                  Primary = PrimaryAction.Fire
133              };
134              
135              var enemyIntents = new SimultaneousIntents(enemy.Id)
136              {
137                  Movement = i % 2 == 0 ? MovementAction.WalkAway : MovementAction.Stand,
138                  Primary = PrimaryAction.Fire
139              };
140  
141              combat.SubmitIntents(player, playerIntents);
142              combat.SubmitIntents(enemy, enemyIntents);
143              
144              // Execute until round completes
145              while (combat.Phase == CombatPhase.Executing)
146              {
147                  combat.ExecuteUntilReactionWindow();
148              }
149  
150              // Assert - After each round, distances should match
151              Assert.Equal(player.DistanceToOpponent, enemy.DistanceToOpponent);
152              
153              // Break if combat ended
154              if (combat.Phase == CombatPhase.Ended)
155                  break;
156          }
157      }
158  }