Go Back   EQEmulator Home > EQEmulator Forums > Support > Spell Support

Spell Support Broken Spells? Want them Fixed? Request it here.

Reply
 
Thread Tools Display Modes
  #1  
Old 12-21-2012, 09:39 AM
Hateborne
Hill Giant
 
Join Date: May 2010
Posts: 125
Question Divine Intervention Code Question

It seems that the Divine Intervention buff works if the limit value is set to Touch of the Divine. If it is set to limit value 0 (or what seems like a non-existent spell), it seems to fail infinitely. I checked a variety of working effects and then checked code.

There seems to be a bit of a copy-paste issue. From current trunk:
Code:
bool Mob::TryDivineSave() {

	/*
	How Touch of the Divine AA works:
	-Gives chance to avoid death when client is killed.
	-Chance is determined by the AA value. (base1)
	-Spell can be triggered from divine save (base2) in this case a Heal
	Note: Heal value does not and should not increase from more levels of this AA.
	-If chance is met, a heal is done and a divine aura like effect 'Touch of the Divine'
	is applied to the client. Determintal spell effects are removed.
	*/
	sint16 SuccessChance = aabonuses.DivineSaveChance[0] + itembonuses.DivineSaveChance[0] + spellbonuses.DivineSaveChance[0];

	if (SuccessChance)
	{
		if (MakeRandomInt(0, 100) <= SuccessChance)
		{
			int32 HealAmt = 0;
			BuffFadeByEffect(SE_DivineSave);
			//Touch of the Divine=4789, an Invulnerability/HoT/Purify effect hard coded to trigger if spell effect is defined from base2.
			if (aabonuses.DivineSaveChance[1] || itembonuses.DivineSaveChance[1] || spellbonuses.DivineSaveChance[1]) {

				SetHP(1);

				if (aabonuses.DivineSaveChance[1])
					SpellOnTarget(aabonuses.DivineSaveChance[1], this);

				if (itembonuses.DivineSaveChance[1])
					SpellOnTarget(aabonuses.DivineSaveChance[1], this);

				if (spellbonuses.DivineSaveChance[1])
					SpellOnTarget(aabonuses.DivineSaveChance[1], this);

				SpellOnTarget(4789, this);
				SendHPUpdate();
				return true;
			}
		}
	}
	return false;
}

I'm guessing those should be set to match the check (i.e. itembonuses = SpellOnTarget(itembonuses.Div...)). This would allow it to proc other effects in addition to the hard coded value. The only immediate problem that I saw were the ability to proc from all checks, netting up to 4 casts of the Touch of the Divine. I do not know how to approach this in the way that is consistent with the EQEMU practices. Example adjustments below.


Code:
bool Mob::TryDivineSave() {

	/*
	How Touch of the Divine AA works:
	-Gives chance to avoid death when client is killed.
	-Chance is determined by the AA value. (base1)
	-Spell can be triggered from divine save (base2) in this case a Heal
	Note: Heal value does not and should not increase from more levels of this AA.
	-If chance is met, a heal is done and a divine aura like effect 'Touch of the Divine'
	is applied to the client. Determintal spell effects are removed.
	*/
	sint16 SuccessChance = aabonuses.DivineSaveChance[0] + itembonuses.DivineSaveChance[0] + spellbonuses.DivineSaveChance[0];

	if (SuccessChance)
	{
		if (MakeRandomInt(0, 100) <= SuccessChance)
		{
			int32 HealAmt = 0;
			BuffFadeByEffect(SE_DivineSave);
			//Touch of the Divine=4789, an Invulnerability/HoT/Purify effect hard coded to trigger if spell effect is defined from base2.
			if (aabonuses.DivineSaveChance[1] || itembonuses.DivineSaveChance[1] || spellbonuses.DivineSaveChance[1]) {

				SetHP(1);

				if (aabonuses.DivineSaveChance[1])
					SpellOnTarget(aabonuses.DivineSaveChance[1], this);

				if (itembonuses.DivineSaveChance[1])
					SpellOnTarget(itembonuses.DivineSaveChance[1], this);

				if (spellbonuses.DivineSaveChance[1])
					SpellOnTarget(spellbonuses.DivineSaveChance[1], this);

				SpellOnTarget(4789, this);
				SendHPUpdate();
				return true;
			}
		}
	}
	return false;
}

To actually lock out other effects, is there some specific way that this should be handled or adjusted? I could see that ability to trigger 4 effects max might be...interesting.


-Hate
Reply With Quote
  #2  
Old 12-21-2012, 10:12 AM
c0ncrete's Avatar
c0ncrete
Dragon
 
Join Date: Dec 2009
Posts: 719
Default

what a strange coincidence.

i just found a bug with some custom trade skill code i'd been working on moments before i read this post. cut-and-paste was the culprit there as well.
Reply With Quote
  #3  
Old 12-21-2012, 11:54 AM
sorvani
Dragon
 
Join Date: May 2010
Posts: 965
Default

i added this in rev 2301, thanks.
Reply With Quote
  #4  
Old 12-21-2012, 02:04 PM
thepoetwarrior
Discordant
 
Join Date: Aug 2007
Posts: 307
Default

Woot thanks
Reply With Quote
  #5  
Old 12-22-2012, 05:37 AM
Kayen
Developer
 
Join Date: Mar 2009
Location: -
Posts: 228
Default

Oops my bad I wrote that code.

Thanks for catching it.
Reply With Quote
  #6  
Old 12-23-2012, 02:50 AM
NatedogEZ's Avatar
NatedogEZ
Developer
 
Join Date: Dec 2012
Posts: 515
Default

Just updated to newest code here are my results ....


Working as an AA

Working as an AA + Spell (they will stack nicely)

Working as a Worn effect

NOT WORKING as a Stand alone Buff slot




The spell I was using was the same for both the Worn / Buff
but as just a buff slot never procs. (had it at 100%)


Anyone have an idea where it might be missing something?


Thanks!
Reply With Quote
  #7  
Old 12-23-2012, 04:16 AM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,742
Default

Attach debugger, add a breakpoint inside the TryDivineSave function and where it calculates the bonus effect, then trace through and see where it goes wrong.
Reply With Quote
  #8  
Old 12-23-2012, 02:38 PM
Hateborne
Hill Giant
 
Join Date: May 2010
Posts: 125
Exclamation

Quote:
Originally Posted by lerxst2112 View Post
Attach debugger, add a breakpoint inside the TryDivineSave function and where it calculates the bonus effect, then trace through and see where it goes wrong.
Did just that and the answer was staring right in my face. The buff cannot fade BEFORE you check for it. The problem I ran into after moving the BuffFadeByEffect was it casting up to 4 effects. This got...interesting.

I added in a basic check to allow only one effect to go off. The only immediate note is that only ONE effect is allowed to go off, AAXP -> items -> spell.

(Should I be submitting as a diff instead?)


Code:
bool Mob::TryDivineSave() {

	/*
	How Touch of the Divine AA works:
	-Gives chance to avoid death when client is killed.
	-Chance is determined by the AA value. (base1)
	-Spell can be triggered from divine save (base2) in this case a Heal
	Note: Heal value does not and should not increase from more levels of this AA.
	-If chance is met, a heal is done and a divine aura like effect 'Touch of the Divine'
	is applied to the client. Determintal spell effects are removed.
	*/
	sint16 SuccessChance = aabonuses.DivineSaveChance[0] + itembonuses.DivineSaveChance[0] + spellbonuses.DivineSaveChance[0];

	if (SuccessChance)
	{
		if (MakeRandomInt(0, 100) <= SuccessChance)
		{
			int32 HealAmt = 0;
			// boolean to check if a single effect has gone off
			bool beenSaved = false;
			//Touch of the Divine=4789, an Invulnerability/HoT/Purify effect hard coded to trigger if spell effect is defined from base2.
			if (aabonuses.DivineSaveChance[1] || itembonuses.DivineSaveChance[1] || spellbonuses.DivineSaveChance[1]) {
			
				SetHP(1);

				/* will check aaxp, items, and then spells (in that priority order)
					if a line procs, any below it are ignored.
				*/
				if (aabonuses.DivineSaveChance[1] && (beenSaved == false))
				{
					SpellOnTarget(aabonuses.DivineSaveChance[1], this);
					beenSaved = true;
				}

				if (itembonuses.DivineSaveChance[1] && (beenSaved == false))
				{
					SpellOnTarget(itembonuses.DivineSaveChance[1], this);
					beenSaved = true;
				}

				if (spellbonuses.DivineSaveChance[1] && (beenSaved == false))
				{
					SpellOnTarget(spellbonuses.DivineSaveChance[1], this);
					beenSaved = true;
				}

				// this was moved INSIDE the check as it always failed when spell was removed AND THEN check took place
				BuffFadeByEffect(SE_DivineSave);

				// if nothing went off or all were blank triggers, make sure we save the player
				if (beenSaved == false)
				{
					SpellOnTarget(4789, this);
				}

				SendHPUpdate();
				return true;
			}
		}
	}
	return false;
}

-Hate
Reply With Quote
  #9  
Old 12-23-2012, 04:13 PM
NatedogEZ's Avatar
NatedogEZ
Developer
 
Join Date: Dec 2012
Posts: 515
Default

Seems to be working as a spell now with this!
Reply With Quote
  #10  
Old 12-23-2012, 06:45 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,742
Default

A diff is generally easier to apply and commit, but for a short function that's being completely replaced it's not that big a deal I guess.

I'm not sure how this works on live, but this logic seems a little odd to me. It seems like the intent was that spell 4789 is always cast but only if there's also another spell to cast based on the aa/spell/item bonus.

With the new logic to restrict it to only one spell cast it might make more sense, but still a little confusing. If the intent is to allow overriding the effect, then it seems like the final check to cast 4789 and save the person should happen even if there's no override as a default.

Does that make sense?
Reply With Quote
  #11  
Old 12-23-2012, 07:35 PM
Hateborne
Hill Giant
 
Join Date: May 2010
Posts: 125
Default

Yes it does lerxst2112.

I am unsure of live, so I cannot make it truly live-like. However with the original post, it was simply removing the buff and THEN checking for the removed buff. After resolving that, the problem with simply putting the BuffFadeByEffect at the end is the ability to proc ALL checks (in cleric's case, Touch of the Divine [AA], Divine Intervention's proc [if any], item DivineSave proc [if any], and then the default heal). It could theoretically allow for four heals/effects. If the Divine Intervention is set to Touch of the Divine effect_limit_value (4789), the effect would just overwrite it self a few times and stop.

If it is the intent to make it STILL pop Touch of the Divine + 1 other, then remove the if (beenSaved == false) { } around the SpellOnTarget. This will give whatever other effect is in place (if any) and still Touch of the Divine. I placed this check so forgetting to add a spell effect as the effect_limit_value (intentionally or accidentally) would still yield the Touch of the Divine.

Heh, now it's my turn. Did that make sense?


-Hate


(seriously though, if I had a bad case of the dumbs while explaining it, PLEASE say so!)
Reply With Quote
  #12  
Old 12-23-2012, 10:07 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,742
Default

Here's my take on this:

If the divine save check is successful then you're always saved, which sets HP to 1 and casts spell 4789. I didn't look at the spell, but based on the comments by default it's an invulnerability effect and removes detrimental effects, so at least you don't die immediately again.

If there are any additional effects setup in the appropriate AA/item/spell fields, then they are cast in that order until one succeeds and then the rest are skipped. I use the return value from SpellOnTarget to decide if the cast was successful which the original code didn't do. I'm not sure if this is a good idea or not. On the plus side if the spell is bogus or can't be cast on that target then the rest of the effects are still checked, but it might be open to abuse if it is possible to block the spell using blocked buffs to force a lower priority effect to be used.

Anyway, I didn't test this, but it's a thought to how it might look:

Code:
bool Mob::TryDivineSave() 
{
	/*
	How Touch of the Divine AA works:
	-Gives chance to avoid death when client is killed.
	-Chance is determined by the sum of AA/item/spell chances.
	-If the chance is met a divine aura like effect 'Touch of the Divine' is applied to the client removing detrimental spell effects.
	-If desired, an additional spell can be triggered from the AA/item/spell effect, generally a heal.
	 Only one additional effect will be triggered in the order of AA/item/spell.  Once an effect has been cast the rest are skipped.
	*/

	sint32 SuccessChance = aabonuses.DivineSaveChance[0] + itembonuses.DivineSaveChance[0] + spellbonuses.DivineSaveChance[0];
	if (SuccessChance && MakeRandomInt(0, 100) <= SuccessChance)
	{
		SetHP(1);

		int16 EffectsToTry[] = 
		{ 
			aabonuses.DivineSaveChance[1],
			itembonuses.DivineSaveChance[1],
			spellbonuses.DivineSaveChance[1]
		};
		//Fade the divine save effect here after saving the old effects off.
		//That way, if desired, the effect could apply SE_DivineSave again.
		BuffFadeByEffect(SE_DivineSave);
		for(size_t i = 0; i < ( sizeof(EffectsToTry) / sizeof(EffectsToTry[0]) ); ++i)
		{
			if( EffectsToTry[i] && SpellOnTarget(EffectsToTry[i], this) )
			{
				break;
			}
		}

		SpellOnTarget(4789, this); //Touch of the Divine=4789, an Invulnerability/HoT/Purify effect
		SendHPUpdate();
		return true;
	}
	return false;
}
The change is that the additional effect is now completely optional but spell 4789 is always cast, and if no additional effect is available it doesn't prevent the client from being saved. I guess the downside to this is you lose the ability to prevent 4789 from being cast, but if the invulnerability effect is not desired the spell could always be replaced.

Since the additional effect is now optional I think that not restricting it to one effect might be better. What I'm thinking is that maybe you have the AA that gives you a small heal, but you also have a buff or item that provides for a larger heal or different effect. This seems more flexible to me.
Reply With Quote
  #13  
Old 12-24-2012, 09:15 AM
Kayen
Developer
 
Join Date: Mar 2009
Location: -
Posts: 228
Default

Code:
I'm not sure how this works on live, but this logic seems a little odd to me. It seems like the intent was that spell 4789 is always cast but only if there's also another spell to cast based on the aa/spell/item bonus.
Before we rip my code to shreds I think some basic understanding of the effect is needed and why it is coded like this.

This spell effect ONLY exists for the AA Touch of the Divine on live.

Thus coding this spell effect the priority is to ensure that functions correctly.

Touch of the Divine in the aa_effects table has a base1 and a base2

Base1 is the chance to fire the trigger

Base2 is a 'heal spell' that triggers.

The 'Touch of the Divine' buff has to be hard coded because it is just part of the spell effect independent of what spell triggers. There is no field in the spell data to set if you want this effect or not.

Everything after this point is basically just whatever we want to do.

First spell buffs and Item worn effects DO NOT exist on live for this and were implemented purely for custom use.

Third, question of how do we stack this. Which again does not exist on live.

You have at max 3 sources, 1 from AA, 1 from worn effect, 1 from spell effect.

I coded as add up all the effects to give yourself your total chance.

Then do all 3 effects together (obviously was little buggy!).

Logic being your taking the combined total chance so you get the combined total effect. As a custom dev this can be useful you could say have +HP on AA, + Mana on item, +end on spell OR whatever ect, but you'd get all 3 if you had all 3.

Alternatively you could also individually check each effect in say a random order, AA, item, spell. Iterate through each do the random checks based on the individual percentages, and stop when one fires off. This might end up being a better way since you can put the 'Touch of the Divine' only in the AA check and leave the others more open.

There are no right answers, but the core AA function must remain as is because that is what any live server will be using.

Kayen
GM Storm Haven
Reply With Quote
  #14  
Old 12-24-2012, 09:50 AM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,742
Default

Quote:
Originally Posted by Kayen View Post
Before we rip my code to shreds I think some basic understanding of the effect is needed and why it is coded like this.
No ripping to shreds, just fixing an issue with having a spell effect when there is no AA effect. The buff was being faded and the bonus recalculated a little too early, so the spell effect was lost and that made the whole thing get skipped.

Does something like this meet your needs? It casts any of the AA/item/spell effects and spell 4789 as the original code did, but it doesn't require that there be an AA/item/spell effect present in order to stop a client from dying and applying the Touch of the Divine effect to them.

Code:
bool Mob::TryDivineSave() 
{
	/*
	How Touch of the Divine AA works:
	-Gives chance to avoid death when client is killed.
	-Chance is determined by the sum of AA/item/spell chances.
	-If the chance is met a divine aura like effect 'Touch of the Divine' is applied to the client removing detrimental spell effects.
	-If desired, an additional spell can be triggered from the AA/item/spell effect, generally a heal.
	*/

	sint32 SuccessChance = aabonuses.DivineSaveChance[0] + itembonuses.DivineSaveChance[0] + spellbonuses.DivineSaveChance[0];
	if (SuccessChance && MakeRandomInt(0, 100) <= SuccessChance)
	{
		SetHP(1);

		int16 EffectsToTry[] = 
		{ 
			aabonuses.DivineSaveChance[1],
			itembonuses.DivineSaveChance[1],
			spellbonuses.DivineSaveChance[1]
		};
		//Fade the divine save effect here after saving the old effects off.
		//That way, if desired, the effect could apply SE_DivineSave again.
		BuffFadeByEffect(SE_DivineSave);
		for(size_t i = 0; i < ( sizeof(EffectsToTry) / sizeof(EffectsToTry[0]) ); ++i)
		{
			if( EffectsToTry[i] )
			{
				SpellOnTarget(EffectsToTry[i], this);
			}
		}

		SpellOnTarget(4789, this); //Touch of the Divine=4789, an Invulnerability/HoT/Purify effect
		SendHPUpdate();
		return true;
	}
	return false;
}
Reply With Quote
  #15  
Old 12-24-2012, 10:30 AM
Kayen
Developer
 
Join Date: Mar 2009
Location: -
Posts: 228
Default

I understand and appreciate your efforts to correct the issues that were broken.

Just wanted people to understand the logic cause I recall how hard was to figure how this spell effect actually worked when implementing it.

I agree and do not see any reason why the base2 effect should be required to get the 'Touch of the Divine' spell trigger.

I am reviewing the code and I feel like I am missing something I thought I implemented with it.

I remembered the reason I forced the check of the base2 for the 'Touch of the Divine'.

I wanted to have it so that if you did not set a base2 then you could just have a it do the death save and set you to 1 HP. That way with the additive AA bonus rule you could have multiple stackable divine save chances.

I have a feeling that what I committed for this was prob not the correct version I had been working on at the time, but who knows.

Either way your code looks good.
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 02:41 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3