Add Buff infrastructure to go through different logic paths from different patches (#5073)
Build / Linux (push) Waiting to run
Build / Windows (push) Waiting to run

This commit is contained in:
dannuic
2026-05-02 22:53:26 -06:00
committed by GitHub
parent c253734c57
commit 18df055f16
201 changed files with 2856 additions and 3105 deletions
+66 -299
View File
@@ -145,7 +145,7 @@ void NPC::SpellProcess()
// the rule is you can cast one triggered (usually timed) spell at a time
// but things like SpellFinished() can run concurrent with a triggered cast
// to allow procs to work
bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
bool Mob::CastSpell(int32 spell_id, uint16 target_id, CastingSlot slot,
int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot,
uint32 timer, uint32 timer_duration, int16 *resist_adjust,
uint32 aa_id)
@@ -291,7 +291,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
// this is the 2nd phase of CastSpell, broken up like this to make it easier
// to repeat a spell for bard songs
//
bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
bool Mob::DoCastSpell(int32 spell_id, uint16 target_id, CastingSlot slot,
int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish,
uint32 item_slot, uint32 timer, uint32 timer_duration,
int16 resist_adjust, uint32 aa_id)
@@ -339,12 +339,12 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spell_id);
if (IsClient())
Message::MessageString(CastToClient(), Chat::SpellFailure, fizzle_msg, spell_link);
ClientPatch::SendMessageString(CastToClient(), Chat::SpellFailure, fizzle_msg, spell_link);
/**
* Song Failure message
*/
Message::CloseMessageString(this, true, RuleI(Range, SpellMessages),
ClientPatch::BroadcastMessageStringInRadius(this, true, RuleI(Range, SpellMessages),
nullptr, true, IsClient() ? FilterPCSpells : FilterNPCSpells)(
Chat::SpellFailure, fizzle_msg == MISS_NOTE ? MISSED_NOTE_OTHER : SPELL_FIZZLE_OTHER, GetName(), spell_link);
@@ -480,7 +480,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
return true;
}
void Mob::DoSpellInterrupt(uint16 spell_id, int32 mana_cost, int my_curmana) {
void Mob::DoSpellInterrupt(int32 spell_id, int32 mana_cost, int my_curmana) {
//The client will prevent spell casting if insufficient mana, this is only for serverside enforcement.
LogSpells("Not enough mana spell [{}] curmana [{}] cost [{}]\n", spell_id, my_curmana, mana_cost);
if (IsClient()) {
@@ -493,7 +493,7 @@ void Mob::DoSpellInterrupt(uint16 spell_id, int32 mana_cost, int my_curmana) {
ZeroCastingVars();
}
void Mob::SendBeginCast(uint16 spell_id, uint32 casttime)
void Mob::SendBeginCast(int32 spell_id, uint32 casttime)
{
auto outapp = new EQApplicationPacket(OP_BeginCast, sizeof(BeginCast_Struct));
auto begincast = (BeginCast_Struct *)outapp->pBuffer;
@@ -922,7 +922,7 @@ bool Mob::DoCastingChecksOnTarget(bool check_on_casting, int32 spell_id, Mob *sp
return true;
}
uint16 Mob::GetSpecializeSkillValue(uint16 spell_id) const {
uint16 Mob::GetSpecializeSkillValue(int32 spell_id) const {
switch(spells[spell_id].skill) {
case EQ::skills::SkillAbjuration:
return(GetSkill(EQ::skills::SkillSpecializeAbjure));
@@ -941,7 +941,7 @@ uint16 Mob::GetSpecializeSkillValue(uint16 spell_id) const {
return(0);
}
void Client::CheckSpecializeIncrease(uint16 spell_id) {
void Client::CheckSpecializeIncrease(int32 spell_id) {
// These are not active because CheckIncreaseSkill() already does so.
// It's such a rare occurance that adding them here is wasted..(ref only)
/*
@@ -973,7 +973,7 @@ void Client::CheckSpecializeIncrease(uint16 spell_id) {
}
}
void Client::CheckSongSkillIncrease(uint16 spell_id){
void Client::CheckSongSkillIncrease(int32 spell_id){
// These are not active because CheckIncreaseSkill() already does so.
// It's such a rare occurance that adding them here is wasted..(ref only)
/*
@@ -1039,12 +1039,12 @@ only works for clients, npcs shouldn't be fizzling..
new algorithm thats closer to live eq (i hope)
TODO: Add aa skills, item mods, reduced the chance to fizzle
*/
bool Mob::CheckFizzle(uint16 spell_id)
bool Mob::CheckFizzle(int32 spell_id)
{
return(true);
}
bool Client::CheckFizzle(uint16 spell_id)
bool Client::CheckFizzle(int32 spell_id)
{
// GMs don't fizzle
if (GetGM()) {
@@ -1228,7 +1228,7 @@ void Mob::ZeroBardPulseVars()
bardsong_timer.Disable();
}
void Mob::InterruptSpell(uint16 spellid)
void Mob::InterruptSpell(int32 spellid)
{
if (!IsValidSpell(spellid)) {
spellid = casting_spell_id;
@@ -1238,7 +1238,7 @@ void Mob::InterruptSpell(uint16 spellid)
}
// color not used right now
void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
void Mob::InterruptSpell(uint16 message, uint16 color, int32 spellid)
{
uint16 message_other;
bool bard_song_mode = false; //has the bard song gone to auto repeat mode
@@ -1303,7 +1303,7 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
// the interrupt message
char spell_link[Links::MAX_LINK_SIZE];
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spellid);
Message::InterruptSpell(CastToClient(), message, GetID(), spell_link);
ClientPatch::InterruptSpell(CastToClient(), message, GetID(), spell_link);
SendSpellBarEnable(spellid);
}
@@ -1331,7 +1331,7 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
// this is the actual message, it works the same as a formatted message
char spell_link[Links::MAX_LINK_SIZE];
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spellid);
Message::InterruptSpellOther(this, message_other, GetID(), GetCleanName(), spell_link);
ClientPatch::InterruptSpellOther(this, message_other, GetID(), GetCleanName(), spell_link);
}
// this is like interrupt, just it doesn't spam interrupt packets to everyone
@@ -1390,7 +1390,7 @@ void Mob::StopCastSpell(int32 spell_id, bool send_spellbar_enable)
// NOTE: do not put range checking, etc into this function. this should
// just check timed spell specific things before passing off to SpellFinished
// which figures out proper targets etc
void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slot,
void Mob::CastedSpellFinished(int32 spell_id, uint32 target_id, CastingSlot slot,
int32 mana_used, uint32 inventory_slot, int16 resist_adjust)
{
if (!IsValidSpell(spell_id))
@@ -1839,7 +1839,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
}
bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, CastingSlot slot, bool isproc)
bool Mob::DetermineSpellTargets(int32 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, CastingSlot slot, bool isproc)
{
/*
The basic types of spells:
@@ -2383,7 +2383,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
// only used from CastedSpellFinished, and procs
// we can't interrupt in this, or anything called from this!
// if you need to abort the casting, return false
bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, int32 mana_used,
bool Mob::SpellFinished(int32 spell_id, Mob *spell_target, CastingSlot slot, int32 mana_used,
uint32 inventory_slot, int16 resist_adjust, bool isproc, int level_override,
uint32 timer, uint32 timer_duration, bool from_casted_spell, uint32 aa_id)
{
@@ -2856,7 +2856,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, in
if (IsClient() && IsEffectInSpell(spell_id, SpellEffect::BindSight)) {
for (int i = 0; i < GetMaxTotalSlots(); i++) {
if (buffs[i].spellid == spell_id) {
CastToClient()->SendBuffNumHitPacket(buffs[i], i);//its hack, it works.
ClientPatch::SendSingleBuffChange(this, buffs[i], i);//its hack, it works.
}
}
}
@@ -2864,7 +2864,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, in
if (IsClient() && spells[spell_id].hit_number) {
for (int i = 0; i < GetMaxTotalSlots(); i++) {
if (buffs[i].spellid == spell_id && buffs[i].hit_number > 0) {
CastToClient()->SendBuffNumHitPacket(buffs[i], i);
ClientPatch::SendSingleBuffChange(this, buffs[i], i);
break;
}
}
@@ -2928,7 +2928,7 @@ bool Mob::ApplyBardPulse(int32 spell_id, Mob *spell_target, CastingSlot slot) {
// even be created depending on the types of mobs involved
//
// right now this is just an outline, working on this..
int Mob::CalcBuffDuration(Mob *caster, Mob *target, uint16 spell_id, int32 caster_level_override)
int Mob::CalcBuffDuration(Mob *caster, Mob *target, int32 spell_id, int32 caster_level_override)
{
int formula, duration;
@@ -3054,7 +3054,7 @@ int CalcBuffDuration_formula(int level, int formula, int duration)
// -1 if they can't stack and spellid2 should be stopped
//currently, a spell will not land if it would overwrite a better spell on any effect
//if all effects are better or the same, we overwrite, else we do nothing
int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1, Mob* caster2, int buffslot)
int Mob::CheckStackConflict(int32 spellid1, int caster_level1, int32 spellid2, int caster_level2, Mob* caster1, Mob* caster2, int buffslot)
{
const SPDat_Spell_Struct &sp1 = spells[spellid1];
const SPDat_Spell_Struct &sp2 = spells[spellid2];
@@ -3411,7 +3411,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
// spells 1-50: no restrictons
// 51-65: SpellLevel/2+15
// 66+ Group Spells 62, Single Target 61
bool Mob::CheckSpellLevelRestriction(Mob *caster, uint16 spell_id)
bool Mob::CheckSpellLevelRestriction(Mob *caster, int32 spell_id)
{
if (spells[spell_id].target_type == ST_Self) {
LogSpells("[CheckSpellLevelRestriction] Self Only spell - no restrictions");
@@ -3517,7 +3517,7 @@ bool Mob::HasDiscBuff()
// stacking problems, and -2 if this is not a buff
// if caster is null, the buff will be added with the caster level being
// the level of the mob
int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_override, bool disable_buff_overwrite)
int Mob::AddBuff(Mob *caster, int32 spell_id, int duration, int32 level_override, bool disable_buff_overwrite)
{
int buffslot, ret, caster_level, emptyslot = -1;
bool will_overwrite = false;
@@ -3720,6 +3720,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
memset(buffs[emptyslot].caster_name, 0, 64);
buffs[emptyslot].casterid = caster ? caster->GetID() : 0;
buffs[emptyslot].ticsremaining = duration;
buffs[emptyslot].initialduration = duration;
buffs[emptyslot].counters = CalculateCounters(spell_id);
buffs[emptyslot].hit_number = spells[spell_id].hit_number;
buffs[emptyslot].client = caster ? caster->IsClient() : 0;
@@ -3741,29 +3742,8 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
}
LogSpells("Buff [{}] added to slot [{}] with caster level [{}]", spell_id, emptyslot, caster_level);
if (IsPet() && GetOwner() && GetOwner()->IsClient())
SendPetBuffsToClient();
if((IsClient() && !CastToClient()->GetPVP()) ||
(IsPet() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()) ||
(IsBot() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()) ||
(IsMerc() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()))
{
EQApplicationPacket *outapp = MakeBuffsPacket();
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQ::versions::maskSoDAndLater);
if(IsClient() && GetTarget() == this)
CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
}
if (IsNPC()) {
EQApplicationPacket *outapp = MakeBuffsPacket();
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQ::versions::maskSoDAndLater, true);
safe_delete(outapp);
}
ClientPatch::SendSingleBuffChange(this, buffs[emptyslot], emptyslot);
ClientPatch::SendFullBuffRefresh(this);
// recalculate bonuses since we stripped/added buffs
CalcBonuses();
@@ -3776,7 +3756,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
// note that this should not be used for determining which slot to place a
// buff into
// returns -1 on stack failure, -2 if all slots full, the slot number if the buff should overwrite another buff, or a free buff slot
int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite)
int Mob::CanBuffStack(int32 spellid, uint8 caster_level, bool iFailIfOverwrite)
{
int i, ret, firstfree = -2;
@@ -3873,7 +3853,7 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite)
// break stuff
//
bool Mob::SpellOnTarget(
uint16 spell_id,
int32 spell_id,
Mob *spelltar,
int reflect_effectiveness,
bool use_resist_adjust,
@@ -4733,11 +4713,11 @@ std::vector<uint16> Mob::GetBuffSpellIDs()
return l;
}
bool Mob::FindBuff(uint16 spell_id, uint16 caster_id)
bool Mob::FindBuff(int32 spell_id, uint16 caster_id)
{
const int buff_count = GetMaxTotalSlots();
for (int buff_slot = 0; buff_slot < buff_count; buff_slot++) {
const uint16 current_spell_id = buffs[buff_slot].spellid;
const int32 current_spell_id = buffs[buff_slot].spellid;
if (
IsValidSpell(current_spell_id) &&
current_spell_id == spell_id &&
@@ -4916,7 +4896,7 @@ void Mob::BuffFadeBySitModifier()
}
}
void Mob::BuffFadeBySpellID(uint16 spell_id)
void Mob::BuffFadeBySpellID(int32 spell_id)
{
bool recalc_bonus = false;
int buff_count = GetMaxTotalSlots();
@@ -4932,7 +4912,7 @@ void Mob::BuffFadeBySpellID(uint16 spell_id)
}
}
void Mob::BuffFadeBySpellIDAndCaster(uint16 spell_id, uint16 caster_id)
void Mob::BuffFadeBySpellIDAndCaster(int32 spell_id, uint16 caster_id)
{
bool recalc_bonus = false;
auto buff_count = GetMaxTotalSlots();
@@ -4977,7 +4957,7 @@ void Mob::BuffFadeSongs() {
int buff_count = GetMaxTotalSlots();
for (int buff_slot = 0; buff_slot < buff_count; buff_slot++) {
const uint16 current_spell_id = buffs[buff_slot].spellid;
const int32 current_spell_id = buffs[buff_slot].spellid;
if (IsBardSong(current_spell_id)) {
BuffFadeBySlot(buff_slot, false);
recalc_bonus = true;
@@ -5027,7 +5007,7 @@ void Mob::BuffDetachCaster(Mob *caster) {
// checks if 'this' can be affected by spell_id from caster
// returns true if the spell should fail, false otherwise
bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
bool Mob::IsImmuneToSpell(int32 spell_id, Mob *caster)
{
int effect_index;
@@ -5267,7 +5247,7 @@ int Mob::GetResist(uint8 resist_type)
// pvp_resist_base
// pvp_resist_calc
// pvp_resist_cap
float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override, int resist_override, bool CharismaCheck, bool CharmTick, bool IsRoot, int level_override)
float Mob::ResistSpell(uint8 resist_type, int32 spell_id, Mob *caster, bool use_resist_override, int resist_override, bool CharismaCheck, bool CharmTick, bool IsRoot, int level_override)
{
if(!caster)
@@ -5651,7 +5631,7 @@ int16 Mob::CalcFearResistChance()
return resist_chance;
}
float Mob::GetAOERange(uint16 spell_id)
float Mob::GetAOERange(int32 spell_id)
{
float range = spells[spell_id].aoe_range;
@@ -5737,7 +5717,7 @@ void Mob::SendSpellBarDisable()
}
// this puts the spell bar back into a usable state fast
void Mob::SendSpellBarEnable(uint16 spell_id)
void Mob::SendSpellBarEnable(int32 spell_id)
{
if(!IsClient())
return;
@@ -5830,54 +5810,7 @@ void Mob::Mesmerize()
StopNavigation();
}
void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message)
{
EQApplicationPacket* outapp = nullptr;
outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffPacket_Struct));
SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer;
sbf->entityid = GetID();
// i dont know why but this works.. for now
sbf->buff.effect_type = 2;
// sbf->slot=m_pp.buffs[slot_id].slotid;
// sbf->level=m_pp.buffs[slot_id].level;
// sbf->effect=m_pp.buffs[slot_id].effect;
sbf->buff.spellid = spell_id;
sbf->slotid = slot_id;
sbf->bufffade = 1;
#if EQDEBUG >= 11
printf("Sending SBF 1 from server:\n");
DumpPacket(outapp);
#endif
QueuePacket(outapp);
/*
sbf->effect=0;
sbf->level=0;
sbf->slot=0;
*/
sbf->buff.spellid = 0xffffffff;
#if EQDEBUG >= 11
printf("Sending SBF 2 from server:\n");
DumpPacket(outapp);
#endif
QueuePacket(outapp);
safe_delete(outapp);
if(send_message)
{
const char *fadetext = spells[spell_id].spell_fades;
outapp = new EQApplicationPacket(OP_ColoredText, sizeof(ColoredText_Struct) + strlen(fadetext));
ColoredText_Struct *bfm = (ColoredText_Struct *) outapp->pBuffer;
bfm->color = Chat::Spells;
memcpy(bfm->msg, fadetext, strlen(fadetext));
QueuePacket(outapp);
safe_delete(outapp);
}
}
void Client::MemSpell(uint16 spell_id, int slot, bool update_client)
void Client::MemSpell(int32 spell_id, int slot, bool update_client)
{
if (slot >= EQ::spells::SPELL_GEM_COUNT || slot < 0) {
return;
@@ -5935,7 +5868,7 @@ void Client::UnmemSpellAll(bool update_client)
}
}
uint32 Client::GetSpellIDByBookSlot(int book_slot) {
int32 Client::GetSpellIDByBookSlot(int book_slot) {
if (book_slot <= EQ::spells::SPELLBOOK_SIZE) {
return GetSpellByBookSlot(book_slot);
}
@@ -5968,7 +5901,7 @@ int Client::MemmedCount() {
return memmed_count;
}
int Client::FindMemmedSpellBySpellID(uint16 spell_id) {
int Client::FindMemmedSpellBySpellID(int32 spell_id) {
for (int spell_gem = 0; spell_gem < EQ::spells::SPELL_GEM_COUNT; spell_gem++) {
if (IsValidSpell(m_pp.mem_spells[spell_gem]) && m_pp.mem_spells[spell_gem] == spell_id) {
return spell_gem;
@@ -5978,7 +5911,7 @@ int Client::FindMemmedSpellBySpellID(uint16 spell_id) {
}
void Client::ScribeSpell(uint16 spell_id, int slot, bool update_client, bool defer_save)
void Client::ScribeSpell(int32 spell_id, int slot, bool update_client, bool defer_save)
{
if (slot >= EQ::spells::SPELLBOOK_SIZE || slot < 0) {
return;
@@ -6046,7 +5979,7 @@ void Client::UnscribeSpellAll(bool update_client)
SaveSpells();
}
void Client::UnscribeSpellBySpellID(uint16 spell_id, bool update_client)
void Client::UnscribeSpellBySpellID(int32 spell_id, bool update_client)
{
for (int index = 0; index < EQ::spells::SPELLBOOK_SIZE; index++) {
if (IsValidSpell(m_pp.spell_book[index]) && m_pp.spell_book[index] == spell_id) {
@@ -6086,7 +6019,7 @@ void Client::UntrainDiscAll(bool update_client)
SaveDisciplines();
}
void Client::UntrainDiscBySpellID(uint16 spell_id, bool update_client)
void Client::UntrainDiscBySpellID(int32 spell_id, bool update_client)
{
for (int slot = 0; slot < MAX_PP_DISCIPLINES; slot++) {
if (m_pp.disciplines.values[slot] == spell_id) {
@@ -6105,7 +6038,7 @@ int Client::GetNextAvailableSpellBookSlot(int starting_slot) {
return -1; //default
}
int Client::FindSpellBookSlotBySpellID(uint16 spellid) {
int Client::FindSpellBookSlotBySpellID(int32 spellid) {
for(int i = 0; i < EQ::spells::SPELLBOOK_SIZE; i++) {
if(m_pp.spell_book[i] == spellid)
return i;
@@ -6114,12 +6047,12 @@ int Client::FindSpellBookSlotBySpellID(uint16 spellid) {
return -1; //default
}
uint32 Client::GetHighestScribedSpellinSpellGroup(uint32 spell_group)
int32 Client::GetHighestScribedSpellinSpellGroup(uint32 spell_group)
{
//Typical live spells follow 1/5/10 rank value for actual ranks 1/2/3, but this can technically be set as anything.
int highest_rank = 0; //highest ranked found in spellgroup
uint32 highest_spell_id = 0; //spell_id of the highest ranked spell you have scribed in that spell rank.
int32 highest_spell_id = 0; //spell_id of the highest ranked spell you have scribed in that spell rank.
for (int i = 0; i < EQ::spells::SPELLBOOK_SIZE; i++) {
@@ -6162,7 +6095,7 @@ std::unordered_map<uint32, std::vector<uint16>> Client::LoadSpellGroupCache(uint
return spell_group_cache;
}
bool Client::SpellGlobalCheck(uint16 spell_id, uint32 character_id) {
bool Client::SpellGlobalCheck(int32 spell_id, uint32 character_id) {
std::string query = fmt::format(
"SELECT qglobal, value FROM spell_globals WHERE spellid = {}",
spell_id
@@ -6239,7 +6172,7 @@ bool Client::SpellGlobalCheck(uint16 spell_id, uint32 character_id) {
return false;
}
bool Client::SpellBucketCheck(uint16 spell_id, uint32 character_id)
bool Client::SpellBucketCheck(int32 spell_id, uint32 character_id)
{
const auto& e = SpellBucketsRepository::FindOne(database, spell_id);
if (!e.spell_id || e.bucket_name.empty() || e.bucket_value.empty()) {
@@ -6269,7 +6202,7 @@ int16 Mob::GetBuffSlotFromType(uint16 type) {
return -1;
}
uint16 Mob::GetSpellIDFromSlot(uint8 slot)
int32 Mob::GetSpellIDFromSlot(uint8 slot)
{
if (IsValidSpell(buffs[slot].spellid)) {
return buffs[slot].spellid;
@@ -6309,7 +6242,7 @@ bool Mob::FindType(uint16 type, bool bOffensive, uint16 threshold) {
return false;
}
bool Mob::IsCombatProc(uint16 spell_id) {
bool Mob::IsCombatProc(int32 spell_id) {
if (RuleB(Spells, FocusCombatProcs)) {
return false;
@@ -6342,7 +6275,7 @@ bool Mob::IsCombatProc(uint16 spell_id) {
return false;
}
bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id, int level_override, uint32 proc_reuse_time) {
bool Mob::AddProcToWeapon(int32 spell_id, bool bPerma, uint16 iChance, int32 base_spell_id, int level_override, uint32 proc_reuse_time) {
if(!IsValidSpell(spell_id)) {
return false;
}
@@ -6402,7 +6335,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b
return false;
}
bool Mob::RemoveProcFromWeapon(uint16 spell_id, bool bAll) {
bool Mob::RemoveProcFromWeapon(int32 spell_id, bool bAll) {
// Special case for Vampiric Embrace. If this is a Shadow Knight, the proc is different.
if (spell_id == SPELL_VAMPIRIC_EMBRACE && GetClass() == Class::ShadowKnight) {
spell_id = SPELL_VAMPIRIC_EMBRACE_OF_SHADOW;
@@ -6421,7 +6354,7 @@ bool Mob::RemoveProcFromWeapon(uint16 spell_id, bool bAll) {
return true;
}
bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id, uint32 proc_reuse_time)
bool Mob::AddDefensiveProc(int32 spell_id, uint16 iChance, int32 base_spell_id, uint32 proc_reuse_time)
{
if(!IsValidSpell(spell_id))
return(false);
@@ -6441,7 +6374,7 @@ bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id
return false;
}
bool Mob::RemoveDefensiveProc(uint16 spell_id, bool bAll)
bool Mob::RemoveDefensiveProc(int32 spell_id, bool bAll)
{
for (int i = 0; i < m_max_procs; i++) {
if (bAll || DefensiveProcs[i].spellID == spell_id) {
@@ -6455,7 +6388,7 @@ bool Mob::RemoveDefensiveProc(uint16 spell_id, bool bAll)
return true;
}
bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id, uint32 proc_reuse_time)
bool Mob::AddRangedProc(int32 spell_id, uint16 iChance, int32 base_spell_id, uint32 proc_reuse_time)
{
if(!IsValidSpell(spell_id))
return(false);
@@ -6475,7 +6408,7 @@ bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id, u
return false;
}
bool Mob::RemoveRangedProc(uint16 spell_id, bool bAll)
bool Mob::RemoveRangedProc(int32 spell_id, bool bAll)
{
for (int i = 0; i < m_max_procs; i++) {
if (bAll || RangedProcs[i].spellID == spell_id) {
@@ -6491,7 +6424,7 @@ bool Mob::RemoveRangedProc(uint16 spell_id, bool bAll)
// this is checked in a few places to decide wether special bard
// behavior should be used.
bool Mob::UseBardSpellLogic(uint16 spell_id, int slot)
bool Mob::UseBardSpellLogic(int32 spell_id, int slot)
{
if (!IsValidSpell(spell_id)) {
spell_id = casting_spell_id;
@@ -6510,7 +6443,7 @@ bool Mob::UseBardSpellLogic(uint16 spell_id, int slot)
);
}
int Mob::GetCasterLevel(uint16 spell_id) {
int Mob::GetCasterLevel(int32 spell_id) {
int level = GetLevel();
if (GetClass() == Class::Bard) {
// Bards receive effective casting level increases to resists/effect. They don't receive benefit from spells like intellectual superiority, however.
@@ -6522,170 +6455,7 @@ int Mob::GetCasterLevel(uint16 spell_id) {
return std::max(1, level);
}
//This member function sets the buff duration on the client
//however it does not work if sent quickly after an action packets, which is what one might perfer to do
//Thus I use this in the buff process to update the correct duration once after casting
//this allows AAs and focus effects that increase buff duration to work correctly, but could probably
//be used for other things as well
void Client::SendBuffDurationPacket(Buffs_Struct &buff, int slot)
{
EQApplicationPacket* outapp = nullptr;
outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffPacket_Struct));
SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer;
sbf->entityid = GetID();
sbf->buff.effect_type = 2;
sbf->buff.level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel();
sbf->buff.bard_modifier = buff.instrument_mod;
sbf->buff.spellid = buff.spellid;
sbf->buff.duration = buff.ticsremaining;
if (buff.dot_rune)
sbf->buff.counters = buff.dot_rune;
else if (buff.magic_rune)
sbf->buff.counters = buff.magic_rune;
else if (buff.melee_rune)
sbf->buff.counters = buff.melee_rune;
else if (buff.counters)
sbf->buff.counters = buff.counters;
sbf->buff.player_id = buff.casterid;
sbf->buff.num_hits = buff.hit_number;
sbf->buff.y = buff.caston_y;
sbf->buff.x = buff.caston_x;
sbf->buff.z = buff.caston_z;
sbf->slotid = slot;
sbf->bufffade = 0;
FastQueuePacket(&outapp);
}
void Client::SendBuffNumHitPacket(Buffs_Struct &buff, int slot)
{
// UF+ use this packet
if (ClientVersion() < EQ::versions::ClientVersion::UF)
return;
EQApplicationPacket *outapp = nullptr;
outapp = new EQApplicationPacket(OP_BuffCreate, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct));
BuffIcon_Struct *bi = (BuffIcon_Struct *)outapp->pBuffer;
bi->entity_id = GetID();
bi->count = 1;
bi->all_buffs = 0;
bi->tic_timer = tic_timer.GetRemainingTime();
bi->entries[0].buff_slot = slot;
bi->entries[0].spell_id = buff.spellid;
bi->entries[0].tics_remaining = buff.ticsremaining;
bi->entries[0].num_hits = buff.hit_number;
strn0cpy(bi->entries[0].caster, buff.caster_name, 64);
bi->name_lengths = strlen(bi->entries[0].caster);
FastQueuePacket(&outapp);
}
void Mob::SendPetBuffsToClient()
{
// Don't really need this check, as it should be checked before this method is called, but it doesn't hurt
// too much to check again.
if(!(GetOwner() && GetOwner()->IsClient()))
return;
int PetBuffCount = 0;
auto outapp = new EQApplicationPacket(OP_PetBuffWindow, sizeof(PetBuff_Struct));
PetBuff_Struct* pbs=(PetBuff_Struct*)outapp->pBuffer;
memset(outapp->pBuffer,0,outapp->size);
pbs->petid=GetID();
int MaxSlots = GetMaxTotalSlots();
if(MaxSlots > PET_BUFF_COUNT)
MaxSlots = PET_BUFF_COUNT;
for(int buffslot = 0; buffslot < MaxSlots; buffslot++)
{
if (IsValidSpell(buffs[buffslot].spellid)) {
pbs->spellid[buffslot] = buffs[buffslot].spellid;
pbs->ticsremaining[buffslot] = buffs[buffslot].ticsremaining;
PetBuffCount++;
}
}
pbs->buffcount=PetBuffCount;
GetOwner()->CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
}
void Mob::SendBuffsToClient(Client *c)
{
if(!c)
return;
if (c->ClientVersionBit() & EQ::versions::maskSoDAndLater)
{
EQApplicationPacket *outapp = MakeBuffsPacket();
c->FastQueuePacket(&outapp);
}
}
EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target, bool clear_buffs)
{
uint32 count = 0;
uint32 buff_count;
// for self we want all buffs, for target, we want to skip song window buffs
// since NPCs and pets don't have a song window, we still see it for them :P
if (for_target) {
buff_count = (clear_buffs) ? 0 : GetMaxBuffSlots();
}
else {
buff_count = GetMaxTotalSlots();
}
for(int i = 0; i < buff_count; ++i) {
if (IsValidSpell(buffs[i].spellid)) {
++count;
}
}
EQApplicationPacket* outapp = nullptr;
//Create it for a targeting window, else create it for a create buff packet.
if(for_target) {
outapp = new EQApplicationPacket(OP_TargetBuffs, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
}
else {
outapp = new EQApplicationPacket(OP_BuffCreate, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
}
BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer;
buff->entity_id = GetID();
buff->count = count;
buff->all_buffs = 1;
buff->tic_timer = tic_timer.GetRemainingTime();
// there are more types, the client doesn't seem to really care though. The others are also currently hard to fill in here ...
// (see comment in common/eq_packet_structs.h)
if (for_target)
buff->type = IsClient() ? 5 : 7;
else
buff->type = 0;
buff->name_lengths = 0; // hacky shit
uint32 index = 0;
for(int i = 0; i < buff_count; ++i) {
if (IsValidSpell(buffs[i].spellid)) {
buff->entries[index].buff_slot = i;
buff->entries[index].spell_id = buffs[i].spellid;
buff->entries[index].tics_remaining = buffs[i].ticsremaining;
buff->entries[index].num_hits = buffs[i].hit_number;
strn0cpy(buff->entries[index].caster, buffs[i].caster_name, 64);
buff->name_lengths += strlen(buff->entries[index].caster);
++index;
}
}
return outapp;
}
void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration)
void Mob::BuffModifyDurationBySpellID(int32 spell_id, int32 newDuration)
{
int buff_count = GetMaxTotalSlots();
for(int i = 0; i < buff_count; ++i)
@@ -6693,10 +6463,7 @@ void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration)
if (buffs[i].spellid == spell_id)
{
buffs[i].ticsremaining = newDuration;
if(IsClient())
{
CastToClient()->SendBuffDurationPacket(buffs[i], i);
}
ClientPatch::SendSingleBuffChange(this, buffs[i], i);
}
}
}
@@ -6749,7 +6516,7 @@ void NPC::UninitializeBuffSlots()
safe_delete_array(buffs);
}
void Client::SendSpellAnim(uint16 target_id, uint16 spell_id)
void Client::SendSpellAnim(uint16 target_id, int32 spell_id)
{
if (!target_id || !IsValidSpell(spell_id)) {
return;
@@ -6972,7 +6739,7 @@ void Mob::CalcDestFromHeading(float heading, float distance, float MaxZDiff, flo
dZ = FindGroundZ(dX, dY, MaxZDiff);
}
void Mob::BeamDirectional(uint16 spell_id, int16 resist_adjust)
void Mob::BeamDirectional(int32 spell_id, int16 resist_adjust)
{
int maxtarget_count = 0;
bool beneficial_targets = false;
@@ -7056,7 +6823,7 @@ void Mob::BeamDirectional(uint16 spell_id, int16 resist_adjust)
}
}
void Mob::ConeDirectional(uint16 spell_id, int16 resist_adjust)
void Mob::ConeDirectional(int32 spell_id, int16 resist_adjust)
{
int maxtarget_count = 0;
bool beneficial_targets = false;
@@ -7236,7 +7003,7 @@ void Client::ResetAllCastbarCooldowns() {
}
}
void Client::ResetCastbarCooldownBySpellID(uint32 spell_id) {
void Client::ResetCastbarCooldownBySpellID(int32 spell_id) {
for (unsigned int i = 0; i < EQ::spells::SPELL_GEM_COUNT; ++i) {
if(IsValidSpell(m_pp.mem_spells[i]) && m_pp.mem_spells[i] == spell_id) {
m_pp.spellSlotRefresh[i] = 1;
@@ -7271,7 +7038,7 @@ void Mob::DoBardCastingFromItemClick(bool is_casting_bard_song, uint32 cast_time
if (cast_time != 0) {
char spell_link[Links::MAX_LINK_SIZE];
Links::FormatSpellLink(spell_link, Links::MAX_LINK_SIZE, spell_id);
Message::InterruptSpell(CastToClient(), SONG_ENDS, GetID(), spell_link);
ClientPatch::InterruptSpell(CastToClient(), SONG_ENDS, GetID(), spell_link);
ZeroCastingVars();
ZeroBardPulseVars();