public BattleDecision CalculateAction(Combatant character) { var decision = new BattleDecision(); decision.Destination = new Point((int)character.Avatar.Location.X, (int)character.Avatar.Location.Y); if (_threat.Count == 0) return decision; // find the enemy with the highest threat var enemy = (from ckv in _threat orderby ckv.Value descending select ckv.Key).First(); // find the point that brings you closest to them var grid = character.GetMovementGrid(BattleBoard.GetAccessibleGrid(character.Faction)); var distance = 65535; for (var x = 0; x < grid.Size.Width; x++) { for (var y = 0; y < grid.Size.Height; y++) { if (grid.Weight[x, y] != 1) continue; var d = BattleBoard.Sandbag.Pathfind( new Point(x, y), new Point((int)enemy.Avatar.Location.X, (int)enemy.Avatar.Location.Y) ).Count(); if (d >= distance || d > 2 || BattleBoard.GetCharacterAt(new Point(x, y)) != null) continue; decision.Destination = new Point(x, y); distance = d; } } var ability = Ability.Factory(_game, "attack"); ability.Character = character; // attack decision.Command = new Command { Ability = ability, Character = character, Target = new Point((int)enemy.Avatar.Location.X, (int)enemy.Avatar.Location.Y) }; return decision; }
/// <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; }; }
/// <summary> /// Process a character that has been selected by the player, showing a radial menu of options. /// </summary> /// <param name="character">The character whose options are to be displayed.</param> public void SelectCharacter(Combatant character) { // if they clicked on the character already being shown, assume they want to close the menu if (character == _selectedCharacter) { DeselectCharacter(); return; } // you can only click on your characters during your turn if (_state != BattleState.PlayerTurn) return; if (character.Faction != 0) return; if (_radialMenuControl != null) { Gui.Screen.Desktop.Children.Remove(_radialMenuControl); _radialMenuControl = null; } var menu = new RadialMenuControl(((IInputService)Game.Services.GetService(typeof(IInputService))).GetMouse()) { CenterX = (int)character.Avatar.Sprite.X + character.Avatar.Sprite.Width/2 - 10, CenterY = (int)character.Avatar.Sprite.Y + character.Avatar.Sprite.Height/2, OnExit = DeselectCharacter }; // move icon, plus event handlers var icon = new RadialButtonControl {ImageFrame = "move", Bounds = new UniRectangle(0, 0, 64, 64)}; if (character.CanMove) { icon.MouseOver += () => { if (!character.CanMove) return; _battleBoardLayer.SetTargettingGrid( character.GetMovementGrid(BattleBoard.GetAccessibleGrid(character.Faction)), new Grid(1, 1) ); }; icon.MouseOut += () => { if (_aimAbility == null) _battleBoardLayer.ResetGrid(); }; icon.MouseClick += () => { SelectAbilityTarget(character, Ability.Factory(Game, "move")); _aimTime = DateTime.Now; }; } else { // if they can't move, this icon does nothing icon.MouseOver = () => { }; icon.MouseOut = () => { }; icon.MouseClick = () => { }; icon.MouseRelease = () => { }; icon.Enabled = false; } menu.AddOption("move", icon); //// attack icon, plus handlers icon = new RadialButtonControl { ImageFrame = "attack", Bounds = new UniRectangle(0, 0, 64, 64) }; if (character.CanAct) { var ability = Ability.Factory(Game, "attack"); ability.Character = character; icon.MouseOver += () => { if (!character.CanAct) return; _battleBoardLayer.SetTargettingGrid( ability.GenerateTargetGrid(BattleBoard.Sandbag.Clone()), new Grid(1, 1) ); }; icon.MouseOut += () => { if (_aimAbility == null) _battleBoardLayer.ResetGrid(); }; icon.MouseRelease += () => { SelectAbilityTarget(character, ability); _aimTime = DateTime.Now; }; } else { // if they can't act, this icon does nothing icon.MouseOver = () => { }; icon.MouseOut = () => { }; icon.MouseClick = () => { }; icon.MouseRelease = () => { }; icon.Enabled = false; } menu.AddOption("attack", icon); //// special abilities icon, plus event handlers icon = new RadialButtonControl { ImageFrame = "special", Bounds = new UniRectangle(0, 0, 64, 64) }; if (character.CanAct) { icon.MouseRelease += () => SelectSpecialAbility(character); } else { // if they can't act, this icon does nothing icon.MouseOver = () => { }; icon.MouseOut = () => { }; icon.MouseClick = () => { }; icon.MouseRelease = () => { }; icon.Enabled = false; } menu.AddOption("special", icon); icon = new RadialButtonControl {ImageFrame = "item", Bounds = new UniRectangle(0, 0, 64, 64), Enabled = false}; menu.AddOption("item", icon); _radialMenuControl = menu; Gui.Screen.Desktop.Children.Add(_radialMenuControl); _selectedCharacter = character; _state = BattleState.CharacterSelected; }