mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-27 08:12:27 +00:00
[Feature] Rule to replace dispel spell effects with suppression effect.
This commit is contained in:
parent
30004716bb
commit
dd6cfcddca
@ -546,6 +546,9 @@ RULE_INT(Spells, PointBlankAOEMaxTargets, 0, "Max number of targets a Point-Blan
|
|||||||
RULE_INT(Spells, DefaultAOEMaxTargets, 0, "Max number of targets that an AOE spell which does not meet other descriptions can cast on. Set to 0 for no limit.")
|
RULE_INT(Spells, DefaultAOEMaxTargets, 0, "Max number of targets that an AOE spell which does not meet other descriptions can cast on. Set to 0 for no limit.")
|
||||||
RULE_BOOL(Spells, AllowFocusOnSkillDamageSpells, false, "Allow focus effects 185, 459, and 482 to enhance SkillAttack spell effect 193")
|
RULE_BOOL(Spells, AllowFocusOnSkillDamageSpells, false, "Allow focus effects 185, 459, and 482 to enhance SkillAttack spell effect 193")
|
||||||
RULE_STRING(Spells, AlwaysStackSpells, "", "Comma-Seperated list of spell IDs to always stack with every other spell, except themselves.")
|
RULE_STRING(Spells, AlwaysStackSpells, "", "Comma-Seperated list of spell IDs to always stack with every other spell, except themselves.")
|
||||||
|
RULE_BOOL(Spells, SuppressDispels, false, "Swaps 'cancel magic' SPA logic with SuppressBuff SPA (527).")
|
||||||
|
RULE_INT(Spells, SuppressDispelsTime, 6, "Number of tics that dispelled buffs will be suppressed for")
|
||||||
|
RULE_INT(Spells, SuppressDebuffSpellID, 21840, "Spell ID to send to client when a spell is supprssed. 21840 = 'Suppression Field'")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Combat)
|
RULE_CATEGORY(Combat)
|
||||||
|
|||||||
@ -966,6 +966,19 @@ bool IsValidSpell(uint32 spell_id)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsValidOrSuppressedSpell(uint32 spell_id)
|
||||||
|
{
|
||||||
|
if (IsValidSpell(spell_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spell_id == SPELL_SUPPRESSED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsHarmTouchSpell(uint16 spell_id)
|
bool IsHarmTouchSpell(uint16 spell_id)
|
||||||
{
|
{
|
||||||
return spell_id == SPELL_HARM_TOUCH ||
|
return spell_id == SPELL_HARM_TOUCH ||
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#define SPELL_UNKNOWN 0xFFFF
|
#define SPELL_UNKNOWN 0xFFFF
|
||||||
#define POISON_PROC 0xFFFE
|
#define POISON_PROC 0xFFFE
|
||||||
|
#define SPELL_SUPPRESSED 0xFFFD
|
||||||
#define SPELLBOOK_UNKNOWN 0xFFFFFFFF //player profile spells are 32 bit
|
#define SPELLBOOK_UNKNOWN 0xFFFFFFFF //player profile spells are 32 bit
|
||||||
|
|
||||||
//some spell IDs which will prolly change, but are needed
|
//some spell IDs which will prolly change, but are needed
|
||||||
@ -1815,6 +1816,7 @@ bool IsEffectInSpell(uint16 spell_id, int effect_id);
|
|||||||
uint16 GetSpellTriggerSpellID(uint16 spell_id, int effect_id);
|
uint16 GetSpellTriggerSpellID(uint16 spell_id, int effect_id);
|
||||||
bool IsBlankSpellEffect(uint16 spell_id, int effect_index);
|
bool IsBlankSpellEffect(uint16 spell_id, int effect_index);
|
||||||
bool IsValidSpell(uint32 spell_id);
|
bool IsValidSpell(uint32 spell_id);
|
||||||
|
bool IsValidOrSuppressedSpell(uint32 spell_id);
|
||||||
bool IsSummonSpell(uint16 spell_id);
|
bool IsSummonSpell(uint16 spell_id);
|
||||||
bool IsDamageSpell(uint16 spell_id);
|
bool IsDamageSpell(uint16 spell_id);
|
||||||
bool IsAnyDamageSpell(uint16 spell_id);
|
bool IsAnyDamageSpell(uint16 spell_id);
|
||||||
|
|||||||
@ -345,6 +345,7 @@ public:
|
|||||||
bool IsClient() const override { return true; }
|
bool IsClient() const override { return true; }
|
||||||
bool IsOfClientBot() const override { return true; }
|
bool IsOfClientBot() const override { return true; }
|
||||||
bool IsOfClientBotMerc() const override { return true; }
|
bool IsOfClientBotMerc() const override { return true; }
|
||||||
|
void ReapplyBuff(uint32 index, bool from_suppress = false);
|
||||||
void CompleteConnect();
|
void CompleteConnect();
|
||||||
bool TryStacking(EQ::ItemInstance* item, uint8 type = ItemPacketTrade, bool try_worn = true, bool try_cursor = true);
|
bool TryStacking(EQ::ItemInstance* item, uint8 type = ItemPacketTrade, bool try_worn = true, bool try_cursor = true);
|
||||||
void SendTraderPacket(Client* trader, uint32 Unknown72 = 51);
|
void SendTraderPacket(Client* trader, uint32 Unknown72 = 51);
|
||||||
|
|||||||
@ -527,6 +527,109 @@ int Client::HandlePacket(const EQApplicationPacket *app)
|
|||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Some buffs have effects that trigger only as part of the original cast. This reapplies those effects.
|
||||||
|
void Client::ReapplyBuff(uint32 index, bool from_suppress)
|
||||||
|
{
|
||||||
|
LogDebug("ReapplyBuff: index [{}] from_suppress [{}]", index, from_suppress);
|
||||||
|
if (!IsValidSpell(buffs[index].spellid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const SPDat_Spell_Struct &spell = spells[buffs[index].spellid];
|
||||||
|
|
||||||
|
int NimbusEffect = GetSpellNimbusEffect(buffs[index].spellid);
|
||||||
|
if (NimbusEffect) {
|
||||||
|
if (!IsNimbusEffectActive(NimbusEffect))
|
||||||
|
SendSpellEffect(NimbusEffect, 500, 0, 1, 3000, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x1 = 0; x1 < EFFECT_COUNT; x1++) {
|
||||||
|
switch (spell.effect_id[x1]) {
|
||||||
|
case SE_Illusion: {
|
||||||
|
if (GetIllusionBlock()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from_suppress || buffs[index].persistant_buff) {
|
||||||
|
Mob *caster = entity_list.GetMobID(buffs[index].casterid);
|
||||||
|
ApplySpellEffectIllusion(spell.id, caster, index, spell.base_value[x1], spell.limit_value[x1], spell.max_value[x1]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SE_SummonHorse: {
|
||||||
|
if (!from_suppress && (RuleB(Character, PreventMountsFromZoning) || !zone->CanCastOutdoor())) {
|
||||||
|
BuffFadeByEffect(SE_SummonHorse);
|
||||||
|
} else {
|
||||||
|
SummonHorse(buffs[index].spellid);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SE_Silence:
|
||||||
|
{
|
||||||
|
Silence(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SE_Amnesia:
|
||||||
|
{
|
||||||
|
Amnesia(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SE_DivineAura:
|
||||||
|
{
|
||||||
|
invulnerable = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SE_Invisibility2:
|
||||||
|
case SE_Invisibility:
|
||||||
|
{
|
||||||
|
SendAppearancePacket(AppearanceType::Invisibility, Invisibility::Invisible);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SE_Levitate:
|
||||||
|
{
|
||||||
|
if (!zone->CanLevitate()) {
|
||||||
|
if (!GetGM()) {
|
||||||
|
SendAppearancePacket(AppearanceType::FlyMode, 0);
|
||||||
|
BuffFadeByEffect(SE_Levitate);
|
||||||
|
Message(Chat::Red, "You can't levitate in this zone.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Message(Chat::White, "Your GM flag allows you to levitate in this zone.");
|
||||||
|
}
|
||||||
|
|
||||||
|
SendAppearancePacket(
|
||||||
|
AppearanceType::FlyMode,
|
||||||
|
(
|
||||||
|
spell.limit_value[x1] == 1 ?
|
||||||
|
EQ::constants::GravityBehavior::LevitateWhileRunning :
|
||||||
|
EQ::constants::GravityBehavior::Levitating
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
!from_suppress
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SE_AddMeleeProc:
|
||||||
|
case SE_WeaponProc:
|
||||||
|
{
|
||||||
|
AddProcToWeapon(GetProcID(buffs[index].spellid, x1), false, 100 + spells[buffs[index].spellid].limit_value[x1], buffs[index].spellid, buffs[index].casterlevel, GetSpellProcLimitTimer(buffs[index].spellid, ProcType::MELEE_PROC));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SE_DefensiveProc:
|
||||||
|
{
|
||||||
|
AddDefensiveProc(GetProcID(buffs[index].spellid, x1), 100 + spells[buffs[index].spellid].limit_value[x1], buffs[index].spellid, GetSpellProcLimitTimer(buffs[index].spellid, ProcType::DEFENSIVE_PROC));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SE_RangedProc:
|
||||||
|
{
|
||||||
|
AddRangedProc(GetProcID(buffs[index].spellid, x1), 100 + spells[buffs[index].spellid].limit_value[x1], buffs[index].spellid, GetSpellProcLimitTimer(buffs[index].spellid, ProcType::RANGED_PROC));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Finish client connecting state
|
// Finish client connecting state
|
||||||
void Client::CompleteConnect()
|
void Client::CompleteConnect()
|
||||||
{
|
{
|
||||||
@ -655,106 +758,9 @@ void Client::CompleteConnect()
|
|||||||
|
|
||||||
//bulk raid send in here eventually
|
//bulk raid send in here eventually
|
||||||
|
|
||||||
//reapply some buffs
|
|
||||||
uint32 buff_count = GetMaxTotalSlots();
|
uint32 buff_count = GetMaxTotalSlots();
|
||||||
for (uint32 j1 = 0; j1 < buff_count; j1++) {
|
for (uint32 j1 = 0; j1 < buff_count; j1++) {
|
||||||
if (!IsValidSpell(buffs[j1].spellid))
|
ReapplyBuff(j1);
|
||||||
continue;
|
|
||||||
|
|
||||||
const SPDat_Spell_Struct &spell = spells[buffs[j1].spellid];
|
|
||||||
|
|
||||||
int NimbusEffect = GetSpellNimbusEffect(buffs[j1].spellid);
|
|
||||||
if (NimbusEffect) {
|
|
||||||
if (!IsNimbusEffectActive(NimbusEffect))
|
|
||||||
SendSpellEffect(NimbusEffect, 500, 0, 1, 3000, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int x1 = 0; x1 < EFFECT_COUNT; x1++) {
|
|
||||||
switch (spell.effect_id[x1]) {
|
|
||||||
case SpellEffect::Illusion: {
|
|
||||||
if (GetIllusionBlock()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffs[j1].persistant_buff) {
|
|
||||||
Mob *caster = entity_list.GetMobID(buffs[j1].casterid);
|
|
||||||
ApplySpellEffectIllusion(spell.id, caster, j1, spell.base_value[x1], spell.limit_value[x1], spell.max_value[x1]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SpellEffect::SummonHorse: {
|
|
||||||
if (RuleB(Character, PreventMountsFromZoning) || !zone->CanCastOutdoor()) {
|
|
||||||
BuffFadeByEffect(SpellEffect::SummonHorse);
|
|
||||||
} else {
|
|
||||||
SummonHorse(buffs[j1].spellid);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SpellEffect::Silence:
|
|
||||||
{
|
|
||||||
Silence(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SpellEffect::Amnesia:
|
|
||||||
{
|
|
||||||
Amnesia(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SpellEffect::DivineAura:
|
|
||||||
{
|
|
||||||
invulnerable = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SpellEffect::Invisibility2:
|
|
||||||
case SpellEffect::Invisibility:
|
|
||||||
{
|
|
||||||
SendAppearancePacket(AppearanceType::Invisibility, Invisibility::Invisible);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SpellEffect::Levitate:
|
|
||||||
{
|
|
||||||
if (!zone->CanLevitate()) {
|
|
||||||
if (!GetGM()) {
|
|
||||||
SendAppearancePacket(AppearanceType::FlyMode, 0);
|
|
||||||
BuffFadeByEffect(SpellEffect::Levitate);
|
|
||||||
Message(Chat::Red, "You can't levitate in this zone.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Message(Chat::White, "Your GM flag allows you to levitate in this zone.");
|
|
||||||
}
|
|
||||||
|
|
||||||
SendAppearancePacket(
|
|
||||||
AppearanceType::FlyMode,
|
|
||||||
(
|
|
||||||
spell.limit_value[x1] == 1 ?
|
|
||||||
EQ::constants::GravityBehavior::LevitateWhileRunning :
|
|
||||||
EQ::constants::GravityBehavior::Levitating
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SpellEffect::AddMeleeProc:
|
|
||||||
case SpellEffect::WeaponProc:
|
|
||||||
{
|
|
||||||
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, buffs[j1].casterlevel, GetSpellProcLimitTimer(buffs[j1].spellid, ProcType::MELEE_PROC));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SpellEffect::DefensiveProc:
|
|
||||||
{
|
|
||||||
AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetSpellProcLimitTimer(buffs[j1].spellid, ProcType::DEFENSIVE_PROC));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SpellEffect::RangedProc:
|
|
||||||
{
|
|
||||||
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetSpellProcLimitTimer(buffs[j1].spellid, ProcType::RANGED_PROC));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sends appearances for all mobs not doing Animation::Standing aka sitting, looting, playing dead */
|
/* Sends appearances for all mobs not doing Animation::Standing aka sitting, looting, playing dead */
|
||||||
|
|||||||
@ -226,6 +226,8 @@ struct Buffs_Struct {
|
|||||||
bool persistant_buff;
|
bool persistant_buff;
|
||||||
bool client; //True if the caster is a client
|
bool client; //True if the caster is a client
|
||||||
bool UpdateClient;
|
bool UpdateClient;
|
||||||
|
uint16 suppressedid;
|
||||||
|
uint32 suppressedticsremaining;
|
||||||
|
|
||||||
// cereal
|
// cereal
|
||||||
template<class Archive>
|
template<class Archive>
|
||||||
|
|||||||
@ -2167,6 +2167,11 @@ void Lua_Mob::BuffFadeBySlot(int slot, bool recalc_bonuses) {
|
|||||||
self->BuffFadeBySlot(slot, recalc_bonuses);
|
self->BuffFadeBySlot(slot, recalc_bonuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Lua_Mob::BuffFadeBySlot(int slot, bool recalc_bonuses, bool suppress, int suppress_tics) {
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->BuffFadeBySlot(slot, recalc_bonuses, suppress, suppress_tics);
|
||||||
|
}
|
||||||
|
|
||||||
int Lua_Mob::CanBuffStack(int spell_id, int caster_level) {
|
int Lua_Mob::CanBuffStack(int spell_id, int caster_level) {
|
||||||
Lua_Safe_Call_Int();
|
Lua_Safe_Call_Int();
|
||||||
return self->CanBuffStack(spell_id, caster_level);
|
return self->CanBuffStack(spell_id, caster_level);
|
||||||
@ -3572,6 +3577,7 @@ luabind::scope lua_register_mob() {
|
|||||||
.def("BuffFadeByEffect", (void(Lua_Mob::*)(int,int))&Lua_Mob::BuffFadeByEffect)
|
.def("BuffFadeByEffect", (void(Lua_Mob::*)(int,int))&Lua_Mob::BuffFadeByEffect)
|
||||||
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int))&Lua_Mob::BuffFadeBySlot)
|
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int))&Lua_Mob::BuffFadeBySlot)
|
||||||
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot)
|
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot)
|
||||||
|
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool,bool,int))&Lua_Mob::BuffFadeBySlot)
|
||||||
.def("BuffFadeBySpellID", (void(Lua_Mob::*)(int))&Lua_Mob::BuffFadeBySpellID)
|
.def("BuffFadeBySpellID", (void(Lua_Mob::*)(int))&Lua_Mob::BuffFadeBySpellID)
|
||||||
.def("BuffFadeDetrimental", (void(Lua_Mob::*)(void))&Lua_Mob::BuffFadeDetrimental)
|
.def("BuffFadeDetrimental", (void(Lua_Mob::*)(void))&Lua_Mob::BuffFadeDetrimental)
|
||||||
.def("BuffFadeDetrimentalByCaster", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::BuffFadeDetrimentalByCaster)
|
.def("BuffFadeDetrimentalByCaster", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::BuffFadeDetrimentalByCaster)
|
||||||
|
|||||||
@ -434,6 +434,7 @@ public:
|
|||||||
void BuffFadeAll();
|
void BuffFadeAll();
|
||||||
void BuffFadeBySlot(int slot);
|
void BuffFadeBySlot(int slot);
|
||||||
void BuffFadeBySlot(int slot, bool recalc_bonuses);
|
void BuffFadeBySlot(int slot, bool recalc_bonuses);
|
||||||
|
void BuffFadeBySlot(int slot, bool recalc_bonuses, bool suppress, int suppress_tics);
|
||||||
int CanBuffStack(int spell_id, int caster_level);
|
int CanBuffStack(int spell_id, int caster_level);
|
||||||
int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite);
|
int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite);
|
||||||
void SetPseudoRoot(bool in);
|
void SetPseudoRoot(bool in);
|
||||||
|
|||||||
@ -452,7 +452,7 @@ public:
|
|||||||
void BuffFadeBeneficial();
|
void BuffFadeBeneficial();
|
||||||
void BuffFadeNonPersistDeath();
|
void BuffFadeNonPersistDeath();
|
||||||
void BuffFadeDetrimental();
|
void BuffFadeDetrimental();
|
||||||
void BuffFadeBySlot(int slot, bool iRecalcBonuses = true);
|
void BuffFadeBySlot(int slot, bool iRecalcBonuses = true, bool suppress = false, uint32 suppresstics = 0);
|
||||||
void BuffFadeDetrimentalByCaster(Mob *caster);
|
void BuffFadeDetrimentalByCaster(Mob *caster);
|
||||||
void BuffFadeBySitModifier();
|
void BuffFadeBySitModifier();
|
||||||
void BuffFadeSongs();
|
void BuffFadeSongs();
|
||||||
@ -966,7 +966,9 @@ public:
|
|||||||
void TrySympatheticProc(Mob *target, uint32 spell_id);
|
void TrySympatheticProc(Mob *target, uint32 spell_id);
|
||||||
uint16 GetSympatheticFocusEffect(focusType type, uint16 spell_id);
|
uint16 GetSympatheticFocusEffect(focusType type, uint16 spell_id);
|
||||||
bool TryFadeEffect(int slot);
|
bool TryFadeEffect(int slot);
|
||||||
void DispelMagic(Mob* casterm, uint16 spell_id, int effect_value);
|
void DispelMagic(Mob* casterm, uint16 spell_id, int effect_value, int chance = 1000, bool detrimental_only = false, bool benficial_only = false);
|
||||||
|
bool IsSuppressableBuff(int slot) const;
|
||||||
|
void SuppressBuff(Mob* caster, uint16 spell_id, int tic_count);
|
||||||
bool TrySpellEffectResist(uint16 spell_id);
|
bool TrySpellEffectResist(uint16 spell_id);
|
||||||
int32 GetVulnerability(Mob *caster, uint32 spell_id, uint32 ticsremaining, bool from_buff_tic = false);
|
int32 GetVulnerability(Mob *caster, uint32 spell_id, uint32 ticsremaining, bool from_buff_tic = false);
|
||||||
int64 GetFcDamageAmtIncoming(Mob *caster, int32 spell_id, bool from_buff_tic = false);
|
int64 GetFcDamageAmtIncoming(Mob *caster, int32 spell_id, bool from_buff_tic = false);
|
||||||
|
|||||||
@ -1044,6 +1044,11 @@ void Perl_Mob_BuffFadeBySlot(Mob* self, int slot, bool recalc_bonuses) // @categ
|
|||||||
self->BuffFadeBySlot(slot, recalc_bonuses);
|
self->BuffFadeBySlot(slot, recalc_bonuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Perl_Mob_BuffFadeBySlot(Mob* self, int slot, bool recalc_bonuses, bool suppress, int suppress_tics) // @categories Script Utility, Spells and Disciplines
|
||||||
|
{
|
||||||
|
self->BuffFadeBySlot(slot, recalc_bonuses, suppress, suppress_tics);
|
||||||
|
}
|
||||||
|
|
||||||
bool Perl_Mob_CanBuffStack(Mob* self, uint16 spell_id, uint8 caster_level) // @categories Script Utility, Spells and Disciplines
|
bool Perl_Mob_CanBuffStack(Mob* self, uint16 spell_id, uint8 caster_level) // @categories Script Utility, Spells and Disciplines
|
||||||
{
|
{
|
||||||
return self->CanBuffStack(spell_id, caster_level);
|
return self->CanBuffStack(spell_id, caster_level);
|
||||||
@ -3647,6 +3652,7 @@ void perl_register_mob()
|
|||||||
package.add("BuffFadeByEffect", (void(*)(Mob*, int, int))&Perl_Mob_BuffFadeByEffect);
|
package.add("BuffFadeByEffect", (void(*)(Mob*, int, int))&Perl_Mob_BuffFadeByEffect);
|
||||||
package.add("BuffFadeBySlot", (void(*)(Mob*, int))&Perl_Mob_BuffFadeBySlot);
|
package.add("BuffFadeBySlot", (void(*)(Mob*, int))&Perl_Mob_BuffFadeBySlot);
|
||||||
package.add("BuffFadeBySlot", (void(*)(Mob*, int, bool))&Perl_Mob_BuffFadeBySlot);
|
package.add("BuffFadeBySlot", (void(*)(Mob*, int, bool))&Perl_Mob_BuffFadeBySlot);
|
||||||
|
package.add("BuffFadeBySlot", (void(*)(Mob*, int, bool, bool, int))&Perl_Mob_BuffFadeBySlot);
|
||||||
package.add("BuffFadeBySpellID", &Perl_Mob_BuffFadeBySpellID);
|
package.add("BuffFadeBySpellID", &Perl_Mob_BuffFadeBySpellID);
|
||||||
package.add("BuffFadeDetrimental", &Perl_Mob_BuffFadeDetrimental);
|
package.add("BuffFadeDetrimental", &Perl_Mob_BuffFadeDetrimental);
|
||||||
package.add("BuffFadeDetrimentalByCaster", &Perl_Mob_BuffFadeDetrimentalByCaster);
|
package.add("BuffFadeDetrimentalByCaster", &Perl_Mob_BuffFadeDetrimentalByCaster);
|
||||||
|
|||||||
@ -1120,24 +1120,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
caster->MessageString(Chat::SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name);
|
caster->MessageString(Chat::SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
TODO: Parsing shows there is no level modifier. However, a consistent -2% modifer was
|
DispelMagic(caster, spell_id, effect_value, spells[spell_id].base_value[i], true);
|
||||||
found on spell with value 950 (95% spells would have 7% failure rates).
|
|
||||||
Further investigation is needed. ~ Kayen
|
|
||||||
*/
|
|
||||||
int chance = spells[spell_id].base_value[i];
|
|
||||||
int buff_count = GetMaxTotalSlots();
|
|
||||||
for(int slot = 0; slot < buff_count; slot++) {
|
|
||||||
if (IsValidSpell(buffs[slot].spellid) &&
|
|
||||||
IsDetrimentalSpell(buffs[slot].spellid) &&
|
|
||||||
spells[buffs[slot].spellid].dispel_flag == 0)
|
|
||||||
{
|
|
||||||
if (zone->random.Int(1, 1000) <= chance){
|
|
||||||
BuffFadeBySlot(slot);
|
|
||||||
slot = buff_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1152,19 +1136,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int chance = spells[spell_id].base_value[i];
|
DispelMagic(caster, spell_id, effect_value, spells[spell_id].base_value[i], false, true);
|
||||||
int buff_count = GetMaxTotalSlots();
|
|
||||||
for(int slot = 0; slot < buff_count; slot++) {
|
|
||||||
if (IsValidSpell(buffs[slot].spellid) &&
|
|
||||||
IsBeneficialSpell(buffs[slot].spellid) &&
|
|
||||||
spells[buffs[slot].spellid].dispel_flag == 0)
|
|
||||||
{
|
|
||||||
if (zone->random.Int(1, 1000) <= chance) {
|
|
||||||
BuffFadeBySlot(slot);
|
|
||||||
slot = buff_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3843,18 +3815,20 @@ void Mob::BuffProcess()
|
|||||||
|
|
||||||
for (int buffs_i = 0; buffs_i < buff_count; ++buffs_i)
|
for (int buffs_i = 0; buffs_i < buff_count; ++buffs_i)
|
||||||
{
|
{
|
||||||
if (IsValidSpell(buffs[buffs_i].spellid))
|
if (IsValidOrSuppressedSpell(buffs[buffs_i].spellid))
|
||||||
{
|
{
|
||||||
DoBuffTic(buffs[buffs_i], buffs_i, entity_list.GetMob(buffs[buffs_i].casterid));
|
DoBuffTic(buffs[buffs_i], buffs_i, entity_list.GetMob(buffs[buffs_i].casterid));
|
||||||
// If the Mob died during DoBuffTic, then the buff we are currently processing will have been removed
|
// If the Mob died during DoBuffTic, then the buff we are currently processing will have been removed
|
||||||
if(!IsValidSpell(buffs[buffs_i].spellid)) {
|
if(!IsValidOrSuppressedSpell(buffs[buffs_i].spellid)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DF_Permanent uses -1 DF_Aura uses -4 but we need to check negatives for some spells for some reason?
|
// DF_Permanent uses -1 DF_Aura uses -4 but we need to check negatives for some spells for some reason?
|
||||||
if (spells[buffs[buffs_i].spellid].buff_duration_formula != DF_Permanent &&
|
if (buffs[buffs_i].spellid == SPELL_SUPPRESSED ||
|
||||||
|
(spells[buffs[buffs_i].spellid].buff_duration_formula != DF_Permanent &&
|
||||||
spells[buffs[buffs_i].spellid].buff_duration_formula != DF_Aura &&
|
spells[buffs[buffs_i].spellid].buff_duration_formula != DF_Aura &&
|
||||||
buffs[buffs_i].ticsremaining != PERMANENT_BUFF_DURATION) {
|
buffs[buffs_i].ticsremaining != PERMANENT_BUFF_DURATION)) {
|
||||||
|
|
||||||
if(!zone->BuffTimersSuspended() || !IsSuspendableSpell(buffs[buffs_i].spellid))
|
if(!zone->BuffTimersSuspended() || !IsSuspendableSpell(buffs[buffs_i].spellid))
|
||||||
{
|
{
|
||||||
--buffs[buffs_i].ticsremaining;
|
--buffs[buffs_i].ticsremaining;
|
||||||
@ -4249,16 +4223,21 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// removes the buff in the buff slot 'slot'
|
// removes the buff in the buff slot 'slot'
|
||||||
void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses, bool suppress, uint32 suppresstics)
|
||||||
{
|
{
|
||||||
if(slot < 0 || slot > GetMaxTotalSlots())
|
if(slot < 0 || slot > GetMaxTotalSlots())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(!IsValidSpell(buffs[slot].spellid))
|
if(!IsValidOrSuppressedSpell(buffs[slot].spellid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (IsClient() && !CastToClient()->IsDead())
|
if (IsClient()) {
|
||||||
CastToClient()->MakeBuffFadePacket(buffs[slot].spellid, slot);
|
auto client = CastToClient();
|
||||||
|
if (!client->IsDead()) {
|
||||||
|
uint32 spell_id = (buffs[slot].spellid != SPELL_SUPPRESSED) ? buffs[slot].spellid : RuleI(Spells, SuppressDebuffSpellID);
|
||||||
|
client->MakeBuffFadePacket(spell_id, slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LogSpells("Fading buff [{}] from slot [{}]", buffs[slot].spellid, slot);
|
LogSpells("Fading buff [{}] from slot [{}]", buffs[slot].spellid, slot);
|
||||||
|
|
||||||
@ -4319,6 +4298,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
|||||||
{
|
{
|
||||||
uint16 procid = GetProcID(buffs[slot].spellid, i);
|
uint16 procid = GetProcID(buffs[slot].spellid, i);
|
||||||
RemoveDefensiveProc(procid);
|
RemoveDefensiveProc(procid);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4387,20 +4367,24 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
|||||||
|
|
||||||
case SpellEffect::Rune:
|
case SpellEffect::Rune:
|
||||||
{
|
{
|
||||||
|
if (!suppress) {
|
||||||
buffs[slot].melee_rune = 0;
|
buffs[slot].melee_rune = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SpellEffect::AbsorbMagicAtt:
|
case SpellEffect::AbsorbMagicAtt:
|
||||||
{
|
{
|
||||||
|
if (!suppress) {
|
||||||
buffs[slot].magic_rune = 0;
|
buffs[slot].magic_rune = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SpellEffect::Familiar:
|
case SpellEffect::Familiar:
|
||||||
{
|
{
|
||||||
Mob *mypet = GetPet();
|
Mob *mypet = GetPet();
|
||||||
if (mypet){
|
if (mypet && !suppress){
|
||||||
if(mypet->IsNPC())
|
if(mypet->IsNPC())
|
||||||
mypet->CastToNPC()->Depop();
|
mypet->CastToNPC()->Depop();
|
||||||
SetPetID(0);
|
SetPetID(0);
|
||||||
@ -4417,7 +4401,11 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
|||||||
|
|
||||||
case SpellEffect::Charm:
|
case SpellEffect::Charm:
|
||||||
{
|
{
|
||||||
if (IsNPC()) {
|
//Trying to restore pet ownership after suppression is too much, so just downgrade to a normal dispel
|
||||||
|
suppress = false;
|
||||||
|
|
||||||
|
if(IsNPC())
|
||||||
|
{
|
||||||
CastToNPC()->RestoreGuardSpotCharm();
|
CastToNPC()->RestoreGuardSpotCharm();
|
||||||
CastToNPC()->ModifyStatsOnCharm(true, GetOwner());
|
CastToNPC()->ModifyStatsOnCharm(true, GetOwner());
|
||||||
}
|
}
|
||||||
@ -4640,7 +4628,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
|||||||
Mob *notify = p;
|
Mob *notify = p;
|
||||||
if(p->IsPet())
|
if(p->IsPet())
|
||||||
notify = p->GetOwner();
|
notify = p->GetOwner();
|
||||||
if(p) {
|
if(p && buffs[slot].spellid != SPELL_SUPPRESSED) {
|
||||||
notify->MessageString(Chat::SpellWornOff, SPELL_WORN_OFF_OF,
|
notify->MessageString(Chat::SpellWornOff, SPELL_WORN_OFF_OF,
|
||||||
spells[buffs[slot].spellid].name, GetCleanName());
|
spells[buffs[slot].spellid].name, GetCleanName());
|
||||||
}
|
}
|
||||||
@ -4663,10 +4651,53 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
|||||||
Numhits(false);
|
Numhits(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spells[buffs[slot].spellid].nimbus_effect > 0)
|
if (IsValidSpell(buffs[slot].spellid) && spells[buffs[slot].spellid].nimbus_effect > 0)
|
||||||
RemoveNimbusEffect(spells[buffs[slot].spellid].nimbus_effect);
|
RemoveNimbusEffect(spells[buffs[slot].spellid].nimbus_effect);
|
||||||
|
|
||||||
|
if (suppress && suppresstics > 0) {
|
||||||
|
if (buffs[slot].spellid != SPELL_SUPPRESSED) {
|
||||||
|
buffs[slot].suppressedid = buffs[slot].spellid;
|
||||||
|
buffs[slot].suppressedticsremaining = buffs[slot].ticsremaining;
|
||||||
|
buffs[slot].spellid = SPELL_SUPPRESSED;
|
||||||
|
}
|
||||||
|
buffs[slot].ticsremaining = suppresstics;
|
||||||
|
} else if (buffs[slot].spellid == SPELL_SUPPRESSED) {
|
||||||
|
buffs[slot].spellid = buffs[slot].suppressedid;
|
||||||
|
buffs[slot].ticsremaining = buffs[slot].suppressedticsremaining;
|
||||||
|
buffs[slot].suppressedid = 0;
|
||||||
|
buffs[slot].suppressedticsremaining = -1;
|
||||||
|
|
||||||
|
if (buffs[slot].hit_number > 0) {
|
||||||
|
Numhits(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsClient()) {
|
||||||
|
//This bit of magic need to arrive before our BuffCreate. It appears to put the client in a state
|
||||||
|
//where it will be more accepting of information like 'Make this player levitate' or 'This buff has num-hit counters'
|
||||||
|
auto client = CastToClient();
|
||||||
|
auto* action_packet = new EQApplicationPacket(OP_Action, sizeof(Action_Struct));
|
||||||
|
auto* action = reinterpret_cast<Action_Struct*>(action_packet->pBuffer);
|
||||||
|
|
||||||
|
action->source = buffs[slot].casterid;
|
||||||
|
action->target = client->GetID();
|
||||||
|
action->level = client->GetLevel();
|
||||||
|
action->instrument_mod = buffs[slot].instrument_mod;
|
||||||
|
action->force = 0;
|
||||||
|
action->hit_heading = client->GetHeading();
|
||||||
|
action->hit_pitch = 0;
|
||||||
|
action->type = 231; // 231 means a spell
|
||||||
|
action->spell = buffs[slot].spellid;
|
||||||
|
action->spell_level = buffs[slot].casterlevel;
|
||||||
|
action->effect_flag = 0x04; // Successful action
|
||||||
|
|
||||||
|
client->QueuePacket(action_packet);
|
||||||
|
safe_delete(action_packet);
|
||||||
|
client->ReapplyBuff(slot, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
buffs[slot].spellid = SPELL_UNKNOWN;
|
buffs[slot].spellid = SPELL_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
if(IsPet() && GetOwner() && GetOwner()->IsClient()) {
|
if(IsPet() && GetOwner() && GetOwner()->IsClient()) {
|
||||||
SendPetBuffsToClient();
|
SendPetBuffsToClient();
|
||||||
}
|
}
|
||||||
@ -7447,20 +7478,66 @@ bool Mob::PassLimitClass(uint32 Classes_, uint16 Class_)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::DispelMagic(Mob* caster, uint16 spell_id, int effect_value)
|
void Mob::DispelMagic(Mob* caster, uint16 spell_id, int effect_value, int chance, bool detrimental_only, bool beneficial_only)
|
||||||
{
|
{
|
||||||
for (int slot = 0; slot < GetMaxTotalSlots(); slot++) {
|
bool target_is_client = IsClient() || (GetUltimateOwner() && GetUltimateOwner()->IsClient());
|
||||||
if (
|
bool caster_is_client = caster && (caster->IsClient() || (caster->GetUltimateOwner() && caster->GetUltimateOwner()->IsClient()));
|
||||||
buffs[slot].spellid != SPELL_UNKNOWN &&
|
|
||||||
spells[buffs[slot].spellid].dispel_flag == 0 &&
|
for (int slot = 0; slot < GetMaxTotalSlots(); ++slot) {
|
||||||
!IsDiscipline(buffs[slot].spellid)
|
auto s = buffs[slot].spellid;
|
||||||
) {
|
|
||||||
if (caster && TryDispel(caster->GetCasterLevel(spell_id), buffs[slot].casterlevel, effect_value)) {
|
if (s == SPELL_UNKNOWN || spells[s].dispel_flag != 0 || IsDiscipline(s)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detrimental_only && !IsDetrimentalSpell(s)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beneficial_only && IsDetrimentalSpell(s)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!detrimental_only && !beneficial_only) {
|
||||||
|
//This check only happens for SE_CancelMagic
|
||||||
|
if (!caster || !TryDispel(caster->GetCasterLevel(spell_id), buffs[slot].casterlevel, effect_value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//This check only happens for SE_DispelDetrimental or SE_DispelBeneficial
|
||||||
|
if (chance < 1000 && zone->random.Int(1, 1000) > chance) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool perma_remove = caster_is_client || !target_is_client;
|
||||||
|
if (perma_remove || !RuleB(Spells, SuppressDispels)) {
|
||||||
BuffFadeBySlot(slot);
|
BuffFadeBySlot(slot);
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
//Additional restrictions on which buffs can be suppressed
|
||||||
|
if (spells[s].short_buff_box) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuffFadeBySlot(slot, true, true, RuleI(Spells, SuppressDispelsTime));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Mob::IsSuppressableBuff(int slot) const {
|
||||||
|
auto sid = buffs[slot].spellid;
|
||||||
|
|
||||||
|
//Suppressed spells can be re-suppressed to refresh their timer
|
||||||
|
if (sid == SPELL_SUPPRESSED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsValidSpell(sid) &&
|
||||||
|
IsBeneficialSpell(sid) &&
|
||||||
|
!IsBardSong(sid) &&
|
||||||
|
spells[sid].dispel_flag == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::TrySpellEffectResist(uint16 spell_id)
|
bool Mob::TrySpellEffectResist(uint16 spell_id)
|
||||||
|
|||||||
@ -3580,10 +3580,17 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
|||||||
for (buffslot = 0; buffslot < buff_count; buffslot++) {
|
for (buffslot = 0; buffslot < buff_count; buffslot++) {
|
||||||
const Buffs_Struct &curbuf = buffs[buffslot];
|
const Buffs_Struct &curbuf = buffs[buffslot];
|
||||||
|
|
||||||
if (IsValidSpell(curbuf.spellid)) {
|
if (curbuf.spellid == SPELL_SUPPRESSED && curbuf.suppressedid == spell_id) {
|
||||||
|
LogSpells("Adding buff [{}]: Refusing to add a buff that is currently being suppressed in slot [{}]", spell_id, buffslot);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsValidOrSuppressedSpell(curbuf.spellid)) {
|
||||||
|
uint16 buff_spellid = curbuf.spellid == SPELL_SUPPRESSED ? curbuf.suppressedid : curbuf.spellid;
|
||||||
|
|
||||||
// there's a buff in this slot
|
// there's a buff in this slot
|
||||||
ret = CheckStackConflict(
|
ret = CheckStackConflict(
|
||||||
curbuf.spellid,
|
buff_spellid,
|
||||||
curbuf.casterlevel,
|
curbuf.casterlevel,
|
||||||
spell_id,
|
spell_id,
|
||||||
caster_level,
|
caster_level,
|
||||||
@ -3596,7 +3603,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
|||||||
LogSpells(
|
LogSpells(
|
||||||
"Adding buff [{}] failed: stacking prevented by spell [{}] in slot [{}] with caster level [{}]",
|
"Adding buff [{}] failed: stacking prevented by spell [{}] in slot [{}] with caster level [{}]",
|
||||||
spell_id,
|
spell_id,
|
||||||
curbuf.spellid,
|
buff_spellid,
|
||||||
buffslot,
|
buffslot,
|
||||||
curbuf.casterlevel
|
curbuf.casterlevel
|
||||||
);
|
);
|
||||||
@ -3609,7 +3616,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
|||||||
"Your {} did not take hold on {}. (Blocked by {}.)",
|
"Your {} did not take hold on {}. (Blocked by {}.)",
|
||||||
spells[spell_id].name,
|
spells[spell_id].name,
|
||||||
GetName(),
|
GetName(),
|
||||||
spells[curbuf.spellid].name
|
spells[buff_spellid].name
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -3622,7 +3629,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
|||||||
caster->GetCleanName(),
|
caster->GetCleanName(),
|
||||||
spells[spell_id].name,
|
spells[spell_id].name,
|
||||||
GetName(),
|
GetName(),
|
||||||
spells[curbuf.spellid].name
|
spells[buff_spellid].name
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -3630,7 +3637,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
|||||||
std::function<std::string()> f = [&]() {
|
std::function<std::string()> f = [&]() {
|
||||||
return fmt::format(
|
return fmt::format(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
curbuf.spellid,
|
buff_spellid,
|
||||||
spell_id
|
spell_id
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -3644,11 +3651,16 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
|||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
} else if (ret == 1 && !will_overwrite) {
|
} else if (ret == 1 && !will_overwrite) {
|
||||||
|
// Reject buffing a superior buff while an inferior one is suppressed or else they end up with both
|
||||||
|
if (curbuf.spellid == SPELL_SUPPRESSED) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// set a flag to indicate that there will be overwriting
|
// set a flag to indicate that there will be overwriting
|
||||||
LogSpells(
|
LogSpells(
|
||||||
"Adding buff [{}] will overwrite spell [{}] in slot [{}] with caster level [{}]",
|
"Adding buff [{}] will overwrite spell [{}] in slot [{}] with caster level [{}]",
|
||||||
spell_id,
|
spell_id,
|
||||||
curbuf.spellid,
|
buff_spellid,
|
||||||
buffslot,
|
buffslot,
|
||||||
curbuf.casterlevel
|
curbuf.casterlevel
|
||||||
);
|
);
|
||||||
@ -3665,7 +3677,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
|||||||
LogSpells(
|
LogSpells(
|
||||||
"Adding buff [{}] will overwrite spell [{}] in slot [{}] with caster level [{}], but ResurrectionEffectBlock is set to 2. Attempting to move [{}] to an empty buff slot.",
|
"Adding buff [{}] will overwrite spell [{}] in slot [{}] with caster level [{}], but ResurrectionEffectBlock is set to 2. Attempting to move [{}] to an empty buff slot.",
|
||||||
spell_id,
|
spell_id,
|
||||||
curbuf.spellid,
|
buff_spellid,
|
||||||
buffslot,
|
buffslot,
|
||||||
curbuf.casterlevel,
|
curbuf.casterlevel,
|
||||||
spell_id
|
spell_id
|
||||||
@ -6628,8 +6640,8 @@ void Mob::SendPetBuffsToClient()
|
|||||||
|
|
||||||
for(int buffslot = 0; buffslot < MaxSlots; buffslot++)
|
for(int buffslot = 0; buffslot < MaxSlots; buffslot++)
|
||||||
{
|
{
|
||||||
if (IsValidSpell(buffs[buffslot].spellid)) {
|
if (IsValidOrSuppressedSpell(buffs[buffslot].spellid)) {
|
||||||
pbs->spellid[buffslot] = buffs[buffslot].spellid;
|
pbs->spellid[buffslot] = buffs[buffslot].spellid != SPELL_SUPPRESSED ? buffs[buffslot].spellid : RuleI(Spells, SuppressDebuffSpellID);
|
||||||
pbs->ticsremaining[buffslot] = buffs[buffslot].ticsremaining;
|
pbs->ticsremaining[buffslot] = buffs[buffslot].ticsremaining;
|
||||||
PetBuffCount++;
|
PetBuffCount++;
|
||||||
}
|
}
|
||||||
@ -6667,7 +6679,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target, bool clear_buffs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < buff_count; ++i) {
|
for(int i = 0; i < buff_count; ++i) {
|
||||||
if (IsValidSpell(buffs[i].spellid)) {
|
if (IsValidOrSuppressedSpell(buffs[i].spellid)) {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6704,6 +6716,20 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target, bool clear_buffs)
|
|||||||
strn0cpy(buff->entries[index].caster, buffs[i].caster_name, 64);
|
strn0cpy(buff->entries[index].caster, buffs[i].caster_name, 64);
|
||||||
buff->name_lengths += strlen(buff->entries[index].caster);
|
buff->name_lengths += strlen(buff->entries[index].caster);
|
||||||
++index;
|
++index;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffs[i].spellid == SPELL_SUPPRESSED) {
|
||||||
|
buff->entries[index].buff_slot = i;
|
||||||
|
buff->entries[index].spell_id = RuleI(Spells, SuppressDebuffSpellID);
|
||||||
|
buff->entries[index].tics_remaining = buffs[i].ticsremaining;
|
||||||
|
buff->entries[index].num_hits = 0;
|
||||||
|
strn0cpy(buff->entries[index].caster, buffs[i].caster_name, 64);
|
||||||
|
buff->name_lengths += strlen(buff->entries[index].caster);
|
||||||
|
++index;
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2897,7 +2897,7 @@ void ZoneDatabase::SaveBuffs(Client *client)
|
|||||||
uint32 character_buff_count = 0;
|
uint32 character_buff_count = 0;
|
||||||
|
|
||||||
for (int slot_id = 0; slot_id < max_buff_slots; slot_id++) {
|
for (int slot_id = 0; slot_id < max_buff_slots; slot_id++) {
|
||||||
if (!IsValidSpell(buffs[slot_id].spellid)) {
|
if (!IsValidOrSuppressedSpell(buffs[slot_id].spellid)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2907,16 +2907,18 @@ void ZoneDatabase::SaveBuffs(Client *client)
|
|||||||
v.reserve(character_buff_count);
|
v.reserve(character_buff_count);
|
||||||
|
|
||||||
for (int slot_id = 0; slot_id < max_buff_slots; slot_id++) {
|
for (int slot_id = 0; slot_id < max_buff_slots; slot_id++) {
|
||||||
if (!IsValidSpell(buffs[slot_id].spellid)) {
|
if (!IsValidOrSuppressedSpell(buffs[slot_id].spellid)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool suppressed = buffs[slot_id].spellid == SPELL_SUPPRESSED;
|
||||||
|
|
||||||
e.character_id = client->CharacterID();
|
e.character_id = client->CharacterID();
|
||||||
e.slot_id = slot_id;
|
e.slot_id = slot_id;
|
||||||
e.spell_id = buffs[slot_id].spellid;
|
e.spell_id = suppressed ? buffs[slot_id].suppressedid : buffs[slot_id].spellid;
|
||||||
e.caster_level = buffs[slot_id].casterlevel;
|
e.caster_level = buffs[slot_id].casterlevel;
|
||||||
e.caster_name = buffs[slot_id].caster_name;
|
e.caster_name = buffs[slot_id].caster_name;
|
||||||
e.ticsremaining = buffs[slot_id].ticsremaining;
|
e.ticsremaining = suppressed ? buffs[slot_id].suppressedticsremaining : buffs[slot_id].ticsremaining;
|
||||||
e.counters = buffs[slot_id].counters;
|
e.counters = buffs[slot_id].counters;
|
||||||
e.numhits = buffs[slot_id].hit_number;
|
e.numhits = buffs[slot_id].hit_number;
|
||||||
e.melee_rune = buffs[slot_id].melee_rune;
|
e.melee_rune = buffs[slot_id].melee_rune;
|
||||||
@ -2999,6 +3001,8 @@ void ZoneDatabase::LoadBuffs(Client *client)
|
|||||||
buffs[e.slot_id].virus_spread_time = 0;
|
buffs[e.slot_id].virus_spread_time = 0;
|
||||||
buffs[e.slot_id].UpdateClient = false;
|
buffs[e.slot_id].UpdateClient = false;
|
||||||
buffs[e.slot_id].instrument_mod = e.instrument_mod;
|
buffs[e.slot_id].instrument_mod = e.instrument_mod;
|
||||||
|
buffs[e.slot_id].suppressedid = 0;
|
||||||
|
buffs[e.slot_id].suppressedticsremaining = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We load up to the most our client supports
|
// We load up to the most our client supports
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user