public void RecordCommand(Command command, List<Hit> hits) { var enemy = command.Character; if (!_threat.ContainsKey(enemy)) { _threat.Add(enemy, 0); } foreach (var hit in hits) { var target = BattleBoard.GetCharacterAt(hit.Target); var damage = hit.Damage; // if nobody is at this spot, ignore it. this shouldn't come up // since a hit is only generated it someone is there, but i'll // account for it anyway if (target == null) continue; // hits against the players team (heal/friendly fire) are inverted // to maintain sanity. healing raises threat, friendly fire lowers it if (target.Faction == 0) damage = 0 - damage; _threat[enemy] += damage; } }
/// <summary> /// Create a callback function to process if the player chooses to have a character attack. This callback will display the targetting grid /// and bind _aimAbility to a function that queues an attack command from the character onto the target. /// </summary> /// <param name="character">The character whose attack is being chosen.</param> /// <param name="ability">The ability currently being aimed.</param> /// <returns></returns> private void SelectAbilityTarget(Combatant character, Ability ability) { _state = BattleState.AimingAbility; Gui.Screen.Desktop.Children.Remove(_radialMenuControl); _battleBoardLayer.SetTargettingGrid( ability.Name == "Move" ? character.GetMovementGrid(BattleBoard.GetAccessibleGrid(character.Faction)) : ability.GenerateTargetGrid(BattleBoard.Sandbag.Clone()), ability.GenerateImpactGrid() ); _battleBoardLayer.AbilityAim = true; _aimAbility = (x, y) => { // only target enemies with angry spells and allies with friendly spells if (!ability.CanTarget(BattleBoard.IsOccupied(new Point(x, y)))) return false; character.Avatar.UpdateVelocity(x - character.Avatar.Location.X, y - character.Avatar.Location.Y); character.Avatar.UpdateVelocity(0, 0); // make sure the ability knows who is casting it. this probably shouldn't // be done here, but there are issues doing it elsewhere. ability.Character = character; var command = new Command { Character = character, Target = new Point(x, y), Ability = ability }; if(ability.Name == "Move") { ExecuteCommand(command); return true; } character.CanAct = false; QueuedCommands.Add(command); _queuedCommands.UpdateControls(); _state = BattleState.Delay; _delayState = BattleState.PlayerTurn; _delayTimer = 0.05F; ResetState(); return true; }; }
private void UpdateBattleStateEnemyTurn() { var combatants = (from c in BattleBoard.Characters where c.Faction == 1 && c.CanMove select c).ToArray(); if (combatants.Any()) { // find first character that can move _selectedCharacter = combatants[0]; // find the optimal location var decision = _commander.CalculateAction(_selectedCharacter); // create move command to that location var moveCommand = new Command { Ability = Ability.Factory(Game, "move"), Character = _selectedCharacter, Target = decision.Destination }; QueuedCommands.Add(moveCommand); if (decision.Command.Ability != null) QueuedCommands.Add(decision.Command); ExecuteQueuedCommands(); return; } ExecuteQueuedCommands(); // all enemy players have moved / attacked ChangeFaction(0); }
/// <summary> /// Process a command given by either the AI or the player. These commands can be attacking, casting a spell, /// using an item or moving. /// </summary> /// <param name="command">The command to be executed.</param> public void ExecuteCommand(Command command) { _state = BattleState.ExecutingCommand; switch (command.Ability.Name) { case "Move": { // special case for movement var grid = BattleBoard.GetAccessibleGrid(command.Character.Faction); // run an A* pathfinding algorithm to get a route var coords = grid.Pathfind(new Point((int)command.Character.Avatar.Location.X, (int)command.Character.Avatar.Location.Y), command.Target); // remove any points on the path that don't require a direction change for (var i = coords.Count - 2; i > 0; i--) { if(coords[i - 1].X == coords[i + 1].X || coords[i - 1].Y == coords[i + 1].Y) { coords.RemoveAt(i); } } _movementCoords = coords; _state = BattleState.MovingCharacter; command.Character.CanMove = false; if (FactionTurn == 1) break; // if this character has any queued commands, cancel them upon moving var queuedCommands = (from c in QueuedCommands where c.Character == command.Character select c).ToArray(); if(queuedCommands.Length > 0) { QueuedCommands.Remove(queuedCommands[0]); command.Character.CanAct = true; } } break; default: var hits = command.Ability.GenerateHits(BattleBoard, command.Target); // remove any hits on characters that no longer exist for (var i = hits.Count - 1; i >= 0; i--) { if(BattleBoard.GetCharacterAt(hits[i].Target) == null) { hits.RemoveAt(i); } } _commander.RecordCommand(command, hits); // if this ability still has hits left, process them normally if (hits.Count > 0) { command.Character.CanAct = false; DisplayHits(hits); command.Character.CurrentMana -= command.Ability.ManaCost; } break; } }