View Single Post
  #1  
Old 11-06-2010, 11:32 PM
Caryatis
Dragon
 
Join Date: May 2009
Location: Milky Way
Posts: 539
Default COMMITTED: Heal Amt, Spell Dmg, Clairvoyance & SE_SpellDamage

I found a post on the formula used for Spell Damage and Heal Amount(from items) so figured I would make these work. Clairvoyance is alittle different but wasnt too hard to find info on it. SE_SpellDamage is from bard songs like Garadell's Fatesong.

Rules SQL:
Code:
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Character:ItemClairvoyanceCap', '250', 'Clairvoyance returns mana after a cast under certain circumstances');
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Character:ItemHealAmtCap', '250', 'Heal Amt adds to heal spells based on their cast & recast time');
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Character:ItemSpellDmgCap', '250', 'Spell Dmg adds to DD spells based on their cast & recast time');
Diff:
Code:
Index: EQEmuServer/common/ruletypes.h
===================================================================
--- EQEmuServer/common/ruletypes.h	(revision 1715)
+++ EQEmuServer/common/ruletypes.h	(working copy)
@@ -60,6 +60,9 @@
 RULE_INT ( Character, ItemStunResistCap, 35)
 RULE_INT ( Character, ItemStrikethroughCap, 35)
 RULE_INT ( Character, ItemATKCap, 250)
+RULE_INT ( Character, ItemHealAmtCap, 250)
+RULE_INT ( Character, ItemSpellDmgCap, 250)
+RULE_INT ( Character, ItemClairvoyanceCap, 250)
 RULE_INT ( Character, SkillUpModifier, 100) //skill ups are at 100%
 RULE_BOOL ( Character, SharedBankPlat, false) //off by default to prevent duping for now
 RULE_BOOL ( Character, BindAnywhere, false)
Index: EQEmuServer/zone/bonuses.cpp
===================================================================
--- EQEmuServer/zone/bonuses.cpp	(revision 1715)
+++ EQEmuServer/zone/bonuses.cpp	(working copy)
@@ -367,6 +367,26 @@
 		else
 			newbon->DoTShielding += item->DotShielding;
 	}
+	
+	if(item->HealAmt > 0) {
+		if((newbon->HealAmt + item->HealAmt) > RuleI(Character, ItemHealAmtCap))
+			newbon->HealAmt = RuleI(Character, ItemHealAmtCap);
+		else
+			newbon->HealAmt += item->HealAmt;
+	}
+	if(item->SpellDmg > 0) {
+		if((newbon->SpellDmg + item->SpellDmg) > RuleI(Character, ItemSpellDmgCap))
+			newbon->SpellDmg = RuleI(Character, ItemSpellDmgCap);
+		else
+			newbon->SpellDmg += item->SpellDmg;
+	}
+	if(item->Clairvoyance > 0) {
+		if((newbon->Clairvoyance + item->Clairvoyance) > RuleI(Character, ItemClairvoyanceCap))
+			newbon->Clairvoyance = RuleI(Character, ItemClairvoyanceCap);
+		else
+			newbon->Clairvoyance += item->Clairvoyance;
+	}
+	
 	if (item->Worn.Effect>0 && (item->Worn.Type == ET_WornEffect)) { // latent effects
 		ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon);
 	}
@@ -1206,8 +1226,12 @@
 					newbon->Accuracy = effect_value;
 				break;
 			}
-
-				
+			case SE_SpellDamage:
+			{
+				// Only used for worn effects and to trigger a buff check
+				newbon->SpellDmg += effect_value;
+				break;
+			}
 		}
 	}
 }
Index: EQEmuServer/zone/client.h
===================================================================
--- EQEmuServer/zone/client.h	(revision 1715)
+++ EQEmuServer/zone/client.h	(working copy)
@@ -390,6 +390,7 @@
 	inline virtual sint16	GetHeroicCR()	const { return itembonuses.HeroicCR; }
 	inline virtual sint16	GetHeroicCorrup()	const { return itembonuses.HeroicCorrup; }
 
+	sint32 Additional_SpellDmg(int16 spell_id);
 	float GetActSpellRange(int16 spell_id, float range);
 	sint32 GetActSpellDamage(int16 spell_id, sint32 value);
 	sint32 GetActSpellHealing(int16 spell_id, sint32 value);
Index: EQEmuServer/zone/effects.cpp
===================================================================
--- EQEmuServer/zone/effects.cpp	(revision 1715)
+++ EQEmuServer/zone/effects.cpp	(working copy)
@@ -39,6 +39,25 @@
 	return (range * extrange) / 100;
 }
 
+sint32 Client::Additional_SpellDmg(int16 spell_id) 
+{
+	sint32 spell_dmg = 0;
+	uint32 buff_count = GetMaxTotalSlots();
+	sint16 focus = 0;
+	
+	for (int i=0; i < buff_count; i++) 
+	{
+		if(IsEffectInSpell(buffs[i].spellid, SE_SpellDamage))
+		{
+			focus = CalcFocusEffect(focusSpellDamage, buffs[i].spellid, spell_id);
+			if(focus)
+				spell_dmg += focus;
+		}
+	}
+	return spell_dmg;
+}
+
 sint32 Client::GetActSpellDamage(int16 spell_id, sint32 value) {
 	// Important variables:
 	// value: the actual damage after resists, passed from Mob::SpellEffect
@@ -47,7 +66,14 @@
 	// chance: critital chance %
 	//all of the ordering and stacking in here might be wrong, but I dont care right now.
 	
-	
+	sint16 spell_dmg = 0;
+	// Formula = SpellDmg * (casttime + recastime) / 7
+	if(this->itembonuses.SpellDmg)
+		spell_dmg = this->itembonuses.SpellDmg * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000;
+	// Spell-based SpellDmg adds directly but it restricted by focuses.
+	if(this->spellbonuses.SpellDmg)
+		spell_dmg += this->Additional_SpellDmg(spell_id);
+		
 	sint32 modifier = 100;
 	
 	//Dunno if this makes sense:
@@ -208,22 +234,29 @@
 			mlog(SPELLS__CRITS, "Attempting spell crit. Spell: %s (%d), Value: %d, Modifier: %d, Chance: %d, Ratio: %d", spells[spell_id].name, spell_id, value, modifier, chance, ratio);
 			if(MakeRandomInt(0,100) <= chance) {
 				modifier += modifier*ratio/100;
-				mlog(SPELLS__CRITS, "Spell crit successful. Final damage modifier: %d, Final Damage: %d", modifier, (value * modifier) / 100);
-				entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), ((-value * modifier) / 100));	
+				spell_dmg *= 2;
+				mlog(SPELLS__CRITS, "Spell crit successful. Final damage modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
+				entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), (-value * modifier / 100) + spell_dmg);	
 			} else 
-				mlog(SPELLS__CRITS, "Spell crit failed. Final Damage Modifier: %d, Final Damage: %d", modifier, (value * modifier) / 100);
+				mlog(SPELLS__CRITS, "Spell crit failed. Final Damage Modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
 		}
 	}
 	
-	return (value * modifier) / 100;
+	return ((value * modifier / 100) - spell_dmg);
 }
 
 sint32 Client::GetActSpellHealing(int16 spell_id, sint32 value) {
+	
 	sint32 modifier = 100;
-
 	modifier += GetFocusEffect(focusImprovedHeal, spell_id);
 						
-	if(spells[spell_id].buffduration < 1) {
+	if(spells[spell_id].buffduration < 1) 
+	{
+		sint16 heal_amt = 0;
+		// Formula = HealAmt * (casttime + recastime) / 7
+		if(this->itembonuses.HealAmt)
+			heal_amt = this->itembonuses.HealAmt * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000;
+		
 		//non-dot
 		switch(GetAA(aaHealingAdept)) {
 		case 1:
@@ -299,22 +332,34 @@
    }
 		
 		if(MakeRandomInt(0,100) < chance) {
-			entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), ((value * modifier) / 50));		
-			return (value * modifier) / 50;
+			entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), ((value * modifier / 50) + heal_amt*2));		
+			return (value * modifier / 50) + heal_amt*2;
 		}
 		else{
-			return (value * modifier) / 100;
+			return (value * modifier / 100) + heal_amt;
 		}		
 	}
 					
-	return (value * modifier) / 100;
+	return (value * modifier / 100);
 }
 
 sint32 Client::GetActSpellCost(int16 spell_id, sint32 cost)
 {
+	// Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell
+	if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%16) - 1] > GetLevel() - 5)
+	{
+		sint16 mana_back = this->itembonuses.Clairvoyance * MakeRandomInt(1, 100) / 100;
+		// Doesnt generate mana, so best case is a free spell
+		if(mana_back > cost)
+			mana_back = cost;
+			
+		cost -= mana_back;
+	}
+	
 	// This formula was derived from the following resource:
 	// http://www.eqsummoners.com/eq1/specialization-library.html
 	// WildcardX
+	
 	float PercentManaReduction = 0;
 	float SpecializeSkill = GetSpecializeSkillValue(spell_id);
 	int SuccessChance = MakeRandomInt(0, 100);
Index: EQEmuServer/zone/mob.h
===================================================================
--- EQEmuServer/zone/mob.h	(revision 1715)
+++ EQEmuServer/zone/mob.h	(working copy)
@@ -90,6 +90,7 @@
 	focusSpellVulnerability,
 	focusTwincast,
 	focusSympatheticProc,
+	focusSpellDamage,
 } focusType;
 
 enum {
@@ -275,6 +276,10 @@
 
 	sint8 HundredHands;		//extra haste, stacks with all other haste  i
 	sint8 MeleeLifetap;
+	sint32 HealAmt;
+	sint32 SpellDmg;
+	sint32 Clairvoyance;
 	int XPRateMod;
 
 	sint8	Packrat;	//weight reduction for items, 1 point = 10%
Index: EQEmuServer/zone/spell_effects.cpp
===================================================================
--- EQEmuServer/zone/spell_effects.cpp	(revision 1715)
+++ EQEmuServer/zone/spell_effects.cpp	(working copy)
@@ -2893,6 +2893,7 @@
 			case SE_EffectOnFade:
 			case SE_MaxHPChange:
 			case SE_SympatheticProc:
+			case SE_SpellDamage:
 			{
 				break;
 			}
@@ -4035,7 +4036,16 @@
 			}
 			break;
 		}
+		case SE_SpellDamage:
+		{
+			if(type == focusSpellDamage)
+				value = focus_spell.base[i];
 
+			break;
+		}
+		
 #if EQDEBUG >= 6
 		//this spits up a lot of garbage when calculating spell focuses
 		//since they have all kinds of extra effects on them.
Reply With Quote