void Start() { Client = GameManager.Instance.Client; if (Client.IsPlayer) { Destroy(gameObject); return; } Instance = this; GameGraph = new BoardGraph(); BoardSpaces = new Dictionary <int, BoardSpace>(); FriendlyMonsters = new List <Monster>(); EnemyMonsters = new List <Monster>(); AttackCalculator = new AttackCalculator(); MoveCalculator = new MoveCalculator(); AvailablePushDestinations = new List <Node>(); BattleSmoke.gameObject.SetActive(false); Client.GameState = this; float attackResultTextRotationOffset = Client.IsHost ? 180 : 0; AttackResultTextPrefab.YRotationOffset = attackResultTextRotationOffset; _actionNumber = 1; if (!Client.IsHost) { _actionNumber = 3; var table = GameObject.Find("Table"); table.transform.localRotation = Quaternion.Euler(table.transform.localRotation.eulerAngles.x, table.transform.localRotation.eulerAngles.y + 180, table.transform.localRotation.eulerAngles.z); } _subActionNumber = 1; for (int i = 0; i < SpacePrefabs.Count; i++) { BoardSpace spacePrefab = SpacePrefabs[i]; if (!BoardSpaces.ContainsKey(i)) { spacePrefab.Node = GameGraph.Nodes[i]; BoardSpaces.Add(i, spacePrefab); } } }
void Start() { DontDestroyOnLoad(gameObject); ActionNumber = 1; SubActionNumber = 1; GameGraph = new BoardGraph(); HostMonsters = new List <Monster>(); GuestMonsters = new List <Monster>(); AttackCalculator = new AttackCalculator(); MoveCalculator = new MoveCalculator(); AvailablePushDestinations = new List <Node>(); GameManager gameManager = GameManager.Instance; if (gameManager == null || gameManager.Server == null) { throw new InvalidOperationException("Server must exist to begin game"); } _hostServer = gameManager.Server; if (_hostServer == null || !_hostServer.IsServerStarted) { throw new InvalidOperationException("Server must be running to begin game"); } if (SceneManager.GetSceneByName("startup").isLoaded) { SceneManager.UnloadSceneAsync("startup"); } AssignMonstersToPlayers(); GameStartMessage gameStartMessage = new GameStartMessage { HostMonsters = JsonConvert.SerializeObject(HostMonsters.Select(m => new { m.MonsterTypeId, m.CurrentNode.Id }).ToDictionary(k => k.MonsterTypeId, v => v.Id)), GuestMonsters = JsonConvert.SerializeObject(GuestMonsters.Select(m => new { m.MonsterTypeId, m.CurrentNode.Id }).ToDictionary(k => k.MonsterTypeId, v => v.Id)), ActionNumber = 1, SubActionNumber = 1 }; _hostServer.SendToAll(gameStartMessage.MessageTypeId, gameStartMessage); }
internal void Apply(ProcessTurnCommand command) { foreach (var move in ActiveTurnMoves) { if (move.Deployment) //deployed { ApplyDomainEvent(new DeployedEvent(Id, Guid.NewGuid(), move.Player, move.Source)); } else //attack { //pick a random unit from the opposing players units in this category to hit var possiblyAttacked = Units.Where(m => m.Value.OwnedByPlayer != move.Player && m.Value.Type == move.Target).ToArray(); if (!possiblyAttacked.Any()) { continue; // they all died! :( } var attacked = possiblyAttacked[_rand.Generate(possiblyAttacked.Length)].Key; var attackResults = AttackCalculator.Attack(_rand, move.Source, move.Target); if (attackResults.success) { ApplyDomainEvent(new DamagedEvent(Id, attacked, move.Target, attackResults.dmg)); //check for destruction if (Units[attacked].Health <= attackResults.dmg) { ApplyDomainEvent(new DestroyedEvent(Id, attacked, Units[attacked].OwnedByPlayer, Units[attacked].Type)); } } else if (attackResults.exc == null) { // haha, failed, do nothing } else { //push an error event... } } } ApplyDomainEvent(new MatchTurnEndedEvent(Id, CurrentTurn)); }
public void AttackCalculator_ReturnsAttackResultWithinMarginOfError() { const int iterations = 1000000; //<attack, defense, attackResult> Dictionary <int, Dictionary <int, Dictionary <AttackResult, decimal> > > resultAverages = new Dictionary <int, Dictionary <int, Dictionary <AttackResult, decimal> > >(); AttackCalculator attackCalculator = new AttackCalculator(); for (int a = 2; a < 9; a++) { //There are no attacks powers of 5 if (a == 5) { continue; } for (int d = 2; d < 9; d++) { if (!resultAverages.ContainsKey(a)) { resultAverages.Add(a, new Dictionary <int, Dictionary <AttackResult, decimal> >()); } if (!resultAverages[a].ContainsKey(d)) { resultAverages[a].Add(d, new Dictionary <AttackResult, decimal>()); } resultAverages[a][d].Add(AttackResult.Kill, 0); resultAverages[a][d].Add(AttackResult.Push, 0); resultAverages[a][d].Add(AttackResult.CounterPush, 0); resultAverages[a][d].Add(AttackResult.CounterKill, 0); } for (int d = 2; d < 9; d++) { for (int i = 0; i < iterations; i++) { AttackResult result = attackCalculator.Calculate(a, d); switch (result) { case AttackResult.Kill: resultAverages[a][d][AttackResult.Kill]++; break; case AttackResult.Push: resultAverages[a][d][AttackResult.Push]++; break; case AttackResult.CounterPush: resultAverages[a][d][AttackResult.CounterPush]++; break; case AttackResult.CounterKill: resultAverages[a][d][AttackResult.CounterKill]++; break; default: throw new ArgumentOutOfRangeException(); } } resultAverages[a][d][AttackResult.Kill] = Math.Round(resultAverages[a][d][AttackResult.Kill] / iterations, 4); resultAverages[a][d][AttackResult.Push] = Math.Round(resultAverages[a][d][AttackResult.Push] / iterations, 4); resultAverages[a][d][AttackResult.CounterPush] = Math.Round(resultAverages[a][d][AttackResult.CounterPush] / iterations, 4); resultAverages[a][d][AttackResult.CounterKill] = Math.Round(resultAverages[a][d][AttackResult.CounterKill] / iterations, 4); } } System.Diagnostics.Debug.WriteLine( "Dictionary<int, Dictionary<int, Dictionary<AttackResult, decimal>>> resultAverages = new Dictionary<int, Dictionary<int, Dictionary<AttackResult, decimal>>>(); "); for (int a = 2; a < 9; a++) { //There are no attacks powers of 5 if (a == 5) { continue; } System.Diagnostics.Debug.WriteLine("resultAverages.Add(" + a + ", new Dictionary<int, Dictionary<AttackResult, decimal>>());"); for (int d = 2; d < 9; d++) { System.Diagnostics.Debug.WriteLine("resultAverages[" + a + "].Add(" + d + ", new Dictionary<AttackResult, decimal>());"); System.Diagnostics.Debug.WriteLine("resultAverages[" + a + "][" + d + "].Add(AttackResult.Kill, " + resultAverages[a][d][AttackResult.Kill] + "m);"); System.Diagnostics.Debug.WriteLine("resultAverages[" + a + "][" + d + "].Add(AttackResult.Push, " + resultAverages[a][d][AttackResult.Push] + "m);"); System.Diagnostics.Debug.WriteLine("resultAverages[" + a + "][" + d + "].Add(AttackResult.CounterPush, " + resultAverages[a][d][AttackResult.CounterPush] + "m);"); System.Diagnostics.Debug.WriteLine("resultAverages[" + a + "][" + d + "].Add(AttackResult.CounterKill, " + resultAverages[a][d][AttackResult.CounterKill] + "m);"); } } }
void Start() { Client = GameManager.Instance.Client; if (!Client.IsPlayer) { Destroy(gameObject); return; } Instance = this; GameGraph = new BoardGraph(); BoardSpaces = new Dictionary <int, BoardSpace>(); FriendlyMonsters = new List <Monster>(); EnemyMonsters = new List <Monster>(); AttackCalculator = new AttackCalculator(); MoveCalculator = new MoveCalculator(); AvailablePushDestinations = new List <Node>(); BattleSmoke.gameObject.SetActive(false); Client.GameState = this; float attackResultTextRotationOffset = Client.IsHost ? 180 : 0; AttackResultTextPrefab.YRotationOffset = attackResultTextRotationOffset; _actionNumber = 1; if (!Client.IsHost) { _actionNumber = 3; var table = GameObject.Find("Table"); table.transform.localRotation = Quaternion.Euler(table.transform.localRotation.eulerAngles.x, table.transform.localRotation.eulerAngles.y + 180, table.transform.localRotation.eulerAngles.z); } _subActionNumber = 1; for (int i = 0; i < SpacePrefabs.Count; i++) { BoardSpace spacePrefab = SpacePrefabs[i]; if (!BoardSpaces.ContainsKey(i)) { spacePrefab.Node = GameGraph.Nodes[i]; BoardSpaces.Add(i, spacePrefab); } } List <Monster> friendlyMonsters = new List <Monster>(); List <Monster> enemyMonsters = new List <Monster>(); foreach (Monster monster in MonsterPrefabs) { if (GameManager.Instance.FriendlyMonsterInitialNodeIds.ContainsKey(monster.MonsterTypeId)) { monster.CurrentNode = GameGraph.Nodes[GameManager.Instance.FriendlyMonsterInitialNodeIds[monster.MonsterTypeId]]; friendlyMonsters.Add(monster); } else { monster.CurrentNode = GameGraph.Nodes[GameManager.Instance.EnemyMonsterInitialNodeIds[monster.MonsterTypeId]]; enemyMonsters.Add(monster); } } DisplayMonsters(friendlyMonsters, enemyMonsters); Client.SendStateAck(GetAdjustedActionNumber(), _subActionNumber); if (GameManager.Instance.Difficulty == 1) { GameObject.Find("selectionPreview").SetActive(false); } }
public void ProcessAttackAction(int attackingMonsterTypeId, int defendingMonsterTypeId) { Monster attacker; Monster defender; bool isHostAttacker = ActionNumber == 1 || ActionNumber == 2; if (isHostAttacker) { attacker = HostMonsters.Single(m => m.MonsterTypeId == attackingMonsterTypeId); defender = GuestMonsters.Single(m => m.MonsterTypeId == defendingMonsterTypeId); } else { attacker = GuestMonsters.Single(m => m.MonsterTypeId == attackingMonsterTypeId); defender = HostMonsters.Single(m => m.MonsterTypeId == defendingMonsterTypeId); } AttackResult attackResult = AttackCalculator.Calculate(attacker.AttackRating, defender.DefenseRating); IEnumerable <Node> friendlyOccupiedNodes = HostMonsters.Select(monster => monster.CurrentNode).ToList(); IEnumerable <Node> enemyOccupiedNodes = GuestMonsters.Select(monster => monster.CurrentNode).ToList(); switch (attackResult) { case AttackResult.Kill: if (isHostAttacker) { GuestMonsters.Remove(defender); } else { HostMonsters.Remove(defender); } SubActionNumber = 0; _hostServer.SendToAll(CustomMessageTypes.AttackKillResponse, new AttackKillResponseMessage { ActionNumber = ActionNumber, SubActionNumber = SubActionNumber, AttackingMonsterTypeId = attackingMonsterTypeId, DefendingMonsterTypeId = defendingMonsterTypeId, AttackResultId = (int)AttackResult.Kill, Message = "Kill" }); break; case AttackResult.CounterKill: if (isHostAttacker) { HostMonsters.Remove(attacker); } else { GuestMonsters.Remove(attacker); } SelectedMonster = null; SubActionNumber = 0; _hostServer.SendToAll(CustomMessageTypes.AttackKillResponse, new AttackKillResponseMessage { ActionNumber = ActionNumber, SubActionNumber = SubActionNumber, AttackingMonsterTypeId = attackingMonsterTypeId, DefendingMonsterTypeId = defendingMonsterTypeId, AttackResultId = (int)AttackResult.CounterKill, Message = "Counter Kill" }); break; case AttackResult.Push: AvailablePushDestinations = MoveCalculator.FindMoves(defender.CurrentNode, 1, friendlyOccupiedNodes.Union(enemyOccupiedNodes)).Select(m => m.DestinationNode); if (!AvailablePushDestinations.Any()) { SubActionNumber = 0; _hostServer.SendToAll(CustomMessageTypes.GameState, new GameStateMessage { ActionNumber = ActionNumber, SubActionNumber = SubActionNumber, Message = "No available push destinations.", HostMonsterState = JsonConvert.SerializeObject(HostMonsters.Select(m => new { m.MonsterTypeId, m.CurrentNode.Id }).ToDictionary(k => k.MonsterTypeId, v => v.Id)), GuestMonsterState = JsonConvert.SerializeObject(GuestMonsters.Select(m => new { m.MonsterTypeId, m.CurrentNode.Id }).ToDictionary(k => k.MonsterTypeId, v => v.Id)) }); } else { SubActionNumber = 6; _hostServer.SendToAll(CustomMessageTypes.AttackPushResponse, new AttackPushResponseMessage { ActionNumber = ActionNumber, SubActionNumber = SubActionNumber, AttackingMonsterTypeId = attackingMonsterTypeId, DefendingMonsterTypeId = defendingMonsterTypeId, AvailablePushDestinationIds = AvailablePushDestinations.Select(d => d.Id).ToArray(), AttackResultId = (int)AttackResult.Push, Message = "Push" }); } break; case AttackResult.CounterPush: AvailablePushDestinations = MoveCalculator.FindMoves(attacker.CurrentNode, 1, friendlyOccupiedNodes.Union(enemyOccupiedNodes)).Select(m => m.DestinationNode); if (!AvailablePushDestinations.Any()) { SubActionNumber = 0; _hostServer.SendToAll(CustomMessageTypes.GameState, new GameStateMessage { ActionNumber = ActionNumber, SubActionNumber = SubActionNumber, Message = "No available push destinations.", HostMonsterState = JsonConvert.SerializeObject(HostMonsters.Select(m => new { m.MonsterTypeId, m.CurrentNode.Id }).ToDictionary(k => k.MonsterTypeId, v => v.Id)), GuestMonsterState = JsonConvert.SerializeObject(GuestMonsters.Select(m => new { m.MonsterTypeId, m.CurrentNode.Id }).ToDictionary(k => k.MonsterTypeId, v => v.Id)) }); } else { SubActionNumber = 7; _hostServer.SendToAll(CustomMessageTypes.AttackPushResponse, new AttackPushResponseMessage { ActionNumber = ActionNumber, SubActionNumber = SubActionNumber, AttackingMonsterTypeId = attackingMonsterTypeId, DefendingMonsterTypeId = defendingMonsterTypeId, AvailablePushDestinationIds = AvailablePushDestinations.Select(d => d.Id).ToArray(), AttackResultId = (int)AttackResult.CounterPush, Message = "Counter Push" }); } break; default: throw new ArgumentOutOfRangeException(); } }