mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 13:41:31 +00:00
Rework spell aggro based on http://www.eqemulator.org/forums/showthread.php?t=39819<F37>
This commit is contained in:
parent
417b034273
commit
a52ab7ae48
@ -1,5 +1,8 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
== 07/16/2013 ==
|
||||||
|
mackal: Rework spell aggro based on http://www.eqemulator.org/forums/showthread.php?t=39819
|
||||||
|
|
||||||
== 07/15/2015 ==
|
== 07/15/2015 ==
|
||||||
Hateborne: Added optional ability to enforce task level requirements in perl and lua via an added, optional parameter to $client->AssignTask and quest::assigntask.
|
Hateborne: Added optional ability to enforce task level requirements in perl and lua via an added, optional parameter to $client->AssignTask and quest::assigntask.
|
||||||
Use cases:
|
Use cases:
|
||||||
|
|||||||
195
zone/aggro.cpp
195
zone/aggro.cpp
@ -44,12 +44,8 @@ void EntityList::CheckClientAggro(Client *around)
|
|||||||
if (mob->IsClient()) //also ensures that mob != around
|
if (mob->IsClient()) //also ensures that mob != around
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (mob->CheckWillAggro(around)) {
|
if (mob->CheckWillAggro(around) && !mob->CheckAggro(around))
|
||||||
if (mob->IsEngaged())
|
mob->AddToHateList(around, 100);
|
||||||
mob->AddToHateList(around);
|
|
||||||
else
|
|
||||||
mob->AddToHateList(around, mob->GetLevel());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -954,11 +950,24 @@ bool Mob::CheckLosFN(float posX, float posY, float posZ, float mobSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//offensive spell aggro
|
//offensive spell aggro
|
||||||
int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
|
int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
|
||||||
{
|
{
|
||||||
int32 AggroAmount = 0;
|
int32 AggroAmount = 0;
|
||||||
int32 nonModifiedAggro = 0;
|
int32 nonModifiedAggro = 0;
|
||||||
uint16 slevel = GetLevel();
|
uint16 slevel = GetLevel();
|
||||||
|
bool add_default = false;
|
||||||
|
bool stun_proc = false;
|
||||||
|
bool dispel = false;
|
||||||
|
bool on_hatelist = target ? target->CheckAggro(this) : false;
|
||||||
|
|
||||||
|
int32 target_hp = target ? target->GetMaxHP() : 18000; // default to max
|
||||||
|
int32 default_aggro = 0;
|
||||||
|
if (target_hp >= 18000) // max
|
||||||
|
default_aggro = 1200;
|
||||||
|
else if (target_hp < 390) // min, 390 is the first number with int division that is 26
|
||||||
|
default_aggro = 25;
|
||||||
|
else
|
||||||
|
default_aggro = target_hp / 15;
|
||||||
|
|
||||||
for (int o = 0; o < EFFECT_COUNT; o++) {
|
for (int o = 0; o < EFFECT_COUNT; o++) {
|
||||||
switch (spells[spell_id].effectid[o]) {
|
switch (spells[spell_id].effectid[o]) {
|
||||||
@ -972,7 +981,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
|
|||||||
case SE_MovementSpeed: {
|
case SE_MovementSpeed: {
|
||||||
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
||||||
if (val < 0)
|
if (val < 0)
|
||||||
AggroAmount += (2 + ((slevel * slevel) / 8));
|
add_default = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_AttackSpeed:
|
case SE_AttackSpeed:
|
||||||
@ -980,60 +989,35 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
|
|||||||
case SE_AttackSpeed3: {
|
case SE_AttackSpeed3: {
|
||||||
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
||||||
if (val < 100)
|
if (val < 100)
|
||||||
AggroAmount += (5 + ((slevel * slevel) / 5));
|
add_default = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_Stun: {
|
case SE_Stun:
|
||||||
int val = (5 + ((slevel * slevel) / 6));
|
add_default = true;
|
||||||
if (isproc && RuleI(Aggro,MaxStunProcAggro) > -1 && (val > RuleI(Aggro,MaxStunProcAggro)))
|
stun_proc = isproc;
|
||||||
val = RuleI(Aggro,MaxStunProcAggro);
|
|
||||||
AggroAmount += val;
|
|
||||||
break;
|
break;
|
||||||
}
|
case SE_Blind:
|
||||||
case SE_Blind: {
|
case SE_Mez:
|
||||||
AggroAmount += (5 + ((slevel * slevel) / 6));
|
case SE_Charm:
|
||||||
|
case SE_Fear:
|
||||||
|
add_default = true;
|
||||||
break;
|
break;
|
||||||
}
|
case SE_Root:
|
||||||
case SE_Mez: {
|
AggroAmount += 10;
|
||||||
AggroAmount += (5 + ((slevel * slevel) / 5));
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case SE_Charm: {
|
|
||||||
AggroAmount += (5 + ((slevel * slevel) / 5));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SE_Root: {
|
|
||||||
AggroAmount += (2 + ((slevel * slevel) / 8));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SE_Fear: {
|
|
||||||
AggroAmount += (5 + ((slevel * slevel) / 6));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SE_ATK:
|
case SE_ATK:
|
||||||
case SE_ACv2:
|
case SE_ACv2:
|
||||||
case SE_ArmorClass: {
|
case SE_ArmorClass: {
|
||||||
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
||||||
if (val < 0)
|
if (val < 0)
|
||||||
AggroAmount -= val * 2;
|
add_default = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_ResistMagic:
|
case SE_ResistMagic:
|
||||||
case SE_ResistFire:
|
case SE_ResistFire:
|
||||||
case SE_ResistCold:
|
case SE_ResistCold:
|
||||||
case SE_ResistPoison:
|
case SE_ResistPoison:
|
||||||
case SE_ResistDisease: {
|
case SE_ResistDisease:
|
||||||
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
|
||||||
if (val < 0)
|
|
||||||
AggroAmount -= val * 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SE_ResistAll: {
|
|
||||||
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
|
||||||
if (val < 0)
|
|
||||||
AggroAmount -= val * 6;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SE_STR:
|
case SE_STR:
|
||||||
case SE_STA:
|
case SE_STA:
|
||||||
case SE_DEX:
|
case SE_DEX:
|
||||||
@ -1043,32 +1027,31 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
|
|||||||
case SE_CHA: {
|
case SE_CHA: {
|
||||||
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
||||||
if (val < 0)
|
if (val < 0)
|
||||||
AggroAmount -= val * 2;
|
AggroAmount += 10;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SE_ResistAll: {
|
||||||
|
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
||||||
|
if (val < 0)
|
||||||
|
AggroAmount += 50;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_AllStats: {
|
case SE_AllStats: {
|
||||||
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
||||||
if (val < 0)
|
if (val < 0)
|
||||||
AggroAmount -= val * 6;
|
AggroAmount += 70;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_BardAEDot: {
|
case SE_BardAEDot:
|
||||||
AggroAmount += slevel * 2;
|
AggroAmount += 10;
|
||||||
break;
|
break;
|
||||||
}
|
case SE_SpinTarget:
|
||||||
case SE_SpinTarget: {
|
|
||||||
AggroAmount += (5 + ((slevel * slevel) / 5));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SE_Amnesia:
|
case SE_Amnesia:
|
||||||
case SE_Silence: {
|
case SE_Silence:
|
||||||
AggroAmount += slevel * 2;
|
case SE_Destroy:
|
||||||
|
add_default = true;
|
||||||
break;
|
break;
|
||||||
}
|
// unsure -- leave them this for now
|
||||||
case SE_Destroy: {
|
|
||||||
AggroAmount += slevel * 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SE_Harmony:
|
case SE_Harmony:
|
||||||
case SE_CastingLevel:
|
case SE_CastingLevel:
|
||||||
case SE_MeleeMitigation:
|
case SE_MeleeMitigation:
|
||||||
@ -1091,6 +1074,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
|
|||||||
AggroAmount += slevel * 2;
|
AggroAmount += slevel * 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// unsure -- leave them this for now
|
||||||
case SE_CurrentMana:
|
case SE_CurrentMana:
|
||||||
case SE_ManaRegen_v2:
|
case SE_ManaRegen_v2:
|
||||||
case SE_ManaPool:
|
case SE_ManaPool:
|
||||||
@ -1101,94 +1085,105 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_CancelMagic:
|
case SE_CancelMagic:
|
||||||
case SE_DispelDetrimental: {
|
case SE_DispelDetrimental:
|
||||||
AggroAmount += slevel;
|
dispel = true;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case SE_ReduceHate:
|
case SE_ReduceHate:
|
||||||
case SE_InstantHate: {
|
case SE_InstantHate:
|
||||||
nonModifiedAggro = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
nonModifiedAggro = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (add_default) {
|
||||||
|
if (stun_proc && RuleI(Aggro, MaxStunProcAggro) > -1 && (default_aggro > RuleI(Aggro, MaxStunProcAggro)))
|
||||||
|
AggroAmount += RuleI(Aggro, MaxStunProcAggro);
|
||||||
|
else if (IsBardSong(spell_id) && default_aggro > 40)
|
||||||
|
AggroAmount += 40; // bard songs seem to cap to 40 for most of their spells?
|
||||||
|
else
|
||||||
|
AggroAmount += default_aggro;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsAEDurationSpell(spell_id))
|
if (dispel && target && target->GetHateAmount(this) < 100)
|
||||||
AggroAmount /= 2;
|
AggroAmount += 50;
|
||||||
|
|
||||||
if (spells[spell_id].HateAdded > 0)
|
if (spells[spell_id].HateAdded > 0) // overrides the hate (ex. tash)
|
||||||
AggroAmount = spells[spell_id].HateAdded;
|
AggroAmount = spells[spell_id].HateAdded;
|
||||||
|
|
||||||
if (IsBardSong(spell_id))
|
|
||||||
AggroAmount = AggroAmount * RuleI(Aggro, SongAggroMod) / 100;
|
|
||||||
if (GetOwner() && IsPet())
|
if (GetOwner() && IsPet())
|
||||||
AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;
|
AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;
|
||||||
|
|
||||||
if (AggroAmount > 0) {
|
if (AggroAmount > 0) {
|
||||||
|
|
||||||
int HateMod = RuleI(Aggro, SpellAggroMod);
|
int HateMod = RuleI(Aggro, SpellAggroMod);
|
||||||
|
|
||||||
HateMod += GetFocusEffect(focusSpellHateMod, spell_id);
|
HateMod += GetFocusEffect(focusSpellHateMod, spell_id);
|
||||||
|
|
||||||
AggroAmount = (AggroAmount * HateMod) / 100;
|
AggroAmount = (AggroAmount * HateMod) / 100;
|
||||||
|
|
||||||
//made up number probably scales a bit differently on live but it seems like it will be close enough
|
|
||||||
//every time you cast on live you get a certain amount of "this is a spell" aggro
|
|
||||||
//confirmed by EQ devs to be 100 exactly at level 85. From their wording it doesn't seem like it's affected
|
|
||||||
//by hate modifiers either.
|
|
||||||
//AggroAmount += (slevel*slevel/72);
|
|
||||||
// Saved so I can reimplement it;
|
|
||||||
// this should only be on the spell to aggro the npc not every spell
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initial aggro gets a bonus 100
|
||||||
|
if (!dispel && spells[spell_id].HateAdded == 0 && !on_hatelist)
|
||||||
|
AggroAmount += 100;
|
||||||
|
|
||||||
return AggroAmount + spells[spell_id].bonushate + nonModifiedAggro;
|
return AggroAmount + spells[spell_id].bonushate + nonModifiedAggro;
|
||||||
}
|
}
|
||||||
|
|
||||||
//healing and buffing aggro
|
//healing and buffing aggro
|
||||||
int32 Mob::CheckHealAggroAmount(uint16 spell_id, uint32 heal_possible)
|
int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possible)
|
||||||
{
|
{
|
||||||
int32 AggroAmount = 0;
|
int32 AggroAmount = 0;
|
||||||
|
auto target_level = target ? target->GetLevel() : GetLevel();
|
||||||
|
bool ignore_default_buff = false; // rune/hot don't use the default 9, HP buffs that heal (virtue) do use the default
|
||||||
|
|
||||||
for (int o = 0; o < EFFECT_COUNT; o++) {
|
for (int o = 0; o < EFFECT_COUNT; o++) {
|
||||||
switch (spells[spell_id].effectid[o]) {
|
switch (spells[spell_id].effectid[o]) {
|
||||||
case SE_CurrentHP: {
|
case SE_CurrentHP: {
|
||||||
AggroAmount += IsBuffSpell(spell_id) ? spells[spell_id].mana / 4 : spells[spell_id].mana;
|
if (heal_possible == 0) {
|
||||||
|
AggroAmount += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_Rune: {
|
// hate based on base healing power of the spell
|
||||||
AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[0], spells[spell_id].base[0], spells[spell_id].max[o], GetLevel(), spell_id) * 2;
|
int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o],
|
||||||
|
spells[spell_id].base[o], spells[spell_id].max[o], GetLevel(), spell_id);
|
||||||
|
if (val > 0) {
|
||||||
|
if (heal_possible < val)
|
||||||
|
val = heal_possible; // capped to amount healed
|
||||||
|
val = 2 * val / 3; // 3:2 ratio
|
||||||
|
|
||||||
|
if (target_level > 50 && val > 1500)
|
||||||
|
val = 1500; // target 51+ seems ~1500
|
||||||
|
else if (target_level <= 50 && val > 800)
|
||||||
|
val = 800; // per live patch notes, capped to 800
|
||||||
|
}
|
||||||
|
AggroAmount += std::max(val, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SE_HealOverTime: {
|
case SE_Rune:
|
||||||
AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], GetLevel(), spell_id);
|
AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[0],
|
||||||
|
spells[spell_id].base[0], spells[spell_id].max[o], GetLevel(), spell_id) * 2;
|
||||||
|
ignore_default_buff = true;
|
||||||
break;
|
break;
|
||||||
}
|
case SE_HealOverTime:
|
||||||
default: {
|
AggroAmount += 10;
|
||||||
|
ignore_default_buff = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (IsBardSong(spell_id))
|
|
||||||
AggroAmount = AggroAmount * RuleI(Aggro, SongAggroMod) / 100;
|
|
||||||
if (GetOwner() && IsPet())
|
if (GetOwner() && IsPet())
|
||||||
AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;
|
AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;
|
||||||
|
|
||||||
|
if (!ignore_default_buff && IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id))
|
||||||
|
AggroAmount = 9;
|
||||||
|
|
||||||
if (AggroAmount > 0) {
|
if (AggroAmount > 0) {
|
||||||
int HateMod = RuleI(Aggro, SpellAggroMod);
|
int HateMod = RuleI(Aggro, SpellAggroMod);
|
||||||
|
|
||||||
HateMod += GetFocusEffect(focusSpellHateMod, spell_id);
|
HateMod += GetFocusEffect(focusSpellHateMod, spell_id);
|
||||||
|
|
||||||
//Live AA - Spell casting subtlety
|
//Live AA - Spell casting subtlety
|
||||||
HateMod += aabonuses.hatemod + spellbonuses.hatemod + itembonuses.hatemod;
|
HateMod += aabonuses.hatemod + spellbonuses.hatemod + itembonuses.hatemod;
|
||||||
|
|
||||||
AggroAmount = (AggroAmount * HateMod) / 100;
|
AggroAmount = (AggroAmount * HateMod) / 100;
|
||||||
|
|
||||||
//made up number probably scales a bit differently on live but it seems like it will be close enough
|
|
||||||
//every time you cast on live you get a certain amount of "this is a spell" aggro
|
|
||||||
//confirmed by EQ devs to be 100 exactly at level 85. From their wording it doesn't seem like it's affected
|
|
||||||
//by hate modifiers either.
|
|
||||||
//AggroAmount += (slevel*slevel/72); // Moved Below
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AggroAmount < 0)
|
if (AggroAmount < 0)
|
||||||
|
|||||||
@ -6220,14 +6220,14 @@ bool Bot::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32 Bot::CheckAggroAmount(uint16 spellid) {
|
int32 Bot::CheckAggroAmount(uint16 spellid) {
|
||||||
int32 AggroAmount = Mob::CheckAggroAmount(spellid);
|
int32 AggroAmount = Mob::CheckAggroAmount(spellid, nullptr);
|
||||||
int32 focusAggro = GetBotFocusEffect(BotfocusSpellHateMod, spellid);
|
int32 focusAggro = GetBotFocusEffect(BotfocusSpellHateMod, spellid);
|
||||||
AggroAmount = (AggroAmount * (100 + focusAggro) / 100);
|
AggroAmount = (AggroAmount * (100 + focusAggro) / 100);
|
||||||
return AggroAmount;
|
return AggroAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Bot::CheckHealAggroAmount(uint16 spellid, uint32 heal_possible) {
|
int32 Bot::CheckHealAggroAmount(uint16 spellid, Mob *target, uint32 heal_possible) {
|
||||||
int32 AggroAmount = Mob::CheckHealAggroAmount(spellid, heal_possible);
|
int32 AggroAmount = Mob::CheckHealAggroAmount(spellid, target, heal_possible);
|
||||||
int32 focusAggro = GetBotFocusEffect(BotfocusSpellHateMod, spellid);
|
int32 focusAggro = GetBotFocusEffect(BotfocusSpellHateMod, spellid);
|
||||||
AggroAmount = (AggroAmount * (100 + focusAggro) / 100);
|
AggroAmount = (AggroAmount * (100 + focusAggro) / 100);
|
||||||
return AggroAmount;
|
return AggroAmount;
|
||||||
|
|||||||
@ -200,7 +200,7 @@ public:
|
|||||||
virtual Mob* GetOwner();
|
virtual Mob* GetOwner();
|
||||||
virtual Mob* GetOwnerOrSelf();
|
virtual Mob* GetOwnerOrSelf();
|
||||||
inline virtual bool HasOwner() { return (GetBotOwner() ? true : false); }
|
inline virtual bool HasOwner() { return (GetBotOwner() ? true : false); }
|
||||||
virtual int32 CheckHealAggroAmount(uint16 spellid, uint32 heal_possible = 0);
|
virtual int32 CheckHealAggroAmount(uint16 spellid, Mob *target, uint32 heal_possible = 0);
|
||||||
virtual int32 CalcMaxMana();
|
virtual int32 CalcMaxMana();
|
||||||
virtual void SetAttackTimer();
|
virtual void SetAttackTimer();
|
||||||
uint32 GetClassHPFactor();
|
uint32 GetClassHPFactor();
|
||||||
|
|||||||
@ -3068,56 +3068,24 @@ bool EntityList::Fighting(Mob *targ)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityList::AddHealAggro(Mob *target, Mob *caster, uint16 thedam)
|
void EntityList::AddHealAggro(Mob *target, Mob *caster, uint16 hate)
|
||||||
{
|
{
|
||||||
NPC *cur = nullptr;
|
if (hate == 0)
|
||||||
uint16 count = 0;
|
return;
|
||||||
std::list<NPC *> npc_sub_list;
|
|
||||||
auto it = npc_list.begin();
|
|
||||||
while (it != npc_list.end()) {
|
|
||||||
cur = it->second;
|
|
||||||
|
|
||||||
if (!cur->CheckAggro(target)) {
|
for (auto &e : npc_list) {
|
||||||
++it;
|
auto &npc = e.second;
|
||||||
|
if (!npc->CheckAggro(target) || npc->IsFeared())
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
if (!cur->IsMezzed() && !cur->IsStunned() && !cur->IsFeared()) {
|
|
||||||
npc_sub_list.push_back(cur);
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (zone->random.Roll(15)) // witness check -- place holder
|
||||||
|
// This is either a level check (con color check?) or a stat roll
|
||||||
|
continue;
|
||||||
|
|
||||||
if (thedam > 1) {
|
if ((npc->IsMezzed() || npc->IsStunned()) && hate > 4) // patch notes say stunned/mezzed NPCs get a fraction of the hate
|
||||||
if (count > 0)
|
npc->AddToHateList(caster, hate / 4); // made up number
|
||||||
thedam /= count;
|
else
|
||||||
|
npc->AddToHateList(caster, hate);
|
||||||
if (thedam < 1)
|
|
||||||
thedam = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur = nullptr;
|
|
||||||
auto sit = npc_sub_list.begin();
|
|
||||||
while (sit != npc_sub_list.end()) {
|
|
||||||
cur = *sit;
|
|
||||||
|
|
||||||
if (cur->IsPet()) {
|
|
||||||
if (caster) {
|
|
||||||
if (cur->CheckAggro(caster)) {
|
|
||||||
cur->AddToHateList(caster, thedam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (caster) {
|
|
||||||
if (cur->CheckAggro(caster)) {
|
|
||||||
cur->AddToHateList(caster, thedam);
|
|
||||||
} else {
|
|
||||||
cur->AddToHateList(caster, thedam * 0.33);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++sit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -333,7 +333,7 @@ public:
|
|||||||
void SendAlarm(Trap* trap, Mob* currenttarget, uint8 kos);
|
void SendAlarm(Trap* trap, Mob* currenttarget, uint8 kos);
|
||||||
Trap* FindNearbyTrap(Mob* searcher, float max_dist);
|
Trap* FindNearbyTrap(Mob* searcher, float max_dist);
|
||||||
|
|
||||||
void AddHealAggro(Mob* target, Mob* caster, uint16 thedam);
|
void AddHealAggro(Mob* target, Mob* caster, uint16 hate);
|
||||||
Mob* FindDefenseNPC(uint32 npcid);
|
Mob* FindDefenseNPC(uint32 npcid);
|
||||||
void OpenDoorsNear(NPC* opener);
|
void OpenDoorsNear(NPC* opener);
|
||||||
void UpdateWho(bool iSendFullUpdate = false);
|
void UpdateWho(bool iSendFullUpdate = false);
|
||||||
|
|||||||
@ -1172,22 +1172,22 @@ bool Lua_Mob::Charmed() {
|
|||||||
|
|
||||||
int Lua_Mob::CheckAggroAmount(int spell_id) {
|
int Lua_Mob::CheckAggroAmount(int spell_id) {
|
||||||
Lua_Safe_Call_Int();
|
Lua_Safe_Call_Int();
|
||||||
return self->CheckAggroAmount(spell_id);
|
return self->CheckAggroAmount(spell_id, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Lua_Mob::CheckAggroAmount(int spell_id, bool is_proc) {
|
int Lua_Mob::CheckAggroAmount(int spell_id, bool is_proc) {
|
||||||
Lua_Safe_Call_Int();
|
Lua_Safe_Call_Int();
|
||||||
return self->CheckAggroAmount(spell_id, is_proc);
|
return self->CheckAggroAmount(spell_id, nullptr, is_proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Lua_Mob::CheckHealAggroAmount(int spell_id) {
|
int Lua_Mob::CheckHealAggroAmount(int spell_id) {
|
||||||
Lua_Safe_Call_Int();
|
Lua_Safe_Call_Int();
|
||||||
return self->CheckHealAggroAmount(spell_id);
|
return self->CheckHealAggroAmount(spell_id, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Lua_Mob::CheckHealAggroAmount(int spell_id, uint32 heal_possible) {
|
int Lua_Mob::CheckHealAggroAmount(int spell_id, uint32 heal_possible) {
|
||||||
Lua_Safe_Call_Int();
|
Lua_Safe_Call_Int();
|
||||||
return self->CheckHealAggroAmount(spell_id, heal_possible);
|
return self->CheckHealAggroAmount(spell_id, nullptr, heal_possible);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Lua_Mob::GetAA(int id) {
|
int Lua_Mob::GetAA(int id) {
|
||||||
|
|||||||
@ -879,8 +879,8 @@ public:
|
|||||||
bool Charmed() const { return charmed; }
|
bool Charmed() const { return charmed; }
|
||||||
static uint32 GetLevelHP(uint8 tlevel);
|
static uint32 GetLevelHP(uint8 tlevel);
|
||||||
uint32 GetZoneID() const; //for perl
|
uint32 GetZoneID() const; //for perl
|
||||||
virtual int32 CheckAggroAmount(uint16 spell_id, bool isproc = false);
|
virtual int32 CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc = false);
|
||||||
virtual int32 CheckHealAggroAmount(uint16 spell_id, uint32 heal_possible = 0);
|
virtual int32 CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possible = 0);
|
||||||
|
|
||||||
uint32 GetInstrumentMod(uint16 spell_id) const;
|
uint32 GetInstrumentMod(uint16 spell_id) const;
|
||||||
int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0);
|
int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0);
|
||||||
|
|||||||
@ -6316,7 +6316,7 @@ XS(XS_Mob_CheckAggroAmount)
|
|||||||
if(THIS == nullptr)
|
if(THIS == nullptr)
|
||||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
RETVAL = THIS->CheckAggroAmount(spellid);
|
RETVAL = THIS->CheckAggroAmount(spellid, nullptr);
|
||||||
XSprePUSH; PUSHu((UV)RETVAL);
|
XSprePUSH; PUSHu((UV)RETVAL);
|
||||||
}
|
}
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
@ -6349,7 +6349,7 @@ XS(XS_Mob_CheckHealAggroAmount)
|
|||||||
possible = (uint32)SvUV(ST(2));
|
possible = (uint32)SvUV(ST(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
RETVAL = THIS->CheckHealAggroAmount(spellid, possible);
|
RETVAL = THIS->CheckHealAggroAmount(spellid, nullptr, possible);
|
||||||
XSprePUSH; PUSHu((UV)RETVAL);
|
XSprePUSH; PUSHu((UV)RETVAL);
|
||||||
}
|
}
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
|
|||||||
@ -3704,7 +3704,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (spelltar->IsAIControlled()) {
|
if (spelltar->IsAIControlled()) {
|
||||||
int32 aggro = CheckAggroAmount(spell_id);
|
int32 aggro = CheckAggroAmount(spell_id, spelltar);
|
||||||
if (aggro > 0) {
|
if (aggro > 0) {
|
||||||
if (!IsHarmonySpell(spell_id))
|
if (!IsHarmonySpell(spell_id))
|
||||||
spelltar->AddToHateList(this, aggro);
|
spelltar->AddToHateList(this, aggro);
|
||||||
@ -3733,20 +3733,20 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
|
|||||||
spelltar->DamageShield(this, true);
|
spelltar->DamageShield(this, true);
|
||||||
|
|
||||||
if (spelltar->IsAIControlled() && IsDetrimentalSpell(spell_id) && !IsHarmonySpell(spell_id)) {
|
if (spelltar->IsAIControlled() && IsDetrimentalSpell(spell_id) && !IsHarmonySpell(spell_id)) {
|
||||||
int32 aggro_amount = CheckAggroAmount(spell_id, isproc);
|
int32 aggro_amount = CheckAggroAmount(spell_id, spelltar, isproc);
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "Spell %d cast on %s generated %d hate", spell_id, spelltar->GetName(), aggro_amount);
|
Log.Out(Logs::Detail, Logs::Spells, "Spell %d cast on %s generated %d hate", spell_id,
|
||||||
if(aggro_amount > 0)
|
spelltar->GetName(), aggro_amount);
|
||||||
spelltar->AddToHateList(this, aggro_amount); else{
|
if (aggro_amount > 0) {
|
||||||
int32 newhate = spelltar->GetHateAmount(this) + aggro_amount;
|
spelltar->AddToHateList(this, aggro_amount);
|
||||||
if (newhate < 1) {
|
|
||||||
spelltar->SetHateAmountOnEnt(this,1);
|
|
||||||
} else {
|
} else {
|
||||||
spelltar->SetHateAmountOnEnt(this,newhate);
|
int32 newhate = spelltar->GetHateAmount(this) + aggro_amount;
|
||||||
|
spelltar->SetHateAmountOnEnt(this, std::max(newhate, 1));
|
||||||
}
|
}
|
||||||
|
} else if (IsBeneficialSpell(spell_id) && !IsSummonPCSpell(spell_id)) {
|
||||||
|
entity_list.AddHealAggro(
|
||||||
|
spelltar, this,
|
||||||
|
CheckHealAggroAmount(spell_id, spelltar, (spelltar->GetMaxHP() - spelltar->GetHP())));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (IsBeneficialSpell(spell_id) && !IsSummonPCSpell(spell_id))
|
|
||||||
entity_list.AddHealAggro(spelltar, this, CheckHealAggroAmount(spell_id, (spelltar->GetMaxHP() - spelltar->GetHP())));
|
|
||||||
|
|
||||||
// make sure spelltar is high enough level for the buff
|
// make sure spelltar is high enough level for the buff
|
||||||
if(RuleB(Spells, BuffLevelRestrictions) && !spelltar->CheckSpellLevelRestriction(spell_id))
|
if(RuleB(Spells, BuffLevelRestrictions) && !spelltar->CheckSpellLevelRestriction(spell_id))
|
||||||
@ -4059,7 +4059,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
|||||||
if(GetSpecialAbility(UNMEZABLE)) {
|
if(GetSpecialAbility(UNMEZABLE)) {
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "We are immune to Mez spells.");
|
Log.Out(Logs::Detail, Logs::Spells, "We are immune to Mez spells.");
|
||||||
caster->Message_StringID(MT_Shout, CANNOT_MEZ);
|
caster->Message_StringID(MT_Shout, CANNOT_MEZ);
|
||||||
int32 aggro = caster->CheckAggroAmount(spell_id);
|
int32 aggro = caster->CheckAggroAmount(spell_id, this);
|
||||||
if(aggro > 0) {
|
if(aggro > 0) {
|
||||||
AddToHateList(caster, aggro);
|
AddToHateList(caster, aggro);
|
||||||
} else {
|
} else {
|
||||||
@ -4086,7 +4086,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
|||||||
{
|
{
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "We are immune to Slow spells.");
|
Log.Out(Logs::Detail, Logs::Spells, "We are immune to Slow spells.");
|
||||||
caster->Message_StringID(MT_Shout, IMMUNE_ATKSPEED);
|
caster->Message_StringID(MT_Shout, IMMUNE_ATKSPEED);
|
||||||
int32 aggro = caster->CheckAggroAmount(spell_id);
|
int32 aggro = caster->CheckAggroAmount(spell_id, this);
|
||||||
if(aggro > 0) {
|
if(aggro > 0) {
|
||||||
AddToHateList(caster, aggro);
|
AddToHateList(caster, aggro);
|
||||||
} else {
|
} else {
|
||||||
@ -4102,7 +4102,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
|||||||
if(GetSpecialAbility(UNFEARABLE)) {
|
if(GetSpecialAbility(UNFEARABLE)) {
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "We are immune to Fear spells.");
|
Log.Out(Logs::Detail, Logs::Spells, "We are immune to Fear spells.");
|
||||||
caster->Message_StringID(MT_Shout, IMMUNE_FEAR);
|
caster->Message_StringID(MT_Shout, IMMUNE_FEAR);
|
||||||
int32 aggro = caster->CheckAggroAmount(spell_id);
|
int32 aggro = caster->CheckAggroAmount(spell_id, this);
|
||||||
if(aggro > 0) {
|
if(aggro > 0) {
|
||||||
AddToHateList(caster, aggro);
|
AddToHateList(caster, aggro);
|
||||||
} else {
|
} else {
|
||||||
@ -4119,7 +4119,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
|||||||
{
|
{
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "Level is %d, cannot be feared by this spell.", GetLevel());
|
Log.Out(Logs::Detail, Logs::Spells, "Level is %d, cannot be feared by this spell.", GetLevel());
|
||||||
caster->Message_StringID(MT_Shout, FEAR_TOO_HIGH);
|
caster->Message_StringID(MT_Shout, FEAR_TOO_HIGH);
|
||||||
int32 aggro = caster->CheckAggroAmount(spell_id);
|
int32 aggro = caster->CheckAggroAmount(spell_id, this);
|
||||||
if (aggro > 0) {
|
if (aggro > 0) {
|
||||||
AddToHateList(caster, aggro);
|
AddToHateList(caster, aggro);
|
||||||
} else {
|
} else {
|
||||||
@ -4142,7 +4142,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
|||||||
{
|
{
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "We are immune to Charm spells.");
|
Log.Out(Logs::Detail, Logs::Spells, "We are immune to Charm spells.");
|
||||||
caster->Message_StringID(MT_Shout, CANNOT_CHARM);
|
caster->Message_StringID(MT_Shout, CANNOT_CHARM);
|
||||||
int32 aggro = caster->CheckAggroAmount(spell_id);
|
int32 aggro = caster->CheckAggroAmount(spell_id, this);
|
||||||
if(aggro > 0) {
|
if(aggro > 0) {
|
||||||
AddToHateList(caster, aggro);
|
AddToHateList(caster, aggro);
|
||||||
} else {
|
} else {
|
||||||
@ -4182,7 +4182,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
|||||||
if(GetSpecialAbility(UNSNAREABLE)) {
|
if(GetSpecialAbility(UNSNAREABLE)) {
|
||||||
Log.Out(Logs::Detail, Logs::Spells, "We are immune to Snare spells.");
|
Log.Out(Logs::Detail, Logs::Spells, "We are immune to Snare spells.");
|
||||||
caster->Message_StringID(MT_Shout, IMMUNE_MOVEMENT);
|
caster->Message_StringID(MT_Shout, IMMUNE_MOVEMENT);
|
||||||
int32 aggro = caster->CheckAggroAmount(spell_id);
|
int32 aggro = caster->CheckAggroAmount(spell_id, this);
|
||||||
if(aggro > 0) {
|
if(aggro > 0) {
|
||||||
AddToHateList(caster, aggro);
|
AddToHateList(caster, aggro);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user