diff --git a/changelog.txt b/changelog.txt index 19198d592..abf75bb1f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,9 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 10/21/2013 == +demonstar55: Changed GetMinLevel return 0 for more cases that EQ uses for some reason ... +demonstar55: Added buff level restrictions, set the Spells:BuffLevelRestrictions to false to have the old behavior. + == 10/18/2013 == Uleat: Expanded the 'Bag Type' enumeration to include all known values. Also, set in place additional 'Bag Type' to 'Skill Type' conversions. Some of these will need to be verified before activation. Uleat: Cleaned up some unused enumerations to show a move towards standardization. More to come... diff --git a/common/ruletypes.h b/common/ruletypes.h index 6a31d7c7a..9fbddd3ca 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -294,6 +294,7 @@ RULE_INT ( Spells, DeathSaveCharismaMod, 3) //Determines how much charisma effec RULE_INT ( Spells, DivineInterventionHeal, 8000) //Divine intervention heal amount. RULE_BOOL ( Spells, AdditiveBonusValues, false) //Allow certain bonuses to be calculated by adding together the value from each item, instead of taking the highest value. (ie Add together all Cleave Effects) RULE_BOOL ( Spells, UseCHAScribeHack, false) //ScribeSpells and TrainDiscs quest functions will ignore entries where field 12 is CHA. What's the best way to do this? +RULE_BOOL ( Spells, BuffLevelRestrictions, true) //Buffs will not land on low level toons like live RULE_CATEGORY_END() RULE_CATEGORY( Combat ) diff --git a/common/spdat.cpp b/common/spdat.cpp index 883a5d9f4..437fd88c7 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -496,7 +496,8 @@ int GetMinLevel(uint16 spell_id) { //if we can't cast the spell return 0 //just so it wont screw up calculations used in other areas of the code - if(min == 255) + //seen 127, 254, 255 + if(min >= 127) return 0; else return(min); diff --git a/zone/StringIDs.h b/zone/StringIDs.h index af955fe7e..c65115151 100644 --- a/zone/StringIDs.h +++ b/zone/StringIDs.h @@ -50,6 +50,7 @@ #define ITEM_OUT_OF_CHARGES 182 //Item is out of charges. #define TARGET_NO_MANA 191 //Your target has no mana to affect #define TARGET_GROUP_MEMBER 196 //You must first target a group member. +#define SPELL_TOO_POWERFUL 197 //Your spell is too powerful for your intended target. #define INSUFFICIENT_MANA 199 //Insufficient Mana to cast this spell! #define SAC_TOO_LOW 203 //This being is not a worthy sacrifice. #define SAC_TOO_HIGH 204 //This being is too powerful to be a sacrifice. diff --git a/zone/client.h b/zone/client.h index 7adbc421f..630c65c7b 100644 --- a/zone/client.h +++ b/zone/client.h @@ -482,6 +482,7 @@ public: int32 GetDotFocus(uint16 spell_id, int32 value); int32 GetActDoTDamage(uint16 spell_id, int32 value); virtual bool CheckFizzle(uint16 spell_id); + virtual bool CheckSpellLevelRestriction(uint16 spell_id); virtual int GetCurrentBuffSlots() const; virtual int GetCurrentSongSlots() const; virtual int GetCurrentDiscSlots() const { return 1; } diff --git a/zone/mob.h b/zone/mob.h index dfcae9d2a..dafed5d2a 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -191,6 +191,7 @@ public: virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction); virtual bool CheckFizzle(uint16 spell_id); + virtual bool CheckSpellLevelRestriction(uint16 spell_id); virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster); virtual float GetAOERange(uint16 spell_id); void InterruptSpell(uint16 spellid = SPELL_UNKNOWN); diff --git a/zone/spells.cpp b/zone/spells.cpp index fbf9ead2e..3b7f391f3 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2709,6 +2709,41 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, return 0; } +// Check Spell Level Restrictions +// returns true if they meet the restrictions, false otherwise +// derived from http://samanna.net/eq.general/buffs.shtml +// spells 1-50: no restrictons +// 51-65: SpellLevel/2+15 +// 66+L Group Spells 62, Single Target 61 +bool Mob::CheckSpellLevelRestriction(uint16 spell_id) +{ + return true; +} + +bool Client::CheckSpellLevelRestriction(uint16 spell_id) +{ + int SpellLevel = GetMinLevel(spell_id); + + // Only check for beneficial buffs, if it's a bard song, only if it's short duration + if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id) && + !(IsBardSong(spell_id) && !IsShortDurationBuff(spell_id))) + { + if(SpellLevel > 65) + { + if(IsGroupSpell(spell_id) && GetLevel() < 62) + return false; + else if(GetLevel() < 61) + return false; + } + else if(SpellLevel > 50) // 51-65 + { + if(GetLevel() < (SpellLevel/2+15)) + return false; + } + } + + return true; +} // returns the slot the buff was added to, -1 if it wasn't added due to // stacking problems, and -2 if this is not a buff @@ -3479,6 +3514,15 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r else if (IsBeneficialSpell(spell_id) && !IsSummonPCSpell(spell_id)) entity_list.AddHealAggro(spelltar, this, CheckHealAggroAmount(spell_id, (spelltar->GetMaxHP() - spelltar->GetHP()))); + // make sure spelltar is high enough level for the buff + if(RuleB(Spells, BuffLevelRestrictions) && !spelltar->CheckSpellLevelRestriction(spell_id)) + { + mlog(SPELLS__BUFFS, "Spell %d failed: recipient did not meet the level restrictions", spell_id); + if(!IsBardSong(spell_id)) + Message_StringID(MT_SpellFailure, SPELL_TOO_POWERFUL); + return false; + } + // cause the effects to the target if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness)) {