示例#1
0
        private object _looterIdSyncLock = new object(); // Clients could try to loot at the same time (frequently do, actually)

        #endregion Fields

        #region Constructors

        /// <summary>For use with NPC mobs.</summary>
        /// <param name="mob">Mob that died.</param>
        /// <param name="decayTime">Miliseconds until corpse decay.</param>
        /// <param name="lootItems">Items which will be part of the corpse's loot.</param>
        internal Corpse(Mob mob, List<InventoryItem> lootItems)
            : base(mob.ID, mob.Name.RemoveDigits() + "'s corpse" + mob.ID.ToString(), "", mob.X, mob.Y, mob.Z, mob.Heading)
        {
            if (lootItems != null)
                _lootItems.AddRange(lootItems);
            this.Platinum = mob.Platinum;
            this.Gold = mob.Gold;
            this.Silver = mob.Silver;
            this.Copper = mob.Copper;

            _changed = false;

            if (IsEmpty())
                _decayTimer = new SimpleTimer(DECAYMS_EMPTY_NPC_CORPSE);
            else
                _decayTimer = new SimpleTimer(mob.Level > 54 ? DECAYMS_BOSS_NPC_CORPSE : DECAYMS_NPC_CORPSE);

            _gender = mob.Gender;
            _race = mob.Race;
            _bodyType = mob.BodyType;
            _size = mob.Size;
            _texture = mob.Texture;
            _helmTexture = mob.HelmTexture;
        }
示例#2
0
 /// <summary>Removes the mob from all of the mobs's hate list.</summary>
 internal void RemoveFromAllHateLists(Mob mob)
 {
     _mobsListLock.EnterReadLock();
     try {
         foreach (Mob m in this.AllMobs)
             m.HateMgr.RemoveHate(mob);
     }
     catch (Exception ex) {
         _log.Error("Error removing a mob from hate lists in the mob mgr... ", ex);
     }
     finally {
         _mobsListLock.ExitReadLock();
     }
 }
示例#3
0
        protected override bool IsAbleToAttack(Mob target, bool spellAttack)
        {
            if (!base.IsAbleToAttack(target, spellAttack))
                return false;

            // TODO: check if we're trying to beat on our pet (not allowed)

            // TODO: handle dueling
            if (target is ZonePlayer)
                return false;

            return true;
        }
示例#4
0
        /// <summary>Make sure to check if able to attack prior to calling as this routine doesn't check if we're able to attack.</summary>
        /// <returns>False if the attack isn't allowed or did not succeed, true if attack successful.</returns>
        internal override bool MeleeAttack(Mob target, bool isPrimaryHand, bool riposte)
        {
            if (!base.MeleeAttack(target, isPrimaryHand, riposte))
                return false;

            // Are we using a weapon?
            Item weapon = isPrimaryHand ? this.GetEquipment(EquipableType.Primary) : this.GetEquipment(EquipableType.Secondary);
            if (weapon != null) {
                if (!weapon.IsWeapon) {
                    _log.DebugFormat("Attack cancelled: {0} is not a weapon.", weapon.Name);
                    return false;
                }
            }

            // Cool, so we're going to attack
            // First calculate the skill and animation to use
            Skill attackSkill;
            AttackAnimation attackAnim;
            GetSkillAndAnimForAttack(weapon, isPrimaryHand, out attackSkill, out attackAnim);
            OnAnimation(new AnimationEventArgs(attackAnim));    // Cue the animation
            //_log.DebugFormat("Attacking {0} with {1} in slot {2} using skill {3}", this.TargetMob.Name, weapon == null ? "Fist" : weapon.Name,
            //    isPrimaryHand ? "Primary" : "Secondary", attackSkill.ToString("f"));

            // Next figure out the potential damage
            int potDamage =  GetWeaponDamage(target, weapon);
            int damage = 0;
            //_log.DebugFormat("Potential damage calculated as {0}", potDamage);

            // If potential damage is more than zero we know it's POSSIBLE to hit the target
            if (potDamage > 0) {
                // TODO: Finishing blow attempt

                CheckForSkillUp(attackSkill, target, -5);
                CheckForSkillUp(Skill.Offense, target, -5);

                // Ok, so we know we CAN hit... let's see if we DO hit
                if (target.TryToHit(this, attackSkill, isPrimaryHand)) {
                    // TODO: Augment potDamage with any Beserker damage bonuses

                    int minHitDmg = 1;
                    int maxHitDmg = this.GetMaxDamage(potDamage, attackSkill);

                    // Level cap the damage
                    if (this.Level < 10)
                        maxHitDmg = Math.Min(maxHitDmg, 20);
                    else if (this.Level < 20)
                        maxHitDmg = Math.Min(maxHitDmg, 40);

                    // TODO: apply damage bonuses (affects min and max dmg as well as hate)

                    // TODO: adjust min damage with any applicable item or buff bonuses

                    maxHitDmg = Math.Max(maxHitDmg, minHitDmg);     // Ensure max is at least min

                    Random rand = new Random();
                    damage = rand.Next(minHitDmg, maxHitDmg + 1);
                    //_log.DebugFormat("Damage calculated to {0} (min {1}, max {2}, str {3}, skill {4}, pot dmg {5}, lvl {6})", damage, minHitDmg,
                    //    maxHitDmg, this.STR, GetSkillLevel(attackSkill), potDamage, this.Level);

                    // With damage now calculated, see if the mob can avoid or mitigate
                    damage = target.TryToAvoidDamage(this, damage);

                    if (damage > 0) {
                        damage = target.TryToMitigateDamage(this, damage, minHitDmg);   // wasn't avoided, try to mitigate
                        // TODO: apply any damage bonuses (is this the right term... bonuses?... wasn't that done by now?
                        // TODO: try a critical hit (why are we trying this after the mitigation?)
                    }

                    //_log.DebugFormat("Damage after avoidance and mitigation: {0}", damage);
                }
                else {
                    // We missed
                    //_log.Debug("Missed.");
                }

                // TODO: riposte

                // TODO: strikethrough
            }
            else
                damage = (int)AttackAvoidanceType.Invulnerable;

            target.Damage(this, damage, 0, attackSkill);    // Send attack damage - even zero and negative damage

            BreakSneakiness();

            // TODO: weapon procs

            if (damage > 0) {
                // TODO: handle lifetap effects?

                // TODO: trigger defensive procs

                return true;
            }
            else
                return false;
        }
示例#5
0
        protected override bool IsAbleToAttack(Mob target, bool spellAttack)
        {
            if (!base.IsAbleToAttack(target, spellAttack))
                return false;

            // TODO: handle attacking another NPC?

            return true;
        }
示例#6
0
        internal override bool MeleeAttack(Mob target, bool isPrimaryHand, bool riposte)
        {
            if (!base.MeleeAttack(target, isPrimaryHand, riposte))
                return false;

            FaceMob(target);

            // Are we using a weapon?
            Item weapon = isPrimaryHand ? this.GetEquipment(EquipableType.Primary) : this.GetEquipment(EquipableType.Secondary);

            // Not much from the weapon is factored into the attack - just the skill type for the correct animations.
            if (weapon != null) {
                if (!isPrimaryHand && weapon.ItemType == (byte)ItemType.Shield) {
                    _log.DebugFormat("{0} attacking with {1}({2}) in secondary - attack with shield cancelled.", this.Name, weapon.Name, weapon.ItemID);
                    return false;
                }
            }

            // First calculate the skill and animation to use
            Skill attackSkill;
            AttackAnimation attackAnim;
            GetSkillAndAnimForAttack(weapon, isPrimaryHand, out attackSkill, out attackAnim);
            OnAnimation(new AnimationEventArgs(attackAnim));    // Cue the animation
            _log.DebugFormat("NPC attacking {0} with {1} in slot {2} using skill {3}", this.TargetMob.Name, weapon == null ? "Fist" : weapon.Name,
                isPrimaryHand ? "Primary" : "Secondary", attackSkill.ToString("f"));

            // Next figure out the potential damage
            int potDamage = GetWeaponDamage(target, weapon);
            int damage = 0;
            //_log.DebugFormat("Potential damage calculated as {0} for {1}", potDamage, this.Name);

            // If potential damage is more than zero we know it's POSSIBLE to hit the target
            if (potDamage > 0) {

                // Elemental & Bane dmg added differently than for PCs - where PCs would use the potential dmg (which has elem & bane included)
                // to figure max dmg, NPCs use the built-in min & max dmg values along with any elem and/or bane dmg.
                int elemBaneDmg = 0;
                if (weapon != null) {
                    if (weapon.BaneDmgBody == (int)target.BodyType)
                        elemBaneDmg += weapon.BaneDmgBodyAmt;
                    if (weapon.BaneDmgRace == target.Race)
                        elemBaneDmg += weapon.BaneDmgRaceAmt;
                    if (weapon.ElemDmgAmt > 0) {
                        // TODO: check for other's resist
                    }
                }

                int minDmg = _minDmg + elemBaneDmg;
                int maxDmg = _maxDmg + elemBaneDmg;

                // Ok, so we know we CAN hit... let's see if we DO hit
                if (target is ZonePlayer && ((ZonePlayer)target).Sitting) {
                    _log.DebugFormat("{0} is sitting - {1} hitting for max damage {2}", ((ZonePlayer)target).Name, this.Name, maxDmg);
                    damage = maxDmg;
                }
                else if (target.TryToHit(this, attackSkill, isPrimaryHand)) {
                    Random rand = new Random();
                    damage = rand.Next(minDmg, maxDmg + 1);
                    //_log.DebugFormat("{4}'s damage calculated to {0} (min {1}, max {2}, pot dmg {3})", damage, minDmg, maxDmg, potDamage, this.Name);

                    // With damage now calculated, see if the mob can avoid and mitigate
                    damage = target.TryToAvoidDamage(this, damage);

                    if (damage > 0) {
                        damage = target.TryToMitigateDamage(this, damage, minDmg);   // wasn't avoided, try to mitigate
                        // TODO: apply any damage bonuses (is this the right term... bonuses?... wasn't that done by now?
                        // TODO: try a critical hit (why are we trying this after the mitigation?)
                    }

                    //_log.DebugFormat("NPC damage after avoidance and mitigation: {0}", damage);
                }
                //else
                //    _log.DebugFormat("{0} missed {1}.", this.Name, this.TargetMob.Name);

                // TODO: cancel a riposte of a riposte
            }
            else
                damage = (int)AttackAvoidanceType.Invulnerable;

            target.Damage(this, damage, 0, attackSkill);    // Send attack damage - even zero and negative damage

            BreakSneakiness();

            // TODO: weapon procs

            // TODO: check if we're getting a riposte back?

            if (damage > 0) {
                // TODO: handle lifetap effects?

                // TODO: trigger defensive procs

                return true;
            }
            else
                return false;
        }
示例#7
0
 /// <summary>Based upon several factors, the spell being cast can have different targets.  This method determines those targets.</summary>
 protected bool DetermineSpellTargets(Spell spell, Mob target, ref Mob aeCenter, out CastActionType cat)
 {
     cat = CastActionType.AECaster;
     return false;   // TODO: unfinished
 }
示例#8
0
        protected virtual bool IsAbleToAttack(Mob target, bool spellAttack)
        {
            if (target == null)
                throw new ArgumentNullException("other");

            return target.IsAttackable;
        }
示例#9
0
        /// <summary>Determines if we are behind a given mob.  Useful for hide, backstab and riposte checks.</summary>
        /// <param name="other">Mob we are seeing if we are behind.</param>
        internal bool IsBehindMob(Mob other)
        {
            float angle, lengthB, vectorX, vectorY;
            float mobX = -(other.X);	// mob xlocation (inverse because eq is confused)
            float mobY = other.Y;		// mobylocation
            float heading = other.Heading;	// mob heading
            heading = (heading * 360.0f) / 256.0f;	// convert to degrees
            if (heading < 270)
                heading += 90;
            else
                heading -= 270;
            heading = heading * 3.1415f / 180.0f;	// convert to radians
            vectorX = mobX + (10.0f * (float)Math.Cos(heading));	// create a vector based on heading
            vectorY = mobY + (10.0f * (float)Math.Sin(heading));	// of mob length 10

            //length of mob to player vector
            //lengthb = (float)sqrtf(pow((-playerx-mobx),2) + pow((playery-moby),2));
            lengthB = (float)Math.Sqrt(((-(this.X) - mobX) * (-(this.X) - mobX)) + ((this.Y - mobY) * (this.Y - mobY)));

            // calculate dot product to get angle
            angle = (float)Math.Acos(((vectorX - mobX) * (-(this.X) - mobX) + (vectorY - mobY) * (this.Y - mobY)) / (10 * lengthB));
            angle = angle * 180f / 3.1415f;
            if (angle > 90.0) //not sure what value to use (90*2=180 degrees is front)
                return true;
            else
                return false;
        }
示例#10
0
        internal float DistanceNoZ(Mob other)
        {
            float xDiff = other.X - this.X;
            float yDiff = other.Y - this.Y;

            return (float)Math.Sqrt((xDiff * xDiff) + (yDiff * yDiff));
        }
示例#11
0
        internal float DistanceNoRoot(Mob other)
        {
            float xDiff = other.X - this.X;
            float yDiff = other.Y - this.Y;
            float zDiff = other.Z - this.Z;

            return ((xDiff * xDiff) + (yDiff * yDiff) + (zDiff * zDiff));
        }
示例#12
0
        /// <summary></summary>
        /// <param name="attacker">Optional parameter of whom is causing the damage.</param>
        /// <param name="dmgAmt">Amount of damage caused.</param>
        /// <param name="spellId">Id of the spell responsible for the damage. Zero indicates no spell.</param>
        internal virtual void Damage(Mob attacker, int dmgAmt, int spellId, Skill attackSkill)
        {
            // TODO: is this from a damage shield?

            int hate = dmgAmt * 2;  // TODO: this value may need tweaked
            if (attacker != null) {
                if (attacker is ZonePlayer) {
                    if (!((ZonePlayer)attacker).IsFeigning)   // only hate on the player if they aren't fd'ing
                        _hateMgr.AddHate(attacker, hate, dmgAmt);
                }
                else
                    _hateMgr.AddHate(attacker, hate, dmgAmt);   // TODO: pets seem to have thier own calc for hate (see NPC::Attack in orig emu)
            }

            if (dmgAmt > 0) {   // Is there some damage actually being done?
                if (attacker != null) {     // Is someone doing the damage?
                    // TODO: harm touch

                    // TODO: lifetap spell effects?
                }

                // TODO: pet shit

                // TODO: rune stuff

                _log.DebugFormat("{0} has taken {1} damage. {2} HP left ({3:P}).", this.Name, dmgAmt, this.HP - dmgAmt, (this.HP - dmgAmt) / (float)this.MaxHP);
                if (dmgAmt >= this.HP) {
                    // TODO: try death save via AA abilities, etc. (in a virtual method)

                    // TODO: do we do the damage msg here or elsewhere?
                    this.Die(attacker, dmgAmt, spellId, attackSkill);
                    return;
                }

                this.HP -= dmgAmt;

                if (this.Sneaking)
                    this.Sneaking = false;

                // TODO: remove mez

                // TODO: check stun chances if bashing

                // TODO: handle chance of spell breaking root - (spellId of 0 is no spell)

                // TODO: handle chance of casting interrupt
            }

            OnDamaged(new DamageEventArgs()
                      {
                          SourceId = (ushort)(attacker == null ? 0 : attacker.ID),
                          Damage = (uint)dmgAmt,
                          Type = Mob.GetDamageTypeForSkill(attackSkill),
                          SpellId = (ushort)spellId
                      }
            );
        }
示例#13
0
        private void PlayerDeath(ZonePlayer zp, Mob lastAttacker, uint spellId, byte damageType, uint damage)
        {
            _log.DebugFormat("{0} bought the farm. Fatal blow dealt by {1} with {2} damage, skill {3}, spell {4}.", zp.Name, lastAttacker.Name,
                damage, damageType, spellId);

            if (zp.IsDePopped) {
                _log.WarnFormat("{0} is trying to die more than once or something... is already depopped!", zp.Name);
                return;
            }

            _zoneSvr.SendLogoutPackets(zp.Client);

            // Make the become corpse packet and queue to player before Death opCode packet
            BecomeCorpse bc = new BecomeCorpse()
            {
                SpawnId = (uint)zp.ID,
                X = zp.X,
                Y = zp.Y,
                Z = zp.Z
            };
            EQApplicationPacket<BecomeCorpse> bcPack = new EQApplicationPacket<BecomeCorpse>(AppOpCode.BecomeCorpse, bc);
            _zoneSvr.QueuePacketToClient(zp.Client, bcPack, true, ZoneConnectionState.All);

            Death d = new Death()
            {
                SpawnId = (uint)zp.ID,
                KillerId = lastAttacker == null ? 0u : (uint)lastAttacker.ID,
                CorpseId = (uint)zp.ID,
                BindToZoneId = zp.PlayerProfile.Binds[0].ZoneId,
                SpellId = spellId == 0u ? 0xFFFFFFFF : spellId,
                AttackSkillId = spellId != 0u ? (uint)0xe7 : damageType,
                Damage = damage
            };
            EQApplicationPacket<Death> dPack = new EQApplicationPacket<Death>(AppOpCode.Death, d);
            _zoneSvr.QueuePacketToClients(lastAttacker, dPack, false);

            RemoveFromAllTargets(zp);
            // orig emu removed self from its own hate list... don't understand why you'd do that, so skipping

            if (!zp.IsGM) {     // GM's don't get penalized from dieing... muwhahaha

                // Figure out how much xp we lose, if any
                int xpLoss = 0;
                if (zp.Level >= WorldServer.ServerConfig.LevelDeathDoesXPLoss)  // TODO: don't lose xp when we have become an NPC?
                    xpLoss = (int)(zp.XP * WorldServer.ServerConfig.XPLossModifier);

                if (lastAttacker is ZonePlayer) // TODO: also check if the attacker is a pet owned by a player (no xp loss in that case)
                    xpLoss = 0; // Don't lose xp when dueling

                _log.DebugFormat("{0} is losing {1} xp due to his ass died.", zp.Name, xpLoss);
                zp.XP -= xpLoss;

                // TODO: fade buffs (ALL - good and bad)
                // TODO: unmem spells (don't send packets)

                PlayerCorpse pc = new PlayerCorpse(zp, xpLoss, _zoneSvr.HasGraveyard());
                AddCorpse(pc);
                _zoneSvr.QueuePacketToClients(zp, bcPack, true);    // send the become corpse packet to all players in the zone
            }
            else {
                // TODO: fade just detrimental buffs
            }

            // Send player to bind point
            _zoneSvr.MovePlayer(zp, zp.PlayerProfile.Binds[0].ZoneId, 0, zp.PlayerProfile.Binds[0].X, zp.PlayerProfile.Binds[0].Y, zp.PlayerProfile.Binds[0].Z, zp.PlayerProfile.Binds[0].Heading, ZoneMode.ZoneToBindPoint);
        }
示例#14
0
        private void NpcDeath(NpcMob npc, Mob lastAttacker, uint spellId, byte damageType, uint damage)
        {
            RemoveFromAllTargets(npc);  // Remove NPC from any entity's target & hate lists

            // Send Death Packet
            Death d = new Death()
            {
                SpawnId = (uint)npc.ID,
                KillerId = lastAttacker == null ? 0u : (uint)lastAttacker.ID,
                BindToZoneId = 0u,
                SpellId = spellId == 0u ? 0xFFFFFFFF : spellId,
                AttackSkillId = damageType,
                Damage = damage
            };
            EQApplicationPacket<Death> dPack = new EQApplicationPacket<Death>(AppOpCode.Death, d);
            _zoneSvr.QueuePacketToClients(lastAttacker, dPack, false);  // TODO: this should be cool with a null lastAttacker, right?

            // TODO: something about respawn?

            Mob killer = npc.HateMgr.GetTopHated();
            Mob xpMob = npc.HateMgr.GetTopDamager();

            // Give xp out
            if (xpMob == null)
                xpMob = killer;
            if (xpMob == null)
                xpMob = lastAttacker;

            // TODO: if xpMob is pet, get the owner

            ZonePlayer xpClient = xpMob as ZonePlayer;
            if (xpClient != null) {
                // TODO: handle raid split, LDON adventure crap, etc.

                float groupBonus = 1.0f;
                if (xpClient.IsGrouped) {
                    // TODO: handle group split

                    // TODO: add group xp bonus
                }
                else {
                    ConLevel conLvl = Mob.GetConsiderDificulty(xpClient.Level, npc.Level);
                    if (conLvl != ConLevel.Green) {
                        // TODO: figure high con bonus, if any
                        int baseXp = (int)(npc.Level * npc.Level * groupBonus * _zoneSvr.Zone.XPMultiplier);
                        xpClient.GiveXP((int)(npc.Level * npc.Level * 75 * _zoneSvr.Zone.XPMultiplier), conLvl);
                    }
                }

                // TODO: raise death merit event?
            }

            // TODO: faction hits

            // Make a corpse and add to the manager
            if (npc.IsLootable) {   // TODO: add additional checks for stuff like a guard killing the mob, etc.
                Corpse c = new Corpse(npc, npc.LootItems);
                AddCorpse(c);

                // TODO: if killer is a pet, get the owner
                if (xpClient != null)
                    c.AllowLooter(killer as ZonePlayer);
            }

            // TODO: raise script event
            _log.DebugFormat("NPC {0} has died", npc.ID);
        }
示例#15
0
 /// <summary>Removes the specified mob from the targets of all mobs, if they have it targeted.</summary>
 internal void RemoveFromAllTargets(Mob mob)
 {
     _mobsListLock.EnterReadLock();
     try {
         foreach (Mob m in this.AllMobs) {
             if (m.TargetMob == mob) {
                 m.HateMgr.RemoveHate(mob);
                 m.TargetMob = null;
             }
         }
     }
     catch (Exception ex) {
         _log.Error("Error removing a mob from targets in the mob mgr... ", ex);
     }
     finally {
         _mobsListLock.ExitReadLock();
     }
 }
示例#16
0
        /// <summary>Makes this mob turn to face the specified mob.</summary>
        /// <param name="mobToFace">The mob that should be faced. If null, faces the currently targeted mob.</param>
        protected void FaceMob(Mob other)
        {
            Mob mobToFace = other == null ? this.TargetMob : other;

            if (mobToFace == null) {
                _log.Error("Unable to face the mob - null was specified and we don't have a mob targeted.");
                return;
            }

            float oldHeading = this.Heading;
            float newHeading = CalculateHeadingToTarget(mobToFace.X, mobToFace.Y);
            if (oldHeading != newHeading) {
                this.Heading = newHeading;
                if (this.IsMoving)
                    OnPositionUpdate(new PosUpdateEventArgs(true, true));
                else
                    OnPositionUpdate(new PosUpdateEventArgs(true, false));
            }
        }
示例#17
0
        /// <summary>Gets the damage for the specified target mob with the specified weapon.</summary>
        /// <param name="target">Mob that is being attacked.</param>
        /// <param name="weapon">Null indicates fists.</param>
        /// <returns>Amount of damage delivered.</returns>
        protected int GetWeaponDamage(Mob target, Item weapon)
        {
            int damage = 0, baneDamage = 0, elemDamage = 0;

            if (target.Invulnerable || target.HasSpecialDefense(SpecialDefenses.ImmuneMelee))
                return 0;

            if (target.HasSpecialDefense(SpecialDefenses.ImmuneMeleeNonmagical)) {
                if (weapon != null) {
                    if (weapon.IsMagic) {   // TODO: look for magic weapon buff as well
                        if (this is ZonePlayer && this.Level < weapon.RecLevel)
                            damage = ZonePlayer.CalcRecommendedLevelBonus(this.Level, weapon.RecLevel, weapon.Damage);
                        else
                            damage = weapon.Damage;

                        // TODO: accumulate weapon augmentation damage bonuses

                        damage = Math.Min(damage, 1);
                    }
                    else
                        return 0;   // Weapon not magical, but one is needed
                }
                else {
                    // TODO: add check below for pet ability to hit
                    if ((this.Class == (byte)CharClasses.Monk || this.Class == (byte)CharClasses.BeastLord) && this.Level >= 30)
                        damage = GetMonkHandToHandDamage();
                    else if (this.HasSpecialAttack(SpecialAttacks.Magical))
                        damage = 1;
                    else
                        return 0;   // No weapon and can't harm with hand to hand
                }
            }
            else {
                if (weapon != null) {
                    if (this is ZonePlayer && this.Level < weapon.RecLevel)
                        damage = ZonePlayer.CalcRecommendedLevelBonus(this.Level, weapon.RecLevel, weapon.Damage);
                    else
                        damage = weapon.Damage;

                    // TODO: accumulate weapon augmentation damage bonuses

                    damage = Math.Max(damage, 1);   // Minimum weapon damage of 1
                }
                else {
                    if (this.Class == (byte)CharClasses.Monk || this.Class == (byte)CharClasses.BeastLord)
                        damage = GetMonkHandToHandDamage();
                    else
                        damage = UNARMED_DAMAGE;
                }
            }

            // TODO: elemental damage (Don't add resist checks - just calculating POTENTIAL damage here)

            // TODO: bane damage

            return damage + baneDamage + elemDamage;
        }
示例#18
0
        /// <summary>Determines if this mob is invisible to another mob.</summary>
        /// <param name="other">Mob that may or may not be capable of seeing this mob.</param>
        internal bool IsInvisibleTo(Mob other)
        {
            // check regular invisibility
            if (this.Invisible && !other.SeeInvis)
                return true;

            // check invis vs. undead
            if (other.BodyType == BodyType.Undead || other.BodyType == BodyType.SummonedUndead) {
                if (this.InvisibleToUndead && !other.SeeInvisToUndead)
                    return true;
            }

            // check invis vs. animals
            if (other.BodyType == BodyType.Animal)
                if (this.InvisibleToAnimals && !other.SeeInvisToAnimals)
                    return true;

            if (this.Hidden) {
                if (!other.SeeHide && !other.SeeImprovedHide)
                    return true;
            }

            if (this.ImprovedHidden && !other.SeeImprovedHide)
                return true;

            if (this.Sneaking && IsBehindMob(other))
                return true;

            return false;
        }
示例#19
0
        /// <summary>Actually executes a spell and its effects on a specified target.</summary>
        /// <param name="spell"></param>
        /// <param name="target"></param>
        /// <param name="slotId"></param>
        /// <param name="invSlotId">Optional slot a used item is in that caused the spell.</param>
        /// <returns></returns>
        internal virtual bool ExecuteSpell(Spell spell, Mob target, uint slotId, uint? invSlotId)
        {
            CastActionType cat;
            Mob aeCenter = null;
            if (!DetermineSpellTargets(spell, target, ref aeCenter, out cat))
                return false;

            return true;    // TODO: unfinished
        }
示例#20
0
        /// <summary>Determines if this mob is within combat range of another mob.</summary>
        /// <param name="other">Mob that may or may not be within combat range of this mob.</param>
        internal bool IsWithinCombatRangeOf(Mob other)
        {
            float sizeMod = this.Size;
            float otherSizeMod = other.Size;

            Races thisRace = (Races)this.Race;
            if (thisRace == Races.LavaDragon || thisRace == Races.Wurm || thisRace == Races.GhostDragon)    // For races with fixed size
                sizeMod = 60.0f;
            else if (sizeMod < 6.0f)
                sizeMod = 8.0f;

            Races otherRace = (Races)this.Race;
            if (otherRace == Races.LavaDragon || otherRace == Races.Wurm || otherRace == Races.GhostDragon)    // For races with fixed size
                otherSizeMod = 60.0f;
            else if (sizeMod < 6.0f)
                otherSizeMod = 8.0f;

            sizeMod = Math.Max(sizeMod, otherSizeMod);

            // not 100% sure what's going on here... seems to be scaling the size modifier a bit
            if (sizeMod > 29)
                sizeMod *= sizeMod;
            else if (sizeMod > 19)
                sizeMod *= sizeMod * 2;
            else
                sizeMod *= sizeMod * 4;

            // Prevent ridiculously sized hit boxes
            if (sizeMod > 10000.0f)
                sizeMod /= 7;

            if (this.DistanceNoRootNoZ(other) <= sizeMod)
                return true;

            return false;
        }
示例#21
0
        internal override void Damage(Mob attacker, int dmgAmt, int spellId, Skill attackSkill)
        {
            // TODO: raise attacked script event

            // TODO: handle LDON treasure traps, etc.

            base.Damage(attacker, dmgAmt, spellId, attackSkill);

            // TODO: upstream pet class should send a msg to its owner

            // TODO: upstream pet class should check if it should flee
        }
示例#22
0
        /// <summary>Performs a melee attack against the specified target mob.</summary>
        /// <param name="target">Mob being attacked.</param>
        /// <param name="isPrimaryHand">Is this the primary hand weapon as opposed to a dual wield attack.</param>
        /// <param name="riposte">Is this a riposte attack?</param>
        /// <returns>True if an attack succeeded, else false if the attack didn't succeed (for whatever reason).</returns>
        internal virtual bool MeleeAttack(Mob target, bool isPrimaryHand, bool riposte)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            return true;
            // Anything else should be handled in the specific entity type
        }
示例#23
0
        protected override void Die(Mob lastAttacker, int damage, int spellId, Skill attackSkill)
        {
            // TODO: kill pet - maybe handle in mob class?

            // TODO: fade buffs

            // TODO: something with LDON treasures

            base.Die(lastAttacker, damage, spellId, attackSkill);
        }
示例#24
0
        /// <summary>Tries to avoid an attack that has already been determined to otherwise land a hit.</summary>
        /// <param name="attacker"></param>
        /// <param name="damage"></param>
        /// <returns>Damage amount after avoidance methods are checked. If successfully avoided the damage will be one of the AttackAvoidanceType values.</returns>
        internal int TryToAvoidDamage(Mob attacker, int damage)
        {
            float bonus = 0.0f;
            uint skill = 0;
            float riposteChance = 0.0f, blockChance = 0.0f, parryChance = 0.0f, dodgeChance = 0.0f;

            // TODO: determine guaranteed hits
            bool autoHit = false;

            // If this mob is enraged, it auto-ripostes (even guaranteed hits apparently)
            if (this is NpcMob && ((NpcMob)this).Enraged && !attacker.IsBehindMob(this)) {
                damage = (int)AttackAvoidanceType.Riposte;
            }

            // Try to Riposte
            if (damage > 0 && this.GetSkillLevel(Skill.Riposte) > 0 && !attacker.IsBehindMob(this)) {
                skill = this.GetSkillLevel(Skill.Riposte);

                if (this is ZonePlayer)
                    ((ZonePlayer)this).CheckForSkillUp(Skill.Riposte, attacker, 0);

                if (!autoHit) { // guaranteed hit discipline trumps riposte
                    bonus = 2.0f + skill / 60.0f + (this.DEX / 200);
                    // TODO: add in riposte related item and spell bonuses
                    riposteChance = bonus;
                }
            }

            // Try to Block
            bool blockFromRear = false;     // TODO: handle Hightened Awareness AA

            if (damage > 0 && this.GetSkillLevel(Skill.Block) > 0 && (!attacker.IsBehindMob(this) || blockFromRear)) {
                skill = this.GetSkillLevel(Skill.Block);

                if (this is ZonePlayer)
                    ((ZonePlayer)this).CheckForSkillUp(Skill.Block, attacker, 0);

                if (!autoHit) {
                    bonus = 2.0f + skill / 35.0f + (this.DEX / 200);
                    blockChance = riposteChance + bonus;
                }

                // TODO: handle Shield Block AA
            }

            // TODO: Try to Parry

            // TODO: Try to Dodge

            Random rand = new Random();
            int roll = rand.Next(1, 101);  // Roll between 1-100
            if (roll <= (riposteChance + blockChance + parryChance + dodgeChance)) {
                // Something worked, now which one was it...
                if (roll <= riposteChance)
                    damage = (int)AttackAvoidanceType.Riposte;
                else if (roll < blockChance)
                    damage = (int)AttackAvoidanceType.Block;
                else if (roll < parryChance)
                    damage = (int)AttackAvoidanceType.Parry;
                else if (roll < dodgeChance)
                    damage = (int)AttackAvoidanceType.Dodge;
            }

            return damage;
        }
示例#25
0
        /// <summary></summary>
        /// <param name="attacker"></param>
        /// <param name="dmgAmt"></param>
        /// <param name="spellId">Id of the damaging spell.  Zero for no spell.</param>
        /// <param name="attackSkill"></param>
        internal override void Damage(Mob attacker, int dmgAmt, int spellId, Skill attackSkill)
        {
            if (this.Dead)
                throw new InvalidOperationException("Cannot damage a dead PC.");    // TODO: do we just want to return instead of throw?

            base.Damage(attacker, dmgAmt, spellId, attackSkill);

            if (dmgAmt > 0) {
                if (spellId == 0)
                    CheckForSkillUp(Skill.Defense, attacker, -5);
            }
        }
示例#26
0
        internal bool TryToHit(Mob attacker, Skill attackSkill, bool isPrimaryHand)
        {
            float hitChance = WorldServer.ServerConfig.BaseHitChance * 100;
            if (attacker is NpcMob) {
                hitChance += WorldServer.ServerConfig.NPCBonusHitChance;
                hitChance += (hitChance * ((NpcMob)attacker).Accuracy / 1000.0f);   // Accuracy can be set in NPC table over 1000 to give the NPC a greater hit chance
            }

            //_log.DebugFormat("Base hit chance with NPC bonus & NPC Accuracy: {0}", hitChance);

            int levelDiff = attacker.Level - this.Level;
            float range = attacker.Level / 4.0f + 3;    // This is changed from orig emu... I chose the attacker to base from for a tighter range

            if (levelDiff < 0) {
                // We are of higher level than the attacker
                if (levelDiff >= -range)
                    hitChance += levelDiff / range * WorldServer.ServerConfig.HitFallOffMinor;                      // 5
                else if (levelDiff >= -(range + 3.0f)) {
                    hitChance -= WorldServer.ServerConfig.HitFallOffMinor;
                    hitChance += ((levelDiff + range) / 3.0f) * WorldServer.ServerConfig.HitFallOffModerate;        // 7
                }
                else {
                    hitChance -= WorldServer.ServerConfig.HitFallOffMinor + WorldServer.ServerConfig.HitFallOffModerate;
                    hitChance += ((levelDiff + range + 3.0f) / 12.0f) * WorldServer.ServerConfig.HitFallOffMajor;   // Basically no f*****g chance
                }
            }
            else
                hitChance += levelDiff * WorldServer.ServerConfig.HitBonusPerLevel;

            //_log.DebugFormat("Hit chance after level diff adj: {0} (attacker level: {1} defender level: {2} diff: {3})", hitChance, attacker.Level, this.Level, levelDiff);

            hitChance -= this.AGI * 0.05f;     // Adjust for agility TODO: const or db

            //_log.DebugFormat("Hit chance after adj for AGI: {0} (AGI: {1})", hitChance, this.AGI);

            if (attacker is ZonePlayer) {
                // TODO: weapon skill & defense skill falloffs?

                // TODO: handle client specific AA bonuses
            }

            // TODO: Add spell and item bonuses relating to ATTACKER melee skill and hit chance skill (Factor this into virtual GetChanceToHitBonuses())

            // TODO: subtract off the defender's avoidance (looks like spell and item bonus related)

            // TODO: defender's AA abilities which mitigate to hit chances

            if (hitChance < 1000.0f) {      // As long as a discipline isn't involved... TODO: what about guaranteed riposte vs. guaranteed hit?
                hitChance = Math.Max(hitChance, TOHIT_MIN);     // Chance to hit max: 95% min: 5%
                hitChance = Math.Min(hitChance, TOHIT_MAX);
            }

            Random rand = new Random();
            int toHitRoll = rand.Next(0, 100);

            //_log.DebugFormat("Final hit chance: {0} Roll: {1})", hitChance, toHitRoll);
            return toHitRoll <= hitChance;
        }
示例#27
0
        protected override void Die(Mob lastAttacker, int damage, int spellId, Skill attackSkill)
        {
            // TODO: interrupt the spell being cast
            // TODO: clear pet
            // TODO: clear mount

            _deadTimer.Start(DEAD_TIMER);

            if (lastAttacker != null) {
                if (lastAttacker is NpcMob) {
                    // TODO: raise slay event for the NPC
                }

                // TODO: handle dueling
            }

            if (this.IsGrouped) {
                // TODO: tell group we zoned (here or in mobMgr?)
            }

            if (this.IsRaidGrouped) {
                // TODO: tell raid we zoned (here or in mobMgr?)
            }

            // TODO: clear proximity?

            base.Die(lastAttacker, damage, spellId, attackSkill);

            // Player's shit is now on their corpse, not on them
            this.Platinum = 0u;
            this.Gold = 0u;
            this.Silver = 0u;
            this.Copper = 0u;
            this.InvMgr.ClearPersonalSlotItems();
            // TODO: clear zone instance ID (when instancing is in)

            Save();
        }
示例#28
0
        /// <summary>Attempts to mitigate the specified damage amount.</summary>
        /// <param name="attacker"></param>
        /// <param name="damage"></param>
        /// <returns>Resulting amount of damage after all mitigation has been applied.</returns>
        internal int TryToMitigateDamage(Mob attacker, int damage, int minDmg)
        {
            if (damage <= 0)
                throw new ArgumentOutOfRangeException("damage", "No need to mitigate damage of zero or less.");

            int totalMit = 0;

            // TODO: Accumulate bonuses from AA abilities related to damage mitigation

            // AC mitigation    TODO: examine these calcs and see if they are wacky or not
            int attackRating = 0;
            int defenseRating = this.AC;
            defenseRating += 125 + (totalMit * defenseRating / 100);
            int acEq100 = 125;

            if (this.Level < 20)
                acEq100 += 15 * this.Level;
            else if (this.Level < 50)
                acEq100 += (285 + ((this.Level - 19) * 30));
            else if (this.Level < 60)
                acEq100 += (1185 + ((this.Level - 49) * 60));
            else if (this.Level < 70)
                acEq100 += (1785 + ((this.Level - 59) * 90));
            else
                acEq100 += (2325 + ((this.Level - 69) * 125));

            if (attacker is ZonePlayer) // TODO: factor below into an AttackRating property?
                attackRating = 10 + attacker.Attack + (int)(attacker.STR + attacker.GetSkillLevel(Skill.Offense) * 9 / 10);
            else
                attackRating = 10 + attacker.Attack + (attacker.STR * 9 / 10);

            float combatRating = defenseRating - attackRating;
            combatRating = 100 * combatRating / acEq100;
            float d1Chance = 6.0f + ((combatRating * 0.39f) / 3);
            float d2d19Chance = 48.0f + (((combatRating * 0.39f) / 3) * 2);

            d1Chance = Math.Max(d1Chance, 1.0f);    // min chance of 1.0
            d2d19Chance = Math.Max(d2d19Chance, 5.0f);  // min chance of 5.0

            Random rand = new Random();
            double roll = rand.NextDouble() * 100;

            int interval = 0;
            if (roll <= d1Chance)
                interval = 1;
            else if (roll <= (d2d19Chance + d1Chance))
                interval = 1 + (int)((((roll - d1Chance) / d2d19Chance) * 18) + 1);
            else
                interval = 20;

            // TODO: the f**k is this shit?
            int db = minDmg;
            double di = ((double)(damage - minDmg) / 19);
            damage = db + (int)(di * (interval - 1));

            // TODO: reduce damage further from shielding item and AA which are based on the min dmg
            // TODO: reduce damage further from spells which are based upon pure damage (not min dmg)

            return Math.Max(damage, minDmg);    // Can't mitigate below min dmg
        }
示例#29
0
        /// <summary>Checks if the player gains a skill point in a particular skill.</summary>
        /// <param name="skill">The skill to check for a skill up for.</param>
        /// <param name="target">The mob the check is being performed against. Null if not that kind of skill.</param>
        /// <param name="chanceMod">Modifier to add to the chance probability. A value of 80+ would almost ensure a skillup.</param>
        internal bool CheckForSkillUp(Skill skill, Mob target, int chanceMod)
        {
            if (this.IsAIControlled)
                return false;

            if (skill > Skill.Highest)
                throw new ArgumentException("Skill type is beyond the range of legal skill types.", "skill");

            uint skillLvl = GetBaseSkillLevel(skill);
            uint maxLvl = GetSkillCap(skill);

            if (skillLvl < maxLvl) {
                if (target != null) {
                    if (target is ZonePlayer || Mob.GetConsiderDificulty(this.Level, target.Level) == ConLevel.Green)
                        return false;   // TODO: add check for aggro immunity on target (spec attack)
                }

                // the higher the current skill level, the harder it is to skill up
                int chance = ((252 - (int)skillLvl) / 20) + chanceMod;
                chance = Math.Max(chance, 1);   // Always have at least a slim chance

                // TODO: add configurable global skill up modifier
                Random rand = new Random();
                if (rand.Next(100) < chance) {
                    SetSkillLevel(skill, skillLvl + 1);
                    _log.DebugFormat("{0} skilled up {1} from skill level {2} with a chance of {3}", this.Name, skill, skillLvl, chance);
                    return true;
                }
                //else
                //    _log.DebugFormat("{0} failed to skill up {1} from skill level {2} with a chance of {3}", this.Name, skill, skillLvl, chance);
            }
            else
                _log.DebugFormat("{0} unable to skill up {1} from skill level {2} due to a cap of {3}", this.Name, skill, skillLvl, maxLvl);

            return false;
        }
示例#30
0
        protected virtual void Die(Mob lastAttacker, int damage, int spellId, Skill attackSkill)
        {
            this.HP = 0;

            OnDamaged(new DamageEventArgs()
            {
                SourceId = (ushort)(lastAttacker == null ? 0 : lastAttacker.ID),
                Damage = (uint)damage,
                Type = Mob.GetDamageTypeForSkill(attackSkill),
                SpellId = (ushort)spellId
            });

            _hateMgr.Clear();
            DePop();
        }