예제 #1
0
 public Drop(Item item, MapObject dropper, int x, int y, int secondsToLive)
 {
     Item = new DroppedItem(item);
     DroppedBy = dropper;
     Position = new Vector2(x, y);
     Expire = Program.CurrentTime.AddSeconds(secondsToLive);
     CanTake = true;
 }
예제 #2
0
 public AttackSequence(MapObject att, uint min, uint max, ushort skillid, uint x = (uint) 0, uint y = (uint) 0)
     : this(att, null, min, max, skillid, true)
 {
     this.x = x;
     this.y = y;
     this.nextAction = Program.CurrentTime.AddMilliseconds(skillInfo.CastTime);
     this.State = AnimationState.AoEShow;
 }
예제 #3
0
 public AttackSequence(MapObject att, MapObject vict, uint min, uint max, ushort skillid, bool derp)
     : this(att, vict, min, max, 0)
 {
     this.skillid = skillid;
     this.minDamage += skillInfo.MinDamage;
     this.maxDamage += skillInfo.MaxDamage;
     this.x = 0;
     this.y = 0;
 }
예제 #4
0
        private MapObject to; // Could be a player too (PvP or EvP)

        #endregion Fields

        #region Constructors

        public AttackSequence_(MapObject from, MapObject to, ushort skill = (ushort) 0xFFFF, ushort attackspeed = (ushort) 1400)
        {
            this.from = from;
            this.to = to;
            toID = to.MapObjectID;
            State = AnimationState.Running;
            nextSequence = Program.CurrentTime;
            attackSpeed = attackspeed;
            skillid = skill;
        }
예제 #5
0
 public AttackSequence(MapObject att, MapObject vict, uint min, uint max, ushort attackspeed)
 {
     this.State = AnimationState.Starting;
     this.attacker = att;
     this.victim = vict;
     this.minDamage = min;
     this.maxDamage = max;
     this.attackspeed = attackspeed;
     this.nextAction = Program.CurrentTime;
     this.skillid = NoSkill;
     this.animationID = att.UpdateCounter;
     this.State = AnimationState.Running;
 }
예제 #6
0
        public static void SendAttackAnimation(MapObject from, ushort objectID, ushort attackspeed, byte stance)
        {
            using (var packet = new Packet(SH9Type.AttackAnimation))
            {
                packet.WriteUShort(from.MapObjectID);
                packet.WriteUShort(objectID);
                packet.WriteByte(stance);

                packet.WriteUShort(attackspeed);

                packet.WriteByte(4);
                packet.WriteByte(100);
                from.MapSector.Broadcast(packet);
            }
        }
예제 #7
0
        public static void SendAttackDamage(MapObject from, ushort objectID, ushort damage, bool crit, uint hpleft, ushort counter)
        {
            using (var packet = new Packet(SH9Type.AttackDamage))
            {
                packet.WriteUShort(from.MapObjectID);
                packet.WriteUShort(objectID);
                packet.WriteBool(crit);
                packet.WriteUShort(damage);
                packet.WriteUInt(hpleft);
                packet.WriteUShort(counter);
                packet.WriteByte(4);
                packet.WriteByte(100);

                from.MapSector.Broadcast(packet);
            }
        }
예제 #8
0
 public static Packet RemoveObject(MapObject obj)
 {
     Packet packet = new Packet(SH7Type.RemoveObject);
     packet.WriteUShort(obj.MapObjectID);
     return packet;
 }
예제 #9
0
 public static void SendStatsUpdate(MapObject pObject, ZoneClient to, bool selectedby)
 {
     using (var packet = new Packet(SH9Type.StatUpdate))
     {
         packet.WriteBool(selectedby);
         packet.WriteUShort(pObject.MapObjectID);
         if (pObject is ZoneCharacter)
         {
             ((ZoneCharacter)pObject).WriteUpdateStats(packet);
         }
         else
         {
             ((Mob)pObject).WriteUpdateStats(packet);
         }
         to.SendPacket(packet);
     }
 }
예제 #10
0
 public virtual void AttackSkill(ushort skillid, MapObject victim)
 {
     if (victim != null && !victim.IsAttackable) return;
 }
예제 #11
0
        public override void AttackSkill(ushort skillid, MapObject victim)
        {
            if (victim == null)
            {
                victim = SelectedObject;
            }

            if (IsAttacking || victim == null || !victim.IsAttackable) return;

            Item weapon;
            this.Inventory.GetEquiptBySlot((byte)ItemSlot.Weapon, out weapon);
            uint dmgmin = (uint)GetWeaponDamage(true);
            uint dmgmax = (uint)(GetWeaponDamage(true) + (GetWeaponDamage(true) % 3));
            if (weapon != null)
            {
                dmgmin += weapon.ItemInfo.MinMelee;
                dmgmax += weapon.ItemInfo.MaxMelee;
            }

            attackingSequence = new AttackSequence(this, victim, dmgmin, dmgmax, skillid, true);
        }
예제 #12
0
        public override void AttackSkill(ushort skillid, MapObject victim)
        {
            base.AttackSkill(skillid, victim); // lol

            if (AttackingSequence != null) return;
            AttackingSequence = new AttackSequence(this, victim, 0, InfoServer.Str, skillid, true);
            Target = victim;
        }
예제 #13
0
        public void Update(DateTime now)
        {
            if (this.State == AnimationState.Ended) return;
            if (this.attacker == null || this.attacker.IsDead)
            {
                this.State = AnimationState.Ended;
                return;
            }
            if (!IsAoE && (this.victim == null || this.victim.IsDead))
            {
                this.State = AnimationState.Ended;
                return;
            }
            if (this.nextAction > now) return;

            if (IsSkill)
            {
                if (IsAoE)
                {
                    if (this.State == AnimationState.AoEShow)
                    {
                        Handler9.SendSkillPosition(attacker, animationID, skillid, x, y);
                        Handler9.SendSkillAnimationForPlayer(attacker, skillid, animationID);
                        this.nextAction = Program.CurrentTime.AddMilliseconds(skillInfo.SkillAniTime);
                        this.State = AnimationState.AoEDo;
                    }
                    else if (this.State == AnimationState.AoEDo)
                    {
                        // Lets create an AoE skill @ X Y
                        List<SkillVictim> victims = new List<SkillVictim>();
                        var pos = new Vector2((int)x, (int)y);
                        // Find victims
                        foreach (var v in attacker.Map.GetObjectsBySectors(attacker.MapSector.SurroundingSectors))
                        {
                            if (attacker == v) continue;
                            if (v is ZoneCharacter) continue;
                            if (Vector2.Distance(v.Position, pos) > skillInfo.Range) continue;
                            // Calculate dmg

                            uint dmg = (uint)Program.Randomizer.Next((int)minDamage, (int)maxDamage);
                            if (dmg > v.HP)
                            {
                                v.HP = 0;
                            }

                            if (!v.IsDead)
                            {
                                v.Attack(attacker);
                            }
                            else
                            {
                                if (v is Mob && attacker is ZoneCharacter)
                                {
                                    uint exp = (v as Mob).InfoServer.MonExp;
                                    (attacker as ZoneCharacter).GiveExp(exp, v.MapObjectID);
                                }
                            }

                            victims.Add(new SkillVictim(v.MapObjectID, dmg, v.HP, 0x01, 0x01, v.UpdateCounter));
                            if (victims.Count == skillInfo.MaxTargets) break;
                        }

                        Handler9.SendSkill(attacker, animationID, victims);
                        foreach (var v in victims)
                        {
                            if (v.HPLeft == 0)
                            {
                                Handler9.SendDieAnimation(attacker, v.MapObjectID);
                            }
                        }

                        victims.Clear();
                        State = AnimationState.Ended;
                    }
                }
                else
                {
                    // Normal skill parsing
                    State = AnimationState.Ended;
                }
            }
            else
            {
                // Just attacking...
                if (victim == null || victim.IsDead)
                {
                    victim = null;
                    attacker = null;
                    State = AnimationState.Ended;
                }
                else
                {
                    // Calculate some damage to do
                    ushort dmg = (ushort)Program.Randomizer.Next((int)minDamage, (int)maxDamage);
                    if (dmg > victim.HP)
                    {
                        victim.HP = 0;
                    }
                    bool crit = Program.Randomizer.Next() % 100 >= 80;
                    byte stance = (byte)(Program.Randomizer.Next(0, 3));
                    victim.Damage(attacker, dmg);
                    Handler9.SendAttackAnimation(attacker, victim.MapObjectID, attackspeed, stance);
                    Handler9.SendAttackDamage(attacker, victim.MapObjectID, dmg, crit, victim.HP, victim.UpdateCounter);

                    if (victim.IsDead)
                    {
                        if (victim is Mob && attacker is ZoneCharacter)
                        {
                            uint exp = (victim as Mob).InfoServer.MonExp;
                            (attacker as ZoneCharacter).GiveExp(exp, victim.MapObjectID);
                        }

                        Handler9.SendDieAnimation(attacker, victim.MapObjectID);
                        victim = null;
                        State = AnimationState.Ended;
                    }
                    else
                    {
                        nextAction = now.AddMilliseconds(attackspeed);
                    }
                }
            }
        }
예제 #14
0
 public static void SendDieAnimation(MapObject from, ushort objectID)
 {
     // DO NOT SEND THIS TO THE DYING PLAYER, LOL
     using (var packet = new Packet(SH9Type.DieAnimation))
     {
         packet.WriteUShort(objectID);
         packet.WriteUShort(from.MapObjectID);
         from.MapSector.Broadcast(packet, objectID);
     }
 }
예제 #15
0
 public static void SendSkill(MapObject user, ushort animid, ushort victimid, uint damage, uint newhp, ushort counter, byte special1 = (byte) 0x10, byte special2 = (byte) 0x00)
 {
     // 9 82 | [E5 3F] [8A 27] [01] [8A 27] [10 00] [09 00 00 00] [5E 00 00 00] [A7 4C]
     // 9 82 | [9A 35] [8A 27] [01] [C2 05] [10 00] [0A 00 00 00] [1D 01 00 00] [73 37]
     // 9 82 | [43 3C] [42 15] [01] [AC 4C] [01 01] [7A 02 00 00] [00 00 00 00] [35 09]
     // 9 82 | [0E 39] [42 15] [01] [00 4A] [21 01] [1C 03 00 00] [00 00 00 00] [8C 0E]
     using (var packet = new Packet(SH9Type.SkillAnimationTarget))
     {
         packet.WriteUShort(animid);
         packet.WriteUShort(user.MapObjectID);
         packet.WriteBool(true);
         packet.WriteUShort(victimid);
         packet.WriteByte(special1);
         packet.WriteByte(special2);
         packet.WriteUInt(damage);
         packet.WriteUInt(newhp);
         packet.WriteUShort(counter);
         user.MapSector.Broadcast(packet);
     }
 }
예제 #16
0
        public void Transfer(MapObject obj, Sector to)
        {
            Objects.Remove(obj.MapObjectID);
            to.AddObject(obj);
            // we remove object first to the 'non display region'
            ZoneCharacter character  = obj as ZoneCharacter;
            List <Sector> oldsectors = Map.GetSectorsOutOfRange(this, to);

            // The idea of this function
            // 1. Remove obj from map for players that are out of range
            // (IF PLAYER) 2. Remove objects that are out of range for obj
            // (IF PLAYER) 3. Spawn objects that are new in range for obj
            // 4. Spawn obj for all players in new range

            using (var removeObjPacket = Handler7.RemoveObject(obj))             // Make new packet to remove object from map for others
            {
                // Even nederlands: Kijken of we mensen kunnen vinden in range?
                foreach (var victimObject in Map.GetObjectsBySectors(oldsectors))
                {
                    if (victimObject is Npc)
                    {
                        continue;                                          // NPC's are for noobs. Can't despawn
                    }
                    if (victimObject is ZoneCharacter)
                    {
                        // Remove obj for player
                        ZoneCharacter victim = victimObject as ZoneCharacter;
                        victim.Client.SendPacket(removeObjPacket);
                    }

                    if (character != null)
                    {
                        // Despawn victimObject for obj
                        using (var removeVictimPacket = Handler7.RemoveObject(victimObject))
                        {
                            character.Client.SendPacket(removeVictimPacket);
                        }
                    }
                }
            }

            //we remove all the drops out of the character's region
            if (character != null && character.Client != null)
            {
                foreach (var dropoutofrange in Map.GetDropsBySectors(oldsectors))
                {
                    using (var despawndrop = Handler6.RemoveDrop(dropoutofrange))
                    {
                        character.Client.SendPacket(despawndrop);
                    }
                }
            }


            //now we spawn the object to other objects in map

            List <Sector>    newsectors = Map.GetSectorsNewInRange(this, to);
            List <MapObject> objects    = Map.GetObjectsBySectors(newsectors);

            using (var packet = obj.Spawn())
            {
                foreach (var mapObject in objects)
                {
                    if (mapObject is Npc)
                    {
                        continue;                                  //we don't respawn NPCs
                    }
                    if (mapObject is ZoneCharacter)
                    {
                        ZoneCharacter rangechar = mapObject as ZoneCharacter;

                        // Send spawn packet of the object (can be both a character and mob) to mapObject (a player)
                        rangechar.Client.SendPacket(packet);
                    }
                    if (character != null)
                    {
                        // Send spawn packet of mapObject to character
                        using (var spawn = mapObject.Spawn())
                        {
                            character.Client.SendPacket(spawn);
                        }
                    }
                }
            }

            if (character != null && character.Client != null)
            {
                using (var spawndrops = Handler7.ShowDrops(Map.GetDropsBySectors(newsectors)))
                {
                    character.Client.SendPacket(spawndrops);
                }
            }
        }
예제 #17
0
        private void Handle()
        {
            if (to != null)
            {
                ushort seed = (ushort)Program.Randomizer.Next(0, 100); //we use one seed & base damage on it

                ushort damage = (ushort)Program.Randomizer.Next(0, seed);
                bool crit = seed >= 80;
                stance = (byte)(Program.Randomizer.Next(0, 3));
                to.Damage(from, damage);
                Handler9.SendAttackAnimation(from, toID, attackSpeed, stance);
                Handler9.SendAttackDamage(from, toID, damage, crit, GetHPLeft(), to.UpdateCounter);

                if (to.IsDead)
                {
                    if (to is Mob && from is ZoneCharacter)
                    {
                        uint exp = (to as Mob).InfoServer.MonExp;
                        (from as ZoneCharacter).GiveExp(exp, toID);
                    }
                    Handler9.SendDieAnimation(from, toID);
                    State = AnimationState.Ended;
                    to = null;
                }
                else
                {
                    SetNewSequenceTime(attackSpeed);
                }
            }
        }
예제 #18
0
        public virtual void Damage(MapObject bully, uint amount, bool isSP = false)
        {
            if (isSP)
            {
                if (SP < amount) SP = 0;
                else SP -= amount;
            }
            else
            {
                if (HP < amount) HP = 0;
                else HP -= amount;
            }

            if (bully == null)
            {
                if (this is ZoneCharacter)
                {
                    ZoneCharacter character = this as ZoneCharacter;
                    if (isSP)
                        Handler9.SendUpdateSP(character);
                    else
                        Handler9.SendUpdateHP(character);
                }
            }
            else
            {
                if (this is Mob && ((Mob)this).AttackingSequence == null)
                {
                    this.Attack(bully);
                }
                else if (this is ZoneCharacter && !((ZoneCharacter)this).IsAttacking)
                {
                    this.Attack(bully);
                }
            }
        }
예제 #19
0
 public static Packet MoveObject(MapObject obj, int oldx, int oldy, bool walk, ushort speed = (ushort) 115)
 {
     Packet packet = new Packet(walk ? SH8Type.Walk : SH8Type.Move);
     packet.WriteUShort(obj.MapObjectID);
     packet.WriteInt(oldx);
     packet.WriteInt(oldy);
     packet.WriteInt(obj.Position.X);
     packet.WriteInt(obj.Position.Y);
     packet.WriteUShort(speed);
     return packet;
 }
예제 #20
0
        public override void Attack(MapObject victim)
        {
            base.Attack(victim); // lol

            if (AttackingSequence != null) return;
            AttackingSequence = new AttackSequence(this, victim, 0, InfoServer.Str, 1400);
            Target = victim;
        }
예제 #21
0
 public static Packet StopObject(MapObject obj)
 {
     Packet packet = new Packet(SH8Type.StopTele);
     packet.WriteUShort(obj.MapObjectID);
     packet.WriteInt(obj.Position.X);
     packet.WriteInt(obj.Position.Y);
     return packet;
 }
예제 #22
0
 public bool FinalizeAdd(MapObject obj)
 {
     Sector sector = GetSectorByPos(obj.Position);
     sector.AddObject(obj, true);
     return Objects.TryAdd(obj.MapObjectID, obj);
 }
예제 #23
0
 public static void SendSkill(MapObject user, ushort animid, List<SkillVictim> victims)
 {
     using (var packet = new Packet(SH9Type.SkillAnimationTarget))
     {
         packet.WriteUShort(animid);
         packet.WriteUShort(user.MapObjectID);
         packet.WriteByte((byte)(victims.Count > 255 ? 255 : victims.Count));
         for (byte i = 0; i < victims.Count && i != 255; i++)
         {
             var victim = victims[i];
             packet.WriteUShort(victim.MapObjectID);
             packet.WriteByte(victim.Stance1);
             packet.WriteByte(victim.Stance2);
             packet.WriteUInt(victim.Damage);
             packet.WriteUInt(victim.HPLeft);
             packet.WriteUShort(victim.HPCounter);
         }
         user.MapSector.Broadcast(packet);
     }
 }
예제 #24
0
 public virtual void Attack(MapObject victim)
 {
     if (victim != null && !victim.IsAttackable) return;
 }
예제 #25
0
 public static void SendSkillAnimationForPlayer(MapObject user, ushort skillid, ushort animid)
 {
     // 9 87 | [E5 3F] [8A 27] [04 06]
     // 9 87 | [97 2D] [9A 26] [06 06]
     using (var packet = new Packet(SH9Type.SkillAnimation))
     {
         packet.WriteUShort(animid);
         packet.WriteUShort(user.MapObjectID);
         packet.WriteUShort(skillid);
         user.MapSector.Broadcast(packet);
     }
 }
예제 #26
0
 public static void SendSkillNoVictim(MapObject user, ushort animid)
 {
     // 9 82 | [75 70] [32 29] [00]
     using (var packet = new Packet(SH9Type.SkillAnimationTarget))
     {
         packet.WriteUShort(animid);
         packet.WriteUShort(user.MapObjectID);
         packet.WriteBool(false);
         user.MapSector.Broadcast(packet);
     }
 }
예제 #27
0
 public bool AssignObjectID(MapObject obj)
 {
     bool result = false;
     lock (availableLifeKeys)
     {
         if (availableLifeKeys.Count == 0)
         {
             if (lifeIndexer == ushort.MaxValue)
             {
                 Log.WriteLine(LogLevel.Warn, "Map is having map object id overflow (cannot handler more than {0})", ushort.MaxValue);
                 result = false;
             }
             else
             {
                 ushort key = lifeIndexer;
                 ++lifeIndexer;
                 obj.MapObjectID = key;
                 result = true;
             }
         }
         else
         {
             ushort key = availableLifeKeys.Dequeue();
             obj.MapObjectID = key;
             result = true;
         }
         if (result)
             obj.Map = this;
         return result;
     }
 }
예제 #28
0
 public static void SendSkillPosition(MapObject user, ushort animid, ushort skillid, uint x, uint y)
 {
     // 9 81 | [32 29] [B8 10] [56 0A 00 00] [3A 27 00 00] [75 70]
     using (var packet = new Packet(SH9Type.SkillAnimationPosition))
     {
         packet.WriteUShort(user.MapObjectID);
         packet.WriteUShort(skillid);
         packet.WriteUInt(x);
         packet.WriteUInt(y);
         packet.WriteUShort(animid);
         user.MapSector.Broadcast(packet);
     }
 }
예제 #29
0
 public bool FullAddObject(MapObject obj)
 {
     Log.WriteLine(LogLevel.Debug, "Added {0} to the map.", obj.GetType().ToString());
     if (AssignObjectID(obj))
     {
         return FinalizeAdd(obj);
     }
     else return false;
 }
예제 #30
0
 public static void SendSkillStartOthers(MapObject user, ushort skillid, ushort victim, ushort animid)
 {
     // 9 79 | [9A 26] [06 06] [8A 27] [97 2D]
     using (var packet = new Packet(SH9Type.SkillUsePrepareOthers))
     {
         packet.WriteUShort(user.MapObjectID);
         packet.WriteUShort(skillid);
         packet.WriteUShort(victim);
         packet.WriteUShort(animid);
         user.MapSector.Broadcast(packet, user.MapObjectID);
     }
 }
예제 #31
0
 public override void Damage(MapObject bully, uint amount, bool isSP = false)
 {
     base.Damage(bully, amount, isSP);
     if (IsDead)
     {
         State = PlayerState.Dead;
         Handler4.SendReviveWindow(this.Client, 3);
     }
 }
예제 #32
0
        public void Update(DateTime now)
        {
            if (State == AnimationState.Ended)
            {
                return;
            }
            if (attacker == null || attacker.IsDead)
            {
                State = AnimationState.Ended;
                return;
            }

            if (!IsAoE && (victim == null || victim.IsDead))
            {
                State = AnimationState.Ended;
                return;
            }

            if (nextAction > now)
            {
                return;
            }

            if (IsSkill)
            {
                if (IsAoE)
                {
                    if (State == AnimationState.AoEShow)
                    {
                        Handler9.SendSkillPosition(attacker, animationID, skillid, x, y);
                        Handler9.SendSkillAnimationForPlayer(attacker, skillid, animationID);
                        nextAction = Program.CurrentTime.AddMilliseconds(skillInfo.SkillAniTime);
                        State      = AnimationState.AoEDo;
                    }
                    else if (State == AnimationState.AoEDo)
                    {
                        // Lets create an AoE skill @ X Y
                        var victims = new List <SkillVictim>();
                        var pos     = new Vector2((int)x, (int)y);
                        // Find victims
                        foreach (var v in attacker.Map.GetObjectsBySectors(attacker.MapSector.SurroundingSectors))
                        {
                            if (attacker == v)
                            {
                                continue;
                            }
                            if (v is ZoneCharacter)
                            {
                                continue;
                            }
                            if (Vector2.Distance(v.Position, pos) > skillInfo.Range)
                            {
                                continue;
                            }
                            // Calculate dmg

                            var dmg = (uint)Program.Randomizer.Next((int)minDamage, (int)maxDamage);
                            if (dmg > v.HP)
                            {
                                v.HP = 0;
                            }

                            if (!v.IsDead)
                            {
                                v.Attack(attacker);
                            }
                            else
                            {
                                if (v is Mob && attacker is ZoneCharacter)
                                {
                                    var exp = (v as Mob).InfoServer.MonExp;
                                    (attacker as ZoneCharacter).GiveExp(exp, v.MapObjectID);
                                }
                            }

                            victims.Add(new SkillVictim(v.MapObjectID, dmg, v.HP, 0x01, 0x01, v.UpdateCounter));
                            if (victims.Count == skillInfo.MaxTargets)
                            {
                                break;
                            }
                        }

                        Handler9.SendSkill(attacker, animationID, victims);
                        foreach (var v in victims)
                        {
                            if (v.HPLeft == 0)
                            {
                                Handler9.SendDieAnimation(attacker, v.MapObjectID);
                            }
                        }

                        victims.Clear();
                        State = AnimationState.Ended;
                    }
                }
                else
                {
                    // Normal skill parsing
                    State = AnimationState.Ended;
                }
            }
            else
            {
                // Just attacking...
                if (victim == null || victim.IsDead)
                {
                    victim   = null;
                    attacker = null;
                    State    = AnimationState.Ended;
                }
                else
                {
                    // Calculate some damage to do
                    var dmg = (ushort)Program.Randomizer.Next((int)minDamage, (int)maxDamage);
                    if (dmg > victim.HP)
                    {
                        victim.HP = 0;
                    }

                    var crit   = Program.Randomizer.Next() % 100 >= 80;
                    var stance = (byte)Program.Randomizer.Next(0, 3);
                    victim.Damage(attacker, dmg);
                    Handler9.SendAttackAnimation(attacker, victim.MapObjectID, attackspeed, stance);
                    Handler9.SendAttackDamage(attacker, victim.MapObjectID, dmg, crit, victim.HP, victim.UpdateCounter);

                    if (victim.IsDead)
                    {
                        if (victim is Mob && attacker is ZoneCharacter)
                        {
                            var exp = (victim as Mob).InfoServer.MonExp;
                            (attacker as ZoneCharacter).GiveExp(exp, victim.MapObjectID);
                        }

                        Handler9.SendDieAnimation(attacker, victim.MapObjectID);
                        victim = null;
                        State  = AnimationState.Ended;
                    }
                    else
                    {
                        nextAction = now.AddMilliseconds(attackspeed);
                    }
                }
            }
        }