From 711e8f62ce49cefad4e4a999ebece61eb3a8968b Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 5 Aug 2021 18:08:49 -0400 Subject: [PATCH] shield ability initial work --- common/spdat.h | 4 +- zone/attack.cpp | 40 ++++++++++++++ zone/bonuses.cpp | 36 +++++++++++-- zone/client_packet.cpp | 116 +++++++++++++++++------------------------ zone/common.h | 11 +++- zone/mob.cpp | 3 ++ zone/mob.h | 8 +++ 7 files changed, 144 insertions(+), 74 deletions(-) diff --git a/common/spdat.h b/common/spdat.h index df059f358..2a524ca8c 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -592,7 +592,7 @@ typedef enum { #define SE_ReduceSkillTimer 227 // implemented #define SE_ReduceFallDamage 228 // implented - reduce the damage that you take from falling #define SE_PersistantCasting 229 // implemented -#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability +#define SE_ExtendedShielding 230 // implemented XXXXXXXXX not used as bonus - increase range of /shield ability #define SE_StunBashChance 231 // implemented - increase chance to stun from bash. #define SE_DivineSave 232 // implemented (base1 == % chance on death to insta-res) (base2 == spell cast on save) #define SE_Metabolism 233 // implemented - Modifies food/drink consumption rates. @@ -617,7 +617,7 @@ typedef enum { #define SE_FrontalBackstabChance 252 // implemented[AA] - chance to perform a full damage backstab from front. #define SE_FrontalBackstabMinDmg 253 // implemented[AA] - allow a frontal backstab for mininum damage. #define SE_Blank 254 // implemented -#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield +#define SE_ShieldDuration 255 // implemented, XXXXXXXXXXXX not implemented as bonus - increases duration of /shield #define SE_ShroudofStealth 256 // implemented #define SE_PetDiscipline 257 // not implemented as bonus - /pet hold - official name is GivePetHold #define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab diff --git a/zone/attack.cpp b/zone/attack.cpp index 6df1c04bb..7d6a071a5 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -5278,9 +5278,49 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac hit.damage_done += (hit.damage_done * pct_damage_reduction / 100) + (defender->GetFcDamageAmtIncoming(this, 0, true, hit.skill)); + if (defender->shield_ability.shielder_id = GetID()) { + hit.damage_done *= 0.50;//Don't round. + DoShieldDamageOnShielder(defender, hit); + } + CheckNumHitsRemaining(NumHit::OutgoingHitSuccess); } +void Mob::DoShieldDamageOnShielder(Mob* defender, DamageHitInfo &hit) +{ + if (!defender) { + return; + } + + Mob *current_shielder = entity_list.GetMob(defender->shield_ability.shielder_id); + + if (!current_shielder) { + return; + } + + int mitigation = 75; + + if (current_shielder->HasShieldEquiped() && current_shielder->IsClient()) { + + EQ::ItemInstance* inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotSecondary); + + if (inst) { + + const EQ::ItemData* shield = inst->GetItem(); + if (shield && shield->ItemType == EQ::item::ItemTypeShield) { + mitigation -= shield->AC * 0.50; //1% increase per 2 AC + } + } + } + + mitigation = std::max(mitigation, 50); + + int shielder_damage_taken = hit.damage_done * 75 / 100; + + current_shielder->Damage(this, shielder_damage_taken, SPELL_UNKNOWN, hit.skill, true, -1, false, m_specialattacks); + current_shielder->CheckNumHitsRemaining(NumHit::OutgoingHitSuccess); +} + void Mob::CommonBreakInvisibleFromCombat() { //break invis when you attack diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 57ca16d6a..cf28bc9c1 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1583,6 +1583,22 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon) break; } + case SE_ExtendedShielding: + { + if (newbon->ExtendedShielding < base1) { + newbon->ExtendedShielding = base1; + } + break; + } + + case SE_ShieldDuration: + { + if (newbon->ShieldDuration < base1) { + newbon->ShieldDuration = base1; + } + break; + } + // to do case SE_PetDiscipline: break; @@ -1592,10 +1608,6 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon) break; case SE_SecondaryForte: break; - case SE_ExtendedShielding: - break; - case SE_ShieldDuration: - break; case SE_ReduceApplyPoisonTime: break; case SE_NimbleEvasion: @@ -3474,6 +3486,22 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne new_bonus->Pet_Add_Atk += effect_value; break; + case SE_ExtendedShielding: + { + if (new_bonus->ExtendedShielding < effect_value) { + new_bonus->ExtendedShielding = effect_value; + } + break; + } + + case SE_ShieldDuration: + { + if (new_bonus->ShieldDuration < effect_value) { + new_bonus->ShieldDuration = effect_value; + } + break; + } + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 41d66705c..860203a19 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -12808,83 +12808,65 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app) LogError("OP size error: OP_Shielding expected:[{}] got:[{}]", sizeof(Shielding_Struct), app->size); return; } - if (GetClass() != WARRIOR) - { + //Enforce level + //Augs on shieldd? + + if (GetLevel() < 30) { + return; //Client gives message + } + + if (GetClass() != WARRIOR){ return; } - if (shield_target) - { - entity_list.MessageCloseString( - this, false, 100, 0, - END_SHIELDING, GetName(), shield_target->GetName()); - for (int y = 0; y < 2; y++) - { - if (shield_target->shielder[y].shielder_id == GetID()) - { - shield_target->shielder[y].shielder_id = 0; - shield_target->shielder[y].shielder_bonus = 0; - } - } - } Shielding_Struct* shield = (Shielding_Struct*)app->pBuffer; + shield_target = entity_list.GetMob(shield->target_id); - bool ack = false; - EQ::ItemInstance* inst = GetInv().GetItem(EQ::invslot::slotSecondary); - if (!shield_target) - return; - if (inst) - { - const EQ::ItemData* shield = inst->GetItem(); - if (shield && shield->ItemType == EQ::item::ItemTypeShield) - { - for (int x = 0; x < 2; x++) - { - if (shield_target->shielder[x].shielder_id == 0) - { - entity_list.MessageCloseString( - this, false, 100, 0, - START_SHIELDING, GetName(), shield_target->GetName()); - shield_target->shielder[x].shielder_id = GetID(); - int shieldbonus = shield->AC * 2; - switch (GetAA(197)) - { - case 1: - shieldbonus = shieldbonus * 115 / 100; - break; - case 2: - shieldbonus = shieldbonus * 125 / 100; - break; - case 3: - shieldbonus = shieldbonus * 150 / 100; - break; - } - shield_target->shielder[x].shielder_bonus = shieldbonus; - shield_timer.Start(); - ack = true; - break; - } - } - } - else - { - Message(0, "You must have a shield equipped to shield a target!"); - shield_target = 0; - return; - } - } - else - { - Message(0, "You must have a shield equipped to shield a target!"); - shield_target = 0; + + if (!shield_target) { return; } - if (!ack) - { + + + if (shield_target->IsNPC()) { + //You must first target a living player //TODO Find string + return; + } + + if (shield_target->GetID() == GetID()) { //Client will give message "You can not shield yourself" + return; + } + + //Does 'Shield Target' already have a 'Shielder' + if (shield_target->shield_ability.shielder_id = GetID()) { MessageString(Chat::White, ALREADY_SHIELDED); - shield_target = 0; return; } + + //Does 'Shielder' already have a 'Shield Target' already have a shielder + if (shield_ability.shielder_id = GetID()) { + MessageString(Chat::White, ALREADY_SHIELDED); + return; + } + //AA to increase SPA 230 extended shielding + if (shield_target->CalculateDistance(GetX(), GetY(), GetZ()) > 15.0f) { + return; //Too far away, no message is given thoughh. //TODO: Timer to enforce distance check + } + + entity_list.MessageCloseString(this, false, 100, 0, START_SHIELDING, GetName(), shield_target->GetName()); + + //Apply to Shielder + shield_ability.shielder_id = GetID(); + shield_ability.shield_target_id = shield_target->GetID(); + + //Apply to Shield Target + shield_target->shield_ability.shielder_id = GetID(); + shield_target->shield_ability.shield_target_id = shield_target->GetID(); + + //Calculate AA for adding time SPA 255 extend shield duration + + shield_timer.Start(12000); + return; } diff --git a/zone/common.h b/zone/common.h index 51fd36225..ed1e05e46 100644 --- a/zone/common.h +++ b/zone/common.h @@ -548,7 +548,9 @@ struct StatBonuses { // AAs - int8 Packrat; //weight reduction for items, 1 point = 10% + int32 ShieldDuration; // extends duration of /shield ability + int32 ExtendedShielding; // extends range of /shield ability + int8 Packrat; // weight reduction for items, 1 point = 10% uint8 BuffSlotIncrease; // Increases number of available buff slots uint32 DelayDeath; // how far below 0 hp you can go int8 BaseMovementSpeed; // Adjust base run speed, does not stack with other movement bonuses. @@ -678,10 +680,17 @@ typedef struct } tProc; struct Shielders_Struct { + uint32 shielder_id; uint16 shielder_bonus; }; +struct ShieldAbility_Struct{ + + uint32 shield_target_id; + uint32 shielder_id; +}; + typedef struct { uint16 increment; diff --git a/zone/mob.cpp b/zone/mob.cpp index aac0078a3..cbf09646b 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -380,6 +380,9 @@ Mob::Mob( shielder[m].shielder_id = 0; shielder[m].shielder_bonus = 0; } + + shield_ability.shield_target_id = 0; + shield_ability.shielder_id = 0; destructibleobject = false; wandertype = 0; diff --git a/zone/mob.h b/zone/mob.h index 970c117ae..9c9d96581 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1126,8 +1126,16 @@ public: void SetMoved(bool moveflag) { moved = moveflag; } Shielders_Struct shielder[MAX_SHIELDERS]; + Trade* trade; + ShieldAbility_Struct shield_ability; + void DoShieldDamageOnShielder(Mob* defender, DamageHitInfo &hit); + inline int GetShielderID() { return shield_ability.shielder_id; } + inline int SetShielderID(int ent_id) { shield_ability.shielder_id = ent_id; } + inline int GetShieldTargetID() { return shield_ability.shield_target_id; } + inline int SetShieldTargetID(int ent_id) { shield_ability.shield_target_id = ent_id; } + inline glm::vec4 GetCurrentWayPoint() const { return m_CurrentWayPoint; } inline float GetCWPP() const { return(static_cast(cur_wp_pause)); } inline int GetCWP() const { return(cur_wp); }