예제 #1
0
        /// <summary>
        /// Checks whether the victim is able to dodge the attacker's swing.
        /// </summary>
        /// <param name="ch"></param>
        /// <param name="victim"></param>
        /// <returns></returns>
        public static bool CheckDodge( CharData ch, CharData victim )
        {
            if( !victim.IsAwake() || victim.CurrentPosition < Position.reclining )
                return false;

            if (ch.IsAffected(Affect.AFFECT_DAZZLE))
                return false;

            if( !victim.HasSkill( "dodge" ) )
                return false;

            int chance = victim.GetSkillChance("dodge");

            // Size difference bonus for dodge for halflings - they get 2% dodge
            // bonus per size difference between them and the attacker. -- Xangis
            // Drow get a flat 15% bonus.
            if( victim.GetRace() == Race.RACE_HALFLING )
            {
                if( ch.CurrentSize > victim.CurrentSize )
                {
                    chance += 3 * ( ch.CurrentSize - victim.CurrentSize );
                }
            }
            else if( victim.HasInnate( Race.RACE_GOOD_DODGE ) )
            {
                chance += 8;
            }
            else if( victim.HasInnate( Race.RACE_BAD_DODGE ) )
            {
                chance -= 3;
            }

            // Bashed mobs/creatures have a hard time dodging
            if( victim.CurrentPosition < Position.fighting )
            {
                chance -= 25;
            }

            // Leap is 16% max at level 50.  Considering crappy thri hitpoints it's necessary.
            if( victim.GetRace() == Race.RACE_THRIKREEN && MUDMath.NumberPercent() <= ( victim.Level / 3 ) )
            {
                SocketConnection.Act( "$N&n leaps over your attack.", ch, null, victim, SocketConnection.MessageTarget.character );
                SocketConnection.Act( "You leap over $n&n's attack.", ch, null, victim, SocketConnection.MessageTarget.victim );
                SocketConnection.Act( "$N&n leaps over $n&n's attack.", ch, null, victim, SocketConnection.MessageTarget.room_vict );
                return true;
            }

            victim.PracticeSkill( "dodge" );

            if( MUDMath.NumberPercent() >= chance - ch.Level )
                return false;

            switch( MUDMath.NumberRange( 1, 2 ) )
            {
                case 1:
                    SocketConnection.Act( "$N&n dodges your attack.", ch, null, victim, SocketConnection.MessageTarget.character );
                    SocketConnection.Act( "You dodge $n&n's attack.", ch, null, victim, SocketConnection.MessageTarget.victim );
                    SocketConnection.Act( "$N&n dodges $n&n's attack.", ch, null, victim, SocketConnection.MessageTarget.room_vict );
                    break;
                case 2:
                    SocketConnection.Act( "$N&n sidesteps your attack.", ch, null, victim, SocketConnection.MessageTarget.character );
                    SocketConnection.Act( "You narrowly dodge $n&n's attack.", ch, null, victim, SocketConnection.MessageTarget.victim );
                    SocketConnection.Act( "$N&n avoids $n&n's attack.", ch, null, victim, SocketConnection.MessageTarget.room_vict );
                    break;
                default:
                    break;
            }

            if( ch.Fighting == null )
                SetFighting( ch, victim );
            if( victim.Fighting == null )
                SetFighting( victim, ch );

            return true;
        }
예제 #2
0
        /// <summary>
        /// Checks for block if holding shield.
        /// </summary>
        /// <param name="ch"></param>
        /// <param name="victim"></param>
        /// <returns></returns>
        static bool CheckShieldBlock( CharData ch, CharData victim )
        {
            if( !victim.HasSkill( "shield block" ) )
                return false;

            if( ch.IsAffected( Affect.AFFECT_DAZZLE ) )
                return false;

            if( !victim.IsAwake() || victim.CurrentPosition < Position.reclining )
                return false;

            Object obj = Object.GetEquipmentOnCharacter( victim, ObjTemplate.WearLocation.hand_one );
            if( !obj || ( obj.ItemType != ObjTemplate.ObjectType.shield ) )
            {
                if( !( obj = Object.GetEquipmentOnCharacter( victim, ObjTemplate.WearLocation.hand_two ) ) )
                    return false;
                if( obj.ItemType != ObjTemplate.ObjectType.shield )
                    return false;
            }
            if( obj.ItemType != ObjTemplate.ObjectType.shield )
            {
                if( !( obj = Object.GetEquipmentOnCharacter( victim, ObjTemplate.WearLocation.hand_two ) ) )
                    return false;
                if( obj.ItemType != ObjTemplate.ObjectType.shield )
                    return false;
            }

            int chance = ch.GetSkillChance("shield block");
            victim.PracticeSkill("shield block");

            if (MUDMath.NumberPercent() >= ((chance - ch.Level) / 2))
            {
                return false;
            }

            switch( MUDMath.NumberRange( 1, 5 ) )
            {
                case 1:
                    SocketConnection.Act( "You block $n&n's attack with your shield.", ch, null, victim, SocketConnection.MessageTarget.victim );
                    SocketConnection.Act( "$N&n blocks your attack with a shield.", ch, null, victim, SocketConnection.MessageTarget.character );
                    SocketConnection.Act( "$N&n blocks $n&n's attack with a shield.", ch, null, victim, SocketConnection.MessageTarget.room_vict );
                    break;
                case 2:
                    // If we were really smart we would check to see whether both the shield
                    // and weapon were made of metal before we gave a sparks message...
                    SocketConnection.Act( "&+CS&n&+cp&+Car&n&+ck&+Cs&n fly off your shield as you block $n&n's attack.", ch, null, victim, SocketConnection.MessageTarget.victim );
                    SocketConnection.Act( "$N&n defends against your attack with a shield.", ch, null, victim, SocketConnection.MessageTarget.character );
                    SocketConnection.Act( "$N&n deflects $n&n's attack with a shield.", ch, null, victim, SocketConnection.MessageTarget.room_vict );
                    break;
                case 3:
                    SocketConnection.Act("You bring up your shield to block $n&n's attack.", ch, null, victim, SocketConnection.MessageTarget.victim);
                    SocketConnection.Act("$N&n brings up %s shield to block your attack.", ch, null, victim, SocketConnection.MessageTarget.character);
                    SocketConnection.Act("$N&n brings up %s shield to blocks $n&n's attack.", ch, null, victim, SocketConnection.MessageTarget.room_vict);
                    break;
                case 4:
                    SocketConnection.Act("You knock $n&n's attack aside with your shield.", ch, null, victim, SocketConnection.MessageTarget.victim);
                    SocketConnection.Act("$N&n knocks your attack aside with $S shield.", ch, null, victim, SocketConnection.MessageTarget.character);
                    SocketConnection.Act("$N&n knocks $n&n's attack aside with $S shield.", ch, null, victim, SocketConnection.MessageTarget.room_vict);
                    break;
                case 5:
                    SocketConnection.Act("You hear a thud as $n&n's weapon smacks into your shield.", ch, null, victim, SocketConnection.MessageTarget.victim);
                    SocketConnection.Act("Your weapon smacks into $N&n's shield with a thud.", ch, null, victim, SocketConnection.MessageTarget.character);
                    SocketConnection.Act("$n&n's weapon smacks into $N&'s shield with a thud.", ch, null, victim, SocketConnection.MessageTarget.room_vict);
                    break;
                default:
                    break;
            }

            if( ch.Fighting == null )
                SetFighting( ch, victim );
            if( victim.Fighting == null )
                SetFighting( victim, ch );

            return true;
        }
예제 #3
0
        /// <summary>
        /// Checks whether the victim is able to parry a swing.
        /// </summary>
        /// <param name="ch"></param>
        /// <param name="victim"></param>
        /// <returns></returns>
        static bool CheckParry( CharData ch, CharData victim )
        {
            if( !victim.IsAwake() || victim.CurrentPosition < Position.reclining )
                return false;

            if (ch.IsAffected(Affect.AFFECT_DAZZLE))
                return false;

            if( !victim.HasSkill( "parry" ) )
                return false;

            int chance = ch.GetSkillChance("parry");
            if (victim.IsNPC())
            {
                // Mobs more often than not don't have weapons
                // so they should get bonuses for actually
                // having them
                if( !Object.GetEquipmentOnCharacter( victim, ObjTemplate.WearLocation.hand_one ) )
                {
                    if( !Object.GetEquipmentOnCharacter( victim, ObjTemplate.WearLocation.hand_two ) )
                        chance -= 5;
                }
                else
                    chance += 5;
            }
            else
            {
                // No weapon means no parry.  Only secondary weapon means 50% chance to parry.
                if( !Object.GetEquipmentOnCharacter( victim, ObjTemplate.WearLocation.hand_one ) )
                {
                    if( !Object.GetEquipmentOnCharacter( victim, ObjTemplate.WearLocation.hand_two ) )
                        return false;
                    chance /= 2;
                }

                victim.PracticeSkill( "parry" );
            }

            if( MUDMath.NumberPercent() >= ( chance - ch.Level ) / 2 )
                return false;

            switch( MUDMath.NumberRange(1,3))
            {
                case 1:
                    SocketConnection.Act( "$N&n skillfully parries your attack.", ch, null, victim, SocketConnection.MessageTarget.character );
                    SocketConnection.Act( "You parry $n&n's fierce attack.", ch, null, victim, SocketConnection.MessageTarget.victim );
                    SocketConnection.Act( "$N&n parries $n&n's attack.", ch, null, victim, SocketConnection.MessageTarget.room_vict );
                    break;
                case 2:
                    SocketConnection.Act("$N&n knocks your blow aside with $S weapon.", ch, null, victim, SocketConnection.MessageTarget.character);
                    SocketConnection.Act("You knock $n&n's clumsy attack aside with your weapon.", ch, null, victim, SocketConnection.MessageTarget.victim);
                    SocketConnection.Act("$N&n knocks $n&n's attack aside with $S weapon.", ch, null, victim, SocketConnection.MessageTarget.room_vict);
                    break;
                case 3:
                    SocketConnection.Act("$N&n deflects your attack with $S weapon.", ch, null, victim, SocketConnection.MessageTarget.character);
                    SocketConnection.Act("You deflect $n&n's attack with your weapon.", ch, null, victim, SocketConnection.MessageTarget.victim);
                    SocketConnection.Act("$N&n deflects $n&n's attack aside with $S weapon.", ch, null, victim, SocketConnection.MessageTarget.room_vict);
                    break;
            }
            if( ch.Fighting == null )
                SetFighting( ch, victim );
            if( victim.Fighting == null )
                SetFighting( victim, ch );
            return true;
        }
예제 #4
0
        /// <summary>
        /// Checks whether the victim is able to riposte the attacker's swing.  Returns false
        /// if failed, true if successful.
        /// </summary>
        /// <param name="ch"></param>
        /// <param name="victim"></param>
        /// <returns></returns>
        static bool CheckRiposte( CharData ch, CharData victim )
        {
            if( !victim.IsAwake() || victim.CurrentPosition < Position.reclining )
                return false;

            if( ch.IsAffected( Affect.AFFECT_DAZZLE ) )
                return false;

            if( ch.IsAffected( Affect.AFFECT_BLIND ) )
                return false;

            if( ch.IsAffected(Affect.AFFECT_CASTING ) )
                return false;

            if( !victim.HasSkill( "riposte" ) )
                return false;

            int chance = ch.GetSkillChance("riposte");
            if (victim.IsNPC())
            {
                // Mobs more often than not don't have weapons
                // so they should get bonuses for actually
                // having them
                if( Object.GetEquipmentOnCharacter( victim, ObjTemplate.WearLocation.hand_one ) )
                {
                    chance += 3;
                }
            }
            else
            {
                if( !Object.GetEquipmentOnCharacter( victim, ObjTemplate.WearLocation.hand_one ) )
                {
                    // Have to have a weapon to riposte.  If only holding secondary weapon chances are lowered.
                    if( !Object.GetEquipmentOnCharacter( victim, ObjTemplate.WearLocation.hand_two ))
                    {
                        return false;
                    }
                    chance /= 2;
                }

                victim.PracticeSkill( "riposte" );
            }

            if( MUDMath.NumberPercent() >= (( chance - ch.Level ) / 3 ) )
                return false;

            switch( MUDMath.NumberRange(1,3))
            {
                case 1:
                    SocketConnection.Act( "$N&n deflects your blow and strikes back at YOU!", ch, null, victim, SocketConnection.MessageTarget.character );
                    SocketConnection.Act( "You deflect $n&n's attack and strike back at $m.", ch, null, victim, SocketConnection.MessageTarget.victim );
                    SocketConnection.Act( "$N&n deflects $n&n's attack and strikes back at $m.", ch, null, victim, SocketConnection.MessageTarget.room_vict );
                    break;
                case 2:
                    SocketConnection.Act("$N&n knocks your swing aside and strikes back at YOU!", ch, null, victim, SocketConnection.MessageTarget.character);
                    SocketConnection.Act("You knock $n&n's attack aside and strikes back at $m.", ch, null, victim, SocketConnection.MessageTarget.victim);
                    SocketConnection.Act("$N&n knocks $n&n's attack aside and strikes back at $m.", ch, null, victim, SocketConnection.MessageTarget.room_vict);
                    break;
                case 3:
                    SocketConnection.Act("$N&n blocks your strike and swings back at YOU!", ch, null, victim, SocketConnection.MessageTarget.character);
                    SocketConnection.Act("You block $n&n's strike aside and swing back at $m.", ch, null, victim, SocketConnection.MessageTarget.victim);
                    SocketConnection.Act("$N&n block $n&n's strike and swings back at $m.", ch, null, victim, SocketConnection.MessageTarget.room_vict);
                    break;
            }
            return true;
        }
예제 #5
0
        /// <summary>
        /// Hit one guy once.
        ///
        /// Hitroll is now done on a 200-sided die rather than a 20-sided die
        /// This allows for more dynamic modifiers to hitroll.
        /// i.e. a couple extra points of strength and whatnot _may_ make the
        /// difference between a hit and a miss rather than incrementing something
        /// every 10-20 points of an ability we can modify it every 1-2 points.
        /// </summary>
        /// <param name="ch">attacker</param>
        /// <param name="victim">person being attacked</param>
        /// <param name="skill">damage type being used (skill)</param>
        /// <param name="weapon">wear location of weapon (usually primary or secondary hand)</param>
        /// <returns>true if victim is killed, otherwise false</returns>
        public static bool SingleAttack(CharData ch, CharData victim, string skill, ObjTemplate.WearLocation weapon)
        {
            string text;
            int dam;
            int chance;

            /*
            * Can't beat a dead char!
            * Guard against weird room-leavings.
            */
            if( victim.CurrentPosition == Position.dead || victim.Hitpoints < -10 )
            {
                text = String.Format("SingleAttack: ch {0} fighting dead victim {1}.", ch.Name, victim.Name );
                Log.Error( text, 0 );
                ch.Fighting = null;
                if( ch.CurrentPosition == Position.fighting )
                    ch.CurrentPosition = Position.standing;
                return true;
            }
            if( ch.InRoom != victim.InRoom )
            {
                text = String.Format("SingleAttack: ch {0} not with victim {1}.", ch.Name, victim.Name );
                Log.Error( text, 0 );
                ch.Fighting = null;
                if( ch.CurrentPosition == Position.fighting )
                    ch.CurrentPosition = Position.standing;
                return false;
            }

            /* No casting/being para'd and hitting at the same time. */
            if ((ch.IsAffected(Affect.AFFECT_CASTING)) || ch.IsAffected(Affect.AFFECT_MINOR_PARA)
                    || ch.IsAffected(Affect.AFFECT_HOLD))
            {
                return false;
            }

            // Inertial barrier will prevent some attacks.  At the following levels a person
            // affected by inertial barrier will be able to avoid this percentage of attacks:
            // 1 = 7%  5 = 10%  10 = 13%  20 = 20%  30 = 27%  40 = 33%  50 = 39%  51 = 40%
            if (victim.IsAffected(Affect.AFFECT_INERTIAL_BARRIER) && MUDMath.NumberPercent() > (victim.Level * 2 / 3 + 7))
                return false;

            // Keep in mind that CheckRiposte returns a boolean.
            if (skill != "kick" && skill != "backstab" && skill != "circle" && CheckRiposte( ch, victim ) )
            {
                SingleAttack( victim, ch, String.Empty, ObjTemplate.WearLocation.hand_one );
                return false;
            }
            if (CheckParry(ch, victim) && skill != "backstab" && skill != "circle")
                return false;
            if (CheckShieldBlock(ch, victim) && skill != "backstab" && skill != "circle")
                return false;
            if (CheckDodge(ch, victim) && skill != "backstab" && skill != "circle")
                return false;

            /*
            * Figure out the type of damage message if we don't have an associated attack skill.
            */
            Object wield = Object.GetEquipmentOnCharacter( ch, weapon );
            if (String.IsNullOrEmpty(skill))
            {
                skill = "barehanded fighting";
                if( wield && wield.ItemType == ObjTemplate.ObjectType.weapon )
                    skill = AttackType.Table[wield.Values[3]].SkillName;
            }

            /*
            * Weapon proficiencies.
            */
            string weaponGsn = "barehanded fighting";
            AttackType.DamageType damType = AttackType.DamageType.bludgeon;
            if( wield && wield.ItemType == ObjTemplate.ObjectType.weapon )
            {
                if( wield.Values[ 3 ] >= 0 && wield.Values[ 3 ] < AttackType.Table.Length )
                {
                    weaponGsn = (AttackType.Table[wield.Values[3]].SkillName);
                    damType = AttackType.Table[ wield.Values[ 3 ] ].DamageInflicted;
                }
                else
                {
                    text = String.Format( "SingleAttack: bad weapon damage type {0} caused by {1} ({2}).",
                              skill, wield.Name, wield.ObjIndexData ?
                              wield.ObjIndexData.IndexNumber : -1 );
                    Log.Error( text, 0 );
                    wield.Values[ 3 ] = 0;
                }
            }

            /*
            * Calculate to-hit-armor-class-0 versus armor.
            */
            int hitroll00 = ch.CharacterClass.HitrollLevel0;
            int hitroll40 = ch.CharacterClass.HitrollLevel40;

            /* Weapon-specific hitroll and damroll */

            int hitroll = MUDMath.Interpolate( ch.Level, hitroll00, hitroll40 )
                          - ( ch.GetHitroll( weapon ) * 3 );
            int victimAC = Math.Max( -100, victim.GetAC() );

            // Added blindfighting skill - Xangis
            if( !CharData.CanSee( ch, victim ) )
            {
                if( ch.CheckSkill( "blindfighting" ) )
                {
                    victimAC -= 5;
                }
                else
                {
                    victimAC -= 40;
                }
            }

            /* Weapon proficiencies *
            *
            * The twohanded version of a weapon proficiency *MUST* follow the onehanded
            * version in the definitions.  This is stupid.
            */
            if( wield && wield.ItemType == ObjTemplate.ObjectType.weapon )
            {
                if( !wield.HasFlag( ObjTemplate.ITEM_TWOHANDED ) )
                {
                    if( ch.CheckSkill( weaponGsn ))
                    {
                        victimAC += 20;
                        ch.PracticeSkill( weaponGsn );
                    }
                }
                else
                {
                    // This is not going to work.
                    if (ch.CheckSkill(weaponGsn+1))
                    {
                        victimAC += 20;
                        ch.PracticeSkill(weaponGsn);
                    }
                }
            }
            else if( ch.CheckSkill("barehanded fighting"))
            {
                victimAC += 20;
            }

            /*
            * The moment of excitement!
            */
            int diceroll = MUDMath.NumberRange( 0, 199 );

            // Give them a small bonus if they can make a successful luck check.
            if( MUDMath.NumberPercent() <= ch.GetCurrLuck() )
                diceroll += 5;

            /* Made really lucky chars get saved by the godz. */
            if( diceroll == 0 || ( diceroll <= 196 && diceroll < hitroll - victimAC )
                     || ( MUDMath.NumberPercent() < victim.GetCurrLuck() / 40 ) )
            {
                /* Miss. */
                return InflictDamage(ch, victim, 0, skill, weapon, damType);
            }

            /*
            * Hit.
            * Calc damage.
            *
            * NPCs are more badass barehanded than players.  If they weren't
            * the game would be too damned easy since mobs almost never have
            * weapons.
            *
            * Increased mob damage by about 1/6
            * It was previously level/2 to level*3/2 (25-75 at 50, average 50)
            * It is now level*3/5 to level*10/6      (30-87 at 50, average 59)
            *
            * Added the + ch.level - 1 'cause mobs still not hittin' hard enough
            */
            if( ch.IsNPC() )
            {
                dam = MUDMath.NumberRange( ( ch.Level * 3 / 5 ), ( ch.Level * 14 / 8 ) )
                      + ( ch.Level - 1 );
                if (wield)
                {
                    dam += MUDMath.Dice(wield.Values[1], wield.Values[2]);
                }
                else if (ch.CheckSkill("unarmed damage"))
                {
                    dam += MUDMath.NumberRange(1, (ch.GetSkillChance("unarmed damage") / 12));
                }
            }
            else
            {
                if (wield)
                {
                    dam = MUDMath.Dice(wield.Values[1], wield.Values[2]);
                }
                else
                {
                    if (!ch.IsClass(CharClass.Names.monk))
                    {
                        dam = MUDMath.NumberRange(1, (2 + (int)ch.CurrentSize / 3));
                        if (ch.CheckSkill("unarmed damage"))
                        {
                            dam += MUDMath.NumberRange(1, (ch.GetSkillChance("unarmed damage") / 12));
                        }
                    }
                    else
                    {
                        int min;
                        // monk barehanded damage - Xangis
                        ch.PracticeSkill("unarmed damage");
                        chance = ch.GetSkillChance("unarmed damage");
                        if (chance < 13)
                        {
                            min = 1;
                        }
                        else
                        {
                            min = chance / 13;
                        }
                        // at max skill for barehanded and unarmed, a monk will get
                        // a damage of 7-38, an average of 22.5 damage per hit before
                        // modifiers.  This is slightly better than a 6d6 weapon (average of 21 dmg)
                        // this is slightly worse than a 6d7 weapon (average of 24 dmg)
                        dam = MUDMath.NumberRange(min, ((chance / 3) + min));
                    }
                }
                if( ( wield && dam > 1000 ) && ch.Level < Limits.LEVEL_AVATAR )
                {
                    text = String.Format( "SingleAttack damage range > 1000 from {0} to {1}",
                              wield.Values[ 1 ], wield.Values[ 2 ] );
                    Log.Error( text, 0 );
                }
            }

            /*
            * Played a character with an armor class of 126 (awful agility).
            * Wasn't getting pounded much at all.  Added a damage bonus applied
            * when the target's ac is worse than 100.
            *
            * This also means that someone who makes their weapon proficiency
            * check against someone with an ac of 81 or higher will also get a
            * damage bonus of 1% per ac point.
            *
            * This applies to mobs too, so if a mob has a terrible AC it will
            * get whacked harder.  I call this the "soft as a pudding" code.
            *
            * This would also make AC debuffs stronger if they can make ac worse
            * than 100.
            */
            if( victimAC > 100 )
            {
                dam += ( (victimAC - 100) * dam) / 100;
            }

            /*
            * Bonuses.
            */
            dam += ch.GetDamroll( weapon );

            /* Weapon proficiencies, players only */
            /* Up to 50% increase based on weapon skill */
            if (wield && !ch.IsNPC())
            {
                dam += dam * ch.GetSkillChance(weaponGsn) / 180;
            }

            /* Up to 33% for offense skill */
            /* This means someone that has mastered a weapon and offense
            automatically does double damage in combat */
            chance = ch.GetSkillChance("offense");
            dam += dam * chance / 270;

            /* Bad idea to get caught napping in a fight */
            if( !victim.IsAwake() )
                dam *= 2;

            /* Backstab: 2 + one per 9 levels, 7x damage at 50 */
            if (skill == "backstab")
            {
                // Cap was previously too low.  It has been raised because a merc that was previously
                // stabbing for 180 now stabs for 64.  Assassins will still be able to stab for
                // 175 and mercs for 116 with this revised cap.  Keep in mind that a sorc can easily
                // fist for 250.
                int cap = 100 + 12 * ch.Level;
                if( ch.IsClass(CharClass.Names.mercenary) || ch.IsClass(CharClass.Names.bard ))
                    cap = cap * 2 / 3;
                dam *= ( 2 + ( ch.Level / 9 ) );
                /* damage cap applied here */
                dam = Math.Min( dam, cap );
            }
            else if (skill == "circle")              /* 150% to 200% at lev. 50 */
                dam += dam / 2 + ( dam * ch.Level ) / 100;

            if( dam <= 0 )
                dam = 1;

            return InflictDamage(ch, victim, dam, skill, weapon, damType);
        }