示例#1
0
        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);
        }
示例#2
0
        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);
        }
示例#3
0
        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"));
        }
示例#4
0
        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));
        }
示例#5
0
        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));
            }
        }
示例#6
0
        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);
        }
示例#7
0
        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));
        }
示例#8
0
        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);
        }
示例#9
0
        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);
        }
示例#10
0
        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);
        }
示例#11
0
        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));
        }