[Feature] Allow NPCs to cast Sacrifice (#4470)

* [Feature] Teach npcs how to cast sacrifice

* [Feature] Teach npcs how to cast sacrifice

- Remove the hardcoded limit preventing npcs from casting sacrifice. The
  npc will receive as loot an emerald essence as expected.

* Update client.cpp
* Update client_packet.cpp
* Update spell_effects.cpp

* rename Client::SacrificeCaster to Client::sacrifice_caster_id
This commit is contained in:
fuzzlecutter 2024-09-12 14:42:44 -05:00 committed by GitHub
parent 913c5da70f
commit cc0171dfe1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 17 additions and 13 deletions

View File

@ -286,6 +286,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob(
memset(&m_epp, 0, sizeof(m_epp));
PendingTranslocate = false;
PendingSacrifice = false;
sacrifice_caster_id = 0;
controlling_boat_id = 0;
controlled_mob_id = 0;
qGlobals = nullptr;
@ -3971,7 +3972,7 @@ void Client::SetEndurance(int32 newEnd)
CheckManaEndUpdate();
}
void Client::SacrificeConfirm(Client *caster)
void Client::SacrificeConfirm(Mob *caster)
{
auto outapp = new EQApplicationPacket(OP_Sacrifice, sizeof(Sacrifice_Struct));
Sacrifice_Struct *ss = (Sacrifice_Struct *)outapp->pBuffer;
@ -3998,14 +3999,14 @@ void Client::SacrificeConfirm(Client *caster)
ss->Confirm = 0;
QueuePacket(outapp);
safe_delete(outapp);
// We store the Caster's name, because when the packet comes back, it only has the victim's entityID in it,
// We store the Caster's id, because when the packet comes back, it only has the victim's entityID in it,
// not the caster.
SacrificeCaster += caster->GetName();
sacrifice_caster_id = caster->GetID();
PendingSacrifice = true;
}
//Essentially a special case death function
void Client::Sacrifice(Client *caster)
void Client::Sacrifice(Mob *caster)
{
if (GetLevel() >= RuleI(Spells, SacrificeMinLevel) && GetLevel() <= RuleI(Spells, SacrificeMaxLevel)) {
int exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000);
@ -4053,8 +4054,11 @@ void Client::Sacrifice(Client *caster)
}
Save();
GoToDeath();
if (caster) // I guess it's possible?
caster->SummonItem(RuleI(Spells, SacrificeItemID));
if (caster && caster->IsClient()) {
caster->CastToClient()->SummonItem(RuleI(Spells, SacrificeItemID));
} else if (caster && caster->IsNPC()) {
caster->CastToNPC()->AddItem(RuleI(Spells, SacrificeItemID), 1, false);
}
}
} else {
caster->MessageString(Chat::Red, SAC_TOO_LOW); // This being is not a worthy sacrifice.

View File

@ -762,8 +762,8 @@ public:
void GetRaidAAs(RaidLeadershipAA_Struct *into) const;
void ClearGroupAAs();
void UpdateGroupAAs(int32 points, uint32 type);
void SacrificeConfirm(Client* caster);
void Sacrifice(Client* caster);
void SacrificeConfirm(Mob* caster);
void Sacrifice(Mob* caster);
void GoToDeath();
inline const int32 GetInstanceID() const { return zone->GetInstanceID(); }
void SetZoning(bool in) { bZoning = in; }
@ -1245,7 +1245,7 @@ public:
bool PendingTranslocate;
time_t TranslocateTime;
bool PendingSacrifice;
std::string SacrificeCaster;
uint16 sacrifice_caster_id;
PendingTranslocate_Struct PendingTranslocateData;
void SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID);

View File

@ -13681,11 +13681,11 @@ void Client::Handle_OP_Sacrifice(const EQApplicationPacket *app)
}
if (ss->Confirm) {
Client *Caster = entity_list.GetClientByName(SacrificeCaster.c_str());
Mob *Caster = entity_list.GetMob(sacrifice_caster_id);
if (Caster) Sacrifice(Caster);
}
PendingSacrifice = false;
SacrificeCaster.clear();
sacrifice_caster_id = 0;
}
void Client::Handle_OP_SafeFallSuccess(const EQApplicationPacket *app) // bit of a misnomer, sent whenever safe fall is used (success of fail)

View File

@ -2202,10 +2202,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#ifdef SPELL_EFFECT_SPAM
snprintf(effect_desc, _EDLEN, "Sacrifice");
#endif
if(!caster || !IsClient() || !caster->IsClient()){
if(!caster || !IsClient() ){
break;
}
CastToClient()->SacrificeConfirm(caster->CastToClient());
CastToClient()->SacrificeConfirm(caster);
break;
}