Merge branch 'master' into Bot_Raid_work

This commit is contained in:
neckkola
2022-02-13 07:26:18 -04:00
committed by GitHub
857 changed files with 92718 additions and 44581 deletions
+360 -243
View File
@@ -44,18 +44,16 @@ float Mob::GetActSpellRange(uint16 spell_id, float range, bool IsBard)
int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
if (spells[spell_id].targettype == ST_Self)
if (spells[spell_id].target_type == ST_Self)
return value;
if (IsNPC())
value += value*CastToNPC()->GetSpellFocusDMG()/100;
Critical = false; //Mitch removed bool
int32 value_BaseEffect = 0;
bool Critical = false;
int32 base_value = value;
int chance = 0;
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
// Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
if ((spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40)
value -= (GetLevel() - 40) * 20;
@@ -99,15 +97,16 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
if (Critical){
value = value_BaseEffect*ratio/100;
value = base_value*ratio/100;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
value += base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
value += int(base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100)*ratio / 100;
if (target) {
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
value += int(base_value*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
value -= target->GetFcDamageAmtIncoming(this, spell_id);
}
@@ -115,12 +114,13 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
value -= GetFocusEffect(focusFcDamageAmt2, spell_id);
value -= GetFocusEffect(focusFcAmplifyAmt, spell_id);
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg)
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio / 100;
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value)*ratio / 100;
else if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5)
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100;
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value)*ratio/100;
else if (IsNPC() && CastToNPC()->GetSpellScale())
value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);
@@ -136,15 +136,16 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
}
}
//Non Crtical Hit Calculation pathway
value = value_BaseEffect;
value = base_value;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
value += base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
value += base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
value += base_value*GetFocusEffect(focusFcAmplifyMod, spell_id)/100;
if (target) {
value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
value += base_value*target->GetVulnerability(this, spell_id, 0)/100;
value -= target->GetFcDamageAmtIncoming(this, spell_id);
}
@@ -152,12 +153,13 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
value -= GetFocusEffect(focusFcDamageAmt2, spell_id);
value -= GetFocusEffect(focusFcAmplifyAmt, spell_id);
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg)
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value);
else if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5)
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value);
if (IsNPC() && CastToNPC()->GetSpellScale())
value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);
@@ -165,15 +167,43 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
return value;
}
int32 Mob::GetActReflectedSpellDamage(int32 spell_id, int32 value, int effectiveness) {
/*
Reflected spells use the spells base damage before any modifiers or formulas applied.
That value can then be modifier by the reflect spells 'max' value, defined here as effectiveness
Default effectiveness is set at 100.
Extra Spell Damage stat from the with the reflect effect will be applied to reflected damage
with no level limitation, this was confirmed with extensive parsing ~Kayen
*/
if (IsNPC()) {
value += value * CastToNPC()->GetSpellFocusDMG() / 100;
if (CastToNPC()->GetSpellScale()) {
value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);
}
}
int32 base_spell_dmg = value;
value = value * effectiveness / 100;
if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) {
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_spell_dmg);
}
return value;
}
int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
if (target == nullptr)
return value;
if (IsNPC()) {
value += value * CastToNPC()->GetSpellFocusDMG() / 100;
}
if (IsNPC())
value += value*CastToNPC()->GetSpellFocusDMG()/100;
int32 value_BaseEffect = 0;
int32 base_value = value;
int32 extra_dmg = 0;
int16 chance = 0;
chance += itembonuses.CriticalDoTChance + spellbonuses.CriticalDoTChance + aabonuses.CriticalDoTChance;
@@ -184,23 +214,32 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance)
chance = spells[spell_id].override_crit_chance;
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
if (chance > 0 && (zone->random.Roll(chance))) {
if (!spells[spell_id].good_effect && chance > 0 && (zone->random.Roll(chance))) {
int32 ratio = 200;
ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease;
value = value_BaseEffect*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
value = base_value*ratio/100;
value += int(base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100;
value += int(base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100)*ratio/100;
value += int(base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100)*ratio/100;
value += int(base_value*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) +
GetFocusEffect(focusFcDamageAmt, spell_id) +
GetFocusEffect(focusFcDamageAmt2, spell_id);
GetFocusEffect(focusFcDamageAmt2, spell_id) +
GetFocusEffect(focusFcAmplifyAmt, spell_id);
if (RuleB(Spells, DOTsScaleWithSpellDmg)) {
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) {
extra_dmg += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value)*ratio/100;
}
else if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
extra_dmg += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value)*ratio/100;
}
}
if (extra_dmg) {
int duration = CalcBuffDuration(this, this, spell_id);
int duration = CalcBuffDuration(this, target, spell_id);
if (duration > 0)
extra_dmg /= duration;
}
@@ -209,18 +248,29 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
}
else {
value = value_BaseEffect;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
value = base_value;
value += base_value*GetFocusEffect(focusImprovedDamage, spell_id)/100;
value += base_value*GetFocusEffect(focusImprovedDamage2, spell_id)/100;
value += base_value*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
value += base_value*GetFocusEffect(focusFcAmplifyMod, spell_id)/100;
value += base_value*target->GetVulnerability(this, spell_id, 0)/100;
extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
GetFocusEffect(focusFcDamageAmtCrit, spell_id) +
GetFocusEffect(focusFcDamageAmt, spell_id) +
GetFocusEffect(focusFcDamageAmt2, spell_id);
GetFocusEffect(focusFcDamageAmt2, spell_id) +
GetFocusEffect(focusFcAmplifyAmt, spell_id);
if (RuleB(Spells, DOTsScaleWithSpellDmg)) {
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) {
extra_dmg += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value);
}
else if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
extra_dmg += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_value);
}
}
if (extra_dmg) {
int duration = CalcBuffDuration(this, this, spell_id);
int duration = CalcBuffDuration(this, target, spell_id);
if (duration > 0)
extra_dmg /= duration;
}
@@ -253,69 +303,104 @@ int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_s
else
extra_spell_amt = extra_spell_amt * total_cast_time / 7000;
if(extra_spell_amt*2 < base_spell_dmg)
return 0;
//Confirmed with parsing 10/9/21 ~Kayen
if (extra_spell_amt * 2 > abs(base_spell_dmg)) {
extra_spell_amt = abs(base_spell_dmg) / 2;
}
return extra_spell_amt;
return extra_spell_amt;
}
int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
if (target == nullptr)
target = this;
if (IsNPC())
value += value*CastToNPC()->GetSpellFocusHeal()/100;
if (IsNPC()) {
value += value * CastToNPC()->GetSpellFocusHeal() / 100;
}
int32 value_BaseEffect = 0;
int16 chance = 0;
int8 modifier = 1;
Critical = false; //mitch
Critical = false;
int32 base_value = value;
int16 critical_chance = 0;
int8 critical_modifier = 1;
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
if (spells[spell_id].buff_duration < 1) {
critical_chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;
value = value_BaseEffect;
if (spellbonuses.CriticalHealDecay) {
critical_chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay);
}
}
else {
critical_chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime;
value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100);
if (spellbonuses.CriticalRegenDecay) {
critical_chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay);
}
}
// Instant Heals
if(spells[spell_id].buffduration < 1) {
if (critical_chance) {
chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
if (spellbonuses.CriticalHealDecay)
chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay);
if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance)
chance = spells[spell_id].override_crit_chance;
if(chance && (zone->random.Roll(chance))) {
Critical = true;
modifier = 2; //At present time no critical heal amount modifier SPA exists.
if (spells[spell_id].override_crit_chance > 0 && critical_chance > spells[spell_id].override_crit_chance) {
critical_chance = spells[spell_id].override_crit_chance;
}
value *= modifier;
value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier;
value += GetFocusEffect(focusFcHealAmt, spell_id);
value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id);
if (zone->random.Roll(critical_chance)) {
critical_modifier = 2; //At present time no critical heal amount modifier SPA exists.
}
}
if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%17) - 1] >= GetLevel() - 5)
value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier;
if (GetClass() == CLERIC) {
value += int(base_value*RuleI(Spells, ClericInnateHealFocus) / 100); //confirmed on live parsing clerics get an innate 5 pct heal focus
}
value += int(base_value*GetFocusEffect(focusImprovedHeal, spell_id) / 100);
value += int(base_value*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100);
value += value*target->GetHealRate(spell_id, this)/100;
// Instant Heals
if (spells[spell_id].buff_duration < 1) {
if (IsNPC() && CastToNPC()->GetHealScale())
if (target) {
value += int(base_value * target->GetFocusEffect(focusFcHealPctIncoming, spell_id, this)/100); //SPA 393 Add before critical
value += int(base_value * target->GetFocusEffect(focusFcHealPctCritIncoming, spell_id, this)/100); //SPA 395 Add before critical (?)
}
value += GetFocusEffect(focusFcHealAmtCrit, spell_id); //SPA 396 Add before critical
//Using IgnoreSpellDmgLvlRestriction to also allow healing to scale
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt) {
value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, base_value);//Item Heal Amt Add before critical
}
else if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, base_value);//Item Heal Amt Add before critical
}
if (target) {
value += value * target->GetHealRate() / 100; //SPA 120 modifies value after Focus Applied but before critical
}
/*
Apply critical hit modifier
*/
value *= critical_modifier;
value += GetFocusEffect(focusFcHealAmt, spell_id); //SPA 392 Add after critical
value += GetFocusEffect(focusFcAmplifyAmt, spell_id); //SPA 508 ? Add after critical
if (target) {
value += target->GetFocusEffect(focusFcHealAmtIncoming, spell_id, this); //SPA 394 Add after critical
}
if (IsNPC() && CastToNPC()->GetHealScale()) {
value = int(static_cast<float>(value) * CastToNPC()->GetHealScale() / 100.0f);
}
if (Critical) {
if (critical_modifier > 1) {
entity_list.MessageCloseString(
this, true, 100, Chat::SpellCrit,
OTHER_CRIT_HEAL, GetName(), itoa(value));
if (IsClient())
if (IsClient()) {
MessageString(Chat::SpellCrit, YOU_CRIT_HEAL, itoa(value));
}
}
return value;
@@ -323,20 +408,32 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
//Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value]
else {
//Using IgnoreSpellDmgLvlRestriction to also allow healing to scale
int32 extra_heal = 0;
if (RuleB(Spells, HOTsScaleWithHealAmt)) {
if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt) {
extra_heal += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, base_value);
}
else if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) {
extra_heal += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, base_value);
}
}
if (extra_heal) {
int duration = CalcBuffDuration(this, target, spell_id);
if (duration > 0) {
extra_heal /= duration;
value += extra_heal;
}
}
chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime;
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
if (spellbonuses.CriticalRegenDecay)
chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay);
if(chance && zone->random.Roll(chance))
value *= 2;
if (critical_chance && zone->random.Roll(critical_chance))
value *= critical_modifier;
}
if (IsNPC() && CastToNPC()->GetHealScale())
if (IsNPC() && CastToNPC()->GetHealScale()) {
value = int(static_cast<float>(value) * CastToNPC()->GetHealScale() / 100.0f);
}
return value;
}
@@ -409,29 +506,6 @@ int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration)
return ifocused + 1;
}
int32 Client::GetActSpellCasttime(uint16 spell_id, int32 casttime)
{
int32 cast_reducer = 0;
cast_reducer += GetFocusEffect(focusSpellHaste, spell_id);
//this function loops through the effects of spell_id many times
//could easily be consolidated.
if (GetLevel() >= 51 && casttime >= 3000 && !BeneficialSpell(spell_id)
&& (GetClass() == SHADOWKNIGHT || GetClass() == RANGER
|| GetClass() == PALADIN || GetClass() == BEASTLORD ))
cast_reducer += (GetLevel()-50)*3;
//LIVE AA SpellCastingDeftness, QuickBuff, QuickSummoning, QuickEvacuation, QuickDamage
if (cast_reducer > RuleI(Spells, MaxCastTimeReduction))
cast_reducer = RuleI(Spells, MaxCastTimeReduction);
casttime = (casttime*(100 - cast_reducer)/100);
return casttime;
}
bool Client::TrainDiscipline(uint32 itemid) {
//get the item info
@@ -534,6 +608,90 @@ bool Client::TrainDiscipline(uint32 itemid) {
return(false);
}
bool Client::MemorizeSpellFromItem(uint32 item_id) {
const EQ::ItemData *item = database.GetItem(item_id);
if(item == nullptr) {
Message(Chat::Red, "Unable to find the scroll!");
LogError("Unable to find scroll id [{}]\n", (unsigned long)item_id);
return false;
}
if (!item->IsClassCommon() || item->ItemType != EQ::item::ItemTypeSpell) {
Message(Chat::Red, "Invalid item type, you cannot learn from this item.");
SummonItem(item_id);
return false;
}
if(!(
item->Name[0] == 'S' &&
item->Name[1] == 'p' &&
item->Name[2] == 'e' &&
item->Name[3] == 'l' &&
item->Name[4] == 'l' &&
item->Name[5] == ':' &&
item->Name[6] == ' '
)) {
Message(Chat::Red, "This item is not a scroll.");
SummonItem(item_id);
return false;
}
int player_class = GetClass();
uint32 cbit = 1 << (player_class - 1);
if(!(item->Classes & cbit)) {
Message(Chat::Red, "Your class cannot learn from this scroll.");
SummonItem(item_id);
return false;
}
uint32 spell_id = item->Scroll.Effect;
if(!IsValidSpell(spell_id)) {
Message(Chat::Red, "This scroll contains invalid knowledge.");
return false;
}
const SPDat_Spell_Struct &spell = spells[spell_id];
uint8 level_to_use = spell.classes[player_class - 1];
if(level_to_use == 255) {
Message(Chat::Red, "Your class cannot learn from this scroll.");
SummonItem(item_id);
return false;
}
if(level_to_use > GetLevel()) {
Message(Chat::Red, "You must be at least level %d to learn this spell.", level_to_use);
SummonItem(item_id);
return false;
}
for (int index = 0; index < EQ::spells::SPELLBOOK_SIZE; index++) {
if (!HasSpellScribed(spell_id)) {
auto next_slot = GetNextAvailableSpellBookSlot();
if (next_slot != -1) {
ScribeSpell(spell_id, next_slot);
return true;
}
else {
Message(
Chat::Red,
"Unable to scribe spell %s (%i) to spellbook: no more spell book slots available.",
((spell_id >= 0 && spell_id < SPDAT_RECORDS) ? spells[spell_id].name : "Out-of-range"),
spell_id
);
SummonItem(item_id);
return false;
}
}
else {
Message(Chat::Red, "You already know this spell.");
SummonItem(item_id);
return false;
}
}
Message(Chat::Red, "You have learned too many spells and can learn no more.");
return false;
}
void Client::TrainDiscBySpellID(int32 spell_id)
{
int i;
@@ -570,8 +728,15 @@ void Client::SendDisciplineUpdate() {
bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
// Dont let client waste a reuse timer if they can't use the disc
if (IsStunned() || IsFeared() || IsMezzed() || IsAmnesiad() || IsPet())
if ((IsStunned() && !IgnoreCastingRestriction(spell_id))||
IsFeared() ||
(IsMezzed() && !IgnoreCastingRestriction(spell_id)) ||
IsAmnesiad() ||
IsPet())
{
if (IsAmnesiad()) {
MessageString(Chat::Red, MELEE_SILENCE);
}
return(false);
}
@@ -590,6 +755,10 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
return(false);
}
if (DivineAura() && !IgnoreCastingRestriction(spell_id)) {
return false;
}
//can we use the spell?
const SPDat_Spell_Struct &spell = spells[spell_id];
uint8 level_to_use = spell.classes[GetClass() - 1];
@@ -605,7 +774,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
return(false);
}
if(GetEndurance() < spell.EndurCost) {
if(GetEndurance() < spell.endurance_cost) {
Message(11, "You are too fatigued to use this skill right now.");
return(false);
}
@@ -617,22 +786,26 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
}
// the client does this check before calling CastSpell, should prevent discs being eaten
if (spell.buffdurationformula != 0 && spell.targettype == ST_Self && HasDiscBuff())
if (spell.buff_duration_formula != 0 && spell.target_type == ST_Self && HasDiscBuff())
return false;
//Check the disc timer
pTimerType DiscTimer = pTimerDisciplineReuseStart + spell.EndurTimerIndex;
pTimerType DiscTimer = pTimerDisciplineReuseStart + spell.timer_id;
if(!p_timers.Expired(&database, DiscTimer, false)) { // lets not set the reuse timer in case CastSpell fails (or we would have to turn off the timer, but CastSpell will set it as well)
/*char val1[20]={0};*/ //unused
/*char val2[20]={0};*/ //unused
uint32 remain = p_timers.GetRemainingTime(DiscTimer);
//MessageString(Chat::White, DISCIPLINE_CANUSEIN, ConvertArray((remain)/60,val1), ConvertArray(remain%60,val2));
Message(0, "You can use this discipline in %d minutes %d seconds.", ((remain)/60), (remain%60));
return(false);
uint32 remaining_time = p_timers.GetRemainingTime(DiscTimer);
Message(
Chat::White,
fmt::format(
"You can use this discipline in {}.",
ConvertSecondsToTime(remaining_time)
).c_str()
);
return false;
}
if(spell.recast_time > 0)
{
bool instant_recast = true;
if (spell.recast_time > 0) {
uint32 reduced_recast = spell.recast_time / 1000;
auto focus = GetFocusEffect(focusReduceRecastTime, spell_id);
// do stupid stuff because custom servers.
@@ -643,22 +816,36 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
reduced_recast = 0;
if (GetPTimers().Enabled((uint32)DiscTimer))
GetPTimers().Clear(&database, (uint32)DiscTimer);
} else {
}
else {
reduced_recast -= focus;
}
if (reduced_recast > 0)
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
else{
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline);
return true;
}
if (reduced_recast > 0) {
instant_recast = false;
SendDisciplineTimer(spells[spell_id].EndurTimerIndex, reduced_recast);
if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) {
if (DoCastingChecksOnCaster(spell_id)) {
SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline, 0, -1, spells[spell_id].resist_difficulty, false, -1, (uint32)DiscTimer, reduced_recast, false);
}
}
else {
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
}
SendDisciplineTimer(spells[spell_id].timer_id, reduced_recast);
}
}
else
{
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline);
if (instant_recast) {
if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) {
if (DoCastingChecksOnCaster(spell_id)) {
SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline, 0, -1, spells[spell_id].resist_difficulty, false, -1, 0xFFFFFFFF, 0, false);
}
}
else {
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline);
}
}
return(true);
}
@@ -666,7 +853,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
uint32 Client::GetDisciplineTimer(uint32 timer_id) {
pTimerType disc_timer_id = pTimerDisciplineReuseStart + timer_id;
uint32 disc_timer = 0;
if (GetPTimers().Enabled((uint32)disc_timer_id)) {
if (GetPTimers().Enabled(disc_timer_id)) {
disc_timer = GetPTimers().GetRemainingTime(disc_timer_id);
}
return disc_timer;
@@ -674,12 +861,22 @@ uint32 Client::GetDisciplineTimer(uint32 timer_id) {
void Client::ResetDisciplineTimer(uint32 timer_id) {
pTimerType disc_timer_id = pTimerDisciplineReuseStart + timer_id;
if (GetPTimers().Enabled((uint32)disc_timer_id)) {
GetPTimers().Clear(&database, (uint32)disc_timer_id);
if (GetPTimers().Enabled(disc_timer_id)) {
GetPTimers().Clear(&database, disc_timer_id);
}
SendDisciplineTimer(timer_id, 0);
}
void Client::ResetAllDisciplineTimers() {
for (pTimerType disc_timer_id = pTimerDisciplineReuseStart; disc_timer_id <= pTimerDisciplineReuseEnd; disc_timer_id++) {
uint32 current_timer_id = (disc_timer_id - pTimerDisciplineReuseStart);
if (GetPTimers().Enabled(disc_timer_id)) {
GetPTimers().Clear(&database, disc_timer_id);
}
SendDisciplineTimer(current_timer_id, 0);
}
}
bool Client::HasDisciplineLearned(uint16 spell_id) {
bool has_learned = false;
for (auto index = 0; index < MAX_PP_DISCIPLINES; ++index) {
@@ -763,7 +960,7 @@ void EntityList::AESpell(
)
{
const auto &cast_target_position =
spells[spell_id].targettype == ST_Ring ?
spells[spell_id].target_type == ST_Ring ?
caster_mob->GetTargetRingLocation() :
static_cast<glm::vec3>(center_mob->GetPosition());
@@ -786,14 +983,14 @@ void EntityList::AESpell(
/**
* Max AOE targets
*/
int max_targets_allowed = 0; // unlimited
int max_targets_allowed = RuleI(Range, AOEMaxTargets); // unlimited
if (max_targets) { // rains pass this in since they need to preserve the count through waves
max_targets_allowed = *max_targets;
}
else if (spells[spell_id].aemaxtargets) {
max_targets_allowed = spells[spell_id].aemaxtargets;
else if (spells[spell_id].aoe_max_targets) {
max_targets_allowed = spells[spell_id].aoe_max_targets;
}
else if (IsTargetableAESpell(spell_id) && is_detrimental_spell && !is_npc) {
else if (IsTargetableAESpell(spell_id) && is_detrimental_spell && !is_npc && !IsEffectInSpell(spell_id, SE_Lull) && !IsEffectInSpell(spell_id, SE_Mez)) {
max_targets_allowed = 4;
}
@@ -823,15 +1020,15 @@ void EntityList::AESpell(
continue;
}
if (spells[spell_id].targettype == ST_TargetAENoPlayersPets && current_mob->IsPetOwnerClient()) {
if (spells[spell_id].target_type == ST_TargetAENoPlayersPets && current_mob->IsPetOwnerClient()) {
continue;
}
if (spells[spell_id].targettype == ST_AreaClientOnly && !current_mob->IsClient()) {
if (spells[spell_id].target_type == ST_AreaClientOnly && !current_mob->IsClient()) {
continue;
}
if (spells[spell_id].targettype == ST_AreaNPCOnly && !current_mob->IsNPC()) {
if (spells[spell_id].target_type == ST_AreaNPCOnly && !current_mob->IsNPC()) {
continue;
}
@@ -865,21 +1062,21 @@ void EntityList::AESpell(
}
if (is_npc && current_mob->IsNPC() &&
spells[spell_id].targettype != ST_AreaNPCOnly) { //check npc->npc casting
spells[spell_id].target_type != ST_AreaNPCOnly) { //check npc->npc casting
FACTION_VALUE faction_value = current_mob->GetReverseFactionCon(caster_mob);
if (is_detrimental_spell) {
//affect mobs that are on our hate list, or
//which have bad faction with us
if (
!(caster_mob->CheckAggro(current_mob) ||
faction_value == FACTION_THREATENLY ||
faction_value == FACTION_THREATENINGLY ||
faction_value == FACTION_SCOWLS)) {
continue;
}
}
else {
//only affect mobs we would assist.
if (!(faction_value <= FACTION_AMIABLE)) {
if (!(faction_value <= FACTION_AMIABLY)) {
continue;
}
}
@@ -919,6 +1116,9 @@ void EntityList::AESpell(
}
}
current_mob->CalcSpellPowerDistanceMod(spell_id, distance_to_target);
caster_mob->SpellOnTarget(spell_id, current_mob, 0, true, resist_adjust);
/**
* Increment hit count if max targets
*/
@@ -928,9 +1128,6 @@ void EntityList::AESpell(
break;
}
}
current_mob->CalcSpellPowerDistanceMod(spell_id, distance_to_target);
caster_mob->SpellOnTarget(spell_id, current_mob, false, true, resist_adjust);
}
LogAoeCast("Done iterating [{}]", caster_mob->GetCleanName());
@@ -1001,90 +1198,6 @@ void EntityList::MassGroupBuff(
}
}
/**
* Causes caster to hit every mob within dist range of center with a bard pulse of spell_id
* NPC spells will only affect other NPCs with compatible faction
*
* @param caster
* @param center
* @param spell_id
* @param affect_caster
*/
void EntityList::AEBardPulse(
Mob *caster,
Mob *center,
uint16 spell_id,
bool affect_caster)
{
Mob *current_mob = nullptr;
float distance = caster->GetAOERange(spell_id);
float distance_squared = distance * distance;
bool is_detrimental_spell = IsDetrimentalSpell(spell_id);
bool is_npc = caster->IsNPC();
for (auto &it : entity_list.GetCloseMobList(caster, distance)) {
current_mob = it.second;
/**
* Skip self
*/
if (current_mob == center) {
continue;
}
if (current_mob == caster && !affect_caster) {
continue;
}
if (DistanceSquared(center->GetPosition(), current_mob->GetPosition()) > distance_squared) { //make sure they are in range
continue;
}
/**
* check npc->npc casting
*/
if (is_npc && current_mob->IsNPC()) {
FACTION_VALUE faction = current_mob->GetReverseFactionCon(caster);
if (is_detrimental_spell) {
//affect mobs that are on our hate list, or
//which have bad faction with us
if (!(caster->CheckAggro(current_mob) || faction == FACTION_THREATENLY || faction == FACTION_SCOWLS)) {
continue;
}
}
else {
//only affect mobs we would assist.
if (!(faction <= FACTION_AMIABLE)) {
continue;
}
}
}
/**
* LOS
*/
if (is_detrimental_spell) {
if (!center->CheckLosFN(current_mob)) {
continue;
}
}
else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies...
// See notes in AESpell() above for more info.
if (caster->IsAttackAllowed(current_mob, true)) {
continue;
}
if (caster->CheckAggro(current_mob)) {
continue;
}
}
current_mob->BardPulse(spell_id, caster);
}
if (caster->IsClient()) {
caster->CastToClient()->CheckSongSkillIncrease(spell_id);
}
}
/**
* Rampage - Normal and Duration rampages
* NPCs handle it differently in Mob::Rampage
@@ -1100,7 +1213,8 @@ void EntityList::AEAttack(
float distance,
int Hand,
int count,
bool is_from_spell)
bool is_from_spell,
int attack_rounds)
{
Mob *current_mob = nullptr;
float distance_squared = distance * distance;
@@ -1112,15 +1226,18 @@ void EntityList::AEAttack(
if (current_mob->IsNPC()
&& current_mob != attacker //this is not needed unless NPCs can use this
&& (attacker->IsAttackAllowed(current_mob))
&& current_mob->GetRace() != 216 && current_mob->GetRace() != 472 /* dont attack horses */
&& !current_mob->IsHorse() /* dont attack mounts */
&& (DistanceSquared(current_mob->GetPosition(), attacker->GetPosition()) <= distance_squared)
) {
if (!attacker->IsClient() || attacker->GetClass() == MONK || attacker->GetClass() == RANGER) {
attacker->Attack(current_mob, Hand, false, false, is_from_spell);
}
else {
attacker->CastToClient()->DoAttackRounds(current_mob, Hand, is_from_spell);
for (int i = 0; i < attack_rounds; i++) {
if (!attacker->IsClient() || attacker->GetClass() == MONK || attacker->GetClass() == RANGER) {
attacker->Attack(current_mob, Hand, false, false, is_from_spell);
}
else {
attacker->CastToClient()->DoAttackRounds(current_mob, Hand, is_from_spell);
}
}
hit_count++;