private async Task <SpellCastingResults> MoveToCastSpellOnEmptyCell(Spell spell, SpellLevels spellLevel) { // We'll move to cast the spell (if we can) with the least number of MP possible KeyValuePair <short, MoveNode>?node = null; int pmUsed = 99; foreach (var kvp in FightsPathfinder.GetReachableZone(_account.Game.Fight, _account.Game.Map.Data, _account.Game.Fight.PlayedFighter.CellId)) { if (!kvp.Value.Reachable) { continue; } // Only choose the safe paths // TODO: Maybe in the futur try to cast the spell even with tackle cost, in a LanguageManager.Translate("66") way of course if (kvp.Value.Path.Ap > 0 || kvp.Value.Path.Mp > 0) { continue; } //if (spell.HandToHand && MapPoint.FromCellId(kvp.Key).DistanceToCell(MapPoint.FromCellId()) // continue; var range = _account.Game.Fight.GetSpellRange(kvp.Key, spellLevel); for (int i = 0; i < range.Count; i++) { if (_account.Game.Fight.CanLaunchSpell(spell.SpellId, kvp.Key, range[i]) != SpellInabilityReasons.NONE) { continue; } if (kvp.Value.Path.Reachable.Count < pmUsed) { node = kvp; pmUsed = kvp.Value.Path.Reachable.Count; } } } if (node != null) { _account.Logger.LogDebug(LanguageManager.Translate("52"), LanguageManager.Translate("63", node.Value.Key, spell.SpellName)); await _account.Game.Managers.Movements.MoveToCellInFight(node); return(SpellCastingResults.MOVED); } return(SpellCastingResults.NOT_CASTED); }
private async Task <SpellCastingResults> MoveToCastSimpleSpell(Spell spell, FighterEntry target) { // We'll move to cast the spell (if we can) with the least number of MP possible KeyValuePair <short, MoveNode>?node = null; int pmUsed = 99; foreach (var kvp in FightsPathfinder.GetReachableZone(_account.Game.Fight, _account.Game.Map.Data, _account.Game.Fight.PlayedFighter.CellId)) { if (!kvp.Value.Reachable) { continue; } // Only choose the safe paths // TODO: Maybe in the futur try to cast the spell even with tackle cost, in a LanguageManager.Translate("66") way of course if (kvp.Value.Path.Ap > 0 || kvp.Value.Path.Mp > 0) { continue; } if (spell.HandToHand && !_account.Game.Fight.IsHandToHandWithAnEnnemy(kvp.Key)) { continue; } if (_account.Game.Fight.CanLaunchSpell(spell.SpellId, kvp.Key, target.CellId) != SpellInabilityReasons.NONE) { continue; } if (kvp.Value.Path.Reachable.Count <= pmUsed) { node = kvp; pmUsed = kvp.Value.Path.Reachable.Count; } } if (node != null) { _account.Logger.LogDebug(LanguageManager.Translate("52"), LanguageManager.Translate("63", node.Value.Key, spell.SpellName)); await _account.Game.Managers.Movements.MoveToCellInFight(node); return(SpellCastingResults.MOVED); } return(SpellCastingResults.NOT_CASTED); }
public KeyValuePair <short, MoveNode>?GetNearestOrFarthestEndMoveNode(bool nearest, bool basedOnAllMonsters = true) { KeyValuePair <short, MoveNode>?node = null; int totalDistances = -1; int distance = -1; // Include our current cell totalDistances = basedOnAllMonsters ? GetTotalDistancesFromEnnemies(_account.Game.Fight.PlayedFighter.CellId) : MapPoint.FromCellId(_account.Game.Fight.PlayedFighter.CellId).DistanceToCell(MapPoint.FromCellId(_account.Game.Fight.GetNearestEnnemy().CellId)); foreach (var kvp in FightsPathfinder.GetReachableZone(_account.Game.Fight, _account.Game.Map.Data, _account.Game.Fight.PlayedFighter.CellId)) { if (!kvp.Value.Reachable) { continue; } int tempTotalDistances = basedOnAllMonsters ? GetTotalDistancesFromEnnemies(kvp.Key) : MapPoint.FromCellId(kvp.Key).DistanceToCell(MapPoint.FromCellId(_account.Game.Fight.GetNearestEnnemy().CellId)); if ((nearest && tempTotalDistances <= totalDistances) || (!nearest && tempTotalDistances >= totalDistances)) { if (nearest) { node = kvp; totalDistances = tempTotalDistances; } // If we need to give the farthest cell, we might aswell give the one that uses the most available MP else if (kvp.Value.Path.Reachable.Count >= distance) { node = kvp; totalDistances = tempTotalDistances; distance = kvp.Value.Path.Reachable.Count; } } } return(node); }
private async Task <SpellCastingResults> CastAOESpell(Spell spell) { if (spell.Target == SpellTargets.ALLY || spell.Target == SpellTargets.EMPTY_CELL) { return(SpellCastingResults.NOT_CASTED); } if (_account.Game.Fight.CanLaunchSpell(spell.SpellId) != SpellInabilityReasons.NONE) { return(SpellCastingResults.NOT_CASTED); } var spellEntry = _account.Game.Character.GetSpell(spell.SpellId); Spells spellData = DataManager.Get <Spells>(spell.SpellId); SpellLevels spellLevel = DataManager.Get <SpellLevels>(spellData.SpellLevels[spellEntry.Level - 1]); // Get all the possible ranges Stopwatch sw = Stopwatch.StartNew(); List <RangeNodeEntry> entries = new List <RangeNodeEntry>(); RangeNodeEntry entry; // Include our current cell entry = GetRangeNodeEntry(_account.Game.Fight.PlayedFighter.CellId, null, spell, spellLevel); if (entry.TouchedEnnemiesByCell.Count > 0) { entries.Add(entry); } foreach (var kvp in FightsPathfinder.GetReachableZone(_account.Game.Fight, _account.Game.Map.Data, _account.Game.Fight.PlayedFighter.CellId)) { if (!kvp.Value.Reachable) { continue; } if (kvp.Value.Ap > 0 || kvp.Value.Mp > 0) { continue; } entry = GetRangeNodeEntry(kvp.Key, kvp.Value, spell, spellLevel); if (entry.TouchedEnnemiesByCell.Count > 0) { entries.Add(entry); } } // Get a cell where we can hit the most // If we need to move, try to move with the least amount of mps (with the same number of touched ennemies of course) short cellId = -1; short fromCellId = -1; KeyValuePair <short, MoveNode>?node = null; byte touchedEnnemies = 0; int usedMps = 99; for (int i = 0; i < entries.Count; i++) { foreach (var kvp in entries[i].TouchedEnnemiesByCell) { // Check for HandToHand if (spell.HandToHand && !_account.Game.Fight.IsHandToHandWithAnEnnemy(entries[i].FromCellId)) { continue; } // Check if we can cast the spell first if (_account.Game.Fight.CanLaunchSpell(spell.SpellId, entries[i].FromCellId, kvp.Key) != SpellInabilityReasons.NONE) { continue; } // >= in case a cell uses less pm if (kvp.Value >= touchedEnnemies) { // If its the same number of touched ennemies, check for the amount of mp we will use //if (kvp.Value > touchedEnnemies || (kvp.Value == touchedEnnemies && entries[i].MpUsed < usedMps)) if (kvp.Value > touchedEnnemies || (kvp.Value == touchedEnnemies && entries[i].MpUsed <= usedMps)) { touchedEnnemies = kvp.Value; cellId = kvp.Key; fromCellId = entries[i].FromCellId; usedMps = entries[i].MpUsed; if (entries[i].Node != null) { node = new KeyValuePair <short, MoveNode>(fromCellId, entries[i].Node); } } } } } if (cellId != -1) { // If node is null, it means that the chosen cellId is within range, so we don't have to move if (node == null) { _account.Logger.LogDebug(LanguageManager.Translate("52"), LanguageManager.Translate("62", spell.SpellName, touchedEnnemies, cellId)); await _account.Game.Fight.LaunchSpell(spell.SpellId, cellId); return(SpellCastingResults.CASTED); } // We need to move else { _account.Logger.LogDebug(LanguageManager.Translate("52"), LanguageManager.Translate("63", fromCellId, spell.SpellName)); // Set the spell to cast _spellIdToCast = spell.SpellId; _targetCellId = cellId; _ennemiesTouched = touchedEnnemies; await _account.Game.Managers.Movements.MoveToCellInFight(node); return(SpellCastingResults.MOVED); } } return(SpellCastingResults.NOT_CASTED); }