public List <short> GetSpellRange(short characterCellId, SpellLevels spellLevel) { List <short> range = new List <short>(); foreach (var mp in SpellShapes.GetSpellRange(characterCellId, spellLevel, _account.Game.Character.Stats.Range.Total)) { if (mp == null || range.Contains(mp.CellId)) { continue; } if (spellLevel.NeedFreeCell && OccupiedCells.Contains(mp.CellId)) { continue; } if ((_account.Game.Map.Data.Cells[mp.CellId].l & 7) == 3) { range.Add(mp.CellId); } } if (spellLevel.CastTestLos) { for (int i = range.Count - 1; i >= 0; i--) { if (Dofus1Line.IsLineObstructed(_account.Game.Map.Data, characterCellId, range[i], OccupiedCells, spellLevel.CastInDiagonal)) { range.RemoveAt(i); } } } return(range); }
public bool SpellIsHittingAnyEnnemy(short fromCellId, SpellLevels spellLevel) { foreach (short spellCell in _account.Game.Fight.GetSpellRange(fromCellId, spellLevel)) { foreach (var ennemy in _account.Game.Fight.Ennemies) { // This ennemy is in range if (spellCell == ennemy.CellId) { return(true); } } } return(false); }
private static Zone GetZoneEffect(SpellLevels spellLevel) { Zone zoneEffect = null; int ray = 63; for (int i = 0; i < spellLevel.Effects.Count; i++) { if (spellLevel.Effects[i]["rawZone"] != null) { var ze = ZonesUtility.ParseZone(spellLevel.Effects[i]["rawZone"].ToString()); if (ze.ZoneSize > 0 && ze.ZoneSize < ray) { ray = ze.ZoneSize; zoneEffect = ze; } } } return(zoneEffect != null ? zoneEffect : ZonesUtility.ParseZone("P")); }
private async Task <SpellCastingResults> CastSpellOnEmptyCell(Spell spell) { if (_account.Game.Fight.CanLaunchSpell(spell.SpellId) != SpellInabilityReasons.NONE) { return(SpellCastingResults.NOT_CASTED); } // In case we need to cast the spell on an empty case next to the character but all of them are taken if (spell.Target == SpellTargets.EMPTY_CELL && _account.Game.Fight.GetHandToHandEnnemies().Count() == 4) { 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]); var range = _account.Game.Fight.GetSpellRange(_account.Game.Fight.PlayedFighter.CellId, spellLevel); for (int i = 0; i < range.Count; i++) { if (_account.Game.Fight.CanLaunchSpell(spell.SpellId, _account.Game.Fight.PlayedFighter.CellId, range[i]) == SpellInabilityReasons.NONE) { if (spell.HandToHand && MapPoint.FromCellId(range[i]).DistanceToCell(MapPoint.FromCellId(_account.Game.Fight.PlayedFighter.CellId)) != 1) { continue; } _account.Logger.LogDebug(LanguageManager.Translate("52"), LanguageManager.Translate("64", spell.SpellName, range[i])); await _account.Game.Fight.LaunchSpell(spell.SpellId, range[i]); return(SpellCastingResults.CASTED); } } // We need to move return(await MoveToCastSpellOnEmptyCell(spell, spellLevel)); }
public static IEnumerable <MapPoint> GetSpellRange(short sourceCellId, SpellLevels spellLevel, int additionalRange = 0) { var mp = MapPoint.FromCellId(sourceCellId); int range = spellLevel.Range + (spellLevel.RangeCanBeBoosted ? additionalRange : 0); if (spellLevel.CastInLine && spellLevel.CastInDiagonal) { return(Shaper.ShapeCross(mp.X, mp.Y, spellLevel.MinRange, range) .Union(Shaper.ShapeStar(mp.X, mp.Y, spellLevel.MinRange, range))); } else if (spellLevel.CastInDiagonal) { return(Shaper.ShapeStar(mp.X, mp.Y, spellLevel.MinRange, range)); } else if (spellLevel.CastInLine) { return(Shaper.ShapeCross(mp.X, mp.Y, spellLevel.MinRange, range)); } else { return(Shaper.ShapeRing(mp.X, mp.Y, spellLevel.MinRange, range)); } }
public static List <MapPoint> GetSpellEffectZone(Map map, SpellLevels spellLevel, short casterCellId, short targetCellId) { List <MapPoint> zone = new List <MapPoint>(); Zone effect = GetZoneEffect(spellLevel); var shaper = Shaper.ShaperMap[effect.ZoneShape]; if (shaper == null) { zone.Add(MapPoint.FromCellId(targetCellId)); return(zone); } var targetCoords = MapPoint.FromCellId(targetCellId); int dirX = 0, dirY = 0; if (shaper.HasDirection) { var casterCoords = MapPoint.FromCellId(casterCellId); dirX = targetCoords.X == casterCoords.X ? 0 : targetCoords.X > casterCoords.X ? 1 : -1; dirY = targetCoords.Y == casterCoords.Y ? 0 : targetCoords.Y > casterCoords.Y ? 1 : -1; } var radiusMin = shaper.WithoutCenter ? (effect.ZoneMinSize == 0 ? 1 : effect.ZoneMinSize): effect.ZoneMinSize; var rangeCoords = shaper.Fn(targetCoords.X, targetCoords.Y, radiusMin, effect.ZoneSize, dirX, dirY); foreach (var mp in rangeCoords) { if (map.Cells[mp.CellId].IsWalkable(true)) { zone.Add(mp); } } return(zone); }
public List <MapPoint> GetSpellZone(int spellId, short fromCellId, short targetCellId, SpellLevels spellLevel = null) { if (spellLevel == null) { var spellEntry = _account.Game.Character.GetSpell(spellId); if (spellEntry == null) { return(null); } var spell = DataManager.Get <Spells>(spellId); if (spell == null) { return(null); } spellLevel = DataManager.Get <SpellLevels>(spell.SpellLevels[spellEntry.Level - 1]); } return(SpellShapes.GetSpellEffectZone(_account.Game.Map.Data, spellLevel, fromCellId, targetCellId)); }
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); }
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 byte GetTouchedEnnemiesCount(short fromCellId, short targetCellId, Spell spell, SpellLevels spellLevel) { byte n = 0; var zone = _account.Game.Fight.GetSpellZone(spell.SpellId, fromCellId, targetCellId, spellLevel); if (zone != null) { for (int i = 0; i < zone.Count; i++) { // Check self if (spell.CarefulAOE && zone[i].CellId == fromCellId) { return(0); } // Check ally if (spell.AvoidAllies) { foreach (var ally in _account.Game.Fight.Allies) { if (ally.CellId == zone[i].CellId) { return(0); } } } foreach (var ennemy in _account.Game.Fight.Ennemies) { if (ennemy.CellId == zone[i].CellId) { n++; } } } } return(n); }
private RangeNodeEntry GetRangeNodeEntry(short fromCellId, MoveNode node, Spell spell, SpellLevels spellLevel) { // Calculate touched ennemies for every cell in SpellRange Dictionary <short, byte> touchedEnnemiesByCell = new Dictionary <short, byte>(); var range = _account.Game.Fight.GetSpellRange(fromCellId, spellLevel); for (int i = 0; i < range.Count; i++) { byte tec = GetTouchedEnnemiesCount(fromCellId, range[i], spell, spellLevel); if (tec > 0) { touchedEnnemiesByCell.Add(range[i], tec); } } return(new RangeNodeEntry(fromCellId, touchedEnnemiesByCell, node)); }