예제 #1
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;
        }
예제 #2
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;
        }