From 71e9dd5a3ca4c2d577abdddfb41bde22a2c9fab2 Mon Sep 17 00:00:00 2001 From: RoTPvP <77220477+RoT-PvP@users.noreply.github.com> Date: Sun, 30 May 2021 18:22:52 -0700 Subject: [PATCH] [PVP] Pvp guard assist code. (Guards will assist in PvP based on faction) (#1367) * Added Guard Assist Code * Added PvP Rule and Detrimental Spell Check * Added IsGuard() Method * Change from uint to bool * Added a faction check to IsGuard() * Simplified Guard Checks, reduced costs * Added IsNPC check to guard check * simplified pet check * Removed Magic numbers * Formatting Fix * Code fixes * Fixed constants Co-authored-by: ProducerZekServer --- common/eq_constants.h | 7 +++++++ common/races.h | 1 - common/ruletypes.h | 1 + zone/attack.cpp | 37 +++++++++++++++++++++++++++++++++++++ zone/npc.cpp | 32 ++++++++++++++++++++++++++++++++ zone/npc.h | 1 + zone/spells.cpp | 19 +++++++++++++++++++ 7 files changed, 97 insertions(+), 1 deletion(-) diff --git a/common/eq_constants.h b/common/eq_constants.h index a585bdd87..057051ff6 100644 --- a/common/eq_constants.h +++ b/common/eq_constants.h @@ -438,6 +438,13 @@ static const uint8 SkillDamageTypes[EQ::skills::HIGHEST_SKILL + 1] = // change t static const uint32 MAX_SPELL_DB_ID_VAL = 65535; +static const uint32 DB_SPELL_CAZIC_TOUCH = 982; +static const uint32 DB_SPELL_TOUCH_OF_VINITRAS = 2859; + +static const uint32 DB_FACTION_GEM_CHOPPERS = 255; +static const uint32 DB_FACTION_HERETICS = 265; +static const uint32 DB_FACTION_KING_AKANON = 333; + enum ChatChannelNames : uint16 { ChatChannel_Guild = 0, diff --git a/common/races.h b/common/races.h index 5e7411a25..b492fb03a 100644 --- a/common/races.h +++ b/common/races.h @@ -860,7 +860,6 @@ uint16 GetRaceIDFromPlayerRaceBit(uint32 player_race_bit); float GetRaceGenderDefaultHeight(int race, int gender); - // player race-/gender-based model feature validators namespace PlayerAppearance { diff --git a/common/ruletypes.h b/common/ruletypes.h index 722ce5dc3..e2c25fb02 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -163,6 +163,7 @@ RULE_BOOL(Character, SoftDeletes, true, "When characters are deleted in characte RULE_INT(Character, DefaultGuild, 0, "If not 0, new characters placed into the guild # indicated") RULE_BOOL(Character, ProcessFearedProximity, false, "Processes proximity checks when feared") RULE_BOOL(Character, EnableCharacterEXPMods, false, "Enables character zone-based experience modifiers.") +RULE_BOOL(Character, PVPEnableGuardFactionAssist, true, "Enables faction based assisting against the aggresor in pvp.") RULE_CATEGORY_END() RULE_CATEGORY(Mercs) diff --git a/zone/attack.cpp b/zone/attack.cpp index de9a6101e..fbf4af53e 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1522,6 +1522,25 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b other->AddToHateList(this, hate); + //Guard Assist Code + if (RuleB(Character, PVPEnableGuardFactionAssist)) { + if (IsClient() || (HasOwner() && GetOwner()->IsClient())) { + auto& mob_list = entity_list.GetCloseMobList(other); + for (auto& e : mob_list) { + auto mob = e.second; + if (mob->IsNPC() && mob->CastToNPC()->IsGuard()) { + float distance = Distance(other->CastToClient()->m_Position, mob->GetPosition()); + if ((mob->CheckLosFN(other) || mob->CheckLosFN(this)) && distance <= 70) { + auto petorowner = GetOwnerOrSelf(); + if (other->GetReverseFactionCon(mob) <= petorowner->GetReverseFactionCon(mob)) { + mob->AddToHateList(this); + } + } + } + } + } + } + /////////////////////////////////////////////////////////// ////// Send Attack Damage /////////////////////////////////////////////////////////// @@ -2002,6 +2021,24 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool } } + //Guard Assist Code + if (RuleB(Character, PVPEnableGuardFactionAssist)) { + if (IsClient() || (HasOwner() && GetOwner()->IsClient())) { + auto& mob_list = entity_list.GetCloseMobList(other); + for (auto& e : mob_list) { + auto mob = e.second; + if (mob->IsNPC() && mob->CastToNPC()->IsGuard()) { + float distance = Distance(other->GetPosition(), mob->GetPosition()); + if ((mob->CheckLosFN(other) || mob->CheckLosFN(this)) && distance <= 70) { + if (other->GetReverseFactionCon(mob) <= GetOwner()->GetReverseFactionCon(mob)) { + mob->AddToHateList(this); + } + } + } + } + } + } + int weapon_damage = GetWeaponDamage(other, weapon); //do attack animation regardless of whether or not we can hit below diff --git a/zone/npc.cpp b/zone/npc.cpp index 9bea0ec67..325f8fb70 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -3368,3 +3368,35 @@ void NPC::ScaleNPC(uint8 npc_level) { npc_scale_manager->ResetNPCScaling(this); npc_scale_manager->ScaleNPC(this); } + +bool NPC::IsGuard() +{ + switch (GetRace()) { + case RT_GUARD: + if (GetTexture() == 1 || GetTexture() == 2) + return true; + break; + case RT_IKSAR_2: + if (GetTexture() == 1) + return true; + break; + case RT_GUARD_2: + case RT_GUARD_3: + case RT_GUARD_4: + case RT_HUMAN_3: + case RT_HALFLING_2: + case RT_ERUDITE_2: + case RT_BARBARIAN_2: + case RT_DARK_ELF_2: + case RT_TROLL_2: + case OGGOK_CITIZEN: + case RT_DWARF_2: + return true; + default: + break; + } + if (GetPrimaryFaction() == DB_FACTION_GEM_CHOPPERS || GetPrimaryFaction() == DB_FACTION_HERETICS || GetPrimaryFaction() == DB_FACTION_KING_AKANON) { //these 3 factions of guards use player races instead of their own races so we must define them by faction. + return true; + } + return false; +} diff --git a/zone/npc.h b/zone/npc.h index b23d15568..995542e0d 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -175,6 +175,7 @@ public: bool DatabaseCastAccepted(int spell_id); bool IsFactionListAlly(uint32 other_faction); + bool IsGuard(); FACTION_VALUE CheckNPCFactionAlly(int32 other_faction); virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther); diff --git a/zone/spells.cpp b/zone/spells.cpp index f7536cd04..15a1151e0 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2044,6 +2044,25 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui if(!IsValidSpell(spell_id)) return false; + //Guard Assist Code + if (RuleB(Character, PVPEnableGuardFactionAssist) && IsDetrimentalSpell(spell_id) && spell_target != this) { + if (IsClient() || (HasOwner() && GetOwner()->IsClient())) { + auto& mob_list = entity_list.GetCloseMobList(spell_target); + for (auto& e : mob_list) { + auto mob = e.second; + if (mob->IsNPC() && mob->CastToNPC()->IsGuard()) { + float distance = Distance(spell_target->GetPosition(), mob->GetPosition()); + if ((mob->CheckLosFN(spell_target) || mob->CheckLosFN(this)) && distance <= 70) { + auto petorowner = GetOwnerOrSelf(); + if (spell_target->GetReverseFactionCon(mob) <= petorowner->GetReverseFactionCon(mob)) { + mob->AddToHateList(this); + } + } + } + } + } + } + if( spells[spell_id].zonetype == 1 && !zone->CanCastOutdoor()){ if(IsClient()){ if(!CastToClient()->GetGM()){