From 5344679c7c5009d42bf675c36fffe9a6cf1a37c4 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 13 Feb 2014 07:41:57 -0500 Subject: [PATCH 01/28] Fixes for numhits system Implementation of new spell table fields Update and further implemention of CastRestriction --- changelog.txt | 9 + common/shareddb.cpp | 4 + common/spdat.cpp | 3 + common/spdat.h | 21 +- .../required/2014_02_13_spells_new_update.sql | 13 + zone/attack.cpp | 59 +-- zone/bonuses.cpp | 20 +- zone/bot.cpp | 20 +- zone/mob.cpp | 31 +- zone/mob.h | 2 + zone/special_attacks.cpp | 8 + zone/spell_effects.cpp | 432 ++++++++++++------ zone/spells.cpp | 18 +- 13 files changed, 450 insertions(+), 190 deletions(-) create mode 100644 utils/sql/git/required/2014_02_13_spells_new_update.sql diff --git a/changelog.txt b/changelog.txt index 7c37ff145..5c631c22b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,14 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/13/2014 == +Kayen: Fixes for buffs not fading under certain conditions in revised numhits system, and other fixes. +Kayen: Implemented support for spell_new field CastRestrictions (limits what type of targets spells can effect). +*A detailed list describing what the values used in this field do can be found in Mob::PassCastRestriction* +Kayen: Implemented support for spell_new field not_reflectable, no_partial_resists. + +Required SQL: utils/sql/git/2014_02_13_spells_new_updates.sql +Names many unknown fields in the table. + == 02/10/2014 == demonstar55 (Secrets): Re-wrote the entity list to be a std::map. This should be used for direct entityID lookups and is noticably faster performance-wise. Also should result in less nil pointers potentially. Secrets: Fixed a crash issue that could occur on #repop related to quest timers. diff --git a/common/shareddb.cpp b/common/shareddb.cpp index ce0c5602f..4222852ad 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1704,11 +1704,13 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) { sp[tempid].ResistDiff=atoi(row[147]); sp[tempid].dot_stacking_exempt=atoi(row[148]); sp[tempid].RecourseLink = atoi(row[150]); + sp[tempid].no_partial_resist = atoi(row[161]) != 0; sp[tempid].short_buff_box = atoi(row[154]); sp[tempid].descnum = atoi(row[155]); sp[tempid].effectdescnum = atoi(row[157]); + sp[tempid].not_reflectable = atoi(row[161]) != 0; sp[tempid].bonushate=atoi(row[162]); sp[tempid].EndurCost=atoi(row[166]); @@ -1736,6 +1738,8 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) { sp[tempid].powerful_flag=atoi(row[209]); sp[tempid].CastRestriction = atoi(row[211]); sp[tempid].AllowRest = atoi(row[212]) != 0; + sp[tempid].NotOutofCombat = atoi(row[213]) != 0; + sp[tempid].NotInCombat = atoi(row[214]) != 0; sp[tempid].persistdeath = atoi(row[224]) != 0; sp[tempid].DamageShieldType = 0; } diff --git a/common/spdat.cpp b/common/spdat.cpp index a5215cb2e..e8605b6e9 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -387,6 +387,9 @@ bool IsAERainNukeSpell(uint16 spell_id) bool IsPartialCapableSpell(uint16 spell_id) { + if (spells[spell_id].no_partial_resist) + return false; + if (IsPureNukeSpell(spell_id) || IsFearSpell(spell_id) || IsEffectInSpell(spell_id, SE_Root) || IsEffectInSpell(spell_id, SE_Charm)) diff --git a/common/spdat.h b/common/spdat.h index 35f928789..368c4018b 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -680,15 +680,18 @@ struct SPDat_Spell_Struct /* 148 */ int8 dot_stacking_exempt; // If 1 doesn't stack with self cast by others. If -1 (not implemented) doesn't stack with same effect (???) /* 149 */ //int deletable; /* 150 */ uint16 RecourseLink; -/* 151 */ // 151: -1, 0, or 1 +/* 151 */ bool no_partial_resist; // 151: -1, 0, or 1 // 152 & 153: all set to 0 /* 154 */ int8 short_buff_box; // != 0, goes to short buff box. /* 155 */ int descnum; // eqstr of description of spell /* 156 */ //int typedescnum; // eqstr of type description /* 157 */ int effectdescnum; // eqstr of effect description -/* 158 */ +/* 158 */ //Category Desc ID 3 +/* 159 */ //bool npc_no_los; +/* 161 */ bool not_reflectable; /* 162 */ int bonushate; /* 163 */ +/* 164 */ // for most spells this appears to mimic ResistDiff /* 166 */ int EndurCost; /* 167 */ int8 EndurTimerIndex; /* 168 */ //int IsDisciplineBuff; //Will goto the combat window when cast @@ -709,8 +712,8 @@ struct SPDat_Spell_Struct /* 191 */ uint8 viral_targets; /* 192 */ uint8 viral_timer; /* 193 */ int NimbusEffect; -/* 194 */ float directional_start; -/* 195 */ float directional_end; +/* 194 */ float directional_start; //Cone Start Angle: +/* 195 */ float directional_end; // Cone End Angle: /* 196 */ /* 197 */ bool not_extendable; /* 198- 199 */ @@ -719,12 +722,14 @@ struct SPDat_Spell_Struct /* 203 */ //int songcap; // individual song cap (how live currently does it, not implemented) /* 204 - 206 */ /* 207 */ int spellgroup; -/* 208 */ -/* 209 */ int powerful_flag; // Need more investigation to figure out what to call this, for now we know -1 makes charm spells not break before their duration is complete, it does alot more though -/* 210 */ +/* 208 */ // int rank - increments AA effects with same name +/* 209 */ int powerful_flag; // Need more investigation to figure out what to call this, for now we know -1 makes charm spells not break before their duration is complete, it does alot more though +/* 210 */ // bool DurationFrozen; ??? /* 211 */ int CastRestriction; //Various restriction categories for spells most seem targetable race related but have also seen others for instance only castable if target hp 20% or lower or only if target out of combat /* 212 */ bool AllowRest; -/* 213 - 218 */ +/* 213 */ bool NotOutofCombat; //Fail if cast out of combat +/* 214 */ bool NotInCombat; //Fail if cast in combat +/* 215 - 218 */ /* 219 */ //int maxtargets; // is used for beam and ring spells for target # limits (not implemented) /* 220 - 223 */ /* 224 */ bool persistdeath; // buff doesn't get stripped on death diff --git a/utils/sql/git/required/2014_02_13_spells_new_update.sql b/utils/sql/git/required/2014_02_13_spells_new_update.sql new file mode 100644 index 000000000..c843d40aa --- /dev/null +++ b/utils/sql/git/required/2014_02_13_spells_new_update.sql @@ -0,0 +1,13 @@ +ALTER TABLE `spells_new` CHANGE `field161` `not_reflectable` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field151` `no_partial_resist` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field189` `MinResist` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field190` `MaxResist` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field194` `ConeStartAngle` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field195` `ConeStopAngle` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field208` `rank` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field159` `npc_no_los` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field213` `NotOutofCombat` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field214` `NotInCombat` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field168` `IsDiscipline` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field211` `CastRestriction` INT(11) NOT NULL DEFAULT '0'; + diff --git a/zone/attack.cpp b/zone/attack.cpp index d9fea1ff9..18571a08f 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -199,11 +199,6 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c if(IsClient() && other->IsClient()) pvpmode = true; - CheckNumHitsRemaining(1); - - if (attacker) - attacker->CheckNumHitsRemaining(2); - if (chance_mod >= 10000) return true; @@ -1318,19 +1313,10 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b if (IsDead()) return false; - if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap)) - { - int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap; - if(lifetap_amt > 100) - lifetap_amt = 100; - - lifetap_amt = damage * lifetap_amt / 100; - - mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage); - //heal self for damage done.. - HealDamage(lifetap_amt); - - } + MeleeLifeTap(damage); + + if (damage > 0) + CheckNumHitsRemaining(5); //break invis when you attack if(invisible) { @@ -1938,6 +1924,11 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool if (HasDied()) //killed by damage shield ect return false; + MeleeLifeTap(damage); + + if (damage > 0) + CheckNumHitsRemaining(5); + //break invis when you attack if(invisible) { mlog(COMBAT__ATTACKS, "Removing invisibility due to melee attack."); @@ -3434,7 +3425,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons mlog(COMBAT__DAMAGE, "Avoiding %d damage due to invulnerability.", damage); damage = -5; } - + if( spell_id != SPELL_UNKNOWN || attacker == nullptr ) avoidable = false; @@ -3444,6 +3435,13 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons DamageShield(attacker); } + if (spell_id == SPELL_UNKNOWN && skill_used) { + CheckNumHitsRemaining(1); //Incoming Hit Attempts + + if (attacker) + attacker->CheckNumHitsRemaining(2); //Outgoing Hit Attempts + } + if(attacker){ if(attacker->IsClient()){ if(!RuleB(Combat, EXPFromDmgShield)) { @@ -3514,16 +3512,20 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons } - ReduceAllDamage(damage); + if (skill_used) + CheckNumHitsRemaining(6); //Incomming Hit Success on Defender - if(IsClient() && CastToClient()->sneaking){ - CastToClient()->sneaking = false; - SendAppearancePacket(AT_Sneak, 0); - } - if(attacker && attacker->IsClient() && attacker->CastToClient()->sneaking){ - attacker->CastToClient()->sneaking = false; - attacker->SendAppearancePacket(AT_Sneak, 0); - } + ReduceAllDamage(damage); + + if(IsClient() && CastToClient()->sneaking){ + CastToClient()->sneaking = false; + SendAppearancePacket(AT_Sneak, 0); + } + if(attacker && attacker->IsClient() && attacker->CastToClient()->sneaking){ + attacker->CastToClient()->sneaking = false; + attacker->SendAppearancePacket(AT_Sneak, 0); + } + //final damage has been determined. SetHP(GetHP() - damage); @@ -3770,6 +3772,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons } } } //end packet sending + } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 37af3021d..fbd4020eb 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1216,6 +1216,18 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) case SE_HealRate: newbon->HealRate += base1; break; + + case SE_MeleeLifetap: + { + + if((base1 < 0) && (newbon->MeleeLifetap > base1)) + newbon->MeleeLifetap = base1; + + else if(newbon->MeleeLifetap < base1) + newbon->MeleeLifetap = base1; + break; + } + } } } @@ -1230,8 +1242,12 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon) uint32 buff_count = GetMaxTotalSlots(); for(i = 0; i < buff_count; i++) { - if(buffs[i].spellid != SPELL_UNKNOWN) + if(buffs[i].spellid != SPELL_UNKNOWN){ ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false, buffs[i].ticsremaining,i); + + if (buffs[i].numhits > 0) + Numhits(true); + } } //Removes the spell bonuses that are effected by a 'negate' debuff. @@ -1750,7 +1766,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne else if((effect_value < 0) && (newbon->MeleeLifetap > effect_value)) newbon->MeleeLifetap = spells[spell_id].base[i]; - if(newbon->MeleeLifetap < spells[spell_id].base[i]) + else if(newbon->MeleeLifetap < spells[spell_id].base[i]) newbon->MeleeLifetap = spells[spell_id].base[i]; break; } diff --git a/zone/bot.cpp b/zone/bot.cpp index edc918609..a1d806502 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -3377,6 +3377,9 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes if (HasDied()) return; + if (damage > 0) + CheckNumHitsRemaining(5); + if((skillinuse == SkillDragonPunch) && GetAA(aaDragonPunch) && MakeRandomInt(0, 99) < 25){ SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff); other->Stun(100); @@ -6593,18 +6596,10 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b if (GetHP() < 0) return false; - if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap)) - { - int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap; - if(lifetap_amt > 100) - lifetap_amt = 100; + MeleeLifeTap(damage); - lifetap_amt = damage * lifetap_amt / 100; - - mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage); - //heal self for damage done.. - HealDamage(lifetap_amt); - } + if (damage > 0) + CheckNumHitsRemaining(5); //break invis when you attack if(invisible) { @@ -8083,6 +8078,9 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, if(!GetTarget())return; if (HasDied()) return; + if (max_damage > 0) + CheckNumHitsRemaining(5); + //[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){ int kb_chance = 25; diff --git a/zone/mob.cpp b/zone/mob.cpp index 6f41e698f..75b4867a4 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3412,8 +3412,6 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used) if(skilldmg_mod < -100) skilldmg_mod = -100; - CheckNumHitsRemaining(6); - return skilldmg_mod; } @@ -4315,16 +4313,37 @@ int16 Mob::GetSkillDmgAmt(uint16 skill) skill_dmg += spellbonuses.SkillDamageAmount2[HIGHEST_SKILL+1] + itembonuses.SkillDamageAmount2[HIGHEST_SKILL+1] + itembonuses.SkillDamageAmount2[skill] + spellbonuses.SkillDamageAmount2[skill]; - CheckNumHitsRemaining(5); - return skill_dmg; } +void Mob::MeleeLifeTap(int32 damage) { + + if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap || aabonuses.MeleeLifetap )) + { + int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap + aabonuses.MeleeLifetap; + + if(lifetap_amt > 100) + lifetap_amt = 100; + + else if (lifetap_amt < -99) + lifetap_amt = -99; + + + lifetap_amt = damage * lifetap_amt / 100; + + mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage); + //heal self for damage done.. + HealDamage(lifetap_amt); + } +} + bool Mob::TryReflectSpell(uint32 spell_id) { - if(!GetTarget()) - return false; + if (spells[spell_id].not_reflectable) + return false; + int chance = itembonuses.reflect_chance + spellbonuses.reflect_chance + aabonuses.reflect_chance; + if(MakeRandomInt(0, 99) < (GetTarget()->itembonuses.reflect_chance + GetTarget()->spellbonuses.reflect_chance)) return true; diff --git a/zone/mob.h b/zone/mob.h index 9fb518f65..a5d594123 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -587,6 +587,8 @@ public: int32 ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard = false); int8 GetDecayEffectValue(uint16 spell_id, uint16 spelleffect); int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg); + void MeleeLifeTap(int32 damage); + bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true); void ModSkillDmgTaken(SkillUseTypes skill_num, int value); int16 GetModSkillDmgTaken(const SkillUseTypes skill_num); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 5da329e54..473af0392 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -155,6 +155,9 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, if(!GetTarget())return; if (HasDied()) return; + if (max_damage > 0) + CheckNumHitsRemaining(5); + //[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){ int kb_chance = 25; @@ -948,6 +951,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item TryCriticalHit(other, SkillArchery, TotalDmg); other->AddToHateList(this, hate, 0, false); + CheckNumHitsRemaining(5); } } else @@ -1052,6 +1056,7 @@ void NPC::RangedAttack(Mob* other) TryCriticalHit(GetTarget(), SkillArchery, TotalDmg); GetTarget()->AddToHateList(this, hate, 0, false); GetTarget()->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery); + CheckNumHitsRemaining(5); } else { @@ -1270,6 +1275,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite TryCriticalHit(other, SkillThrowing, TotalDmg); int32 hate = (2*WDmg); other->AddToHateList(this, hate, 0, false); + CheckNumHitsRemaining(5); } } @@ -2181,6 +2187,8 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes if (HasDied()) return; + CheckNumHitsRemaining(5); + if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skillinuse){ int kb_chance = 25; kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 0c4d30ad0..49f0f2a1c 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -183,7 +183,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) numhit += caster->CastToClient()->GetFocusEffect(focusIncreaseNumHits, spell_id); } - Numhits(true); buffs[buffslot].numhits = numhit; } @@ -218,83 +217,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) int32 dmg = effect_value; if(dmg < 0) { - - /*Special Cases where Base2 is defined - Range 105 : Plant - Range 120 : Undead - Range 123 : Humanoid - Range 190 : No Raid boss flag *not implemented - Range 191 : This spell will deal less damage to 'exceptionally strong targets' - Raid boss flag *not implemented - Range 201 : Damage if HP > 75% - Range 221 - 299 : Causing damage dependent on how many pets/swarmpets are attacking your target. - Range 300 - 303 : UNKOWN *not implemented - Range 399 - 499 : Heal if HP within a specified range (400 = 0-25% 401 = 25 - 35% 402 = 35-45% ect) - Range 500 - 599 : Heal if HP less than a specified value - Range 600 - 699 : Limit to Body Type [base2 - 600 = Body] - Range 818 - 819 : If Undead/If Not Undead - Range 835 - : Unknown *not implemented - Range 836 - 837 : Progression Server / Live Server *not implemented - Range 839 - : Unknown *not implemented - Range 10000+ : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement) - - */ - - if (spells[spell_id].base2[i] > 0){ - - //It is unlikely these effects would give a fail message (Need to confirm) - if (spells[spell_id].base2[i] == 105){ - if (GetBodyType() != BT_Plant) - break; - } - - else if (spells[spell_id].base2[i] == 120){ - if (GetBodyType() != BT_Undead) - break; - } - - else if (spells[spell_id].base2[i] == 123){ - if (GetBodyType() != BT_Humanoid) - break; - } - - //Limit to Body Type. - else if (spells[spell_id].base2[i] >= 600 && spells[spell_id].base2[i] <= 699){ - if (GetBodyType() != (spells[spell_id].base2[i] - 600)){ - //caster->Message_StringID(13,CANNOT_AFFECT_NPC); - break; - } - } - - else if (spells[spell_id].base2[i] == 201){ - if (GetHPRatio() < 75) - break; - } - - //Limit to Race. *Not implemented on live - else if (spells[spell_id].base2[i] >= 10000 && spells[spell_id].base2[i] <= 11000){ - if (GetRace() != (spells[spell_id].base2[i] - 10000)){ - break; - } - } - - //Limit to amount of pets - else if (spells[spell_id].base2[i] >= 221 && spells[spell_id].base2[i] <= 299){ - bool allow_spell = false; - int count = hate_list.SummonedPetCount(this); - - for (int base2_value = 221; base2_value <= 233; ++base2_value){ - if (spells[spell_id].base2[i] == base2_value){ - if (count >= (base2_value - 220)){ - allow_spell = true; - break; - } - } - } - - if (!allow_spell) - break; - } - } + if (!PassCastRestriction(false, spells[spell_id].base2[i], true)) + break; // take partial damage into account dmg = (int32) (dmg * partial / 100); @@ -308,60 +232,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) } else if(dmg > 0) { //healing spell... - - if (spells[spell_id].base2[i] > 0) - { - bool allow_spell = false; - - //Heal only if HP within specified range. [Doesn't follow a set forumla for all values...] - if (spells[spell_id].base2[i] >= 400 && spells[spell_id].base2[i] <= 408){ - for (int base2_value = 400; base2_value <= 408; ++base2_value){ - if (spells[spell_id].base2[i] == base2_value){ - - if (spells[spell_id].base2[i] == 400){ - if (GetHPRatio() <= 25){ - allow_spell = true; - break; - } - } - - else if (spells[spell_id].base2[i] == base2_value){ - if (GetHPRatio() > 25+((base2_value - 401)*10) && GetHPRatio() <= 35+((base2_value - 401)*10)){ - allow_spell = true; - break; - } - } - } - } - } - - else if (spells[spell_id].base2[i] >= 500 && spells[spell_id].base2[i] <= 520){ - for (int base2_value = 500; base2_value <= 520; ++base2_value){ - if (spells[spell_id].base2[i] == base2_value){ - - if (spells[spell_id].base2[i] == base2_value){ - if (GetHPRatio() < (base2_value - 500)*5) { - allow_spell = true; - break; - } - } - } - } - } + if (!PassCastRestriction(false, spells[spell_id].base2[i], false)) + break; - else if (spells[spell_id].base2[i] == 399){ - if (GetHPRatio() > 15 && GetHPRatio() <= 25){ - allow_spell = true; - break; - } - } - - if(!allow_spell) - break; - } - - if(caster) dmg = caster->GetActSpellHealing(spell_id, dmg, this); @@ -5704,3 +5578,301 @@ bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){ return false; } +bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDamage) +{ + /*If return TRUE spell met all restrictions and can continue (this = target). + This check is used when the spell_new field CastRestriction is defined OR spell effect '0'(DD/Heal) has a defined limit + Range 1 : UNKNOWN + Range 100 : *Animal OR Humanoid + Range 101 : *Dragon + Range 102 : *Animal OR Insect + Range 103 : NOT USED + Range 104 : *Animal + Range 105 : Plant + Range 106 : *Giant + Range 107 : NOT USED + Range 108 : NOT Animal or Humaniod + Range 109 : *Bixie + Range 111 : *Harpy + Range 112 : *Sporali + Range 113 : *Kobold + Range 114 : *Shade Giant + Range 115 : *Drakkin + Range 116 : NOT USED + Range 117 : *Animal OR Plant + Range 118 : *Summoned + Range 119 : *Firepet + Range 120 : Undead + Range 121 : *Living (NOT Undead) + Range 122 : *Fairy + Range 123 : Humanoid + Range 124 : *Undead HP < 10% + Range 125 : *Clockwork HP < 10% + Range 126 : *Wisp HP < 10% + Range 127-130 : UNKNOWN + Range 150 : UNKNOWN + Range 190 : No Raid boss flag *not implemented + Range 191 : This spell will deal less damage to 'exceptionally strong targets' - Raid boss flag *not implemented + Range 201 : Damage if HP > 75% + Range 203 : Damage if HP < 20% + Range 216 : TARGET NOT IN COMBAT + Range 221 - 249 : Causing damage dependent on how many pets/swarmpets are attacking your target. + Range 250 : Damage if HP < 35% + Range 300 - 303 : UNKOWN *not implemented + Range 304 : Chain + Plate class (buffs) + Range 399 - 409 : Heal if HP within a specified range (400 = 0-25% 401 = 25 - 35% 402 = 35-45% ect) + Range 410 - 411 : UNKOWN + Range 500 - 599 : Heal if HP less than a specified value + Range 600 - 699 : Limit to Body Type [base2 - 600 = Body] + Range 700 : UNKNOWN + Range 701 : NOT PET + Range 800 : UKNOWN + Range 818 - 819 : If Undead/If Not Undead + Range 820 - 822 : UKNOWN + Range 835 : Unknown *not implemented + Range 836 - 837 : Progression Server / Live Server *not implemented + Range 839 : Unknown *not implemented + Range 842 - 844 : Humaniod lv MAX ((842 - 800) * 2) + Range 845 - 847 : UNKNOWN + Range 10000+ : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement) + THIS IS A WORK IN PROGRESS + */ + + if (value <= 0) + return true; + + if (IsDamage || UseCastRestriction) { + + switch(value) + { + case 100: + if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Humanoid)) + return true; + break; + + case 101: + if (GetBodyType() == BT_Dragon) + return true; + break; + + case 102: + if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Insect)) + return true; + break; + + case 104: + if (GetBodyType() == BT_Animal) + return true; + break; + + case 105: + if (GetBodyType() == BT_Plant) + return true; + break; + + case 106: + if (GetBodyType() == BT_Giant) + return true; + break; + + case 108: + if ((GetBodyType() != BT_Animal) || (GetBodyType() != BT_Humanoid)) + return true; + break; + + case 109: + if ((GetRace() == 520) ||(GetRace() == 79)) + return true; + break; + + case 111: + if ((GetRace() == 527) ||(GetRace() == 11)) + return true; + break; + + case 112: + if ((GetRace() == 456) ||(GetRace() == 28)) + return true; + break; + + case 113: + if ((GetRace() == 456) ||(GetRace() == 48)) + return true; + break; + + case 114: + if (GetRace() == 526) + return true; + break; + + case 115: + if (GetRace() == 522) + return true; + break; + + case 117: + if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Plant)) + return true; + break; + + case 118: + if (GetBodyType() == BT_Summoned) + return true; + break; + + case 119: + if (IsPet() && ((GetRace() == 212) || ((GetRace() == 75) && GetTexture() == 1))) + return true; + break; + + case 120: + if (GetBodyType() == BT_Undead) + return true; + break; + + case 121: + if (GetBodyType() != BT_Undead) + return true; + break; + + case 122: + if ((GetRace() == 473) || (GetRace() == 425)) + return true; + break; + + case 123: + if (GetBodyType() == BT_Humanoid) + return true; + break; + + case 124: + if ((GetBodyType() == BT_Undead) && (GetHPRatio() < 10)) + return true; + break; + + case 125: + if ((GetRace() == 457 || GetRace() == 88) && (GetHPRatio() < 10)) + return true; + break; + + case 126: + if ((GetRace() == 581 || GetRace() == 69) && (GetHPRatio() < 10)) + return true; + break; + + case 201: + if (GetHPRatio() > 75) + return true; + break; + + case 204: + if (GetHPRatio() < 20) + return true; + break; + + case 216: + if (!IsEngaged()) + return true; + break; + + case 250: + if (GetHPRatio() < 35) + return true; + break; + + case 304: + if (IsClient() && + ((GetClass() == WARRIOR) || (GetClass() == BARD) || (GetClass() == SHADOWKNIGHT) || (GetClass() == PALADIN) || (GetClass() == CLERIC) + || (GetClass() == RANGER) || (GetClass() == SHAMAN) || (GetClass() == ROGUE) || (GetClass() == BERSERKER))) + return true; + break; + + case 818: + if (GetBodyType() == BT_Undead) + return true; + break; + + case 819: + if (GetBodyType() != BT_Undead) + return true; + break; + + case 842: + if (GetBodyType() == BT_Humanoid && GetLevel() <= 84) + return true; + break; + + case 843: + if (GetBodyType() == BT_Humanoid && GetLevel() <= 86) + return true; + break; + + case 844: + if (GetBodyType() == BT_Humanoid && GetLevel() <= 88) + return true; + break; + } + + //Limit to amount of pets + if (value >= 221 && value <= 249){ + int count = hate_list.SummonedPetCount(this); + + for (int base2_value = 221; base2_value <= 249; ++base2_value){ + if (value == base2_value){ + if (count >= (base2_value - 220)){ + return true; + } + } + } + } + + //Limit to Body Type + if (value >= 600 && value <= 699){ + if (GetBodyType() == (value - 600)) + return true; + } + + //Limit to Race. *Not implemented on live + if (value >= 10000 && value <= 11000){ + if (GetRace() == (value - 10000)) + return true; + } + } //End Damage + + if (!IsDamage || UseCastRestriction) { + + //Heal only if HP within specified range. [Doesn't follow a set forumla for all values...] + if (value >= 400 && value <= 408){ + for (int base2_value = 400; base2_value <= 408; ++base2_value){ + if (value == base2_value){ + + if (value == 400 && GetHPRatio() <= 25) + return true; + + else if (value == base2_value){ + if (GetHPRatio() > 25+((base2_value - 401)*10) && GetHPRatio() <= 35+((base2_value - 401)*10)) + return true; + } + } + } + } + + else if (value >= 500 && value <= 549){ + for (int base2_value = 500; base2_value <= 520; ++base2_value){ + if (value == base2_value){ + if (GetHPRatio() < (base2_value - 500)*5) + return true; + } + } + } + + else if (value == 399) { + if (GetHPRatio() > 15 && GetHPRatio() <= 25) + return true; + } + } // End Heal + + + return false; +} + diff --git a/zone/spells.cpp b/zone/spells.cpp index d3b24cd78..ca3fef4fa 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1361,6 +1361,11 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce mlog(AA__MESSAGE, "Project Illusion overwrote target caster: %s spell id: %d was ON", GetName(), spell_id); targetType = ST_GroupClientAndPet; } + + if (spell_target && !spell_target->PassCastRestriction(true, spells[spell_id].CastRestriction)){ + Message_StringID(13,SPELL_NEED_TAR); + return false; + } switch (targetType) { @@ -3355,7 +3360,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } } // Reflect - if(TryReflectSpell(spell_id) && spelltar && !reflect && IsDetrimentalSpell(spell_id) && this != spelltar) { + if(spelltar && spelltar->TryReflectSpell(spell_id) && !reflect && IsDetrimentalSpell(spell_id) && this != spelltar) { int reflect_chance = 0; switch(RuleI(Spells, ReflectType)) { @@ -3402,9 +3407,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } } - if (spelltar && IsDetrimentalSpell(spell_id)) - spelltar->CheckNumHitsRemaining(3); - // resist check - every spell can be resisted, beneficial or not // add: ok this isn't true, eqlive's spell data is fucked up, buffs are // not all unresistable, so changing this to only check certain spells @@ -3438,6 +3440,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } } + spelltar->CheckNumHitsRemaining(3); + safe_delete(action_packet); return false; } @@ -3575,7 +3579,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r safe_delete(action_packet); return false; } - + // cause the effects to the target if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness)) { @@ -3588,6 +3592,10 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r return false; } + + if (spelltar && IsDetrimentalSpell(spell_id)) + spelltar->CheckNumHitsRemaining(3); //Incoming spells + // send the action packet again now that the spell is successful // NOTE: this is what causes the buff icon to appear on the client, if // this is a buff - but it sortof relies on the first packet. From a3f9d5e7078aa96b6a632de94b2d98174b58a6af Mon Sep 17 00:00:00 2001 From: SecretsOTheP Date: Thu, 13 Feb 2014 12:02:26 -0500 Subject: [PATCH 02/28] bot.cpp was missing nullptr instead of NULL, that is now fixed. hate_list.cpp potential crash fix related to center being nullptr --- zone/bot.cpp | 2 +- zone/hate_list.cpp | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index a1241626f..8a58fc42a 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -16351,7 +16351,7 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) { std::string WindowText; int LastCon = -1; int CurrentCon = 0; - Mob* curMob = NULL; + Mob* curMob = nullptr; uint32 array_counter = 0; diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index 49058fc5e..7f986949b 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -268,6 +268,9 @@ Mob *HateList::GetTop(Mob *center) Mob* top = nullptr; int32 hate = -1; + if(center == nullptr) + return nullptr; + if (RuleB(Aggro,SmartAggroList)){ Mob* topClientTypeInRange = nullptr; int32 hateClientTypeInRange = -1; @@ -380,15 +383,15 @@ Mob *HateList::GetTop(Mob *center) } if(!isTopClientType) - return topClientTypeInRange; + return topClientTypeInRange ? topClientTypeInRange : nullptr; - return top; + return top ? top : nullptr; } else { if(top == nullptr && skipped_count > 0) { - return center->GetTarget(); + return center->GetTarget() ? center->GetTarget() : nullptr; } - return top; + return top ? top : nullptr; } } else{ @@ -413,10 +416,11 @@ Mob *HateList::GetTop(Mob *center) ++iterator; } if(top == nullptr && skipped_count > 0) { - return center->GetTarget(); + return center->GetTarget() ? center->GetTarget() : nullptr; } - return top; + return top ? top : nullptr; } + return nullptr; } Mob *HateList::GetMostHate(){ From 9d938cdd583dc8942b2bf26dba97295bf874b70a Mon Sep 17 00:00:00 2001 From: sorvani Date: Thu, 13 Feb 2014 11:24:54 -0600 Subject: [PATCH 03/28] Cleaned up GetUnusedInstanceID logic and renamed instance_lockout* tables to instance_list* --- changelog.txt | 5 + common/database.cpp | 109 ++++++------------ ...4_02_13_Rename_instance_lockout_tables.sql | 3 + zone/zonedb.cpp | 6 +- 4 files changed, 46 insertions(+), 77 deletions(-) create mode 100644 utils/sql/git/required/2014_02_13_Rename_instance_lockout_tables.sql diff --git a/changelog.txt b/changelog.txt index 7c37ff145..83b5fbbaa 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,10 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/13/2014 == +Sorvani: Renamed the instance_lockout and instance_lockout_player tables to instance_list and instance_list_player. Cleaned up the Database::GetUnusedInstanceID logic. + +Required SQL: utils/sql/git/2014_02_13_Rename_instance_lockout_tables.sql + == 02/10/2014 == demonstar55 (Secrets): Re-wrote the entity list to be a std::map. This should be used for direct entityID lookups and is noticably faster performance-wise. Also should result in less nil pointers potentially. Secrets: Fixed a crash issue that could occur on #repop related to quest timers. diff --git a/common/database.cpp b/common/database.cpp index ace5bf4ea..d0e2f3c59 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -668,7 +668,7 @@ bool Database::DeleteCharacter(char *name) #if DEBUG >= 5 printf(" instances"); #endif - RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE charid='%d'", charid), errbuf, nullptr, &affected_rows); + RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_list_player WHERE charid='%d'", charid), errbuf, nullptr, &affected_rows); if(query) { safe_delete_array(query); @@ -2278,7 +2278,7 @@ bool Database::VerifyZoneInstance(uint32 zone_id, uint16 instance_id) char *query = 0; MYSQL_RES *result; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where id=%u AND zone=%u", + if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_list where id=%u AND zone=%u", instance_id, zone_id), errbuf, &result)) { safe_delete_array(query); @@ -2308,7 +2308,7 @@ bool Database::CharacterInInstanceGroup(uint16 instance_id, uint32 char_id) MYSQL_RES *result; bool lockout_instance_player = false; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_lockout_player where id=%u AND charid=%u", + if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_list_player where id=%u AND charid=%u", instance_id, char_id), errbuf, &result)) { safe_delete_array(query); @@ -2330,10 +2330,10 @@ void Database::DeleteInstance(uint16 instance_id) char errbuf[MYSQL_ERRMSG_SIZE]; char *query = 0; - RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout WHERE id=%u", instance_id), errbuf); + RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_list WHERE id=%u", instance_id), errbuf); safe_delete_array(query); - RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%u", instance_id), errbuf); + RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_list_player WHERE id=%u", instance_id), errbuf); safe_delete_array(query); RunQuery(query, MakeAnyLenString(&query, "DELETE FROM respawn_times WHERE instance_id=%u", instance_id), errbuf); @@ -2354,7 +2354,7 @@ bool Database::CheckInstanceExpired(uint16 instance_id) int32 start_time = 0; int32 duration = 0; uint32 never_expires = 0; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration, never_expires FROM instance_lockout WHERE id=%u", + if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", instance_id), errbuf, &result)) { safe_delete_array(query); @@ -2400,7 +2400,7 @@ uint32 Database::ZoneIDFromInstanceID(uint16 instance_id) MYSQL_ROW row; uint32 ret; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT zone FROM instance_lockout where id=%u", instance_id), + if (RunQuery(query, MakeAnyLenString(&query, "SELECT zone FROM instance_list where id=%u", instance_id), errbuf, &result)) { safe_delete_array(query); @@ -2433,7 +2433,7 @@ uint32 Database::VersionFromInstanceID(uint16 instance_id) MYSQL_ROW row; uint32 ret; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_lockout where id=%u", instance_id), + if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_list where id=%u", instance_id), errbuf, &result)) { safe_delete_array(query); @@ -2468,7 +2468,7 @@ uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma) uint32 duration = 0; uint32 never_expires = 0; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration, never_expires FROM instance_lockout WHERE id=%u", + if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u", instance_id), errbuf, &result)) { safe_delete_array(query); @@ -2516,68 +2516,29 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id) MYSQL_RES *result; MYSQL_ROW row; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT COUNT(*) FROM instance_lockout"), errbuf, &result)) - { - safe_delete_array(query); - if (mysql_num_rows(result) != 0) - { - row = mysql_fetch_row(result); - int count = atoi(row[0]); - if(count == 0) - { - mysql_free_result(result); - instance_id = RuleI(Zone, ReservedInstances) + 1; - return true; - } - } - else - { - mysql_free_result(result); - } - mysql_free_result(result); - } - else - { - safe_delete_array(query); - instance_id = 0; - return false; - } + uint32 count = RuleI(Zone, ReservedInstances) + 1; + uint32 max = 65535; - int32 count = RuleI(Zone, ReservedInstances) + 1; - int32 max = 65535; - - if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where id >= %i ORDER BY id", count), errbuf, &result)) - { + if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_list where id >= %i ORDER BY id", count), errbuf, &result)) { safe_delete_array(query); - if (mysql_num_rows(result) != 0) - { - while((row = mysql_fetch_row(result))) - { - if(count < atoi(row[0])) - { + if (mysql_num_rows(result) != 0) { + while((row = mysql_fetch_row(result))) { + if(count < atoi(row[0])) { instance_id = count; mysql_free_result(result); return true; - } - else if(count > max) - { + } else if(count > max) { instance_id = 0; mysql_free_result(result); return false; - } - else - { + } else { count++; } } - } - else - { + } else { mysql_free_result(result); } - } - else - { + } else { safe_delete_array(query); } instance_id = count; @@ -2590,7 +2551,7 @@ bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version char errbuf[MYSQL_ERRMSG_SIZE]; char *query = 0; - if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_lockout (id, zone, version, start_time, duration)" + if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_list (id, zone, version, start_time, duration)" " values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)", (unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration), errbuf)) { safe_delete_array(query); @@ -2611,7 +2572,7 @@ void Database::PurgeExpiredInstances() MYSQL_ROW row; uint16 id = 0; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where " + if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_list where " "(start_time+duration) <= UNIX_TIMESTAMP() and never_expires = 0"), errbuf, &result)) { safe_delete_array(query); @@ -2638,7 +2599,7 @@ bool Database::AddClientToInstance(uint16 instance_id, uint32 char_id) char errbuf[MYSQL_ERRMSG_SIZE]; char *query = 0; - if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_lockout_player(id, charid) " + if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_list_player(id, charid) " "values(%lu, %lu)", (unsigned long)instance_id, (unsigned long)char_id), errbuf)) { safe_delete_array(query); @@ -2656,7 +2617,7 @@ bool Database::RemoveClientFromInstance(uint16 instance_id, uint32 char_id) char errbuf[MYSQL_ERRMSG_SIZE]; char *query = 0; - if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%lu AND charid=%lu", + if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_list_player WHERE id=%lu AND charid=%lu", (unsigned long)instance_id, (unsigned long)char_id), errbuf)) { safe_delete_array(query); @@ -2674,7 +2635,7 @@ bool Database::RemoveClientsFromInstance(uint16 instance_id) char errbuf[MYSQL_ERRMSG_SIZE]; char *query = 0; - if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%lu", + if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_list_player WHERE id=%lu", (unsigned long)instance_id), errbuf)) { safe_delete_array(query); @@ -2693,7 +2654,7 @@ bool Database::CheckInstanceExists(uint16 instance_id) char *query = 0; MYSQL_RES *result; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT * FROM instance_lockout where id=%u", instance_id), + if (RunQuery(query, MakeAnyLenString(&query, "SELECT * FROM instance_list where id=%u", instance_id), errbuf, &result)) { safe_delete_array(query); @@ -2738,7 +2699,7 @@ uint16 Database::GetInstanceVersion(uint16 instance_id) MYSQL_ROW row; uint32 ret; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_lockout where id=%u", instance_id), + if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_list where id=%u", instance_id), errbuf, &result)) { safe_delete_array(query); @@ -2771,9 +2732,9 @@ uint16 Database::GetInstanceID(const char* zone, uint32 charid, int16 version) MYSQL_ROW row; uint16 ret; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_lockout.id FROM instance_lockout, instance_lockout_player " - "WHERE instance_lockout.zone=%u AND instance_lockout.version=%u AND instance_lockout.id=instance_lockout_player.id AND " - "instance_lockout_player.charid=%u LIMIT 1;", GetZoneID(zone), version, charid, charid), errbuf, &result)) + if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_list.id FROM instance_list, instance_list_player " + "WHERE instance_list.zone=%u AND instance_list.version=%u AND instance_list.id=instance_list_player.id AND " + "instance_list_player.charid=%u LIMIT 1;", GetZoneID(zone), version, charid, charid), errbuf, &result)) { safe_delete_array(query); if (mysql_num_rows(result) != 0) @@ -2808,9 +2769,9 @@ uint16 Database::GetInstanceID(uint32 zone, uint32 charid, int16 version) MYSQL_ROW row; uint16 ret; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_lockout.id FROM instance_lockout, instance_lockout_player " - "WHERE instance_lockout.zone=%u AND instance_lockout.version=%u AND instance_lockout.id=instance_lockout_player.id AND " - "instance_lockout_player.charid=%u LIMIT 1;", zone, version, charid), errbuf, &result)) + if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_list.id FROM instance_list, instance_list_player " + "WHERE instance_list.zone=%u AND instance_list.version=%u AND instance_list.id=instance_list_player.id AND " + "instance_list_player.charid=%u LIMIT 1;", zone, version, charid), errbuf, &result)) { safe_delete_array(query); if (mysql_num_rows(result) != 0) @@ -2840,7 +2801,7 @@ void Database::GetCharactersInInstance(uint16 instance_id, std::list &ch MYSQL_RES *result; MYSQL_ROW row; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_lockout_player WHERE id=%u", instance_id), errbuf, &result)) { + if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_list_player WHERE id=%u", instance_id), errbuf, &result)) { safe_delete_array(query); while ((row = mysql_fetch_row(result))) { @@ -2950,7 +2911,7 @@ void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration) char errbuf[MYSQL_ERRMSG_SIZE]; char *query = 0; - if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `instance_lockout` SET start_time=UNIX_TIMESTAMP(), " + if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), " "duration=%u WHERE id=%u", new_duration, instance_id), errbuf)) { safe_delete_array(query); @@ -2970,7 +2931,7 @@ bool Database::GlobalInstance(uint16 instance_id) MYSQL_ROW row; bool ret; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT is_global from instance_lockout where id=%u LIMIT 1", instance_id), errbuf, &result)) + if (RunQuery(query, MakeAnyLenString(&query, "SELECT is_global from instance_list where id=%u LIMIT 1", instance_id), errbuf, &result)) { safe_delete_array(query); row = mysql_fetch_row(result); diff --git a/utils/sql/git/required/2014_02_13_Rename_instance_lockout_tables.sql b/utils/sql/git/required/2014_02_13_Rename_instance_lockout_tables.sql new file mode 100644 index 000000000..7f9668715 --- /dev/null +++ b/utils/sql/git/required/2014_02_13_Rename_instance_lockout_tables.sql @@ -0,0 +1,3 @@ +-- rename the instance_lockout tables to instance_list. They have nothing to do with lockouts. +ALTER TABLE `peq`.`instance_lockout` RENAME TO `peq`.`instance_list` ; +ALTER TABLE `peq`.`instance_lockout_player` RENAME TO `peq`.`instance_list_player` ; \ No newline at end of file diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index ea90b9f08..480cd80cb 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -2484,9 +2484,9 @@ void ZoneDatabase::ListAllInstances(Client* c, uint32 charid) MYSQL_ROW row; - if (RunQuery(query,MakeAnyLenString(&query, "SELECT instance_lockout.id, zone, version FROM instance_lockout JOIN" - " instance_lockout_player ON instance_lockout.id = instance_lockout_player.id" - " WHERE instance_lockout_player.charid=%lu", (unsigned long)charid),errbuf,&result)) + if (RunQuery(query,MakeAnyLenString(&query, "SELECT instance_list.id, zone, version FROM instance_list JOIN" + " instance_list_player ON instance_list.id = instance_list_player.id" + " WHERE instance_list_player.charid=%lu", (unsigned long)charid),errbuf,&result)) { safe_delete_array(query); From 5f02de1c951433bca2c89703b514d48dcfa7a653 Mon Sep 17 00:00:00 2001 From: JJ Date: Thu, 13 Feb 2014 21:14:05 -0500 Subject: [PATCH 04/28] Remove db name from sql. --- .../required/2014_02_13_Rename_instance_lockout_tables.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/sql/git/required/2014_02_13_Rename_instance_lockout_tables.sql b/utils/sql/git/required/2014_02_13_Rename_instance_lockout_tables.sql index 7f9668715..fcb083904 100644 --- a/utils/sql/git/required/2014_02_13_Rename_instance_lockout_tables.sql +++ b/utils/sql/git/required/2014_02_13_Rename_instance_lockout_tables.sql @@ -1,3 +1,3 @@ -- rename the instance_lockout tables to instance_list. They have nothing to do with lockouts. -ALTER TABLE `peq`.`instance_lockout` RENAME TO `peq`.`instance_list` ; -ALTER TABLE `peq`.`instance_lockout_player` RENAME TO `peq`.`instance_list_player` ; \ No newline at end of file +ALTER TABLE `instance_lockout` RENAME TO `instance_list` ; +ALTER TABLE `instance_lockout_player` RENAME TO `instance_list_player` ; \ No newline at end of file From 46f87233148e4f023bb0d3a014a720759e30ae4a Mon Sep 17 00:00:00 2001 From: SecretsOTheP Date: Fri, 14 Feb 2014 12:30:50 -0500 Subject: [PATCH 05/28] Fixed an order-of-operations crash within the Quest Parser classes --- zone/QuestParserCollection.cpp | 6 ++++++ zone/QuestParserCollection.h | 3 ++- zone/net.cpp | 4 +++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/zone/QuestParserCollection.cpp b/zone/QuestParserCollection.cpp index 06e191b49..cab48a768 100644 --- a/zone/QuestParserCollection.cpp +++ b/zone/QuestParserCollection.cpp @@ -46,6 +46,12 @@ void QuestParserCollection::RegisterQuestInterface(QuestInterface *qi, std::stri _load_precedence.push_back(qi); } +void QuestParserCollection::ClearInterfaces() { + _interfaces.clear(); + _extensions.clear(); + _load_precedence.clear(); +} + void QuestParserCollection::AddVar(std::string name, std::string val) { std::list::iterator iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { diff --git a/zone/QuestParserCollection.h b/zone/QuestParserCollection.h index e8a930b64..f9da8c79c 100644 --- a/zone/QuestParserCollection.h +++ b/zone/QuestParserCollection.h @@ -39,7 +39,8 @@ public: ~QuestParserCollection(); void RegisterQuestInterface(QuestInterface *qi, std::string ext); - + void UnRegisterQuestInterface(QuestInterface *qi, std::string ext); + void ClearInterfaces(); void AddVar(std::string name, std::string val); void Init(); void ReloadQuests(bool reset_timers = true); diff --git a/zone/net.cpp b/zone/net.cpp index 98ef19362..1d49d17ed 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -476,6 +476,8 @@ int main(int argc, char** argv) { entity_list.Clear(); + parse->ClearInterfaces(); + #ifdef EMBPERL safe_delete(perl_parser); #endif @@ -496,7 +498,7 @@ int main(int argc, char** argv) { dbasync->StopThread(); safe_delete(taskmanager); command_deinit(); - + safe_delete(parse); CheckEQEMuErrorAndPause(); _log(ZONE__INIT, "Proper zone shutdown complete."); return 0; From 49df0a5d33ce82808d7ead890040bfba77521d6d Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 15 Feb 2014 08:16:41 -0500 Subject: [PATCH 06/28] fixes --- common/shareddb.cpp | 2 +- zone/mob.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 4222852ad..aa136c41b 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1704,7 +1704,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) { sp[tempid].ResistDiff=atoi(row[147]); sp[tempid].dot_stacking_exempt=atoi(row[148]); sp[tempid].RecourseLink = atoi(row[150]); - sp[tempid].no_partial_resist = atoi(row[161]) != 0; + sp[tempid].no_partial_resist = atoi(row[151]) != 0; sp[tempid].short_buff_box = atoi(row[154]); sp[tempid].descnum = atoi(row[155]); diff --git a/zone/mob.cpp b/zone/mob.cpp index 75b4867a4..078fed266 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4344,7 +4344,7 @@ bool Mob::TryReflectSpell(uint32 spell_id) int chance = itembonuses.reflect_chance + spellbonuses.reflect_chance + aabonuses.reflect_chance; - if(MakeRandomInt(0, 99) < (GetTarget()->itembonuses.reflect_chance + GetTarget()->spellbonuses.reflect_chance)) + if(chance && MakeRandomInt(0, 99) < chance) return true; return false; From 1b7271359e1866ac987088fa67e98bc702fbd796 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 15 Feb 2014 22:34:48 -0500 Subject: [PATCH 07/28] fix for LimitCombatSkills fix for Extended Inginuity table data --- common/spdat.cpp | 14 ++++++++++++++ common/spdat.h | 1 + .../required/2014_02_13_spells_new_update.sql | 4 ++++ zone/spell_effects.cpp | 19 +++++++++---------- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/common/spdat.cpp b/common/spdat.cpp index e8605b6e9..2cbf8a97d 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -675,6 +675,20 @@ bool IsDiscipline(uint16 spell_id) return false; } +bool IsCombatSkill(uint16 spell_id) +{ + if (!IsValidSpell(spell_id)) + return false; + + //Check if Discipline OR melee proc (from non-castable spell) + if ((spells[spell_id].mana == 0 && + (spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep)) || + ((spells[spell_id].cast_time == 0) && (spells[spell_id].recast_time == 0) && (spells[spell_id].recovery_time == 0))) + return true; + + return false; +} + bool IsResurrectionEffects(uint16 spell_id) { // spell id 756 is Resurrection Effects spell diff --git a/common/spdat.h b/common/spdat.h index 368c4018b..64b3aedc1 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -800,6 +800,7 @@ int32 CalculateCorruptionCounters(uint16 spell_id); int32 CalculateCounters(uint16 spell_id); bool IsDisciplineBuff(uint16 spell_id); bool IsDiscipline(uint16 spell_id); +bool IsCombatSkill(uint16 spell_id); bool IsResurrectionEffects(uint16 spell_id); bool IsRuneSpell(uint16 spell_id); bool IsMagicRuneSpell(uint16 spell_id); diff --git a/utils/sql/git/required/2014_02_13_spells_new_update.sql b/utils/sql/git/required/2014_02_13_spells_new_update.sql index c843d40aa..3c3675587 100644 --- a/utils/sql/git/required/2014_02_13_spells_new_update.sql +++ b/utils/sql/git/required/2014_02_13_spells_new_update.sql @@ -11,3 +11,7 @@ ALTER TABLE `spells_new` CHANGE `field214` `NotInCombat` INT(11) NOT NULL DEFAUL ALTER TABLE `spells_new` CHANGE `field168` `IsDiscipline` INT(11) NOT NULL DEFAULT '0'; ALTER TABLE `spells_new` CHANGE `field211` `CastRestriction` INT(11) NOT NULL DEFAULT '0'; +UPDATE altadv_vars SET sof_next_id = 8261 WHERE skill_id = 8232; +UPDATE altadv_vars SET sof_next_id = 0 WHERE skill_id = 8261; +UPDATE altadv_vars SET sof_current_level = 3 WHERE skill_id = 8261; + diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 49f0f2a1c..d9438ef90 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -4026,13 +4026,12 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) } break; - case SE_LimitCombatSkills: - if (base1 == 0){ - if((spell.cast_time == 0) && (spell.recast_time == 0) && (spell.recovery_time == 0)) //Exclude procs - LimitFailure = true; - } - break; + if (base1 == 0 && IsCombatSkill(spell_id)) //Exclude Discs + LimitFailure = true; + else if (base1 == 1 && !IsCombatSkill(spell_id)) //Exclude Spells + LimitFailure = true; + break; case SE_LimitSpellGroup: if(base1 < 0) { @@ -4429,10 +4428,10 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo break; case SE_LimitCombatSkills: - if (focus_spell.base[i] == 0){ - if((spell.cast_time == 0) && (spell.recast_time == 0) && (spell.recovery_time == 0)) //Exclude procs - return 0; - } + if (focus_spell.base[i] == 0 && IsCombatSkill(spell_id)) //Exclude Disc + return 0; + else if (focus_spell.base[i] == 1 && !IsCombatSkill(spell_id)) //Include Spells + return 0; break; case SE_LimitSpellGroup: From 1ebf88abbb658c988868bcd92fd91cc779aca765 Mon Sep 17 00:00:00 2001 From: SecretsOTheP Date: Sat, 15 Feb 2014 23:50:32 -0500 Subject: [PATCH 08/28] Fixed a performance issue involving std::string and EQStream identification. Fixed a denial-of-service exploit in EQStream. --- common/EQStreamFactory.cpp | 18 +++++++++--------- common/EQStreamFactory.h | 2 +- common/EQStreamIdent.cpp | 1 + 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/common/EQStreamFactory.cpp b/common/EQStreamFactory.cpp index 403db3627..c91bdf110 100644 --- a/common/EQStreamFactory.cpp +++ b/common/EQStreamFactory.cpp @@ -144,7 +144,8 @@ void EQStreamFactory::Push(EQStream *s) void EQStreamFactory::ReaderLoop() { fd_set readset; -std::map::iterator stream_itr; +std::map,EQStream *>::iterator stream_itr; +EQStream* currStream = NULL; int num; int length; unsigned char buffer[2048]; @@ -183,14 +184,13 @@ timeval sleep_time; { // What do we wanna do? } else { - char temp[25]; - sprintf(temp,"%u.%d",ntohl(from.sin_addr.s_addr),ntohs(from.sin_port)); MStreams.lock(); - if ((stream_itr=Streams.find(temp))==Streams.end()) { + stream_itr=Streams.find(std::make_pair(from.sin_addr.s_addr, from.sin_port)); + if (stream_itr == Streams.end()) { if (buffer[1]==OP_SessionRequest) { EQStream *s = new EQStream(from); s->SetStreamType(StreamType); - Streams[temp]=s; + Streams[std::make_pair(from.sin_addr.s_addr, from.sin_port)]=s; WriterWork.Signal(); Push(s); s->AddBytesRecv(length); @@ -225,7 +225,7 @@ void EQStreamFactory::CheckTimeout() MStreams.lock(); unsigned long now=Timer::GetCurrentTime(); - std::map::iterator stream_itr; + std::map,EQStream *>::iterator stream_itr; for(stream_itr=Streams.begin();stream_itr!=Streams.end();) { EQStream *s = stream_itr->second; @@ -241,7 +241,7 @@ void EQStreamFactory::CheckTimeout() } else { //everybody is done, we can delete it now //std::cout << "Removing connection" << std::endl; - std::map::iterator temp=stream_itr; + std::map,EQStream *>::iterator temp=stream_itr; stream_itr++; //let whoever has the stream outside delete it delete temp->second; @@ -257,7 +257,7 @@ void EQStreamFactory::CheckTimeout() void EQStreamFactory::WriterLoop() { -std::map::iterator stream_itr; +std::map,EQStream *>::iterator stream_itr; bool havework=true; std::vector wants_write; std::vector::iterator cur,end; @@ -292,7 +292,7 @@ Timer DecayTimer(20); //bullshit checking, to see if this is really happening, GDB seems to think so... if(stream_itr->second == nullptr) { - fprintf(stderr, "ERROR: nullptr Stream encountered in EQStreamFactory::WriterLoop for: %s", stream_itr->first.c_str()); + fprintf(stderr, "ERROR: nullptr Stream encountered in EQStreamFactory::WriterLoop for: %i", stream_itr->first.first, stream_itr->first.second); continue; } diff --git a/common/EQStreamFactory.h b/common/EQStreamFactory.h index 866cd23d5..dd0b7f1b8 100644 --- a/common/EQStreamFactory.h +++ b/common/EQStreamFactory.h @@ -27,7 +27,7 @@ class EQStreamFactory : private Timeoutable { std::queue NewStreams; Mutex MNewStreams; - std::map Streams; + std::map,EQStream *> Streams; Mutex MStreams; virtual void CheckTimeout(); diff --git a/common/EQStreamIdent.cpp b/common/EQStreamIdent.cpp index 05fa1c6b5..de1f457b5 100644 --- a/common/EQStreamIdent.cpp +++ b/common/EQStreamIdent.cpp @@ -56,6 +56,7 @@ void EQStreamIdentifier::Process() { //if stream hasn't finished initializing then continue; if(r->stream->GetState() == UNESTABLISHED) { + cur++; continue; } if(r->stream->GetState() != ESTABLISHED) { From bb8a82030f3bfeddc86220feefd0eba77dd792f5 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 16 Feb 2014 00:17:25 -0500 Subject: [PATCH 09/28] Post-inc to pre-inc --- common/EQStreamFactory.cpp | 8 ++++---- common/EQStreamIdent.cpp | 10 +++++----- common/EQStreamLocator.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common/EQStreamFactory.cpp b/common/EQStreamFactory.cpp index c91bdf110..858a7586d 100644 --- a/common/EQStreamFactory.cpp +++ b/common/EQStreamFactory.cpp @@ -242,7 +242,7 @@ void EQStreamFactory::CheckTimeout() //everybody is done, we can delete it now //std::cout << "Removing connection" << std::endl; std::map,EQStream *>::iterator temp=stream_itr; - stream_itr++; + ++stream_itr; //let whoever has the stream outside delete it delete temp->second; Streams.erase(temp); @@ -250,7 +250,7 @@ void EQStreamFactory::CheckTimeout() } } - stream_itr++; + ++stream_itr; } MStreams.unlock(); } @@ -285,7 +285,7 @@ Timer DecayTimer(20); //copy streams into a seperate list so we dont have to keep //MStreams locked while we are writting MStreams.lock(); - for(stream_itr=Streams.begin();stream_itr!=Streams.end();stream_itr++) { + for(stream_itr=Streams.begin();stream_itr!=Streams.end();++stream_itr) { // If it's time to decay the bytes sent, then let's do it before we try to write if (decay) stream_itr->second->Decay(); @@ -307,7 +307,7 @@ Timer DecayTimer(20); //do the actual writes cur = wants_write.begin(); end = wants_write.end(); - for(; cur != end; cur++) { + for(; cur != end; ++cur) { (*cur)->Write(sock); (*cur)->ReleaseFromUse(); } diff --git a/common/EQStreamIdent.cpp b/common/EQStreamIdent.cpp index de1f457b5..d4332c9a0 100644 --- a/common/EQStreamIdent.cpp +++ b/common/EQStreamIdent.cpp @@ -11,7 +11,7 @@ EQStreamIdentifier::~EQStreamIdentifier() { std::vector::iterator cur, end; cur = m_streams.begin(); end = m_streams.end(); - for(; cur != end; cur++) { + for(; cur != end; ++cur) { Record *r = *cur; r->stream->ReleaseFromUse(); delete r; @@ -19,7 +19,7 @@ EQStreamIdentifier::~EQStreamIdentifier() { std::vector::iterator curp, endp; curp = m_patches.begin(); endp = m_patches.end(); - for(; curp != endp; curp++) { + for(; curp != endp; ++curp) { delete *curp; } } @@ -56,7 +56,7 @@ void EQStreamIdentifier::Process() { //if stream hasn't finished initializing then continue; if(r->stream->GetState() == UNESTABLISHED) { - cur++; + ++cur; continue; } if(r->stream->GetState() != ESTABLISHED) { @@ -94,7 +94,7 @@ void EQStreamIdentifier::Process() { //foreach possbile patch... curp = m_patches.begin(); endp = m_patches.end(); - for(; !found_one && curp != endp; curp++) { + for(; !found_one && curp != endp; ++curp) { Patch *p = *curp; //ask the stream to see if it matches the supplied signature @@ -137,7 +137,7 @@ void EQStreamIdentifier::Process() { delete r; cur = m_streams.erase(cur); } else { - cur++; + ++cur; } } //end foreach stream } diff --git a/common/EQStreamLocator.h b/common/EQStreamLocator.h index ab93f1afb..5732c2ef1 100644 --- a/common/EQStreamLocator.h +++ b/common/EQStreamLocator.h @@ -138,7 +138,7 @@ public: iterator cur, end; cur = streams.begin(); end = streams.end(); - for(; cur != end; cur++) { + for(; cur != end; ++cur) { if(cur->second == it) { streams.erase(cur); //lazy recursive delete for now, since we have to redo From 88eb0dcdfc01e3288df95c559a3660eab196af84 Mon Sep 17 00:00:00 2001 From: SecretsOTheP Date: Sun, 16 Feb 2014 19:16:18 -0500 Subject: [PATCH 10/28] potential crash issue involving backstab & missing primary weapons resolved. --- common/EQStreamFactory.cpp | 1 - zone/special_attacks.cpp | 16 +++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/common/EQStreamFactory.cpp b/common/EQStreamFactory.cpp index c91bdf110..260be7d56 100644 --- a/common/EQStreamFactory.cpp +++ b/common/EQStreamFactory.cpp @@ -145,7 +145,6 @@ void EQStreamFactory::ReaderLoop() { fd_set readset; std::map,EQStream *>::iterator stream_itr; -EQStream* currStream = NULL; int num; int length; unsigned char buffer[2048]; diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 5da329e54..eb0ca4db5 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -606,14 +606,16 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) if(IsClient()){ const ItemInst *wpn = nullptr; wpn = CastToClient()->GetInv().GetItem(SLOT_PRIMARY); - primaryweapondamage = GetWeaponDamage(other, wpn); - backstab_dmg = wpn->GetItem()->BackstabDmg; - for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i) - { - ItemInst *aug = wpn->GetAugment(i); - if(aug) + if(wpn) { + primaryweapondamage = GetWeaponDamage(other, wpn); + backstab_dmg = wpn->GetItem()->BackstabDmg; + for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i) { - backstab_dmg += aug->GetItem()->BackstabDmg; + ItemInst *aug = wpn->GetAugment(i); + if(aug) + { + backstab_dmg += aug->GetItem()->BackstabDmg; + } } } } From 85f2b46fe93adb240ea9939fc99f91cab0a1e9e2 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 16 Feb 2014 23:58:18 -0500 Subject: [PATCH 11/28] Fix mod_spell_resist to be no-op by default ... --- zone/mod_functions.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index 31aa32d75..0a9a66537 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -183,8 +183,7 @@ int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint1 //Sum of various resists rolled against a value of 200. int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) { - int final = resist_chance + level_mod + resist_modifier + target_resist; - return(final); + return(resist_chance); } //Spell is cast by this on spelltar, called from spellontarget after the event_cast_on NPC event From 169b9161b9c99a2b8b129617b8d1cd928e1f2356 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 17 Feb 2014 17:34:02 -0500 Subject: [PATCH 12/28] Performance: Changed RampageArray to be a vector of IDs --- zone/MobAI.cpp | 41 ++++++++++++++++++----------------------- zone/mob.h | 2 +- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/zone/MobAI.cpp b/zone/MobAI.cpp index 8c6a40e58..b7f719b27 100644 --- a/zone/MobAI.cpp +++ b/zone/MobAI.cpp @@ -1997,59 +1997,54 @@ bool Mob::Flurry(ExtraAttackOptions *opts) bool Mob::AddRampage(Mob *mob) { - if(!mob) + if (!mob) return false; if (!GetSpecialAbility(SPECATK_RAMPAGE)) return false; - for (int i = 0; i < RampageArray.size(); i++) - { - // if name is already on the list dont add it again - if (strcasecmp(mob->GetName(), RampageArray[i].c_str()) == 0) + for (int i = 0; i < RampageArray.size(); i++) { + // if Entity ID is already on the list don't add it again + if (mob->GetID() == RampageArray[i]) return false; } - std::string r_name = mob->GetName(); - RampageArray.push_back(r_name); + RampageArray.push_back(mob->GetID()); return true; } -void Mob::ClearRampage(){ +void Mob::ClearRampage() +{ RampageArray.clear(); } bool Mob::Rampage(ExtraAttackOptions *opts) { int index_hit = 0; - if (!IsPet()) { + if (!IsPet()) entity_list.MessageClose_StringID(this, true, 200, MT_NPCRampage, NPC_RAMPAGE, GetCleanName()); - } else { + else entity_list.MessageClose_StringID(this, true, 200, MT_PetFlurry, NPC_RAMPAGE, GetCleanName()); - } int rampage_targets = GetSpecialAbilityParam(SPECATK_RAMPAGE, 1); rampage_targets = rampage_targets > 0 ? rampage_targets : RuleI(Combat, MaxRampageTargets); - for (int i = 0; i < RampageArray.size(); i++) - { - if(index_hit >= rampage_targets) + for (int i = 0; i < RampageArray.size(); i++) { + if (index_hit >= rampage_targets) break; // range is important - Mob *m_target = entity_list.GetMob(RampageArray[i].c_str()); - if(m_target) - { - if(m_target == GetTarget()) + Mob *m_target = entity_list.GetMob(RampageArray[i]); + if (m_target) { + if (m_target == GetTarget()) continue; - if (CombatRange(m_target)) - { + if (CombatRange(m_target)) { Attack(m_target, 13, false, false, false, opts); index_hit++; } } } - - if(index_hit < rampage_targets) { + + if (index_hit < rampage_targets) Attack(GetTarget(), 13, false, false, false, opts); - } + return true; } diff --git a/zone/mob.h b/zone/mob.h index a5d594123..9220844e2 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -880,7 +880,7 @@ protected: bool IsFullHP; bool moved; - std::vector RampageArray; + std::vector RampageArray; std::map m_EntityVariables; int16 SkillDmgTaken_Mod[HIGHEST_SKILL+2]; From 53a14381ba1a402deb78c681a24b4795e44cc085 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 17 Feb 2014 19:38:37 -0500 Subject: [PATCH 13/28] Only build flurry attack opts on success --- zone/MobAI.cpp | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/zone/MobAI.cpp b/zone/MobAI.cpp index b7f719b27..5de69152d 100644 --- a/zone/MobAI.cpp +++ b/zone/MobAI.cpp @@ -1173,39 +1173,34 @@ void Mob::AI_Process() { int flurry_chance = GetSpecialAbilityParam(SPECATK_FLURRY, 0); flurry_chance = flurry_chance > 0 ? flurry_chance : RuleI(Combat, NPCFlurryChance); - ExtraAttackOptions opts; - int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2); - if(cur > 0) { - opts.damage_percent = cur / 100.0f; - } + if (MakeRandomInt(0, 99) < flurry_chance) { + ExtraAttackOptions opts; + int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2); + if (cur > 0) + opts.damage_percent = cur / 100.0f; - cur = GetSpecialAbilityParam(SPECATK_FLURRY, 3); - if(cur > 0) { - opts.damage_flat = cur; - } + cur = GetSpecialAbilityParam(SPECATK_FLURRY, 3); + if (cur > 0) + opts.damage_flat = cur; - cur = GetSpecialAbilityParam(SPECATK_FLURRY, 4); - if(cur > 0) { - opts.armor_pen_percent = cur / 100.0f; - } + cur = GetSpecialAbilityParam(SPECATK_FLURRY, 4); + if (cur > 0) + opts.armor_pen_percent = cur / 100.0f; - cur = GetSpecialAbilityParam(SPECATK_FLURRY, 5); - if(cur > 0) { - opts.armor_pen_flat = cur; - } + cur = GetSpecialAbilityParam(SPECATK_FLURRY, 5); + if (cur > 0) + opts.armor_pen_flat = cur; - cur = GetSpecialAbilityParam(SPECATK_FLURRY, 6); - if(cur > 0) { - opts.crit_percent = cur / 100.0f; - } + cur = GetSpecialAbilityParam(SPECATK_FLURRY, 6); + if (cur > 0) + opts.crit_percent = cur / 100.0f; - cur = GetSpecialAbilityParam(SPECATK_FLURRY, 7); - if(cur > 0) { - opts.crit_flat = cur; - } + cur = GetSpecialAbilityParam(SPECATK_FLURRY, 7); + if (cur > 0) + opts.crit_flat = cur; - if (MakeRandomInt(0, 99) < flurry_chance) Flurry(&opts); + } } if (IsPet()) { From a503c1af97665a3fc9fd3051259177b34ea434d3 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 17 Feb 2014 20:38:40 -0500 Subject: [PATCH 14/28] Fix Mob double/triple/quad check to work if a lower one isn't set --- zone/MobAI.cpp | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/zone/MobAI.cpp b/zone/MobAI.cpp index 5de69152d..dedd49f79 100644 --- a/zone/MobAI.cpp +++ b/zone/MobAI.cpp @@ -1141,30 +1141,26 @@ void Mob::AI_Process() { Attack(target, 13); } - if (target) - { + if (target) { //we use this random value in three comparisons with different //thresholds, and if its truely random, then this should work //out reasonably and will save us compute resources. int32 RandRoll = MakeRandomInt(0, 99); - if (CanThisClassDoubleAttack() - //check double attack, this is NOT the same rules that clients use... - && RandRoll < (GetLevel() + NPCDualAttackModifier)) - { + if ((CanThisClassDoubleAttack() || GetSpecialAbility(SPECATK_TRIPLE) + || GetSpecialAbility(SPECATK_QUAD)) + //check double attack, this is NOT the same rules that clients use... + && RandRoll < (GetLevel() + NPCDualAttackModifier)) { Attack(target, 13); // lets see if we can do a triple attack with the main hand //pets are excluded from triple and quads... - if (GetSpecialAbility(SPECATK_TRIPLE) - && !IsPet() && RandRoll < (GetLevel()+NPCTripleAttackModifier)) - { + if ((GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD)) + && !IsPet() && RandRoll < (GetLevel() + NPCTripleAttackModifier)) { Attack(target, 13); // now lets check the quad attack if (GetSpecialAbility(SPECATK_QUAD) - && RandRoll < (GetLevel() + NPCQuadAttackModifier)) - { + && RandRoll < (GetLevel() + NPCQuadAttackModifier)) { Attack(target, 13); } - } } } @@ -1204,12 +1200,10 @@ void Mob::AI_Process() { } if (IsPet()) { - Mob *owner = GetOwner(); - - if (owner){ - int16 flurry_chance = owner->aabonuses.PetFlurry + owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry; - + if (owner) { + int16 flurry_chance = owner->aabonuses.PetFlurry + + owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry; if (flurry_chance && (MakeRandomInt(0, 99) < flurry_chance)) Flurry(nullptr); } @@ -1289,7 +1283,7 @@ void Mob::AI_Process() { if(cur > 0) { opts.crit_flat = cur; } - + AreaRampage(&opts); } } From d7f9cdf6b6bb1c1e50b65911599d5afcd6fe9694 Mon Sep 17 00:00:00 2001 From: gpanula Date: Mon, 17 Feb 2014 19:45:47 -0600 Subject: [PATCH 15/28] Update tblWorldServerRegistration.sql login server expects a "ServerTrusted" column --- loginserver/login_util/tblWorldServerRegistration.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/loginserver/login_util/tblWorldServerRegistration.sql b/loginserver/login_util/tblWorldServerRegistration.sql index 74818fe0b..e0ee4dc9f 100644 --- a/loginserver/login_util/tblWorldServerRegistration.sql +++ b/loginserver/login_util/tblWorldServerRegistration.sql @@ -9,5 +9,6 @@ CREATE TABLE IF NOT EXISTS tblWorldServerRegistration ( ServerLastIPAddr varchar(15) NULL, ServerAdminID integer NOT NULL, Note varchar(300) NULL, + ServerTrusted int(11), PRIMARY KEY (ServerID, ServerLongName) ) ENGINE=InnoDB; From 6e474f22a20717dcf951b1e316c9a0a4e3d18b33 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 18 Feb 2014 16:52:51 -0500 Subject: [PATCH 16/28] Added single target HalveAggro and DoubleAggro Both exported to perl/lua pass the target you wish to change their hate. --- zone/lua_mob.cpp | 12 +++++++++ zone/lua_mob.h | 4 ++- zone/mob.h | 2 ++ zone/perl_mob.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 851c1293a..673fb63ab 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -908,6 +908,16 @@ void Lua_Mob::SetHate(Lua_Mob other, int hate, int damage) { self->SetHate(other, hate, damage); } +void Lua_Mob::HalveAggro(Lua_Mob other) { + Lua_Safe_Call_Void(); + self->HalveAggro(other); +} + +void Lua_Mob::DoubleAggro(Lua_Mob other) { + Lua_Safe_Call_Void(); + self->DoubleAggro(other); +} + uint32 Lua_Mob::GetHateAmount(Lua_Mob target) { Lua_Safe_Call_Int(); return self->GetHateAmount(target); @@ -1962,6 +1972,8 @@ luabind::scope lua_register_mob() { .def("SetHate", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::SetHate) .def("SetHate", (void(Lua_Mob::*)(Lua_Mob,int))&Lua_Mob::SetHate) .def("SetHate", (void(Lua_Mob::*)(Lua_Mob,int,int))&Lua_Mob::SetHate) + .def("HalveAggro", &Lua_Mob::HalveAggro) + .def("DoubleAggro", &Lua_Mob::DoubleAggro) .def("GetHateAmount", (uint32(Lua_Mob::*)(Lua_Mob))&Lua_Mob::GetHateAmount) .def("GetHateAmount", (uint32(Lua_Mob::*)(Lua_Mob,bool))&Lua_Mob::GetHateAmount) .def("GetDamageAmount", (uint32(Lua_Mob::*)(Lua_Mob))&Lua_Mob::GetDamageAmount) diff --git a/zone/lua_mob.h b/zone/lua_mob.h index 160fae5ad..b0ad150fd 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -192,6 +192,8 @@ public: void SetHate(Lua_Mob other); void SetHate(Lua_Mob other, int hate); void SetHate(Lua_Mob other, int hate, int damage); + void HalveAggro(Lua_Mob other); + void DoubleAggro(Lua_Mob other); uint32 GetHateAmount(Lua_Mob target); uint32 GetHateAmount(Lua_Mob target, bool is_damage); uint32 GetDamageAmount(Lua_Mob target); @@ -345,4 +347,4 @@ public: }; #endif -#endif \ No newline at end of file +#endif diff --git a/zone/mob.h b/zone/mob.h index 9220844e2..7f64fbd90 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -427,6 +427,8 @@ public: bool bFrenzy = false, bool iBuffTic = false); bool RemoveFromHateList(Mob* mob); void SetHate(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.Set(other,hate,damage);} + void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate > 1 ? in_hate / 2 : 1)); } + void DoubleAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate ? in_hate * 2 : 1)); } uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHate(tmob,is_dam);} uint32 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHate(tmob, true);} Mob* GetHateTop() { return hate_list.GetTop(this);} diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index 13698cea9..a2958db27 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -5341,6 +5341,72 @@ XS(XS_Mob_SetHate) XSRETURN_EMPTY; } +XS(XS_Mob_HalveAggro); +XS(XS_Mob_HalveAggro) +{ + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Mob::HalveAggro(THIS, other)"); + { + Mob * THIS; + Mob * other; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + if (sv_derived_from(ST(1), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(1))); + other = INT2PTR(Mob *,tmp); + } + else + Perl_croak(aTHX_ "other is not of type Mob"); + if(other == nullptr) + Perl_croak(aTHX_ "other is nullptr, avoiding crash."); + + THIS->HalveAggro(other); + } + XSRETURN_EMPTY; +} + +XS(XS_Mob_DoubleAggro); +XS(XS_Mob_DoubleAggro) +{ + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Mob::DoubleAggro(THIS, other)"); + { + Mob * THIS; + Mob * other; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + if (sv_derived_from(ST(1), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(1))); + other = INT2PTR(Mob *,tmp); + } + else + Perl_croak(aTHX_ "other is not of type Mob"); + if(other == nullptr) + Perl_croak(aTHX_ "other is nullptr, avoiding crash."); + + THIS->DoubleAggro(other); + } + XSRETURN_EMPTY; +} + XS(XS_Mob_GetHateAmount); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_GetHateAmount) { @@ -8274,6 +8340,8 @@ XS(boot_Mob) newXSproto(strcpy(buf, "IsRooted"), XS_Mob_IsRooted, file, "$"); newXSproto(strcpy(buf, "AddToHateList"), XS_Mob_AddToHateList, file, "$$;$$$$$"); newXSproto(strcpy(buf, "SetHate"), XS_Mob_SetHate, file, "$$;$$"); + newXSproto(strcpy(buf, "HalveAggro"), XS_Mob_HalveAggro, file, "$$"); + newXSproto(strcpy(buf, "DoubleAggro"), XS_Mob_DoubleAggro, file, "$$"); newXSproto(strcpy(buf, "GetHateAmount"), XS_Mob_GetHateAmount, file, "$$;$"); newXSproto(strcpy(buf, "GetDamageAmount"), XS_Mob_GetDamageAmount, file, "$$"); newXSproto(strcpy(buf, "GetHateTop"), XS_Mob_GetHateTop, file, "$"); From ab4c9581ad608e1efc288a06dfa5db447e497129 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 18 Feb 2014 18:22:19 -0500 Subject: [PATCH 17/28] Fix NPC rampage to be more in-line with live New rules: RuleI: Combat, DefaultRampageTargets Set to 1 If the specatk db entry has no extra param it will use this RuleB: Combat, RampageHitsTargets Defaults to false If true, if number hit is still less than RampageTargets, try tank If you want the old behavior still set DefaultRampageTargets to 3 and RampageHitsTargets to true --- common/ruletypes.h | 2 ++ zone/MobAI.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 26acc7434..7ca940722 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -333,6 +333,8 @@ RULE_REAL ( Combat, ArcheryBaseDamageBonus, 1) // % Modifier to Base Archery Dam RULE_REAL ( Combat, ArcheryNPCMultiplier, 1.0) // this is multiplied by the regular dmg to get the archery dmg RULE_BOOL ( Combat, AssistNoTargetSelf, true) //when assisting a target that does not have a target: true = target self, false = leave target as was before assist (false = live like) RULE_INT ( Combat, MaxRampageTargets, 3) //max number of people hit with rampage +RULE_INT ( Combat, DefaultRampageTargets, 1) // default number of people to hit with rampage +RULE_BOOL ( Combat, RampageHitsTarget, false) // rampage will hit the target if it still has targets left RULE_INT ( Combat, MaxFlurryHits, 2) //max number of extra hits from flurry RULE_INT ( Combat, MonkDamageTableBonus, 5) //% bonus monks get to their damage table calcs RULE_INT ( Combat, FlyingKickBonus, 25) //% Modifier that this skill gets to str and skill bonuses diff --git a/zone/MobAI.cpp b/zone/MobAI.cpp index dedd49f79..e65e357ad 100644 --- a/zone/MobAI.cpp +++ b/zone/MobAI.cpp @@ -2015,7 +2015,10 @@ bool Mob::Rampage(ExtraAttackOptions *opts) entity_list.MessageClose_StringID(this, true, 200, MT_PetFlurry, NPC_RAMPAGE, GetCleanName()); int rampage_targets = GetSpecialAbilityParam(SPECATK_RAMPAGE, 1); - rampage_targets = rampage_targets > 0 ? rampage_targets : RuleI(Combat, MaxRampageTargets); + if (rampage_targets == 0) // if set to 0 or not set in the DB + rampage_targets = RuleI(Combat, DefaultRampageTargets); + if (rampage_targets > RuleI(Combat, MaxRampageTargets)) + rampage_targets = RuleI(Combat, MaxRampageTargets); for (int i = 0; i < RampageArray.size(); i++) { if (index_hit >= rampage_targets) break; @@ -2031,7 +2034,7 @@ bool Mob::Rampage(ExtraAttackOptions *opts) } } - if (index_hit < rampage_targets) + if (RuleB(Combat, RampageHitsTarget) && index_hit < rampage_targets) Attack(GetTarget(), 13, false, false, false, opts); return true; From 0fc7dade478c5109f49da7e12b540e5bd13c39ad Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 18 Feb 2014 21:59:33 -0500 Subject: [PATCH 18/28] Spell Effect additions Minor fixes --- changelog.txt | 5 +++++ common/spdat.cpp | 2 +- common/spdat.h | 12 ++++++------ zone/MobAI.cpp | 3 ++- zone/aggro.cpp | 9 +++------ zone/attack.cpp | 8 ++++++++ zone/bonuses.cpp | 11 ++++++++++- zone/bot.cpp | 4 ++-- zone/common.h | 1 + zone/merc.cpp | 2 +- zone/mob.cpp | 27 ++++++++++++++++++--------- zone/mob.h | 1 + zone/spell_effects.cpp | 35 +++++++++++++++++++++++++++++++---- 13 files changed, 89 insertions(+), 31 deletions(-) diff --git a/changelog.txt b/changelog.txt index db22c784e..eb1785b41 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,10 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/18/2014 == +Kayen: Implemented SE_TriggerOnReqCaster - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) +Kayen: Implemented SE_ImprovedTaunt - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y +Kayen: Fixed an error where SE_ChangeAggro was adding its bonus x 2 for spell generated aggro. (this applies also to spell casting subtlety AA reduction) + == 02/14/2014 == Kayen: Fixes for buffs not fading under certain conditions in revised numhits system, and other fixes. Kayen: Implemented support for spell_new field CastRestrictions (limits what type of targets spells can effect). diff --git a/common/spdat.cpp b/common/spdat.cpp index 2cbf8a97d..807a1ba2d 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -949,7 +949,7 @@ bool IsDebuffSpell(uint16 spell_id) if (IsBeneficialSpell(spell_id) || IsEffectHitpointsSpell(spell_id) || IsStunSpell(spell_id) || IsMezSpell(spell_id) || IsCharmSpell(spell_id) || IsSlowSpell(spell_id) || IsEffectInSpell(spell_id, SE_Root) || IsEffectInSpell(spell_id, SE_CancelMagic) || - IsEffectInSpell(spell_id, SE_MovementSpeed) || IsFearSpell(spell_id) || IsEffectInSpell(spell_id, SE_Calm)) + IsEffectInSpell(spell_id, SE_MovementSpeed) || IsFearSpell(spell_id) || IsEffectInSpell(spell_id, SE_InstantHate)) return false; else return true; diff --git a/common/spdat.h b/common/spdat.h index 64b3aedc1..237125b90 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -148,7 +148,7 @@ typedef enum { // full listing: https://forums.station.sony.com/eq/index.php?threads/enumerated-spa-list.206288/ // mirror: http://pastebin.com/MYeQqGwe #define SE_CurrentHP 0 // implemented - Heals and nukes, repeates every tic if in a buff -#define SE_ArmorClass 1 // implemented +#define SE_ArmorClass 1 // implemented #define SE_ATK 2 // implemented #define SE_MovementSpeed 3 // implemented - SoW, SoC, etc #define SE_STR 4 // implemented @@ -239,7 +239,7 @@ typedef enum { #define SE_ModelSize 89 // implemented - Shrink, Growth #define SE_Cloak 90 // *not implemented - Used in only 2 spells #define SE_SummonCorpse 91 // implemented -#define SE_Calm 92 // implemented - Hate modifier stuff(poorly named) +#define SE_InstantHate 92 // implemented - add hate #define SE_StopRain 93 // implemented - Wake of Karana #define SE_NegateIfCombat 94 // *not implemented? - Works client side but there is comment todo in spell effects...Component of Spirit of Scale #define SE_Sacrifice 95 // implemented @@ -572,7 +572,7 @@ typedef enum { #define SE_LimitUseMin 422 // implemented - limit a focus to require a min amount of numhits value (used with above) #define SE_LimitUseType 423 // implemented - limit a focus to require a certain numhits type #define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace -#define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626) +//#define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626) #define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window #define SE_SkillProc 427 // implemented - chance to proc when using a skill(ie taunt) #define SE_LimitToSkill 428 // implemented - limits what skills will effect a skill proc @@ -589,9 +589,9 @@ typedef enum { #define SE_IncreaseAssassinationLvl 439 // *not implemented[AA] - increases the maximum level of humanoid that can be affected by assassination #define SE_FinishingBlowLvl 440 // implemented[AA] - Sets the level Finishing blow can be triggered on an NPC #define SE_CancleIfMoved 441 // *not implemented - Buff is removed from target when target moves X amount of distance away from where initially hit. -#define SE_TriggerOnValueAmount 442 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) -#define SE_TriggerIfMovement 443 // *not implemented - Trigger a spell if you move (37846 | Chopping Block) -#define SE_ImprovedTaunt 444 // *not implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% up to level Z +#define SE_TriggerOnReqTarget 442 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) +#define SE_TriggerOnReqCaster 443 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) +#define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y #define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs. //#define SE_AStacker 446 // *not implementet - bufff stacking blocker ? (26219 | Qirik's Watch) //#define SE_BStacker 447 // *not implemented diff --git a/zone/MobAI.cpp b/zone/MobAI.cpp index e65e357ad..38addf695 100644 --- a/zone/MobAI.cpp +++ b/zone/MobAI.cpp @@ -1054,7 +1054,8 @@ void Mob::AI_Process() { SetTarget(hate_list.GetTop(this)); } } else { - SetTarget(hate_list.GetTop(this)); + if (!ImprovedTaunt()) + SetTarget(hate_list.GetTop(this)); } } diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 8fa426a67..326e320c0 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -1257,7 +1257,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc) break; } case SE_ReduceHate: - case SE_Calm: { + case SE_InstantHate: { nonModifiedAggro = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id); break; } @@ -1282,9 +1282,6 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc) if (IsClient()) HateMod += CastToClient()->GetFocusEffect(focusSpellHateMod, spell_id); - //Live AA - Spell casting subtlety - HateMod += aabonuses.hatemod + spellbonuses.hatemod + itembonuses.hatemod; - AggroAmount = (AggroAmount * HateMod) / 100; //made up number probably scales a bit differently on live but it seems like it will be close enough @@ -1405,7 +1402,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) { return true; //1: The mob has a default 25% chance of being allowed a resistance check against the charm. - if (MakeRandomInt(0, 100) > RuleI(Spells, CharmBreakCheckChance)) + if (MakeRandomInt(0, 99) > RuleI(Spells, CharmBreakCheckChance)) return true; //2: The mob makes a resistance check against the charm @@ -1419,7 +1416,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) { //3: At maxed ability, Total Domination has a 50% chance of preventing the charm break that otherwise would have occurred. uint16 TotalDominationBonus = caster->aabonuses.CharmBreakChance + caster->spellbonuses.CharmBreakChance + caster->itembonuses.CharmBreakChance; - if (MakeRandomInt(0, 100) < TotalDominationBonus) + if (MakeRandomInt(0, 99) < TotalDominationBonus) return true; } diff --git a/zone/attack.cpp b/zone/attack.cpp index 18571a08f..32a8318da 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1303,6 +1303,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b // Hate Generation is on a per swing basis, regardless of a hit, miss, or block, its always the same. // If we are this far, this means we are atleast making a swing. + if (!bRiposte) // Ripostes never generate any aggro. other->AddToHateList(this, hate); @@ -1868,6 +1869,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool mlog(COMBAT__HITS, "Generating hate %d towards %s", hate, GetName()); // now add done damage to the hate list other->AddToHateList(this, hate); + } else { if(opts) { damage *= opts->damage_percent; @@ -2402,7 +2404,9 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack } void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) { + assert(other != nullptr); + if (other == this) return; @@ -2483,6 +2487,10 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, if(damage > GetHP()) damage = GetHP(); + if (spellbonuses.ImprovedTaunt[1] && (GetLevel() < spellbonuses.ImprovedTaunt[0]) + && other && (buffs[spellbonuses.ImprovedTaunt[0]].casterid != other->GetID())) + hate = (hate*spellbonuses.ImprovedTaunt[1])/100; + hate_list.Add(other, hate, damage, bFrenzy, !iBuffTic); if(other->IsClient()) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index fbd4020eb..dc8776c67 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2496,7 +2496,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } - case SE_TriggerOnValueAmount: + case SE_TriggerOnReqTarget: + case SE_TriggerOnReqCaster: newbon->TriggerOnValueAmount = true; break; @@ -2504,6 +2505,14 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->DivineAura = true; break; + case SE_ImprovedTaunt: + if (newbon->ImprovedTaunt[0] < effect_value) { + newbon->ImprovedTaunt[0] = effect_value; + newbon->ImprovedTaunt[1] = spells[spell_id].base2[i]; + newbon->ImprovedTaunt[2] = buffslot; + } + break; + } } } diff --git a/zone/bot.cpp b/zone/bot.cpp index ff732d50c..3805dd025 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -12973,7 +12973,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) { pacer->Say("Trying to pacify %s \n", target->GetCleanName()); if(pacer->Bot_Command_CalmTarget(target)) { - if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_Calm)) + if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_InstantHate)) //if(pacer->IsPacified(target)) c->Message(0, "I have successfully pacified %s.", target->GetCleanName()); return; @@ -12989,7 +12989,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) { pacer->Say("Trying to pacify %s \n", target->GetCleanName()); if(pacer->Bot_Command_CalmTarget(target)) { - if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_Calm)) + if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_InstantHate)) //if(pacer->IsPacified(target)) c->Message(0, "I have successfully pacified %s.", target->GetCleanName()); return; diff --git a/zone/common.h b/zone/common.h index 758dd1cc4..622dafb6f 100644 --- a/zone/common.h +++ b/zone/common.h @@ -328,6 +328,7 @@ struct StatBonuses { bool CriticalHealDecay; // increase critical heal chance, decays based on spell level cast bool CriticalDotDecay; // increase critical dot chance, decays based on spell level cast bool DivineAura; // invulnerability + int16 ImprovedTaunt[3]; // 0 = Max Level 1 = Aggro modifier 2 = buffid //bool AbsorbMagicAtt; // Magic Rune *Need to be implemented for NegateEffect //bool MeleeRune; // Melee Rune *Need to be implemented for NegateEffect diff --git a/zone/merc.cpp b/zone/merc.cpp index 6da94f3e3..ef5818b6d 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -3670,7 +3670,7 @@ MercSpell Merc::GetBestMercSpellForHate(Merc* caster) { result.time_cancast = 0; if(caster) { - std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_Calm); + std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_InstantHate); for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order diff --git a/zone/mob.cpp b/zone/mob.cpp index 078fed266..cee9003cc 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3228,11 +3228,20 @@ void Mob::TryApplyEffect(Mob *target, uint32 spell_id) void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsPet) { /* + At present time there is no obvious difference between ReqTarget and ReqCaster + ReqTarget is typically used in spells cast on a target where the trigger occurs on that target. + ReqCaster is typically self only spells where the triggers on self. + Regardless both trigger on the owner of the buff. + */ + + /* + Base2 Range: 1004 = Below < 80% HP Base2 Range: 500-520 = Below (base2 - 500)*5 HP Base2 Range: 521 = Below (?) Mana UKNOWN - Will assume its 20% unless proven otherwise Base2 Range: 522 = Below (40%) Endurance Base2 Range: 523 = Below (40%) Mana Base2 Range: 220-? = Number of pets on hatelist to trigger (base2 - 220) (Set at 30 pets max for now) + 38311 = < 10% mana; */ if (!spellbonuses.TriggerOnValueAmount) @@ -3250,21 +3259,25 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP for(int i = 0; i < EFFECT_COUNT; i++){ - if (spells[spell_id].effectid[i] == SE_TriggerOnValueAmount){ + if ((spells[spell_id].effectid[i] == SE_TriggerOnReqTarget) || (spells[spell_id].effectid[i] == SE_TriggerOnReqCaster)) { int base2 = spells[spell_id].base2[i]; bool use_spell = false; if (IsHP){ - if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5){ + if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5) + use_spell = true; + + else if (base2 = 1004 && GetHPRatio() < 80) use_spell = true; - } } else if (IsMana){ - if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40)) { + if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40)) + use_spell = true; + + else if (base2 = 38311 && GetManaRatio() < 10) use_spell = true; - } } else if (IsEndur){ @@ -3283,10 +3296,6 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP if (use_spell){ SpellFinished(spells[spell_id].base[i], this, 10, 0, -1, spells[spell_id].ResistDiff); - /*Note, spell data shows numhits values of 0 or 1, however many descriptions of these spells indicate they should - be fading when consumed even with numhits of 0 (It makes sense they should fade...). - Unless proven otherwise, they should fade when triggered. */ - if(!TryFadeEffect(e)) BuffFadeBySlot(e); } diff --git a/zone/mob.h b/zone/mob.h index 7f64fbd90..7ab28f127 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -591,6 +591,7 @@ public: int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg); void MeleeLifeTap(int32 damage); bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true); + bool ImprovedTaunt(); void ModSkillDmgTaken(SkillUseTypes skill_num, int value); int16 GetModSkillDmgTaken(const SkillUseTypes skill_num); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index d9438ef90..5e4ac7bfd 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2667,7 +2667,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_ChangeAggro: case SE_Hate2: case SE_Identify: - case SE_Calm: + case SE_InstantHate: case SE_ReduceHate: case SE_SpellDamageShield: case SE_ReverseDS: @@ -2806,7 +2806,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_DoubleRangedAttack: case SE_ShieldEquipHateMod: case SE_ShieldEquipDmgMod: - case SE_TriggerOnValueAmount: + case SE_TriggerOnReqTarget: case SE_LimitRace: case SE_FcLimitUse: case SE_FcMute: @@ -5577,6 +5577,28 @@ bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){ return false; } + +bool Mob::ImprovedTaunt(){ + + if (spellbonuses.ImprovedTaunt[2]){ + + if (GetLevel() > spellbonuses.ImprovedTaunt[0]) + return false; + + target = entity_list.GetMob(buffs[spellbonuses.ImprovedTaunt[2]].casterid); + + if (target){ + SetTarget(target); + return true; + } + else + BuffFadeByEffect(spellbonuses.ImprovedTaunt[2]); //If caster killed removed effect. + } + + return false; +} + + bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDamage) { /*If return TRUE spell met all restrictions and can continue (this = target). @@ -5633,7 +5655,7 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama Range 839 : Unknown *not implemented Range 842 - 844 : Humaniod lv MAX ((842 - 800) * 2) Range 845 - 847 : UNKNOWN - Range 10000+ : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement) + Range 10000 - 11000 : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement) THIS IS A WORK IN PROGRESS */ @@ -5650,7 +5672,7 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama break; case 101: - if (GetBodyType() == BT_Dragon) + if (GetBodyType() == BT_Dragon || GetBodyType() == BT_VeliousDragon || GetBodyType() == BT_Dragon3) return true; break; @@ -5786,6 +5808,11 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama return true; break; + case 701: + if (!IsPet()) + return true; + break; + case 818: if (GetBodyType() == BT_Undead) return true; From 0ca01641ff81fad336ec3811b44ae100083cd1be Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 18 Feb 2014 23:24:14 -0500 Subject: [PATCH 19/28] fix --- zone/spell_effects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 5e4ac7bfd..75c83cb3e 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -5592,7 +5592,7 @@ bool Mob::ImprovedTaunt(){ return true; } else - BuffFadeByEffect(spellbonuses.ImprovedTaunt[2]); //If caster killed removed effect. + BuffFadeBySlot(spellbonuses.ImprovedTaunt[2]); //If caster killed removed effect. } return false; From 58c5003ad569cce5b4bdbdc27ae8aa8a965515d7 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 18 Feb 2014 23:26:09 -0500 Subject: [PATCH 20/28] fix --- zone/attack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 32a8318da..1518e0a0e 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2488,7 +2488,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, damage = GetHP(); if (spellbonuses.ImprovedTaunt[1] && (GetLevel() < spellbonuses.ImprovedTaunt[0]) - && other && (buffs[spellbonuses.ImprovedTaunt[0]].casterid != other->GetID())) + && other && (buffs[spellbonuses.ImprovedTaunt[2]].casterid != other->GetID())) hate = (hate*spellbonuses.ImprovedTaunt[1])/100; hate_list.Add(other, hate, damage, bFrenzy, !iBuffTic); From eb3a11b49a1fe2458ba9c197034442f177fd8c1d Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 19 Feb 2014 20:29:19 -0500 Subject: [PATCH 21/28] NPC vs Client damage revamp Shot list of things that changed: AC Softcap is based on your defensive skill (the scaling factors are based on at least previously stated dev quotes) The over AC Softcap returns are now based on exact calculations made with the Armor of Wisdom AA. Shielding item bonus and Melee mitigation spell bonus (nerfs) NPCs damage will now correctly follow the "damage base + (damage interval * [1, 20])" formula. These changes might seem a little weird but I didn't want to change any of the other damage situations since they were fairly good, but they still could use a revamp as well. New rules: RULE_BOOL ( Combat, OldACSoftcapRules, false) // use old softcaps RULE_BOOL ( Combat, UseOldDamageIntervalRules, false) // use old damage formulas for everything RULE_REAL ( Combat, WarACSoftcapReturn, 0.3448) // new AC returns RULE_REAL ( Combat, ClrRngMnkBrdACSoftcapReturn, 0.3030) RULE_REAL ( Combat, PalShdACSoftcapReturn, 0.3226) RULE_REAL ( Combat, DruNecWizEncMagACSoftcapReturn, 0.2000) RULE_REAL ( Combat, RogShmBstBerACSoftcapReturn, 0.2500) RULE_REAL ( Combat, SoftcapFactor, 1.88) If you want to use the old calculations only, set Combat:OldACSoftcapRules and Combat:UseOldDamageIntervalRules to true --- common/ruletypes.h | 8 ++ zone/attack.cpp | 281 +++++++++++++++++++++++++-------------------- zone/client.h | 1 + zone/mob.h | 1 + 4 files changed, 167 insertions(+), 124 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 7ca940722..b610c308d 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -357,6 +357,14 @@ RULE_REAL ( Combat, LowPlateChainACSoftcapReturn, 0.23) RULE_REAL ( Combat, LowChainLeatherACSoftcapReturn, 0.17) RULE_REAL ( Combat, CasterACSoftcapReturn, 0.06) RULE_REAL ( Combat, MiscACSoftcapReturn, 0.3) +RULE_BOOL ( Combat, OldACSoftcapRules, false) // use old softcaps +RULE_BOOL ( Combat, UseOldDamageIntervalRules, false) // use old damage formulas for everything +RULE_REAL ( Combat, WarACSoftcapReturn, 0.3448) // new AC returns +RULE_REAL ( Combat, ClrRngMnkBrdACSoftcapReturn, 0.3030) +RULE_REAL ( Combat, PalShdACSoftcapReturn, 0.3226) +RULE_REAL ( Combat, DruNecWizEncMagACSoftcapReturn, 0.2000) +RULE_REAL ( Combat, RogShmBstBerACSoftcapReturn, 0.2500) +RULE_REAL ( Combat, SoftcapFactor, 1.88) RULE_REAL ( Combat, ACthac0Factor, 0.55) RULE_REAL ( Combat, ACthac20Factor, 0.55) RULE_INT ( Combat, HitCapPre20, 40) // live has it capped at 40 for whatever dumb reason... this is mainly for custom servers diff --git a/zone/attack.cpp b/zone/attack.cpp index 18571a08f..65510a8b5 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -536,17 +536,16 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts) { - if(damage <= 0) + if (damage <= 0) return; Mob* defender = this; - float aa_mit = 0; + float aa_mit = (aabonuses.CombatStability + itembonuses.CombatStability + + spellbonuses.CombatStability) / 100.0f; - aa_mit = (aabonuses.CombatStability + itembonuses.CombatStability + spellbonuses.CombatStability)/100.0f; - - if(RuleB(Combat, UseIntervalAC)) - { - float softcap = 0.0; + if (RuleB(Combat, UseIntervalAC)) { + float softcap = (GetSkill(SkillDefense) + GetLevel()) * + RuleR(Combat, SoftcapFactor) * (1.0 + aa_mit); float mitigation_rating = 0.0; float attack_rating = 0.0; int shield_ac = 0; @@ -556,150 +555,101 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac float monkweight = RuleI(Combat, MonkACBonusWeight); monkweight = mod_monk_weight(monkweight, attacker); - if(IsClient()) - { + if (IsClient()) { armor = CastToClient()->GetRawACNoShield(shield_ac); weight = (CastToClient()->CalcCurrentWeight() / 10.0); - } - else if(IsNPC()) - { + } else if (IsNPC()) { armor = CastToNPC()->GetRawAC(); - if(!IsPet()) - { + if (!IsPet()) armor = (armor / RuleR(Combat, NPCACFactor)); - } armor += spellbonuses.AC + itembonuses.AC + 1; } - if(opts) { + if (opts) { armor *= (1.0f - opts->armor_pen_percent); armor -= opts->armor_pen_flat; } - if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER) - { - softcap = RuleI(Combat, ClothACSoftcap); - } - else if(GetClass() == MONK && weight <= monkweight) - { - softcap = RuleI(Combat, MonkACSoftcap); - } - else if(GetClass() == DRUID || GetClass() == BEASTLORD || GetClass() == MONK) - { - softcap = RuleI(Combat, LeatherACSoftcap); - } - else if(GetClass() == SHAMAN || GetClass() == ROGUE || GetClass() == BERSERKER || GetClass() == RANGER) - { - softcap = RuleI(Combat, ChainACSoftcap); - } - else - { - softcap = RuleI(Combat, PlateACSoftcap); + if (RuleB(Combat, OldACSoftcapRules)) { + if (GetClass() == WIZARD || GetClass() == MAGICIAN || + GetClass() == NECROMANCER || GetClass() == ENCHANTER) + softcap = RuleI(Combat, ClothACSoftcap); + else if (GetClass() == MONK && weight <= monkweight) + softcap = RuleI(Combat, MonkACSoftcap); + else if(GetClass() == DRUID || GetClass() == BEASTLORD || GetClass() == MONK) + softcap = RuleI(Combat, LeatherACSoftcap); + else if(GetClass() == SHAMAN || GetClass() == ROGUE || + GetClass() == BERSERKER || GetClass() == RANGER) + softcap = RuleI(Combat, ChainACSoftcap); + else + softcap = RuleI(Combat, PlateACSoftcap); } softcap += shield_ac; armor += shield_ac; - softcap += (softcap * (aa_mit * RuleR(Combat, AAMitigationACFactor))); - if(armor > softcap) - { + if (RuleB(Combat, OldACSoftcapRules)) + softcap += (softcap * (aa_mit * RuleR(Combat, AAMitigationACFactor))); + if (armor > softcap) { int softcap_armor = armor - softcap; - if(GetClass() == WARRIOR) - { - softcap_armor = softcap_armor * RuleR(Combat, WarriorACSoftcapReturn); - } - else if(GetClass() == SHADOWKNIGHT || GetClass() == PALADIN || (GetClass() == MONK && weight <= monkweight)) - { - softcap_armor = softcap_armor * RuleR(Combat, KnightACSoftcapReturn); - } - else if(GetClass() == CLERIC || GetClass() == BARD || GetClass() == BERSERKER || GetClass() == ROGUE || GetClass() == SHAMAN || GetClass() == MONK) - { - softcap_armor = softcap_armor * RuleR(Combat, LowPlateChainACSoftcapReturn); - } - else if(GetClass() == RANGER || GetClass() == BEASTLORD) - { - softcap_armor = softcap_armor * RuleR(Combat, LowChainLeatherACSoftcapReturn); - } - else if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER || GetClass() == DRUID) - { - softcap_armor = softcap_armor * RuleR(Combat, CasterACSoftcapReturn); - } - else - { - softcap_armor = softcap_armor * RuleR(Combat, MiscACSoftcapReturn); + if (RuleB(Combat, OldACSoftcapRules)) { + if (GetClass() == WARRIOR) + softcap_armor = softcap_armor * RuleR(Combat, WarriorACSoftcapReturn); + else if (GetClass() == SHADOWKNIGHT || GetClass() == PALADIN || + (GetClass() == MONK && weight <= monkweight)) + softcap_armor = softcap_armor * RuleR(Combat, KnightACSoftcapReturn); + else if (GetClass() == CLERIC || GetClass() == BARD || + GetClass() == BERSERKER || GetClass() == ROGUE || + GetClass() == SHAMAN || GetClass() == MONK) + softcap_armor = softcap_armor * RuleR(Combat, LowPlateChainACSoftcapReturn); + else if (GetClass() == RANGER || GetClass() == BEASTLORD) + softcap_armor = softcap_armor * RuleR(Combat, LowChainLeatherACSoftcapReturn); + else if (GetClass() == WIZARD || GetClass() == MAGICIAN || + GetClass() == NECROMANCER || GetClass() == ENCHANTER || + GetClass() == DRUID) + softcap_armor = softcap_armor * RuleR(Combat, CasterACSoftcapReturn); + else + softcap_armor = softcap_armor * RuleR(Combat, MiscACSoftcapReturn); + } else { + if (GetClass() == WARRIOR) + softcap_armor *= RuleR(Combat, WarACSoftcapReturn); + else if (GetClass() == PALADIN || GetClass() == SHADOWKNIGHT) + softcap_armor *= RuleR(Combat, PalShdACSoftcapReturn); + else if (GetClass() == CLERIC || GetClass() == RANGER || + GetClass() == MONK || GetClass() == BARD) + softcap_armor *= RuleR(Combat, ClrRngMnkBrdACSoftcapReturn); + else if (GetClass() == DRUID || GetClass() == NECROMANCER || + GetClass() == WIZARD || GetClass() == ENCHANTER || + GetClass() == MAGICIAN) + softcap_armor *= RuleR(Combat, DruNecWizEncMagACSoftcapReturn); + else if (GetClass() == ROGUE || GetClass() == SHAMAN || + GetClass() == BEASTLORD || GetClass() == BERSERKER) + softcap_armor *= RuleR(Combat, RogShmBstBerACSoftcapReturn); + else + softcap_armor *= RuleR(Combat, MiscACSoftcapReturn); } armor = softcap + softcap_armor; } - mitigation_rating = 0.0; - if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER) - { + if (GetClass() == WIZARD || GetClass() == MAGICIAN || + GetClass() == NECROMANCER || GetClass() == ENCHANTER) mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 4.0) + armor + 1; - } else - { mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 3.0) + (armor * 1.333333) + 1; - } mitigation_rating *= 0.847; mitigation_rating = mod_mitigation_rating(mitigation_rating, attacker); - if(attacker->IsClient()) - { + if (attacker->IsClient()) attack_rating = (attacker->CastToClient()->CalcATK() + ((attacker->GetSTR()-66) * 0.9) + (attacker->GetSkill(SkillOffense)*1.345)); - } else - { attack_rating = (attacker->GetATK() + (attacker->GetSkill(SkillOffense)*1.345) + ((attacker->GetSTR()-66) * 0.9)); - } attack_rating = attacker->mod_attack_rating(attack_rating, this); - float d = 10.0; - float mit_roll = MakeRandomFloat(0, mitigation_rating); - float atk_roll = MakeRandomFloat(0, attack_rating); - - if(atk_roll > mit_roll) - { - float a_diff = (atk_roll - mit_roll); - float thac0 = attack_rating * RuleR(Combat, ACthac0Factor); - float thac0cap = ((attacker->GetLevel() * 9) + 20); - if(thac0 > thac0cap) - { - thac0 = thac0cap; - } - d -= 10.0 * (a_diff / thac0); - } - else if(mit_roll > atk_roll) - { - float m_diff = (mit_roll - atk_roll); - float thac20 = mitigation_rating * RuleR(Combat, ACthac20Factor); - float thac20cap = ((defender->GetLevel() * 9) + 20); - if(thac20 > thac20cap) - { - thac20 = thac20cap; - - - - } - d += 10 * (m_diff / thac20); - } - - if(d < 0.0) - { - d = 0.0; - } - - if(d > 20) - { - d = 20.0; - } - - float interval = (damage - minhit) / 20.0; - damage = damage - ((int)d * interval); - } - else{ + damage = GetMeleeMitDmg(attacker, damage, minhit, mitigation_rating, attack_rating); + } else { //////////////////////////////////////////////////////// // Scorpious2k: Include AC in the calculation // use serverop variables to set values @@ -750,17 +700,100 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac if(damage != 0 && damage < minhit) damage = minhit; + //reduce the damage from shielding item and aa based on the min dmg + //spells offer pure mitigation + damage -= (minhit * defender->itembonuses.MeleeMitigation / 100); + damage -= (damage * defender->spellbonuses.MeleeMitigation / 100); } - //reduce the damage from shielding item and aa based on the min dmg - //spells offer pure mitigation - damage -= (minhit * defender->itembonuses.MeleeMitigation / 100); - damage -= (damage * defender->spellbonuses.MeleeMitigation / 100); - - if(damage < 0) + if (damage < 0) damage = 0; } +// This is called when the Mob is the one being hit +int32 Mob::GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, + float mit_rating, float atk_rating) +{ + float d = 10.0; + float mit_roll = MakeRandomFloat(0, mit_rating); + float atk_roll = MakeRandomFloat(0, atk_rating); + + if (atk_roll > mit_roll) { + float a_diff = atk_roll - mit_roll; + float thac0 = atk_rating * RuleR(Combat, ACthac0Factor); + float thac0cap = attacker->GetLevel() * 9 + 20; + if (thac0 > thac0cap) + thac0 = thac0cap; + + d -= 10.0 * (a_diff / thac0); + } else if (mit_roll > atk_roll) { + float m_diff = mit_roll - atk_roll; + float thac20 = mit_rating * RuleR(Combat, ACthac20Factor); + float thac20cap = GetLevel() * 9 + 20; + if (thac20 > thac20cap) + thac20 = thac20cap; + + d += 10.0 * (m_diff / thac20); + } + + if (d < 0.0) + d = 0.0; + else if (d > 20.0) + d = 20.0; + + float interval = (damage - minhit) / 20.0; + damage -= ((int)d * interval); + + damage -= (minhit * itembonuses.MeleeMitigation / 100); + damage -= (damage * spellbonuses.MeleeMitigation / 100); + return damage; +} + +// This is called when the Client is the one being hit +int32 Client::GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, + float mit_rating, float atk_rating) +{ + if (!attacker->IsNPC() || RuleB(Combat, UseOldDamageIntervalRules)) + return Mob::GetMeleeMitDmg(attacker, damage, minhit, mit_rating, atk_rating); + int d = 10; + // floats for the rounding issues + float dmg_interval = (damage - minhit) / 19.0; + float dmg_bonus = minhit - dmg_interval; + float spellMeleeMit = spellbonuses.MeleeMitigation / 100.0; + if (GetClass() == WARRIOR) + spellMeleeMit += 0.05; + dmg_bonus -= dmg_bonus * (itembonuses.MeleeMitigation / 100.0); + dmg_interval -= dmg_interval * spellMeleeMit; + + float mit_roll = MakeRandomFloat(0, mit_rating); + float atk_roll = MakeRandomFloat(0, atk_rating); + + if (atk_roll > mit_roll) { + float a_diff = atk_roll - mit_roll; + float thac0 = atk_rating * RuleR(Combat, ACthac0Factor); + float thac0cap = attacker->GetLevel() * 9 + 20; + if (thac0 > thac0cap) + thac0 = thac0cap; + + d += 10 * (a_diff / thac0); + } else if (mit_roll > atk_roll) { + float m_diff = mit_roll - atk_roll; + float thac20 = mit_rating * RuleR(Combat, ACthac20Factor); + float thac20cap = GetLevel() * 9 + 20; + if (thac20 > thac20cap) + thac20 = thac20cap; + + d -= 10 * (m_diff / thac20); + } + + if (d < 1) + d = 1; + else if (d > 20) + d = 20; + + return static_cast((dmg_bonus + dmg_interval * d)); +} + //Returns the weapon damage against the input mob //if we cannot hit the mob with the current weapon we will get a value less than or equal to zero //Else we know we can hit. @@ -1246,7 +1279,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b hate *= opts->hate_percent; hate += opts->hate_flat; } - + //check to see if we hit.. if(!other->CheckHitChance(this, skillinuse, Hand)) { mlog(COMBAT__ATTACKS, "Attack missed. Damage set to 0."); @@ -1314,7 +1347,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b if (IsDead()) return false; MeleeLifeTap(damage); - + if (damage > 0) CheckNumHitsRemaining(5); diff --git a/zone/client.h b/zone/client.h index c2ef8675e..d714bb007 100644 --- a/zone/client.h +++ b/zone/client.h @@ -221,6 +221,7 @@ public: virtual Raid* GetRaid() { return entity_list.GetRaidByClient(this); } virtual Group* GetGroup() { return entity_list.GetGroupByClient(this); } virtual inline bool IsBerserk() { return berserk; } + virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); void AI_Init(); void AI_Start(uint32 iMoveDelay = 0); diff --git a/zone/mob.h b/zone/mob.h index 7f64fbd90..703463ae9 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -143,6 +143,7 @@ public: virtual void DoRiposte(Mob* defender); void ApplyMeleeDamageBonus(uint16 skill, int32 &damage); virtual void MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts = nullptr); + virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); bool CombatRange(Mob* other); virtual inline bool IsBerserk() { return false; } // only clients From 0caa1fd40ba646a5c10ab10520eeace52e2b1e8b Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 20 Feb 2014 01:04:34 -0500 Subject: [PATCH 22/28] new spell effects buff struct/tables - required sql Removed: death_save_chance and deathsave_aa_chance (no longer used) Added: dot_rune, caston_x, caston_y, caston_z minor fixes --- common/spdat.cpp | 3 +- common/spdat.h | 104 +++++++++--------- .../git/required/2014_02_20_buff_update.txt | 16 +++ zone/attack.cpp | 26 ++++- zone/bonuses.cpp | 30 ++++- zone/bot.cpp | 29 ++--- zone/command.cpp | 3 - zone/common.h | 8 +- zone/spell_effects.cpp | 88 +++++++++------ zone/spells.cpp | 6 +- zone/zonedb.cpp | 35 +++--- 11 files changed, 215 insertions(+), 133 deletions(-) create mode 100644 utils/sql/git/required/2014_02_20_buff_update.txt diff --git a/common/spdat.cpp b/common/spdat.cpp index 807a1ba2d..04af27424 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -391,8 +391,7 @@ bool IsPartialCapableSpell(uint16 spell_id) return false; if (IsPureNukeSpell(spell_id) || IsFearSpell(spell_id) || - IsEffectInSpell(spell_id, SE_Root) || - IsEffectInSpell(spell_id, SE_Charm)) + IsEffectInSpell(spell_id, SE_Root)) return true; return false; diff --git a/common/spdat.h b/common/spdat.h index 237125b90..70f4c4b24 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -293,7 +293,7 @@ typedef enum { #define SE_LimitCastTimeMin 143 // implemented #define SE_LimitCastTimeMax 144 // implemented (*not used in any known live spell) #define SE_Teleport2 145 // implemented - Banishment of the Pantheon -#define SE_ElectricityResist 146 // *not implemented (Lightning Rod: 23233) +//#define SE_ElectricityResist 146 // *not implemented (Lightning Rod: 23233) #define SE_PercentalHeal 147 // implemented #define SE_StackingCommand_Block 148 // implemented? #define SE_StackingCommand_Overwrite 149 // implemented? @@ -349,73 +349,73 @@ typedef enum { #define SE_Taunt 199 // implemented - % chance to taunt the target #define SE_ProcChance 200 // implemented #define SE_RangedProc 201 // implemented -#define SE_IllusionOther 202 // *not implemented as bonus(Project Illusion) -#define SE_MassGroupBuff 203 // *not implemented as bonus +//#define SE_IllusionOther 202 // *not implemented as bonus(Project Illusion) +//#define SE_MassGroupBuff 203 // *not implemented as bonus #define SE_GroupFearImmunity 204 // *not implemented as bonus #define SE_Rampage 205 // implemented #define SE_AETaunt 206 // implemented #define SE_FleshToBone 207 // implemented //#define SE_PurgePoison 208 // not used #define SE_DispelBeneficial 209 // implemented -#define SE_PetShield 210 // *not implemented +//#define SE_PetShield 210 // *not implemented #define SE_AEMelee 211 // implemented -#define SE_CastingSkills 212 // *not implemented -Include/Exclude Casting Skill type. (*no longer used on live) +//#define SE_CastingSkills 212 // *not implemented -Include/Exclude Casting Skill type. (*no longer used on live) #define SE_PetMaxHP 213 // implemented[AA] - increases the maximum hit points of your pet #define SE_MaxHPChange 214 // implemented #define SE_PetAvoidance 215 // implemented[AA] - increases pet ability to avoid melee damage #define SE_Accuracy 216 // implemented -#define SE_HeadShot 217 // not implemented as bonus - ability to head shot (base2 = damage) +//#define SE_HeadShot 217 // not implemented as bonus - ability to head shot (base2 = damage) #define SE_PetCriticalHit 218 // implemented[AA] - gives pets a baseline critical hit chance #define SE_SlayUndead 219 // implemented - Allow extra damage against undead (base1 = rate, base2 = damage mod). #define SE_SkillDamageAmount 220 // implemented -#define SE_Packrat 221 // not implemented as bonus +#define SE_Packrat 221 // implemented as bonus #define SE_BlockBehind 222 // implemented - Chance to block from behind (with our without Shield) //#define SE_DoubleRiposte 223 // not used #define SE_GiveDoubleRiposte 224 // implemented[AA] #define SE_GiveDoubleAttack 225 // implemented[AA] - Allow any class to double attack with set chance. -#define SE_TwoHandBash 226 // not implemented as bonus +#define SE_TwoHandBash 226 // *not implemented as bonus #define SE_ReduceSkillTimer 227 // implemented #define SE_ReduceFallDamage 228 // not implented as bonus - reduce the damage that you take from falling #define SE_PersistantCasting 229 // implemented -#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability +//#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability #define SE_StunBashChance 231 // implemented - increase chance to stun from bash. #define SE_DivineSave 232 // implemented (base1 == % chance on death to insta-res) (base2 == spell cast on save) -#define SE_Metabolism 233 // *not implemented - (Crown of Feathers) Increase metabolism? -#define SE_ReduceApplyPoisonTime 234 // not implemented as bonus - reduces the time to apply poison +//#define SE_Metabolism 233 // *not implemented - (Crown of Feathers) Increase metabolism? +//#define SE_ReduceApplyPoisonTime 234 // not implemented as bonus - reduces the time to apply poison #define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live. //#define SE_FreePet 236 // not used #define SE_GivePetGroupTarget 237 // implemented[AA] - (Pet Affinity) -#define SE_IllusionPersistence 238 // *not implemented - lends persistence to your illusionary disguises, causing them to last until you die or the illusion is forcibly removed. -#define SE_FeignedCastOnChance 239 // *not implemented as bonus - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you. +//#define SE_IllusionPersistence 238 // *not implemented - lends persistence to your illusionary disguises, causing them to last until you die or the illusion is forcibly removed. +//#define SE_FeignedCastOnChance 239 // *not implemented as bonus - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you. //#define SE_StringUnbreakable 240 // not used [Likely related to above - you become immune to feign breaking on a resisted spell and have a good chance of feigning through a spell that successfully lands upon you.] #define SE_ImprovedReclaimEnergy 241 // not implemented as bonus - increase the amount of mana returned to you when reclaiming your pet. #define SE_IncreaseChanceMemwipe 242 // implemented - increases the chance to wipe hate with memory blurr #define SE_CharmBreakChance 243 // implemented - Total Domination #define SE_RootBreakChance 244 // implemented[AA] reduce the chance that your root will break. -#define SE_TrapCircumvention 245 // *not implemented[AA] - decreases the chance that you will set off a trap when opening a chest -#define SE_SetBreathLevel 246 // not implemented as bonus +//#define SE_TrapCircumvention 245 // *not implemented[AA] - decreases the chance that you will set off a trap when opening a chest +#define SE_SetBreathLevel 246 // *not implemented as bonus #define SE_RaiseSkillCap 247 // *not implemented[AA] - adds skill over the skill cap. -#define SE_SecondaryForte 248 // not implemented as bonus(gives you a 2nd specialize skill that can go past 50 to 100) +//#define SE_SecondaryForte 248 // not implemented as bonus(gives you a 2nd specialize skill that can go past 50 to 100) #define SE_SecondaryDmgInc 249 // implemented[AA] Allows off hand weapon to recieve a damage bonus (Sinister Strikes) #define SE_SpellProcChance 250 // implemented - Increase chance to sympathetic proc by % #define SE_ConsumeProjectile 251 // implemented[AA] - chance to not consume an arrow (ConsumeProjectile = 100) #define SE_FrontalBackstabChance 252 // implemented[AA] - chance to perform a full damage backstab from front. #define SE_FrontalBackstabMinDmg 253 // implemented[AA] - allow a frontal backstab for mininum damage. #define SE_Blank 254 // implemented -#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield -#define SE_ShroudofStealth 256 // not implemented as bonus - rogue improved invs -#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold +//#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield +//#define SE_ShroudofStealth 256 // not implemented as bonus - rogue improved invs +//#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold #define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab #define SE_CombatStability 259 // implemented[AA] - damage mitigation #define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType #define SE_SongModCap 261 // implemented[AA] - Song Mod cap increase (no longer used on live) #define SE_RaiseStatCap 262 // implemented #define SE_TradeSkillMastery 263 // implemented - lets you raise more than one tradeskill above master. -#define SE_HastenedAASkill 264 // not implemented as bonus - Use redux field in aa_actions table for this effect +//#define SE_HastenedAASkill 264 // not implemented as bonus - Use redux field in aa_actions table for this effect #define SE_MasteryofPast 265 // implemented[AA] - Spells less than effect values level can not be fizzled #define SE_ExtraAttackChance 266 // implemented - increase chance to score an extra attack with a 2-Handed Weapon. #define SE_PetDiscipline2 267 // *not implemented - /pet focus, /pet no cast -#define SE_ReduceTradeskillFail 268 // *not implemented? - reduces chance to fail with given tradeskill by a percent chance +//#define SE_ReduceTradeskillFail 268 // *not implemented? - reduces chance to fail with given tradeskill by a percent chance #define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound. #define SE_BardSongRange 270 // implemented[AA] - increase range of beneficial bard songs (Sionachie's Crescendo) #define SE_BaseMovementSpeed 271 // implemented[AA] - mods basemove speed, doesn't stack with other move mods @@ -428,11 +428,11 @@ typedef enum { #define SE_FinishingBlow 278 // implemented[AA] - chance to do massive damage under 10% HP (base1 = chance, base2 = damage) #define SE_Flurry 279 // implemented #define SE_PetFlurry 280 // implemented[AA] -#define SE_FeignedMinion 281 // *not implemented[AA] ability allows you to instruct your pet to feign death via the '/pet feign' command. value = succeed chance +//#define SE_FeignedMinion 281 // *not implemented[AA] ability allows you to instruct your pet to feign death via the '/pet feign' command. value = succeed chance #define SE_ImprovedBindWound 282 // implemented[AA] - increase bind wound amount by percent. #define SE_DoubleSpecialAttack 283 // implemented[AA] - Chance to perform second special attack as monk //#define SE_LoHSetHeal 284 // not used -#define SE_NimbleEvasion 285 // *not implemented - base1 = 100 for max +//#define SE_NimbleEvasion 285 // *not implemented - base1 = 100 for max #define SE_FcDamageAmt 286 // implemented - adds direct spell damage #define SE_SpellDurationIncByTic 287 // implemented #define SE_SpecialAttackKBProc 288 // implemented[AA] - Chance to to do a knockback from special attacks [AA Dragon Punch]. @@ -453,13 +453,13 @@ typedef enum { #define SE_FcDamageAmtCrit 303 // implemented - adds direct spell damage #define SE_OffhandRiposteFail 304 // implemented as bonus - enemy cannot riposte offhand attacks #define SE_MitigateDamageShield 305 // implemented - off hand attacks only (Shielding Resistance) -#define SE_ArmyOfTheDead 306 // *not implemented NecroAA - This ability calls up to five shades of nearby corpses back to life to serve the necromancer. The soulless abominations will mindlessly fight the target until called back to the afterlife some time later. The first rank summons up to three shades that serve for 60 seconds, and each additional rank adds one more possible shade and increases their duration by 15 seconds -#define SE_Appraisal 307 // *not implemented Rogue AA - This ability allows you to estimate the selling price of an item you are holding on your cursor. +//#define SE_ArmyOfTheDead 306 // *not implemented NecroAA - This ability calls up to five shades of nearby corpses back to life to serve the necromancer. The soulless abominations will mindlessly fight the target until called back to the afterlife some time later. The first rank summons up to three shades that serve for 60 seconds, and each additional rank adds one more possible shade and increases their duration by 15 seconds +//#define SE_Appraisal 307 // *not implemented Rogue AA - This ability allows you to estimate the selling price of an item you are holding on your cursor. #define SE_SuspendMinion 308 // not implemented as bonus #define SE_YetAnotherGate 309 // implemented #define SE_ReduceReuseTimer 310 // implemented #define SE_LimitCombatSkills 311 // implemented - Excludes focus from procs (except if proc is a memorizable spell) -#define SE_Sanctuary 312 // *not implemented +//#define SE_Sanctuary 312 // *not implemented #define SE_ForageAdditionalItems 313 // implemented[AA] - chance to forage additional items #define SE_Invisibility2 314 // implemented - fixed duration invisible #define SE_InvisVsUndead2 315 // implemented - fixed duration ITU @@ -472,14 +472,14 @@ typedef enum { #define SE_GateToHomeCity 322 // implemented #define SE_DefensiveProc 323 // implemented #define SE_HPToMana 324 // implemented -#define SE_ChanceInvsBreakToAoE 325 // *not implemented[AA] - [AA Nerves of Steel] increasing chance to remain hidden when they are an indirect target of an AoE spell. -#define SE_SpellSlotIncrease 326 // not implemented as bonus - increases your spell slot availability +//#define SE_ChanceInvsBreakToAoE 325 // *not implemented[AA] - [AA Nerves of Steel] increasing chance to remain hidden when they are an indirect target of an AoE spell. +#define SE_SpellSlotIncrease 326 // *not implemented as bonus - increases your spell slot availability #define SE_MysticalAttune 327 // implemented - increases amount of buffs that a player can have #define SE_DelayDeath 328 // implemented - increases how far you can fall below 0 hp before you die #define SE_ManaAbsorbPercentDamage 329 // implemented #define SE_CriticalDamageMob 330 // implemented -#define SE_Salvage 331 // *not implemented - chance to recover items that would be destroyed in failed tradeskill combine -#define SE_SummonToCorpse 332 // *not implemented AA - Call of the Wild (Druid/Shaman Res spell with no exp) +#define SE_Salvage 331 // implemented - chance to recover items that would be destroyed in failed tradeskill combine +//#define SE_SummonToCorpse 332 // *not implemented AA - Call of the Wild (Druid/Shaman Res spell with no exp) #define SE_EffectOnFade 333 // implemented #define SE_BardAEDot 334 // implemented #define SE_BlockNextSpellFocus 335 // implemented - base1 chance to block next spell ie Puratus (8494) @@ -492,15 +492,15 @@ typedef enum { #define SE_ImmuneFleeing 342 // implemented - stop mob from fleeing #define SE_InterruptCasting 343 // implemented - % chance to interrupt spells being cast every tic. Cacophony (8272) #define SE_ChannelChanceItems 344 // implemented[AA] - chance to not have ITEM effects interrupted when you take damage. -#define SE_AssassinationLevel 345 // not implemented as bonus - AA Assisination max level to kill -#define SE_HeadShotLevel 346 // not implemented as bonus - AA HeadShot max level to kill +//#define SE_AssassinationLevel 345 // not implemented as bonus - AA Assisination max level to kill +//#define SE_HeadShotLevel 346 // not implemented as bonus - AA HeadShot max level to kill #define SE_DoubleRangedAttack 347 // implemented - chance at an additional archery attack (consumes arrow) #define SE_LimitManaMin 348 // implemented #define SE_ShieldEquipHateMod 349 // implemented[AA] Increase melee hate when wearing a shield. #define SE_ManaBurn 350 // implemented - Drains mana for damage/heal at a defined ratio up to a defined maximum amount of mana. -#define SE_PersistentEffect 351 // *not implemented. creates a trap/totem that casts a spell (spell id + base1?) when anything comes near it. can probably make a beacon for this -#define SE_IncreaseTrapCount 352 // *not implemented - looks to be some type of invulnerability? Test ITC (8755) -#define SE_AdditionalAura 353 // *not implemented - allows use of more than 1 aura, aa effect +//#define SE_PersistentEffect 351 // *not implemented. creates a trap/totem that casts a spell (spell id + base1?) when anything comes near it. can probably make a beacon for this +//#define SE_IncreaseTrapCount 352 // *not implemented - looks to be some type of invulnerability? Test ITC (8755) +//#define SE_AdditionalAura 353 // *not implemented - allows use of more than 1 aura, aa effect //#define SE_DeactivateAllTraps 354 // *not implemented - looks to be some type of invulnerability? Test DAT (8757) //#define SE_LearnTrap 355 // *not implemented - looks to be some type of invulnerability? Test LT (8758) //#define SE_ChangeTriggerType 356 // not used @@ -509,17 +509,17 @@ typedef enum { #define SE_Invulnerabilty 359 // *not implemented - Invulnerability (Brell's Blessing) #define SE_SpellOnKill 360 // implemented - a buff that has a base1 % to cast spell base2 when you kill a "challenging foe" base3 min level #define SE_SpellOnDeath 361 // implemented - casts spell on death of buffed -#define SE_PotionBeltSlots 362 // *not implemented[AA] 'Quick Draw' expands the potion belt by one additional available item slot per rank. -#define SE_BandolierSlots 363 // *not implemented[AA] 'Battle Ready' expands the bandolier by one additional save slot per rank. +//#define SE_PotionBeltSlots 362 // *not implemented[AA] 'Quick Draw' expands the potion belt by one additional available item slot per rank. +//#define SE_BandolierSlots 363 // *not implemented[AA] 'Battle Ready' expands the bandolier by one additional save slot per rank. #define SE_TripleAttackChance 364 // implemented #define SE_SpellOnKill2 365 // implemented - chance to trigger a spell on kill when the kill is caused by a specific spell with this effect in it (10470 Venin) #define SE_ShieldEquipDmgMod 366 // implemented[AA] Damage modifier to melee if shield equiped. (base1 = dmg mod , base2 = ?) ie Shield Specialist AA #define SE_SetBodyType 367 // implemented - set body type of base1 so it can be affected by spells that are limited to that type (Plant, Animal, Undead, etc) -#define SE_FactionMod 368 // *not implemented - increases faction with base1 (faction id, live won't match up w/ ours) by base2 +//#define SE_FactionMod 368 // *not implemented - increases faction with base1 (faction id, live won't match up w/ ours) by base2 #define SE_CorruptionCounter 369 // implemented #define SE_ResistCorruption 370 // implemented #define SE_AttackSpeed4 371 // implemented - stackable slow effect 'Inhibit Melee' -#define SE_ForageSkill 372 // *not implemented[AA] Will increase the skill cap for those that have the Forage skill and grant the skill and raise the cap to those that do not. +//#define SE_ForageSkill 372 // *not implemented[AA] Will increase the skill cap for those that have the Forage skill and grant the skill and raise the cap to those that do not. #define SE_CastOnWearoff 373 // implemented - Triggers only if fades after natural duration. #define SE_ApplyEffect 374 // implemented #define SE_DotCritDmgIncrease 375 // implemented - Increase damage of DoT critical amount @@ -528,30 +528,30 @@ typedef enum { #define SE_SpellEffectResistChance 378 // implemented - Increase chance to resist specific spell effect (base1=value, base2=spell effect id) #define SE_ShadowStepDirectional 379 // implemented - handled by client #define SE_Knockdown 380 // implemented - small knock back(handled by client) -#define SE_KnockTowardCaster 381 // *not implemented (Call of Hither) knocks you back to caster (value) distance units infront +//#define SE_KnockTowardCaster 381 // *not implemented (Call of Hither) knocks you back to caster (value) distance units infront #define SE_NegateSpellEffect 382 // implemented - negates specific spell bonuses for duration of the debuff. #define SE_SympatheticProc 383 // implemented - focus on items that has chance to proc a spell when you cast #define SE_Leap 384 // implemented - Leap effect, ie stomping leap #define SE_LimitSpellGroup 385 // implemented - Limits to spell group(ie type 3 reuse reduction augs that are class specific and thus all share s SG) #define SE_CastOnCurer 386 // implemented - Casts a spell on the person curing #define SE_CastOnCure 387 // implemented - Casts a spell on the cured person -#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA) +//#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA) #define SE_FcTimerRefresh 389 // implemented - Refresh spell icons -#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited. +//#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited. #define SE_LimitManaMax 391 // implemented #define SE_FcHealAmt 392 // implemented - Adds or removes healing from spells #define SE_FcHealPctIncoming 393 // implemented - HealRate with focus restrictions. #define SE_FcHealAmtIncoming 394 // implemented - Adds/Removes amount of healing on target by X value with foucs restrictions. #define SE_FcHealPctCritIncoming 395 // implemented[AA] - Increases chance of having a heal crit when cast on you. [focus limited] #define SE_FcHealAmtCrit 396 // implemented - Adds a direct healing amount to spells -#define SE_PetMeleeMitigation 397 // *not implemented[AA] - additional mitigation to your pets. +//#define SE_PetMeleeMitigation 397 // *not implemented[AA] - additional mitigation to your pets. #define SE_SwarmPetDuration 398 // implemented - Affects the duration of swarm pets #define SE_FcTwincast 399 // implemented - cast 2 spells for every 1 #define SE_HealGroupFromMana 400 // implemented - Drains mana and heals for each point of mana drained #define SE_ManaDrainWithDmg 401 // implemented - Deals damage based on the amount of mana drained #define SE_EndDrainWithDmg 402 // implemented - Deals damage for the amount of endurance drained -#define SE_LimitSpellClass 403 // *not implemented - unclear what this refers too (not 'right click' spell bar) -#define SE_LimitSpellSubclass 404 // *not implemented - unclear what this refers too (not 'right click' spell bar) +//#define SE_LimitSpellClass 403 // *not implemented - unclear what this refers too (not 'right click' spell bar) +//#define SE_LimitSpellSubclass 404 // *not implemented - unclear what this refers too (not 'right click' spell bar) #define SE_TwoHandBluntBlock 405 // implemented - chance to block attacks when using two hand blunt weapons (similiar to shield block) #define SE_CastonNumHitFade 406 // implemented - casts a spell when a buff fades due to its numhits being depleted #define SE_CastonFocusEffect 407 // implemented - casts a spell if focus limits are met (ie triggers when a focus effects is applied) @@ -573,7 +573,7 @@ typedef enum { #define SE_LimitUseType 423 // implemented - limit a focus to require a certain numhits type #define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace //#define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626) -#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window +//#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window #define SE_SkillProc 427 // implemented - chance to proc when using a skill(ie taunt) #define SE_LimitToSkill 428 // implemented - limits what skills will effect a skill proc #define SE_SkillProc2 429 // implemented - chance to proc when using a skill (most have hit limits) @@ -584,20 +584,20 @@ typedef enum { #define SE_CriticalHealDecay 434 // implemented - increase critical heal chance, effect decays based on level of spell it effects. #define SE_CriticalRegenDecay 435 // implemented - increase critical heal over time chance, effect decays based on level of spell it effects. //#define SE_BeneficialCountDownHold 436 // not used ( 23491 | ABTest Buff Hold) -#define SE_TeleporttoAnchor 437 // *not implemented - Teleport Guild Hall Anchor(33099) -#define SE_TranslocatetoAnchor 438 // *not implemented - Translocate Primary Anchor (27750) -#define SE_IncreaseAssassinationLvl 439 // *not implemented[AA] - increases the maximum level of humanoid that can be affected by assassination +//#define SE_TeleporttoAnchor 437 // *not implemented - Teleport Guild Hall Anchor(33099) +//#define SE_TranslocatetoAnchor 438 // *not implemented - Translocate Primary Anchor (27750) +//#define SE_IncreaseAssassinationLvl 439 // *not implemented[AA] - increases the maximum level of humanoid that can be affected by assassination #define SE_FinishingBlowLvl 440 // implemented[AA] - Sets the level Finishing blow can be triggered on an NPC -#define SE_CancleIfMoved 441 // *not implemented - Buff is removed from target when target moves X amount of distance away from where initially hit. +#define SE_DistanceRemoval 441 // implemented - Buff is removed from target when target moves X amount of distance away from where initially hit. #define SE_TriggerOnReqTarget 442 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) #define SE_TriggerOnReqCaster 443 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) #define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y -#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs. +//#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs. //#define SE_AStacker 446 // *not implementet - bufff stacking blocker ? (26219 | Qirik's Watch) //#define SE_BStacker 447 // *not implemented //#define SE_CStacker 448 // *not implemented //#define SE_DStacker 449 // *not implemented -//#define SE_DotGuard 450 // *not implemented +#define SE_MitigateDotDamage 450 // implemented DOT spell mitigation rune with max value #define SE_MeleeThresholdGuard 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage #define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage #define SE_TriggerMeleeThreshold 453 // implemented Trigger effect on X amount of melee damage taken diff --git a/utils/sql/git/required/2014_02_20_buff_update.txt b/utils/sql/git/required/2014_02_20_buff_update.txt new file mode 100644 index 000000000..e691a0a67 --- /dev/null +++ b/utils/sql/git/required/2014_02_20_buff_update.txt @@ -0,0 +1,16 @@ +-- UPDATE BUFF TABLES +ALTER TABLE `character_buffs` CHANGE `death_save_chance` `dot_rune` INT(10) NOT NULL DEFAULT '0'; +ALTER TABLE `merc_buffs` CHANGE `DeathSaveSuccessChance` `dot_rune` INT(10) NOT NULL DEFAULT '0'; +ALTER TABLE `botbuffs` CHANGE `DeathSaveSuccessChance` `dot_rune` INT(10) NOT NULL DEFAULT '0'; + +ALTER TABLE `character_buffs` CHANGE `death_save_aa_chance` `caston_x` INT(10) NOT NULL DEFAULT '0'; +ALTER TABLE `merc_buffs` CHANGE `CasterAARank` `caston_x` INT(10) NOT NULL DEFAULT '0'; +ALTER TABLE `botbuffs` CHANGE `CasterAARank` `caston_x` INT(10) NOT NULL DEFAULT '0'; + +ALTER TABLE `character_buffs` ADD `caston_y` INT(10) NOT NULL DEFAULT '0'; +ALTER TABLE `merc_buffs` ADD `caston_y` INT(10) NOT NULL DEFAULT '0'; +ALTER TABLE `botbuffs` ADD `caston_y` INT(10) NOT NULL DEFAULT '0'; + +ALTER TABLE `character_buffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0'; +ALTER TABLE `merc_buffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0'; +ALTER TABLE `botbuffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0'; \ No newline at end of file diff --git a/zone/attack.cpp b/zone/attack.cpp index 73ae7053f..4467d6320 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3273,8 +3273,28 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi } // If this is a DoT, use DoT Shielding... - if(iBuffTic) - damage -= (damage * itembonuses.DoTShielding / 100); + if(iBuffTic) { + damage -= (damage * itembonuses.DoTShielding / 100); + + if (spellbonuses.MitigateDotRune[0]){ + slot = spellbonuses.MitigateDotRune[1]; + if(slot >= 0) + { + int damage_to_reduce = damage * spellbonuses.MitigateDotRune[0] / 100; + if(damage_to_reduce > buffs[slot].dot_rune) + { + damage -= damage_to_reduce; + if(!TryFadeEffect(slot)) + BuffFadeBySlot(slot); + } + else + { + buffs[slot].dot_rune = (buffs[slot].dot_rune - damage_to_reduce); + damage -= damage_to_reduce; + } + } + } + } // This must be a DD then so lets apply Spell Shielding and runes. else @@ -3342,7 +3362,7 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi BuffFadeBySlot(slot); } else{ - buffs[slot].melee_rune = (buffs[slot].magic_rune - damage); + buffs[slot].magic_rune = (buffs[slot].magic_rune - damage); } } } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index dc8776c67..f97bcd34b 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2239,6 +2239,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne } break; } + + case SE_MitigateDotDamage: + { + if (newbon->MitigateDotRune[0] < effect_value){ + newbon->MitigateDotRune[0] = effect_value; + newbon->MitigateDotRune[1] = buffslot; + } + break; + } case SE_ManaAbsorbPercentDamage: { @@ -2513,6 +2522,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne } break; + + case SE_DistanceRemoval: + newbon->DistanceRemoval = true; + break; + } } } @@ -3558,6 +3572,11 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) spellbonuses.MitigateSpellRune[1] = -1; break; + case SE_MitigateDotDamage: + spellbonuses.MitigateDotRune[0] = effect_value; + spellbonuses.MitigateDotRune[1] = -1; + break; + case SE_ManaAbsorbPercentDamage: spellbonuses.ManaAbsorbPercentDamage[0] = effect_value; spellbonuses.ManaAbsorbPercentDamage[1] = -1; @@ -3841,7 +3860,16 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.CriticalMend = effect_value; aabonuses.CriticalMend = effect_value; break; - + + case SE_DistanceRemoval: + spellbonuses.DistanceRemoval = effect_value; + break; + + case SE_ImprovedTaunt: + spellbonuses.ImprovedTaunt[0] = effect_value; + spellbonuses.ImprovedTaunt[1] = effect_value; + spellbonuses.ImprovedTaunt[2] = -1; + } } } diff --git a/zone/bot.cpp b/zone/bot.cpp index 3805dd025..9054df6a5 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2476,7 +2476,7 @@ void Bot::SaveBuffs() { if(!database.RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO botbuffs (BotId, SpellId, CasterLevel, DurationFormula, " "TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, " - "DeathSaveSuccessChance, CasterAARank, Persistent) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);", + "dot_rune, caston_x, Persistent, caston_y, caston_z) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);", GetBotID(), buffs[BuffCount].spellid, buffs[BuffCount].casterlevel, spells[buffs[BuffCount].spellid].buffdurationformula, buffs[BuffCount].ticsremaining, CalculatePoisonCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0, @@ -2484,8 +2484,8 @@ void Bot::SaveBuffs() { CalculateCurseCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0, CalculateCorruptionCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0, buffs[BuffCount].numhits, buffs[BuffCount].melee_rune, buffs[BuffCount].magic_rune, - buffs[BuffCount].deathSaveSuccessChance, - buffs[BuffCount].deathsaveCasterAARank, IsPersistent), TempErrorMessageBuffer)) { + buffs[BuffCount].dot_rune, + buffs[BuffCount].caston_x, IsPersistent, buffs[BuffCount].caston_y,buffs[BuffCount].caston_z), TempErrorMessageBuffer)) { errorMessage = std::string(TempErrorMessageBuffer); safe_delete(Query); Query = 0; @@ -2515,7 +2515,7 @@ void Bot::LoadBuffs() { bool BuffsLoaded = false; - if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, DeathSaveSuccessChance, CasterAARank, Persistent FROM botbuffs WHERE BotId = %u", GetBotID()), TempErrorMessageBuffer, &DatasetResult)) { + if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, caston_x, Persistent, caston_y, caston_z FROM botbuffs WHERE BotId = %u", GetBotID()), TempErrorMessageBuffer, &DatasetResult)) { errorMessage = std::string(TempErrorMessageBuffer); } else { @@ -2541,8 +2541,8 @@ void Bot::LoadBuffs() { buffs[BuffCount].numhits = atoi(DataRow[8]); buffs[BuffCount].melee_rune = atoi(DataRow[9]); buffs[BuffCount].magic_rune = atoi(DataRow[10]); - buffs[BuffCount].deathSaveSuccessChance = atoi(DataRow[11]); - buffs[BuffCount].deathsaveCasterAARank = atoi(DataRow[12]); + buffs[BuffCount].dot_rune = atoi(DataRow[11]); + buffs[BuffCount].caston_x = atoi(DataRow[12]); buffs[BuffCount].casterid = 0; bool IsPersistent = false; @@ -2550,6 +2550,9 @@ void Bot::LoadBuffs() { if(atoi(DataRow[13])) IsPersistent = true; + buffs[BuffCount].caston_x = atoi(DataRow[14]); + buffs[BuffCount].caston_x = atoi(DataRow[15]); + buffs[BuffCount].persistant_buff = IsPersistent; BuffCount++; @@ -6818,13 +6821,6 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) SpellSkill_Found = true; break; - case SE_LimitSpellSubclass:{ - int16 spell_skill = spell.skill * -1; - if(base1 == spell_skill) - LimitFound = true; - break; - } - case SE_LimitClass: //Do not use this limit more then once per spell. If multiple class, treat value like items would. if (!PassLimitClass(base1, GetClass())) @@ -7423,13 +7419,6 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel SpellSkill_Found = true; break; - case SE_LimitSpellSubclass:{ - int16 spell_skill = spell.skill * -1; - if(focus_spell.base[i] == spell_skill) - return 0; - break; - } - case SE_LimitClass: //Do not use this limit more then once per spell. If multiple class, treat value like items would. if (!PassLimitClass(focus_spell.base[i], GetClass())) diff --git a/zone/command.cpp b/zone/command.cpp index 329584140..1b8ce3365 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -11047,9 +11047,6 @@ void command_showbonusstats(Client *c, const Seperator *sep) c->Message(0, " Target Spell Bonuses:"); c->Message(0, " Accuracy: %i%% Divine Save: %i%%",c->GetTarget()->GetSpellBonuses().Accuracy, c->GetTarget()->GetSpellBonuses().DivineSaveChance); c->Message(0, " Flurry: %i%% HitChance: %i%% ",c->GetTarget()->GetSpellBonuses().FlurryChance, c->GetTarget()->GetSpellBonuses().HitChance / 15); - int deathsaveslot = c->GetTarget()->GetBuffSlotFromType(SE_DeathSave); - int dschance = deathsaveslot >= 0 ? c->GetTarget()->GetBuffs()[deathsaveslot].deathSaveSuccessChance : 0; - c->Message(0, " Death Save: %i%%",dschance); } c->Message(0, " Effective Casting Level: %i",c->GetTarget()->GetCasterLevel(0)); } diff --git a/zone/common.h b/zone/common.h index 622dafb6f..97b94887a 100644 --- a/zone/common.h +++ b/zone/common.h @@ -155,8 +155,10 @@ struct Buffs_Struct { uint32 numhits; //the number of physical hits this buff can take before it fades away, lots of druid armor spells take advantage of this mixed with powerful effects uint32 melee_rune; uint32 magic_rune; - uint8 deathSaveSuccessChance; - uint8 deathsaveCasterAARank; + uint32 dot_rune; + uint32 caston_x; + uint32 caston_y; + uint32 caston_z; bool persistant_buff; bool client; //True if the caster is a client bool UpdateClient; @@ -319,6 +321,7 @@ struct StatBonuses { uint16 MeleeThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. uint16 SpellThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. uint16 MitigateSpellRune[2]; // 0 = Mitigation value 1 = Buff Slot + uint16 MitigateDotRune[2]; // 0 = Mitigation value 1 = Buff Slot uint32 TriggerMeleeThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger uint32 TriggerSpellThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger uint16 ManaAbsorbPercentDamage[2]; // 0 = Mitigation value 1 = Buff Slot @@ -328,6 +331,7 @@ struct StatBonuses { bool CriticalHealDecay; // increase critical heal chance, decays based on spell level cast bool CriticalDotDecay; // increase critical dot chance, decays based on spell level cast bool DivineAura; // invulnerability + bool DistanceRemoval; // Check if Cancle if Moved effect is present int16 ImprovedTaunt[3]; // 0 = Max Level 1 = Aggro modifier 2 = buffid //bool AbsorbMagicAtt; // Magic Rune *Need to be implemented for NegateEffect //bool MeleeRune; // Melee Rune *Need to be implemented for NegateEffect diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 75c83cb3e..f307e08e2 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1284,6 +1284,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } + case SE_MitigateDotDamage: + { + buffs[buffslot].dot_rune = spells[spell_id].max[i]; + break; + } + case SE_TriggerMeleeThreshold: { buffs[buffslot].melee_rune = spells[spell_id].base2[i]; @@ -1296,7 +1302,14 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - + case SE_DistanceRemoval: + { + buffs[buffslot].caston_x = int(GetX()); + buffs[buffslot].caston_y = int(GetY()); + buffs[buffslot].caston_z = int(GetZ()); + break; + } + case SE_Levitate: { #ifdef SPELL_EFFECT_SPAM @@ -2361,30 +2374,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - case SE_DeathSave: { -#ifdef SPELL_EFFECT_SPAM - snprintf(effect_desc, _EDLEN, "Death Save: %+i", effect_value); -#endif - uint8 BonusChance = 0; - if(caster) { - - BonusChance = caster->aabonuses.UnfailingDivinity + - caster->itembonuses.UnfailingDivinity + - caster->spellbonuses.UnfailingDivinity; - } - -#ifdef SPELL_EFFECT_SPAM - //snprintf(effect_desc, _EDLEN, "Death Save Chance: %+i", SuccessChance); -#endif - //buffs[buffslot].deathSaveSuccessChance = SuccessChance; - //buffs[buffslot].deathsaveCasterAARank = caster->GetAA(aaUnfailingDivinity); - buffs[buffslot].deathsaveCasterAARank = BonusChance; - //SetDeathSaveChance(true); - - - break; - } - case SE_SummonAndResAllCorpses: { if(IsClient()) @@ -2763,7 +2752,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_MitigateDamageShield: case SE_FcBaseEffects: case SE_LimitClass: - case SE_LimitSpellSubclass: case SE_BlockBehind: case SE_ShieldBlock: case SE_PetCriticalHit: @@ -2816,6 +2804,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_IncreaseChanceMemwipe: case SE_CriticalMend: case SE_LimitCastTimeMax: + case SE_DeathSave: + case SE_TriggerOnReqCaster: { break; } @@ -3378,6 +3368,26 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste } break; } + + case SE_DistanceRemoval: + { + if (spellbonuses.DistanceRemoval){ + + int distance = sqrt( + ((int(GetX()) - buffs[slot].caston_x) * (int(GetX()) - buffs[slot].caston_x)) + + ((int(GetY()) - buffs[slot].caston_y) * (int(GetY()) - buffs[slot].caston_y)) + + ((int(GetZ()) - buffs[slot].caston_z) * (int(GetZ()) - buffs[slot].caston_z)) + ); + + if (distance > spells[spell_id].base[i]){ + + if(!TryFadeEffect(slot)) + BuffFadeBySlot(slot , true); + } + break; + } + } + default: { // do we need to do anyting here? @@ -5249,9 +5259,14 @@ bool Mob::TryDeathSave() { int SuccessChance = 0; int buffSlot = spellbonuses.DeathSave[1]; - uint8 UD_HealMod = buffs[buffSlot].deathsaveCasterAARank; //Contains value of UD heal modifier. + int16 UD_HealMod = 0; uint32 HealAmt = 300; //Death Pact max Heal + Mob* caster = entity_list.GetMobID(buffs[buffSlot].casterid); + + if (caster) + UD_HealMod = caster->spellbonuses.UnfailingDivinity + caster->itembonuses.UnfailingDivinity + caster->aabonuses.UnfailingDivinity; + if(buffSlot >= 0){ SuccessChance = ( (GetCHA() * (RuleI(Spells, DeathSaveCharismaMod))) + 1) / 10; //(CHA Mod Default = 3) @@ -5580,19 +5595,24 @@ bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){ bool Mob::ImprovedTaunt(){ - if (spellbonuses.ImprovedTaunt[2]){ + if (spellbonuses.ImprovedTaunt[0]){ if (GetLevel() > spellbonuses.ImprovedTaunt[0]) return false; - target = entity_list.GetMob(buffs[spellbonuses.ImprovedTaunt[2]].casterid); + if (spellbonuses.ImprovedTaunt[2] >= 0){ - if (target){ - SetTarget(target); - return true; + target = entity_list.GetMob(buffs[spellbonuses.ImprovedTaunt[2]].casterid); + + if (target){ + SetTarget(target); + return true; + } + else { + if(!TryFadeEffect(spellbonuses.ImprovedTaunt[2])) + BuffFadeBySlot(spellbonuses.ImprovedTaunt[2], true); //If caster killed removed effect. + } } - else - BuffFadeBySlot(spellbonuses.ImprovedTaunt[2]); //If caster killed removed effect. } return false; diff --git a/zone/spells.cpp b/zone/spells.cpp index ca3fef4fa..de16af190 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2953,8 +2953,10 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid buffs[emptyslot].numhits = spells[spell_id].numhits; buffs[emptyslot].client = caster ? caster->IsClient() : 0; buffs[emptyslot].persistant_buff = 0; - buffs[emptyslot].deathsaveCasterAARank = 0; - buffs[emptyslot].deathSaveSuccessChance = 0; + buffs[emptyslot].caston_x = 0; + buffs[emptyslot].caston_y = 0; + buffs[emptyslot].caston_z = 0; + buffs[emptyslot].dot_rune = 0; if (level_override > 0) { buffs[emptyslot].UpdateClient = true; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 480cd80cb..aa68888fd 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1815,7 +1815,7 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) { if(!database.RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO merc_buffs (MercId, SpellId, CasterLevel, DurationFormula, " "TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, " - "DeathSaveSuccessChance, CasterAARank, Persistent) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);", + "dot_rune, caston_x, Persistent, caston_y, caston_z) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);", merc->GetMercID(), buffs[BuffCount].spellid, buffs[BuffCount].casterlevel, spells[buffs[BuffCount].spellid].buffdurationformula, buffs[BuffCount].ticsremaining, CalculatePoisonCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0, @@ -1823,8 +1823,8 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) { CalculateCurseCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0, CalculateCorruptionCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0, buffs[BuffCount].numhits, buffs[BuffCount].melee_rune, buffs[BuffCount].magic_rune, - buffs[BuffCount].deathSaveSuccessChance, - buffs[BuffCount].deathsaveCasterAARank, IsPersistent), TempErrorMessageBuffer)) { + buffs[BuffCount].dot_rune, + buffs[BuffCount].caston_x, IsPersistent, buffs[BuffCount].caston_y, buffs[BuffCount].caston_z), TempErrorMessageBuffer)) { errorMessage = std::string(TempErrorMessageBuffer); safe_delete(Query); Query = 0; @@ -1856,7 +1856,7 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) { bool BuffsLoaded = false; - if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, DeathSaveSuccessChance, CasterAARank, Persistent FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer, &DatasetResult)) { + if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, CasterAARank, Persistent FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer, &DatasetResult)) { errorMessage = std::string(TempErrorMessageBuffer); } else { @@ -1882,8 +1882,8 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) { buffs[BuffCount].numhits = atoi(DataRow[8]); buffs[BuffCount].melee_rune = atoi(DataRow[9]); buffs[BuffCount].magic_rune = atoi(DataRow[10]); - buffs[BuffCount].deathSaveSuccessChance = atoi(DataRow[11]); - buffs[BuffCount].deathsaveCasterAARank = atoi(DataRow[12]); + buffs[BuffCount].dot_rune = atoi(DataRow[11]); + buffs[BuffCount].caston_x = atoi(DataRow[12]); buffs[BuffCount].casterid = 0; bool IsPersistent = false; @@ -1891,6 +1891,9 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) { if(atoi(DataRow[13])) IsPersistent = true; + buffs[BuffCount].caston_y = atoi(DataRow[13]); + buffs[BuffCount].caston_z = atoi(DataRow[14]); + buffs[BuffCount].persistant_buff = IsPersistent; BuffCount++; @@ -2566,11 +2569,11 @@ void ZoneDatabase::SaveBuffs(Client *c) { for (int i = 0; i < buff_count; i++) { if(buffs[i].spellid != SPELL_UNKNOWN) { if(!database.RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `character_buffs` (character_id, slot_id, spell_id, " - "caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, magic_rune, persistent, death_save_chance, " - "death_save_aa_chance) VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", + "caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, magic_rune, persistent, dot_rune, " + "caston_x, caston_y, caston_z) VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", c->CharacterID(), i, buffs[i].spellid, buffs[i].casterlevel, buffs[i].caster_name, buffs[i].ticsremaining, buffs[i].counters, buffs[i].numhits, buffs[i].melee_rune, buffs[i].magic_rune, buffs[i].persistant_buff, - buffs[i].deathSaveSuccessChance, buffs[i].deathsaveCasterAARank), + buffs[i].dot_rune, buffs[i].caston_x, buffs[i].caston_y, buffs[i].caston_z), errbuf)) { LogFile->write(EQEMuLog::Error, "Error in SaveBuffs query '%s': %s", query, errbuf); } @@ -2592,7 +2595,7 @@ void ZoneDatabase::LoadBuffs(Client *c) { MYSQL_RES *result; MYSQL_ROW row; if (RunQuery(query, MakeAnyLenString(&query, "SELECT spell_id, slot_id, caster_level, caster_name, ticsremaining, counters, " - "numhits, melee_rune, magic_rune, persistent, death_save_chance, death_save_aa_chance FROM `character_buffs` WHERE " + "numhits, melee_rune, magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z FROM `character_buffs` WHERE " "`character_id`='%u'", c->CharacterID()), errbuf, &result)) { @@ -2617,8 +2620,10 @@ void ZoneDatabase::LoadBuffs(Client *c) { uint32 melee_rune = atoul(row[7]); uint32 magic_rune = atoul(row[8]); uint8 persistent = atoul(row[9]); - uint32 death_save_chance = atoul(row[10]); - uint32 death_save_aa_chance = atoul(row[11]); + uint32 dot_rune = atoul(row[10]); + uint32 caston_x = atoul(row[11]); + uint32 caston_y = atoul(row[12]); + uint32 caston_z = atoul(row[13]); buffs[slot_id].spellid = spell_id; buffs[slot_id].casterlevel = caster_level; @@ -2638,8 +2643,10 @@ void ZoneDatabase::LoadBuffs(Client *c) { buffs[slot_id].melee_rune = melee_rune; buffs[slot_id].magic_rune = magic_rune; buffs[slot_id].persistant_buff = persistent ? true : false; - buffs[slot_id].deathSaveSuccessChance = death_save_chance; - buffs[slot_id].deathsaveCasterAARank = death_save_aa_chance; + buffs[slot_id].dot_rune = dot_rune; + buffs[slot_id].caston_x = caston_x; + buffs[slot_id].caston_y = caston_y; + buffs[slot_id].caston_z = caston_z; buffs[slot_id].UpdateClient = false; if(IsRuneSpell(spell_id)) { c->SetHasRune(true); From 402a10c4881e88212bd7fdddb4ea6da635f3f3a1 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 20 Feb 2014 01:05:44 -0500 Subject: [PATCH 23/28] change log --- changelog.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.txt b/changelog.txt index eb1785b41..7ad5f7ae6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,11 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/20/2014 == +Kayen: Implemented SE_MitigateDotDamage - dot spell mitigation rune with max value +Kayen: Implemented SE_DistanceRemoval - removed from target when target moves X amount of distance away from where initially hit. + +Required SQL: utils/sql/git/2014_02_20_buff_updates.sql + == 02/18/2014 == Kayen: Implemented SE_TriggerOnReqCaster - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) Kayen: Implemented SE_ImprovedTaunt - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y From 808977f69a6268d11e1aaa0b999ad1666aed1f53 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 20 Feb 2014 01:35:59 -0500 Subject: [PATCH 24/28] (Performance) Corpse drag will now fetch entity by ID --- zone/client.cpp | 23 ++++++++++++----------- zone/client.h | 4 ++-- zone/client_packet.cpp | 8 ++++---- zone/entity.cpp | 4 ++-- zone/entity.h | 2 +- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 114550ebc..6cf490960 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6045,11 +6045,10 @@ void Client::NPCSpawn(NPC *target_npc, const char *identifier, uint32 extra) } } -bool Client::IsDraggingCorpse(const char *CorpseName) +bool Client::IsDraggingCorpse(uint16 CorpseID) { - for(std::list::iterator Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator) - { - if(!strcasecmp((*Iterator).c_str(), CorpseName)) + for (auto It = DraggedCorpses.begin(); It != DraggedCorpses.end(); ++It) { + if (It->second == CorpseID) return true; } @@ -6058,20 +6057,22 @@ bool Client::IsDraggingCorpse(const char *CorpseName) void Client::DragCorpses() { - for(std::list::iterator Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator) - { - Mob* corpse = entity_list.GetMob((*Iterator).c_str()); + for (auto It = DraggedCorpses.begin(); It != DraggedCorpses.end(); ++It) { + Mob *corpse = entity_list.GetMob(It->second); - if(corpse && corpse->IsPlayerCorpse() && (DistNoRootNoZ(*corpse) <= RuleR(Character, DragCorpseDistance))) + if (corpse && corpse->IsPlayerCorpse() && + (DistNoRootNoZ(*corpse) <= RuleR(Character, DragCorpseDistance))) continue; - if(!corpse || !corpse->IsPlayerCorpse() || corpse->CastToCorpse()->IsBeingLooted() || !corpse->CastToCorpse()->Summon(this, false, false)) - { + if (!corpse || !corpse->IsPlayerCorpse() || + corpse->CastToCorpse()->IsBeingLooted() || + !corpse->CastToCorpse()->Summon(this, false, false)) { Message_StringID(MT_DefaultText, CORPSEDRAG_STOP); - Iterator = DraggedCorpses.erase(Iterator); + It = DraggedCorpses.erase(It); } } } + void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_override, int pet_count, int pet_duration) { if(!target || !IsValidSpell(spell_id) || this->GetID() == target->GetID()) diff --git a/zone/client.h b/zone/client.h index d714bb007..be1c29c1c 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1078,7 +1078,7 @@ public: void ClearHover(); inline bool IsBlockedBuff(int16 SpellID) { return PlayerBlockedBuffs.find(SpellID) != PlayerBlockedBuffs.end(); } inline bool IsBlockedPetBuff(int16 SpellID) { return PetBlockedBuffs.find(SpellID) != PetBlockedBuffs.end(); } - bool IsDraggingCorpse(const char* CorpseName); + bool IsDraggingCorpse(uint16 CorpseID); inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); } void DragCorpses(); inline void ClearDraggedCorpses() { DraggedCorpses.clear(); } @@ -1481,7 +1481,7 @@ private: std::set PlayerBlockedBuffs; std::set PetBlockedBuffs; - std::list DraggedCorpses; + std::list > DraggedCorpses; uint8 MaxXTargets; bool XTargetAutoAddHaters; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 010d66fcb..387afa3ec 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -12379,7 +12379,7 @@ void Client::Handle_OP_CorpseDrag(const EQApplicationPacket *app) if(!corpse || !corpse->IsPlayerCorpse() || corpse->CastToCorpse()->IsBeingLooted()) return; - Client *c = entity_list.FindCorpseDragger(cds->CorpseName); + Client *c = entity_list.FindCorpseDragger(corpse->GetID()); if(c) { @@ -12394,7 +12394,7 @@ void Client::Handle_OP_CorpseDrag(const EQApplicationPacket *app) if(!corpse->CastToCorpse()->Summon(this, false, true)) return; - DraggedCorpses.push_back(cds->CorpseName); + DraggedCorpses.push_back(std::pair(cds->CorpseName, corpse->GetID())); Message_StringID(MT_DefaultText, CORPSEDRAG_BEGIN, cds->CorpseName); } @@ -12408,9 +12408,9 @@ void Client::Handle_OP_CorpseDrop(const EQApplicationPacket *app) return; } - for(std::list::iterator Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator) + for (auto Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator) { - if(!strcasecmp((*Iterator).c_str(), (const char *)app->pBuffer)) + if(!strcasecmp(Iterator->first.c_str(), (const char *)app->pBuffer)) { Message_StringID(MT_DefaultText, CORPSEDRAG_STOP); Iterator = DraggedCorpses.erase(Iterator); diff --git a/zone/entity.cpp b/zone/entity.cpp index 8f4b663ea..9103ed157 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4512,11 +4512,11 @@ void EntityList::GetTargetsForConeArea(Mob *start, uint32 radius, uint32 height, } } -Client *EntityList::FindCorpseDragger(const char *CorpseName) +Client *EntityList::FindCorpseDragger(uint16 CorpseID) { auto it = client_list.begin(); while (it != client_list.end()) { - if (it->second->IsDraggingCorpse(CorpseName)) + if (it->second->IsDraggingCorpse(CorpseID)) return it->second; ++it; } diff --git a/zone/entity.h b/zone/entity.h index 9de73ff0e..dbdeb5dcd 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -167,7 +167,7 @@ public: Spawn2* GetSpawnByID(uint32 id); - Client* FindCorpseDragger(const char *CorpseName); + Client* FindCorpseDragger(uint16 CorpseID); inline Object *GetObjectByID(uint16 id) { return object_list.count(id) ? object_list.at(id) : nullptr; } From 451d422b8a68eb0ce060dbf0e6f6d980a8d13d07 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 21 Feb 2014 04:04:18 -0500 Subject: [PATCH 25/28] Keep track of base spell id for SpellProcs/PermaProcs This will fix numhits issue for procs from spells --- zone/client_packet.cpp | 2 +- zone/mob.h | 2 +- zone/pets.cpp | 4 ++-- zone/spell_effects.cpp | 4 ++-- zone/spells.cpp | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 387afa3ec..af17626fb 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -9466,7 +9466,7 @@ void Client::CompleteConnect() case SE_AddMeleeProc: case SE_WeaponProc: { - AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100+spells[buffs[j1].spellid].base2[x1]); + AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100+spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid); break; } case SE_DefensiveProc: diff --git a/zone/mob.h b/zone/mob.h index 6ae558915..f636b5ea7 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -500,7 +500,7 @@ public: bool AddSkillProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN); bool RemoveSkillProc(uint16 spell_id, bool bAll = false); bool HasSkillProcs() const; - bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3); + bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN); bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false); bool HasProcs() const; diff --git a/zone/pets.cpp b/zone/pets.cpp index 7254f2690..5e81c3f84 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -605,9 +605,9 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) { // We need to reapply buff based procs // We need to do this here so suspended pets also regain their procs. if (spells[buffs[j1].spellid].base2[x1] == 0) { - AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100); + AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100, buffs[j1].spellid); } else { - AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100+spells[buffs[j1].spellid].base2[x1]); + AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100+spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid); } break; case SE_Charm: diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 75c83cb3e..28f806483 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1695,9 +1695,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #endif if(spells[spell_id].base2[i] == 0) - AddProcToWeapon(procid, false, 100); + AddProcToWeapon(procid, false, 100, spell_id); else - AddProcToWeapon(procid, false, spells[spell_id].base2[i]+100); + AddProcToWeapon(procid, false, spells[spell_id].base2[i]+100, spell_id); break; } diff --git a/zone/spells.cpp b/zone/spells.cpp index ca3fef4fa..7da17ff82 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -4824,7 +4824,7 @@ bool Mob::FindType(uint16 type, bool bOffensive, uint16 threshold) { return false; } -bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance) { +bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id) { if(spell_id == SPELL_UNKNOWN) return(false); @@ -4834,7 +4834,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance) { if (PermaProcs[i].spellID == SPELL_UNKNOWN) { PermaProcs[i].spellID = spell_id; PermaProcs[i].chance = iChance; - PermaProcs[i].base_spellID = SPELL_UNKNOWN; + PermaProcs[i].base_spellID = base_spell_id; mlog(SPELLS__PROCS, "Added permanent proc spell %d with chance %d to slot %d", spell_id, iChance, i); return true; @@ -4846,7 +4846,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance) { if (SpellProcs[i].spellID == SPELL_UNKNOWN) { SpellProcs[i].spellID = spell_id; SpellProcs[i].chance = iChance; - SpellProcs[i].base_spellID = SPELL_UNKNOWN;; + SpellProcs[i].base_spellID = base_spell_id;; mlog(SPELLS__PROCS, "Added spell-granted proc spell %d with chance %d to slot %d", spell_id, iChance, i); return true; } From 026f019f58bcd5129e2fc9f3c151b33a038d0b2b Mon Sep 17 00:00:00 2001 From: Michael Cook Date: Fri, 21 Feb 2014 22:57:15 -0500 Subject: [PATCH 26/28] Changed SE_SingingSkill to SE_Amplificatoin This effect will now stack with other singing spell/item mods like it does on live. --- common/spdat.h | 2 +- zone/bonuses.cpp | 15 ++++++--------- zone/client_mods.cpp | 2 +- zone/common.h | 1 + zone/spell_effects.cpp | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/common/spdat.h b/common/spdat.h index 237125b90..9a6c1b1ea 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -265,7 +265,7 @@ typedef enum { #define SE_Hunger 115 // implemented - Song of Sustenance #define SE_CurseCounter 116 // implemented #define SE_MagicWeapon 117 // implemented - makes weapon magical -#define SE_SingingSkill 118 // *implemented - needs AA conversion +#define SE_Amplification 118 // implemented - Harmonize/Amplification (stacks with other singing mods) #define SE_AttackSpeed3 119 // implemented #define SE_HealRate 120 // implemented - reduces healing by a % #define SE_ReverseDS 121 // implemented diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index dc8776c67..c92de1034 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1607,12 +1607,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->reflect_chance += effect_value; break; - case SE_SingingSkill: - { - if(effect_value > newbon->singingMod) - newbon->singingMod = effect_value; + case SE_Amplification: + newbon->Amplification += effect_value; break; - } case SE_ChangeAggro: newbon->hatemod += effect_value; @@ -3124,10 +3121,10 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.reflect_chance = effect_value; break; - case SE_SingingSkill: - spellbonuses.singingMod = effect_value; - itembonuses.singingMod = effect_value; - aabonuses.singingMod = effect_value; + case SE_Amplification: + spellbonuses.Amplification = effect_value; + itembonuses.Amplification = effect_value; + aabonuses.Amplification = effect_value; break; case SE_ChangeAggro: diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 925aa15a4..8c29f05eb 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -1857,7 +1857,7 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const effectmod = itembonuses.singingMod; else effectmod = spellbonuses.singingMod; - effectmod += aabonuses.singingMod; + effectmod += aabonuses.singingMod + spellbonuses.Amplification; break; default: effectmod = 10; diff --git a/zone/common.h b/zone/common.h index 622dafb6f..8ac23b5df 100644 --- a/zone/common.h +++ b/zone/common.h @@ -231,6 +231,7 @@ struct StatBonuses { int effective_casting_level; int reflect_chance; // chance to reflect incoming spell uint16 singingMod; + uint16 Amplification; // stacks with singingMod uint16 brassMod; uint16 percussionMod; uint16 windMod; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 28f806483..03a5d6d2e 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2631,7 +2631,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_MeleeMitigation: case SE_Reflect: case SE_Screech: - case SE_SingingSkill: + case SE_Amplification: case SE_MagicWeapon: case SE_Hunger: case SE_MagnifyVision: From 44c833fbe6666d3b8746fbefbebf31afbe85a1dc Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 22 Feb 2014 01:34:16 -0500 Subject: [PATCH 27/28] fixes Re implemented deathsavechanceAA ect as ExtraDIChance Confirmed on live that this effect persists even if caster not in zone. --- .../git/required/2014_02_20_buff_update.txt | 6 +- zone/bot.cpp | 15 +++-- zone/common.h | 7 ++- zone/spell_effects.cpp | 60 ++++++++++++++++--- zone/spells.cpp | 1 + zone/zonedb.cpp | 30 +++++----- 6 files changed, 88 insertions(+), 31 deletions(-) diff --git a/utils/sql/git/required/2014_02_20_buff_update.txt b/utils/sql/git/required/2014_02_20_buff_update.txt index e691a0a67..a53930481 100644 --- a/utils/sql/git/required/2014_02_20_buff_update.txt +++ b/utils/sql/git/required/2014_02_20_buff_update.txt @@ -13,4 +13,8 @@ ALTER TABLE `botbuffs` ADD `caston_y` INT(10) NOT NULL DEFAULT '0'; ALTER TABLE `character_buffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0'; ALTER TABLE `merc_buffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0'; -ALTER TABLE `botbuffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0'; \ No newline at end of file +ALTER TABLE `botbuffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0'; + +ALTER TABLE `character_buffs` ADD `ExtraDIChance` INT(10) NOT NULL DEFAULT '0'; +ALTER TABLE `merc_buffs` ADD `ExtraDIChance` INT(10) NOT NULL DEFAULT '0'; +ALTER TABLE `botbuffs` ADD `ExtraDIChance` INT(10) NOT NULL DEFAULT '0'; \ No newline at end of file diff --git a/zone/bot.cpp b/zone/bot.cpp index 9054df6a5..a7ff02f1b 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2476,7 +2476,7 @@ void Bot::SaveBuffs() { if(!database.RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO botbuffs (BotId, SpellId, CasterLevel, DurationFormula, " "TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, " - "dot_rune, caston_x, Persistent, caston_y, caston_z) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);", + "dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);", GetBotID(), buffs[BuffCount].spellid, buffs[BuffCount].casterlevel, spells[buffs[BuffCount].spellid].buffdurationformula, buffs[BuffCount].ticsremaining, CalculatePoisonCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0, @@ -2485,7 +2485,11 @@ void Bot::SaveBuffs() { CalculateCorruptionCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0, buffs[BuffCount].numhits, buffs[BuffCount].melee_rune, buffs[BuffCount].magic_rune, buffs[BuffCount].dot_rune, - buffs[BuffCount].caston_x, IsPersistent, buffs[BuffCount].caston_y,buffs[BuffCount].caston_z), TempErrorMessageBuffer)) { + buffs[BuffCount].caston_x, + IsPersistent, + buffs[BuffCount].caston_y, + buffs[BuffCount].caston_z, + buffs[BuffCount].ExtraDIChance), TempErrorMessageBuffer)) { errorMessage = std::string(TempErrorMessageBuffer); safe_delete(Query); Query = 0; @@ -2515,7 +2519,7 @@ void Bot::LoadBuffs() { bool BuffsLoaded = false; - if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, caston_x, Persistent, caston_y, caston_z FROM botbuffs WHERE BotId = %u", GetBotID()), TempErrorMessageBuffer, &DatasetResult)) { + if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance FROM botbuffs WHERE BotId = %u", GetBotID()), TempErrorMessageBuffer, &DatasetResult)) { errorMessage = std::string(TempErrorMessageBuffer); } else { @@ -2550,8 +2554,9 @@ void Bot::LoadBuffs() { if(atoi(DataRow[13])) IsPersistent = true; - buffs[BuffCount].caston_x = atoi(DataRow[14]); - buffs[BuffCount].caston_x = atoi(DataRow[15]); + buffs[BuffCount].caston_y = atoi(DataRow[14]); + buffs[BuffCount].caston_z = atoi(DataRow[15]); + buffs[BuffCount].ExtraDIChance = atoi(DataRow[16]); buffs[BuffCount].persistant_buff = IsPersistent; diff --git a/zone/common.h b/zone/common.h index 97b94887a..ec364931b 100644 --- a/zone/common.h +++ b/zone/common.h @@ -156,9 +156,10 @@ struct Buffs_Struct { uint32 melee_rune; uint32 magic_rune; uint32 dot_rune; - uint32 caston_x; - uint32 caston_y; - uint32 caston_z; + int32 caston_x; + int32 caston_y; + int32 caston_z; + int32 ExtraDIChance; bool persistant_buff; bool client; //True if the caster is a client bool UpdateClient; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index f307e08e2..99c45ea0f 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1321,6 +1321,20 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } + case SE_DeathSave: { + + int16 mod = 0; + + if(caster) { + mod = caster->aabonuses.UnfailingDivinity + + caster->itembonuses.UnfailingDivinity + + caster->spellbonuses.UnfailingDivinity; + } + + buffs[buffslot].ExtraDIChance = mod; + break; + } + case SE_Illusion: { #ifdef SPELL_EFFECT_SPAM @@ -1432,10 +1446,17 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) snprintf(effect_desc, _EDLEN, "Memory Blur: %d", effect_value); #endif int wipechance = spells[spell_id].base[i]; - int bonus = spellbonuses.IncreaseChanceMemwipe + itembonuses.IncreaseChanceMemwipe + aabonuses.IncreaseChanceMemwipe; + int bonus = 0; + + if (caster){ + bonus = caster->spellbonuses.IncreaseChanceMemwipe + + caster->itembonuses.IncreaseChanceMemwipe + + caster->aabonuses.IncreaseChanceMemwipe; + } + wipechance += wipechance*bonus/100; - if(MakeRandomInt(0, 100) < wipechance) + if(MakeRandomInt(0, 99) < wipechance) { if(IsAIControlled()) { @@ -2804,7 +2825,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_IncreaseChanceMemwipe: case SE_CriticalMend: case SE_LimitCastTimeMax: - case SE_DeathSave: case SE_TriggerOnReqCaster: { break; @@ -3267,6 +3287,31 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste break; } + case SE_WipeHateList: + { + + int wipechance = spells[spell_id].base[i]; + int bonus = 0; + + if (caster){ + bonus = caster->spellbonuses.IncreaseChanceMemwipe + + caster->itembonuses.IncreaseChanceMemwipe + + caster->aabonuses.IncreaseChanceMemwipe; + } + + wipechance += wipechance*bonus/100; + + if(MakeRandomInt(0, 99) < wipechance) + { + if(IsAIControlled()) + { + WipeHateList(); + } + Message(13, "Your mind fogs. Who are my friends? Who are my enemies?... it was all so clear a moment ago..."); + } + break; + } + case SE_Charm: { if (!caster || !PassCharismaCheck(caster, this, spell_id)) { BuffFadeByEffect(SE_Charm); @@ -5262,13 +5307,10 @@ bool Mob::TryDeathSave() { int16 UD_HealMod = 0; uint32 HealAmt = 300; //Death Pact max Heal - Mob* caster = entity_list.GetMobID(buffs[buffSlot].casterid); - - if (caster) - UD_HealMod = caster->spellbonuses.UnfailingDivinity + caster->itembonuses.UnfailingDivinity + caster->aabonuses.UnfailingDivinity; - if(buffSlot >= 0){ + UD_HealMod = buffs[buffSlot].ExtraDIChance; + SuccessChance = ( (GetCHA() * (RuleI(Spells, DeathSaveCharismaMod))) + 1) / 10; //(CHA Mod Default = 3) if (SuccessChance > 95) @@ -5333,6 +5375,8 @@ bool Mob::TryDeathSave() { } } } + + BuffFadeBySlot(buffSlot); } return false; } diff --git a/zone/spells.cpp b/zone/spells.cpp index de16af190..eceade9b1 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2957,6 +2957,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid buffs[emptyslot].caston_y = 0; buffs[emptyslot].caston_z = 0; buffs[emptyslot].dot_rune = 0; + buffs[emptyslot].ExtraDIChance = 0; if (level_override > 0) { buffs[emptyslot].UpdateClient = true; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index aa68888fd..278f87eaf 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1815,7 +1815,7 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) { if(!database.RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO merc_buffs (MercId, SpellId, CasterLevel, DurationFormula, " "TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, " - "dot_rune, caston_x, Persistent, caston_y, caston_z) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);", + "dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);", merc->GetMercID(), buffs[BuffCount].spellid, buffs[BuffCount].casterlevel, spells[buffs[BuffCount].spellid].buffdurationformula, buffs[BuffCount].ticsremaining, CalculatePoisonCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0, @@ -1824,7 +1824,11 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) { CalculateCorruptionCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0, buffs[BuffCount].numhits, buffs[BuffCount].melee_rune, buffs[BuffCount].magic_rune, buffs[BuffCount].dot_rune, - buffs[BuffCount].caston_x, IsPersistent, buffs[BuffCount].caston_y, buffs[BuffCount].caston_z), TempErrorMessageBuffer)) { + buffs[BuffCount].caston_x, + IsPersistent, + buffs[BuffCount].caston_y, + buffs[BuffCount].caston_z, + buffs[BuffCount].ExtraDIChance), TempErrorMessageBuffer)) { errorMessage = std::string(TempErrorMessageBuffer); safe_delete(Query); Query = 0; @@ -1856,7 +1860,7 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) { bool BuffsLoaded = false; - if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, CasterAARank, Persistent FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer, &DatasetResult)) { + if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer, &DatasetResult)) { errorMessage = std::string(TempErrorMessageBuffer); } else { @@ -1893,6 +1897,7 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) { buffs[BuffCount].caston_y = atoi(DataRow[13]); buffs[BuffCount].caston_z = atoi(DataRow[14]); + buffs[BuffCount].ExtraDIChance = atoi(DataRow[15]); buffs[BuffCount].persistant_buff = IsPersistent; @@ -2570,10 +2575,10 @@ void ZoneDatabase::SaveBuffs(Client *c) { if(buffs[i].spellid != SPELL_UNKNOWN) { if(!database.RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `character_buffs` (character_id, slot_id, spell_id, " "caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, magic_rune, persistent, dot_rune, " - "caston_x, caston_y, caston_z) VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", + "caston_x, caston_y, caston_z, ExtraDIChance) VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%i', '%i', '%i', '%i')", c->CharacterID(), i, buffs[i].spellid, buffs[i].casterlevel, buffs[i].caster_name, buffs[i].ticsremaining, buffs[i].counters, buffs[i].numhits, buffs[i].melee_rune, buffs[i].magic_rune, buffs[i].persistant_buff, - buffs[i].dot_rune, buffs[i].caston_x, buffs[i].caston_y, buffs[i].caston_z), + buffs[i].dot_rune, buffs[i].caston_x, buffs[i].caston_y, buffs[i].caston_z, buffs[i].ExtraDIChance), errbuf)) { LogFile->write(EQEMuLog::Error, "Error in SaveBuffs query '%s': %s", query, errbuf); } @@ -2595,7 +2600,7 @@ void ZoneDatabase::LoadBuffs(Client *c) { MYSQL_RES *result; MYSQL_ROW row; if (RunQuery(query, MakeAnyLenString(&query, "SELECT spell_id, slot_id, caster_level, caster_name, ticsremaining, counters, " - "numhits, melee_rune, magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z FROM `character_buffs` WHERE " + "numhits, melee_rune, magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z, ExtraDIChance FROM `character_buffs` WHERE " "`character_id`='%u'", c->CharacterID()), errbuf, &result)) { @@ -2621,9 +2626,10 @@ void ZoneDatabase::LoadBuffs(Client *c) { uint32 magic_rune = atoul(row[8]); uint8 persistent = atoul(row[9]); uint32 dot_rune = atoul(row[10]); - uint32 caston_x = atoul(row[11]); - uint32 caston_y = atoul(row[12]); - uint32 caston_z = atoul(row[13]); + int32 caston_x = atoul(row[11]); + int32 caston_y = atoul(row[12]); + int32 caston_z = atoul(row[13]); + int32 ExtraDIChance = atoul(row[14]); buffs[slot_id].spellid = spell_id; buffs[slot_id].casterlevel = caster_level; @@ -2647,6 +2653,7 @@ void ZoneDatabase::LoadBuffs(Client *c) { buffs[slot_id].caston_x = caston_x; buffs[slot_id].caston_y = caston_y; buffs[slot_id].caston_z = caston_z; + buffs[slot_id].ExtraDIChance = ExtraDIChance; buffs[slot_id].UpdateClient = false; if(IsRuneSpell(spell_id)) { c->SetHasRune(true); @@ -2655,11 +2662,6 @@ void ZoneDatabase::LoadBuffs(Client *c) { c->SetHasSpellRune(true); } - /* - if(IsDeathSaveSpell(spell_id)) { - c->SetDeathSaveChance(true); - } - */ } mysql_free_result(result); } From 2a28e88bcfc6e56633dd1df91eafb249bbbe40f1 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 22 Feb 2014 02:23:37 -0500 Subject: [PATCH 28/28] not_reflectable -> reflectable --- common/shareddb.cpp | 2 +- common/spdat.h | 2 +- ...{2014_02_20_buff_update.txt => 2014_02_20_buff_update.sql} | 4 +++- zone/mob.cpp | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) rename utils/sql/git/required/{2014_02_20_buff_update.txt => 2014_02_20_buff_update.sql} (92%) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index aa136c41b..a49cec4e8 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1710,7 +1710,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) { sp[tempid].descnum = atoi(row[155]); sp[tempid].effectdescnum = atoi(row[157]); - sp[tempid].not_reflectable = atoi(row[161]) != 0; + sp[tempid].reflectable = atoi(row[161]) != 0; sp[tempid].bonushate=atoi(row[162]); sp[tempid].EndurCost=atoi(row[166]); diff --git a/common/spdat.h b/common/spdat.h index 70f4c4b24..d308206e3 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -688,7 +688,7 @@ struct SPDat_Spell_Struct /* 157 */ int effectdescnum; // eqstr of effect description /* 158 */ //Category Desc ID 3 /* 159 */ //bool npc_no_los; -/* 161 */ bool not_reflectable; +/* 161 */ bool reflectable; /* 162 */ int bonushate; /* 163 */ /* 164 */ // for most spells this appears to mimic ResistDiff diff --git a/utils/sql/git/required/2014_02_20_buff_update.txt b/utils/sql/git/required/2014_02_20_buff_update.sql similarity index 92% rename from utils/sql/git/required/2014_02_20_buff_update.txt rename to utils/sql/git/required/2014_02_20_buff_update.sql index a53930481..636fa0221 100644 --- a/utils/sql/git/required/2014_02_20_buff_update.txt +++ b/utils/sql/git/required/2014_02_20_buff_update.sql @@ -17,4 +17,6 @@ ALTER TABLE `botbuffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0'; ALTER TABLE `character_buffs` ADD `ExtraDIChance` INT(10) NOT NULL DEFAULT '0'; ALTER TABLE `merc_buffs` ADD `ExtraDIChance` INT(10) NOT NULL DEFAULT '0'; -ALTER TABLE `botbuffs` ADD `ExtraDIChance` INT(10) NOT NULL DEFAULT '0'; \ No newline at end of file +ALTER TABLE `botbuffs` ADD `ExtraDIChance` INT(10) NOT NULL DEFAULT '0'; + +ALTER TABLE `spells_new` CHANGE `not_reflectable` `reflectable` INT(11) NOT NULL DEFAULT '0'; \ No newline at end of file diff --git a/zone/mob.cpp b/zone/mob.cpp index cee9003cc..a77589d63 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4348,7 +4348,7 @@ void Mob::MeleeLifeTap(int32 damage) { bool Mob::TryReflectSpell(uint32 spell_id) { - if (spells[spell_id].not_reflectable) + if (!spells[spell_id].reflectable) return false; int chance = itembonuses.reflect_chance + spellbonuses.reflect_chance + aabonuses.reflect_chance;