diff --git a/changelog.txt b/changelog.txt index 0204c266b..40a933c56 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,14 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/08/2015 == +Kayen: Implemented npc specialability (44) COUNTER_AVOID_DAMAGE which when applied to the ATTACKING NPC will make their attacks more difficult to be avoided by riposte/dodge/parry/block. +Parama0: Negative modifer value that affects ALL avoid damage types dodge/parry/riposte/block) chance on defender. Ie (44,50 = 50 pct reduction to ALL) +Parama1: Negative modifer value that affects RIPOSTE chance on defender. Ie (44,1,0,50 = 50 pct reduction to riposte chance) +Parama2: Negative modifer value that affects PARRY chance on defender. Ie (44,1,0,0,50 = 50 pct reduction to parry chance) +Parama3: Negative modifer value that affects BLOCK chance on defender. Ie (44,1,0,0,0,50 = 50 pct reduction to block chance) +Parama4: Negative modifer value that affects DODGE chance on defender. e (44,1,0,0,0,0,50 = 50 pct reduction to dodge chance) +Example of usage: Player has Improved Dodge V (+50 pct dodge chance), you want to negate this bonus you would set 44,1,0,0,0,0,50 on your NPC. + == 02/07/2015 == Akkadius: Reduced #repop time dramatically by taking down hundreds of individual SELECT/DELETE/INSERT queries in routines and bringing it down to very few See: https://www.youtube.com/watch?v=9kSFbyTBuAk diff --git a/zone/attack.cpp b/zone/attack.cpp index bfd4a5cc2..ef57b4b6b 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -362,13 +362,40 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) //garunteed hit bool ghit = false; - if((attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500) + if((attacker->aabonuses.MeleeSkillCheck + attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500) ghit = true; + bool InFront = false; + + if (attacker->InFrontMob(this, attacker->GetX(), attacker->GetY())) + InFront = true; + + /* + This special ability adds a negative modifer to the defenders riposte/block/parry/chance + therefore reducing the defenders chance to successfully avoid the melee attack. At present + time this is the only way to fine tune counter these mods on players. This may + ultimately end up being more useful as fields in npc_types. + */ + + int counter_all = 0; + int counter_riposte = 0; + int counter_block = 0; + int counter_parry = 0; + int counter_dodge = 0; + + if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)){ + + counter_all = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 0); + counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE,1); + counter_block = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 2); + counter_parry = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 3); + counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4); + } + ////////////////////////////////////////////////////////// // make enrage same as riposte ///////////////////////////////////////////////////////// - if (IsEnraged() && other->InFrontMob(this, other->GetX(), other->GetY())) { + if (IsEnraged() && InFront) { damage = -3; Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack."); } @@ -377,9 +404,10 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) // riposte ///////////////////////////////////////////////////////// float riposte_chance = 0.0f; - if (CanRiposte && damage > 0 && CanThisClassRiposte() && other->InFrontMob(this, other->GetX(), other->GetY())) + if (CanRiposte && damage > 0 && CanThisClassRiposte() && InFront) { - riposte_chance = (100.0f + (float)defender->aabonuses.RiposteChance + (float)defender->spellbonuses.RiposteChance + (float)defender->itembonuses.RiposteChance) / 100.0f; + riposte_chance = (100.0f + static_cast(aabonuses.RiposteChance + spellbonuses.RiposteChance + + itembonuses.RiposteChance - counter_riposte - counter_all)) / 100.0f; skill = GetSkill(SkillRiposte); if (IsClient()) { CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10); @@ -398,28 +426,19 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) /////////////////////////////////////////////////////// bool bBlockFromRear = false; - bool bShieldBlockFromRear = false; - if (this->IsClient()) { - int aaChance = 0; + // a successful roll on this does not mean a successful block is forthcoming. only that a chance to block + // from a direction other than the rear is granted. - // a successful roll on this does not mean a successful block is forthcoming. only that a chance to block - // from a direction other than the rear is granted. + int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind; - //Live AA - HightenedAwareness - int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind; - - if (BlockBehindChance && zone->random.Roll(BlockBehindChance)) { - bBlockFromRear = true; - - if (spellbonuses.BlockBehind || itembonuses.BlockBehind) - bShieldBlockFromRear = true; //This bonus should allow a chance to Shield Block from behind. - } - } + if (BlockBehindChance && zone->random.Roll(BlockBehindChance)) + bBlockFromRear = true; float block_chance = 0.0f; - if (damage > 0 && CanThisClassBlock() && (other->InFrontMob(this, other->GetX(), other->GetY()) || bBlockFromRear)) { - block_chance = (100.0f + (float)spellbonuses.IncreaseBlockChance + (float)itembonuses.IncreaseBlockChance) / 100.0f; + if (damage > 0 && CanThisClassBlock() && (InFront || bBlockFromRear)) { + block_chance = (100.0f + static_cast(aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance + + itembonuses.IncreaseBlockChance - counter_block - counter_all)) / 100.0f; skill = CastToClient()->GetSkill(SkillBlock); if (IsClient()) { CastToClient()->CheckIncreaseSkill(SkillBlock, other, -10); @@ -435,32 +454,20 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) RollTable[1] = RollTable[0]; } - if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) - && (other->InFrontMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) { - - float bonusShieldBlock = 0.0f; - bonusShieldBlock = static_cast(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock); - RollTable[1] += bonusShieldBlock; - } - - if(IsClient() && damage > 0 && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) - && (other->InFrontMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) { - if(CastToClient()->m_inv.GetItem(MainPrimary)) { - float bonusStaffBlock = 0.0f; - if (CastToClient()->m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HBlunt){ - bonusStaffBlock = static_cast(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock); - RollTable[1] += bonusStaffBlock; - } - } - } + //Try Shield Block OR TwoHandBluntBlockCheck + if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear)) + RollTable[1] += static_cast(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock - counter_block - counter_all); + else if(damage > 0 && HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear)) + RollTable[1] += static_cast(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock - counter_block - counter_all); + ////////////////////////////////////////////////////// // parry ////////////////////////////////////////////////////// float parry_chance = 0.0f; - if (damage > 0 && CanThisClassParry() && other->InFrontMob(this, other->GetX(), other->GetY())) - { - parry_chance = (100.0f + (float)defender->spellbonuses.ParryChance + (float)defender->itembonuses.ParryChance) / 100.0f; + if (damage > 0 && CanThisClassParry() && InFront){ + parry_chance = (100.0f + static_cast(aabonuses.ParryChance + itembonuses.ParryChance + + itembonuses.ParryChance - counter_parry - counter_all)) / 100.0f; skill = CastToClient()->GetSkill(SkillParry); if (IsClient()) { CastToClient()->CheckIncreaseSkill(SkillParry, other, -10); @@ -481,9 +488,11 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) // dodge //////////////////////////////////////////////////////// float dodge_chance = 0.0f; - if (damage > 0 && CanThisClassDodge() && other->InFrontMob(this, other->GetX(), other->GetY())) - { - dodge_chance = (100.0f + (float)defender->spellbonuses.DodgeChance + (float)defender->itembonuses.DodgeChance) / 100.0f; + if (damage > 0 && CanThisClassDodge() && InFront){ + + dodge_chance = (100.0f + static_cast(aabonuses.DodgeChance + spellbonuses.DodgeChance + + itembonuses.DodgeChance - counter_dodge - counter_all)) / 100.0f; + skill = CastToClient()->GetSkill(SkillDodge); if (IsClient()) { CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10); diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 8e99f9b23..a76860ce4 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -139,7 +139,8 @@ void Client::CalcItemBonuses(StatBonuses* newbon) { // Clear item faction mods ClearItemFactionBonuses(); - ShieldEquiped(false); + SetShieldEquiped(false); + SetTwoHandBluntEquiped(false); unsigned int i; //should not include 21 (SLOT_AMMO) @@ -149,9 +150,12 @@ void Client::CalcItemBonuses(StatBonuses* newbon) { continue; AddItemBonuses(inst, newbon); - //Check if item is secondary slot is a 'shield'. Required for multiple spelll effects. - if (i == MainSecondary && (m_inv.GetItem(MainSecondary)->GetItem()->ItemType == ItemTypeShield)) - ShieldEquiped(true); + //These are given special flags due to how often they are checked for various spell effects. + const Item_Struct *item = inst->GetItem(); + if (i == MainSecondary && (item && item->ItemType == ItemTypeShield)) + SetShieldEquiped(true); + else if (i == MainPrimary && (item && item->ItemType == ItemType2HBlunt)) + SetTwoHandBluntEquiped(true); } //Power Source Slot diff --git a/zone/common.h b/zone/common.h index 639eee91e..56ab6f819 100644 --- a/zone/common.h +++ b/zone/common.h @@ -136,7 +136,8 @@ enum { ALLOW_TO_TANK = 41, IGNORE_ROOT_AGGRO_RULES = 42, CASTING_RESIST_DIFF = 43, - MAX_SPECIAL_ATTACK = 44 + COUNTER_AVOID_DAMAGE = 44, + MAX_SPECIAL_ATTACK = 45 }; typedef enum { //fear states diff --git a/zone/mob.cpp b/zone/mob.cpp index e9cee33e4..ea86ff4dc 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -170,6 +170,7 @@ Mob::Mob(const char* in_name, findable = false; trackable = true; has_shieldequiped = false; + has_twohandbluntequiped = false; has_numhits = false; has_MGB = false; has_ProjectIllusion = false; diff --git a/zone/mob.h b/zone/mob.h index e7318007e..fb8148713 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -308,7 +308,9 @@ public: void SetTargetable(bool on); bool IsTargetable() const { return m_targetable; } bool HasShieldEquiped() const { return has_shieldequiped; } - inline void ShieldEquiped(bool val) { has_shieldequiped = val; } + inline void SetShieldEquiped(bool val) { has_shieldequiped = val; } + bool HasTwoHandBluntEquiped() const { return has_twohandbluntequiped; } + inline void SetTwoHandBluntEquiped(bool val) { has_twohandbluntequiped = val; } virtual uint16 GetSkill(SkillUseTypes skill_num) const { return 0; } virtual uint32 GetEquipment(uint8 material_slot) const { return(0); } virtual int32 GetEquipmentMaterial(uint8 material_slot) const; @@ -1150,6 +1152,7 @@ protected: uint16 viral_spells[MAX_SPELL_TRIGGER*2]; // Stores the spell ids of the viruses on target and caster ids bool offhand; bool has_shieldequiped; + bool has_twohandbluntequiped; bool has_numhits; bool has_MGB; bool has_ProjectIllusion;