Aller au contenu

Photo

Spell Resistance - Working Solution


  • Veuillez vous connecter pour répondre
68 réponses à ce sujet

#26
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

tests:

There can indeed be more than one spell resistance Effect applied to a creature-object. That is, multiple applications accrue on target (if not removed / managed by using a spell-Id etc).

Module event "On Player Equip Item Script" is triggered for each equipped-item, including 'hidden slots', when a PC or Companion spawns into the game world. It doesn't seem to run for monsters/NPCs or Familiars though. (... assume "On Player Unequip Item Script" follows the same rules.)

GetSpellResistance() will return the SR of an equipped item, the highest value if two+ items with Spell Resistance are equipped. Or a feat's SR if highest. A scripted SR-effect returns as expected, falling in line with item-SR and feat-SR, if highest. (This implies that iterating over equipped items is merely a complication that could be replaced by using GetSpellResistance(), unless you *want* to check the item-SR values specifically.)


Present conclusion: the item-SR fix in Kaedrin's pack, or any scripts that hook via a module's Player-Equip/Unequip event, works only on PCs and Companions. Monsters & NPCs should hook a script-fix via their OnSpawn events (or some other event that fires in a way that allows iteration over their equipped items, including hides especially and whatnot).


Addenda
I. these are the spells and feats that apply/change SR (the ones I found..)



Spells.2da
124  - Nature's Balance (spell)            'nw_s0_naturebal' - decrease effect, deleted
1041 - Greater Visage of the Deity (spell) 'nx_s0_gvisage'
1124 - Inner Armor (spellability)          'nx_s2_innerarmor'
168  - Spell Resistance (spell)            'nw_s0_splresis'
1105 - Weaken Spirits (spellability)       'nx_s2_weakenspirits' - decrease effect
912  - CounterSong (bard song)             'nw_s2_sngcountr'
84   - Holy Aura (spell)                   'nw_s0_holyaura'
187  - Unholy Aura (spell)                 'nw_s0_unhaura'
862  - Assay Resistance (spell)            'nw_s0_assayrest' - decrease effect
122  - Mordenkainen's Disjunction (spell)  'nw_s0_morddisj' - decrease effect
98   - Lesser Spell Breach (spell)         'nw_s0_lsspbrch' - decrease effect
72   - Greater Spell Breach (spell)        'nw_s0_grspbrch' - decrease effect

Feat.2da (all these appear to be hardcoded, based on having SpellID = "****")
699  -
708  - Epic Improved Spell Resistances
1075 - Drow Resistance
1078 - Svirfneblin Resistance
1085 - Aasimar Resistance
1089 - Tiefling Resistance
1495 - Group Spell Resistance
1833 - Gith Resistance
1868 -
1871 - Genasi Resistances
2091 - Hagspawn Resistance
2118 - Racial Spell Resistance
2171 - Spell Resistance
2189 - Fiendish Resistance
215  - Diamond Soul
36   - Spell Penetration
401  - Greater Spell Penetration
618  - Epic Spell Penetration
II. further reading at NwN2.wiki
Spell Resistance

III. see also Saralach's efforts for warlocks - which I believe addresses special issues re. Invocations


Hi KevL,

Thanks for this informative post.

It sounds like I may not need to do the individual item check then. I double-check that part of my code. Otherwise, it appears my approach is the same as Kaedrin's by the sounds of it. I do PCs/Comps via OnEquip/OnUnEquip and monsters via OnSpawn. I may take a look at Kaedrin's work too, to see if it covers something I may have missed.

Cheers,
Lance.

#27
kevL

kevL
  • Members
  • 4 052 messages
Kaedrin's fix is pretty simple once ya get the hang of it. It's the preliminaries, of setting the option in his Options .2da, then making sure the module's onLoad (or similar) hooks his custom onLoad script, which transfers the setting "UseSRFix" from the .2da to a local on the module-object, and then that the module's onEquip/Unequip scripts check that setting and run ApplySRFix() *on a delay* of ~0.3 seconds ....


here's something tho: I thought about using GetSpellResistance() instead of looping across items. Not good (at least not for PCs/Companions).

because, -if- there happens to be a temporary spell resistance effect on a character when he/she equips/unequips an item, then the 'fix' script could/would effectively turn the effect from a temporary to a permanent ..... because it would get the temporary value of the character's current SR -- from Spell Resistance spell, eg. -- and apply it permanently at that same value. If it's the highest SR on the creature ofc.

But monsters/NPCs don't really have to worry about that since they get their application only once at onSpawn -- and they [probably] aren't going to have any temporary effects at that time.


so strongly suggest sticking to loops over items for onEquip/Unequip per PC's & Companions,

#28
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Kaedrin's fix is pretty simple once ya get the hang of it. It's the preliminaries, of setting the option in his Options .2da, then making sure the module's onLoad (or similar) hooks his custom onLoad script, which transfers the setting "UseSRFix" from the .2da to a local on the module-object, and then that the module's onEquip/Unequip scripts check that setting and run ApplySRFix() *on a delay* of ~0.3 seconds ....


I DL to take a look, but found only NCS files and no NSS ones. Do you know how to open the NCS to view? (I tried just dropping them into an override to try and open in the toolset, but got nothing .... I guess they also look for the NSS version.)
 

here's something tho: I thought about using GetSpellResistance() instead of looping across items. Not good (at least not for PCs/Companions).

because, -if- there happens to be a temporary spell resistance effect on a character when he/she equips/unequips an item, then the 'fix' script could/would effectively turn the effect from a temporary to a permanent ..... because it would get the temporary value of the character's current SR -- from Spell Resistance spell, eg. -- and apply it permanently at that same value. If it's the highest SR on the creature ofc.


I came back to post the same thing in my own tests (with my own code). I reverted back to testing individual items due to this. (As in the code I posted above.) That appears to work without any such issues.
 

But monsters/NPCs don't really have to worry about that since they get their application only once at onSpawn -- and they [probably] aren't going to have any temporary effects at that time.

so strongly suggest sticking to loops over items for onEquip/Unequip per PC's & Companions,


Exactly. :)

Cheers,
Lance.

#29
kevL

kevL
  • Members
  • 4 052 messages

I DL to take a look, but found only NCS files and no NSS ones. Do you know how to open the NCS to view? (I tried just dropping them into an override to try and open in the toolset, but got nothing .... I guess they also look for the NSS version.)


Kaedrin doesn't distribute the source anymore.

#30
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Kaedrin doesn't distribute the source anymore.


Woh! I never thought I would hear that. Oh well ...

Cheers,
Lance.

#31
kevL

kevL
  • Members
  • 4 052 messages
the last thing i'm sorta wondering about, is if a creature spawns as an NPC but then joins the Roster ...

maybe force a PC-application ? or just let it work itself out

#32
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

the last thing i'm sorta wondering about, is if a creature spawns as an NPC but then joins the Roster ...

maybe force a PC-application ? or just let it work itself out


Hi KevL,

I reckon (in theory), it should all work itself out. For instance, if you have a PC with SR 12 (E.g. Adaur) as a NPC to start off with, then the system will give him "permanent" SR12 OnSpawn. However, as soon as he equips an item (now under the control of the player), then the OnEquip will take over. At least, that what I reckon will happen.

However, I do need to ask ... SR (the spell), I have not checked yet, but I assume it uses the correct method anyway (applying "permanently" as such, until the spell duration is over)?

Cheers,
Lance.


Cheers,
Lance.

#33
Dann-J

Dann-J
  • Members
  • 3 161 messages

It's possible to decompile the NSC file, but it gets converted into PCODE rather than the original NSS plain text. PCODE is enough to get the gist of what's going on (such as the functions used), but you'll miss a lot of the scripting details. Unless you're well versed in the PCODE structure - which I'm certainly not.

 

I think the Advanced Script Compiler has a decompiling option. There is also something called NWNNSSCOMP that will also do the trick.



#34
kevL

kevL
  • Members
  • 4 052 messages
...
spell Spell Resistance is applied as a temporary for caster-level turns -- all proper.

 

I reckon (in theory), it should all work itself out. For instance, if you have a PC with SR 12 (E.g. Adaur) as a NPC to start off with, then the system will give him "permanent" SR12 OnSpawn. However, as soon as he equips an item (now under the control of the player), then the OnEquip will take over. At least, that what I reckon will happen.


hm, I think i spot the glitch there. An application of EffectSpellResistanceIncrease() will not overwrite a previous application. They will co-exist on the character. The PC-application *will not* overwrite nor necessarily overrule the Spawn-application; the latter (either, actually) will remain on the Character unless explicitly removed.

The easiest way to clean the effect is to assign it a spell-ID, at the same time as setting it Supernatural, then use that same ID both onSpawn *and* onEquip/Unequip. And at the top of the PC fix, do this:
RemoveSpellEffects(SR_FIX_ID, oCreature, oCreature); // 'nw_i0_spells'
note, that should be called *every* time the onEquip/Unequip fix runs. Else it applies again and again and again and ...... And by doing Remove first, if the item-loop finds SR==0, the previous effect will be removed (without touching temporaries). Then the creature should be gtg.


When i need a unique spell-ID, I just make one up between 5000 and 10000. The point is it needs to be consistent between the Spawn-application and the PC-application. Effect construction, for both types, should look like this:
effect eSR = EffectSpellResistanceIncrease(iSR);
eSR = SetEffectSpellId(eSR, SR_FIX_ID); // define this in your constants file ...
eSR = SupernaturalEffect(eSR);
the kPrC pack defines that spell ID as "-4000". I think i'm likely going to stick to that,

#35
kevL

kevL
  • Members
  • 4 052 messages
edit: be careful you may have to do some hocus-pocus (or use a different function), to get the parameters of RemoveSpellEffects() just right ...

this one should work better
void RemoveEffectByID(int iSpell_ID, object oTarget)
{
    effect eEffect = GetFirstEffect(oTarget);
    while (GetIsEffectValid(eEffect))
    {
        if (GetEffectSpellId(eEffect) == iSpell_ID)
        {
            RemoveEffect(oTarget, eEffect);
            eEffect = GetFirstEffect(oTarget);
        }
        else
        {
            eEffect = GetNextEffect(oTarget);
        }
    }
}


#36
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

<SNIP> hm, I think i spot the glitch there. An application of EffectSpellResistanceIncrease() will not overwrite a previous application. They will co-exist on the character. The PC-application *will not* overwrite nor necessarily overrule the Spawn-application; the latter (either, actually) will remain on the Character unless explicitly removed.</SNIP>


Hi KevL,

Actually, I don't have this problem using the "ITEM-FEAT" method that I outline in previous posts. Because, if the item is removed then so is the feat, and any SR related to the ITEM-FEAT disappears along with it, leaving any original SR in place at time of OnSpawn.
 

The easiest way to clean the effect is to assign it a spell-ID, at the same time as setting it Supernatural, then use that same ID both onSpawn *and* onEquip/Unequip. And at the top of the PC fix, do this:




RemoveSpellEffects(SR_FIX_ID, oCreature, oCreature); // 'nw_i0_spells'
note, that should be called *every* time the onEquip/Unequip fix runs. Else it applies again and again and again and ...... And by doing Remove first, if the item-loop finds SR==0, the previous effect will be removed (without touching temporaries). Then the creature should be gtg.


I imagine this is doing something similar to what my assigning it as a "feat" does.

EDIT: Looking at your SPELL ID scripts, I reckon that is what the feat thing does. i.e. My feat simply applies the unique spell line that adds the SR effect. I just chose to "display" the SR as a "feat" benefit (via an item) rather than add the SR benefit "silently" as it were (apart from the character sheet).

Does that make sense?

Cheers,
Lance

#37
kevL

kevL
  • Members
  • 4 052 messages
if you're using a feat to assign and remove the sr-fix effect on both 'modes' I think you're okay. (as long as you're sure that removing the feat *really* removes the sr-effect correctly)


Are you doing that on the PC-application? Because, my concern is (barring PC-come-Party, doesn't matter for this), that the onEquip/Unequip will continue to apply the effect -- multiple times, unless regulated by removing its previous application first ... or regulating it with the custom feat (which to me is a roundabout way of using a spell-ID, shrug*)

*albeit a nice touch.

#38
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

if you're using a feat to assign and remove the sr-fix effect on both 'modes' I think you're okay. (as long as you're sure that removing the feat *really* removes the sr-effect correctly)


Are you doing that on the PC-application? Because, my concern is (barring PC-come-Party, doesn't matter for this), that the onEquip/Unequip will continue to apply the effect -- multiple times, unless regulated by removing its previous application first ... or regulating it with the custom feat (which to me is a roundabout way of using a spell-ID, shrug*)

*albeit a nice touch.


Hi KevL,

Well, I did this for a test ....

1) I set an NPC (which can become a companion) with a succubus skin (18 SR) and when I added them to the party, she had the correct 18 SR showing.

2) I then gave her a SR 20 cloak and had her put it on .... SR went up to SR 20 as the "FEAT - ITEM SR" was added to her.

3) Then I had her un-equip the item and the feat (and associated SR) also came off, leaving her with her "natural" SR 18.

So, unless I have missed anything else, then it looks good to go. :)

And as you say, very similar to the "spell" route I guess.

Cheers,
Lance.

#39
kevL

kevL
  • Members
  • 4 052 messages
Creature skins are, ofc, Items. So you say she got a feat for putting on a cloak; does she get a feat for wearing the skin?



The 2 questions i'd be asking here are:

1. How many SR-effects does the character have at any given time. ( by looping over effects and counting those of type EFFECT_TYPE_SPELL_RESISTANCE_INCREASE )

2. What is the character's SR at any given time and is it still valid after a hostile spell's spell resistance check. ( according to GetSpellResistance() )


note that spell-Id has little to do with spells for this (except that they shouldn't conflict with real spell-Ids). It's just a tool for *uniquely identifying* the particular application(s) of the SR effect.

#40
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Creature skins are, ofc, Items. So you say she got a feat for putting on a cloak; does she get a feat for wearing the skin?


Actually, she *didn't* get the feat for the skin, as the code does not check "equipped" items (inc skins) for her OnSpawn, but gave her the SR because of the skin. Now, this could *potentially* be a problem if we do want to end up "mixing" natural fixes with equipment fixes this way. I suppose I could still do the "item check" and simply apply the permanent SR again (as per OnSpawn method) rather than add the feat if the "skin is returned".
 

The 2 questions i'd be asking here are:

1. How many SR-effects does the character have at any given time. ( by looping over effects and counting those of type EFFECT_TYPE_SPELL_RESISTANCE_INCREASE )


It only ever applies the highest SR found.
 

2. What is the character's SR at any given time and is it still valid after a hostile spell's spell resistance check. ( according to GetSpellResistance() )


See opening comment. The effect is currently lost, but I will look at doing what I said to see if this addresses the "lose" after first attack again.
 

note that spell-Id has little to do with spells for this (except that they shouldn't conflict with real spell-Ids). It's just a tool for *uniquely identifying* the particular application(s) of the SR effect.


Noted.

EDIT: OK, something unexpected happened for me in this test .... The NPC (who became a companion) did *NOT* maintain her SR after an initial attack having had the normal OnSpawn application of SR. Something about the nature of the SR changed with respect to the value applied at time of OnSpawn. Will double-check with a"normal" monster, but seems odd. OOPS: My bad, I have different OnSpawn scripts on potential companions at the moment.

EDIT 2: I also forgot something I discovered about "skins" on PC controlled creatures, which I need to work around now: - http://worldofalthea...n-problems.html
i.e. So instead, I will apply a "SKINSR" as a variable if they have some form of natural SR. (By the way, this is probably going way beyond my own needs, but it is good to consider for others potential needs.) Basically, any potential companion or creature that the player can control and will add armour to, should not have a skin applied.



Lance.

#41
kevL

kevL
  • Members
  • 4 052 messages
will wait a bit ...

#42
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

will wait a bit ...


Hi KevL,

I will post updated scripts tomorrow, but I do have something that I think will work. It just takes a bit more to do due to having to avoid any potential "skin" problems that could be involved with player controlled companions.

Back tomorrow. Night for now.

Cheers,
Lance.

#43
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages
Hi KevL,

I had to rewrite the scripts because of a few points that needed addressing when it came to how SR was applied to either an NPC that could become a companion (and could be raised, equip/un-equip SR items), or an NPC that simply needed the SR fixed. These scripts should address the following points:-

1) Applies a permanent "natural" SR fix to NPCs that are simply monsters via SKIN SR value. E.g. Succubus with SR attached to "SKIN" item.
2) Applies a permanent "natural" SR fix to NPCs that can become companions via a variable SR value. i.e. Companions MUST NOT use "SKINS". (See http://worldofalthea...n-problems.html)
3A) Reapplies a permanent "natural" SR fix to companions raised from the dead. (Because SR fix is removed upon "death".)
3B) The function UpdateSRCondition that fixes SR can be delayed to double check any automatically re-equipped equipment after a resurrection if need be. (E.g. Used in my own campaign with the Tombstone system. See http://worldofalthea...h-recovery.html )
4) A dedicated ITEM SR FEAT is applied to a any player controlled PC who equips an item that has a higher SR than any "natural" SR they may have. If the item is removed, any "natural" SR is returned and made permanent in its place.

Below is a list of the functions, followed by which scripts to call them from, and the feat spell script. The FEAT should be added as a persistent feat, so that it activates immediately and stays active all the while the conditions are met (the creature wears the SR ITEM).
 
**** IMPORTANT ****
 
The function GetMainPC() is a homebrew function that checks if the object returned is one that a player can control, whether they currently possess that creature or not. i.e. You will need to use your own appropriate function to determine this within the function.

I hope this all makes sense ... and that *should* be it ... unless I have missed something?

Cheers,
Lance.

THE FUNCTIONS
 
///////////////////////////////////////////////////////////////////////////////////////////////////
// RETURN (& STORE) THE SUB VALUE OF AN ITEM PROPERTY ON AN ITEM (E.g. SR Value of an SR property.)
// DEFAULT: STORES/CACHES ALL PROPERTY SUB-VALUES ON ITEM WHEN CALLED FOR ITEM. UNTESTED WITH MANY PROPS.
// E.g. IF iPROPERTY = ITEM_PROPERTY_SPELL_RESISTANCE (or 39), then this function will cycle through
// an item's properties looking to see if it had Spell Resistance. If it does, then this 
// function will return the sub value of the SR property on the oItem.
// It will also STORE the SUB VALUE on the item in a variable "PROP39_SUBPROP0" (39 is int for SR)
// BEST USAGE: Use this function when acquiring an item for the first time, and then refer to the
// stored integer values recorded at the time of acquisition, rather than risk looping if possible.
///////////////////////////////////////////////////////////////////////////////////////////////////
int LBGetItemPropertySubValue(object oItem, int iPROPERTY = -1);
int LBGetItemPropertySubValue(object oItem, int iPROPERTY = -1)
{	
	// ONCE IS ENOUGH (DELETE TO UPDATE)
	SetLocalInt(oItem, "SUBPROPSDONE", 1);
	
	// PREPARE A NEGATIVE RETURN
	int iSubValue = -1;
	
	// LOOK FOR THE PROPERTY ON THE ITEM
	itemproperty iProp = GetFirstItemProperty(oItem);
    
	while (GetIsItemPropertyValid(iProp))
    {
        int iPROPFOUND = GetItemPropertyType(iProp);
		
		// FOUND THE PROPERTY WE ARE LOOKING FOR
		if(iPROPFOUND == iPROPERTY || iPROPERTY == -1)
		{
			// FIND THE ROW INDICATING THE SUB-VALUE 2DA TO USE (E.g. SR returns 11)
			// AS A NOTE: THIS FUNCTION MAY GET ITS REFERENCE FROM THE itempropdef.2da
			int iPROPERTY_COSTTABLE_ROW = GetItemPropertyCostTable(iProp);
	        
			// NOW WE CAN DETERMINE THE SUB VALUE FOR THIS PROPERTY ATTACHED TO THIS ITEM
			// IF A VALID SUB-VALUE COST 2DA IS RETURNED (WHICH SHOULD BE > 0)
			if(iPROPERTY_COSTTABLE_ROW > 0)
	        {
	            // DETERMINE THE NAME OF THE SUB PROPERTY 2DA TO USE
				string sSubTable2da = Get2DAString("iprp_costtable", "Name", iPROPERTY_COSTTABLE_ROW);
				
				// THIS FUNCTION DETERMINES THE SUB-VALUE 2DA ROW NUMBER FOR THE PROPERTY
				int iROW_SUBVAL = GetItemPropertyCostTableValue(iProp);
				
				// RETRIEVE THE SUB-VALUE FROM THE SUB-VALUE 2da
	            string sSUBValue = Get2DAString(sSubTable2da, "Value", iROW_SUBVAL);
				
				// RETURN AS AN INT            
				iSubValue = StringToInt(sSUBValue);				
				
				// A FURTHER DISTINGUISHER IF REQUIRED (E.g. DIFFERENT ABILITIES ON SAME ITEM, EACH DIFFERING VALUE)
				int iSubType = GetItemPropertySubType(iProp);				
				string sSUBVALUE = "PROP" + IntToString(iPROPFOUND) + "_SUBPROP" + IntToString(iSubType);
				
				// STORE VALUE ON ITEM
				SetLocalInt(oItem, sSUBVALUE, iSubValue);				
				
				// DEBUG
				//SetNoticeTextAll("ITEM SUB PROPERTY VALUES >>>> " + sSUBValue + " STORED WITHIN " + sSUBVALUE, 1);				 
	        }
		}
        
		iProp = GetNextItemProperty(oItem);
    }
	
	// RETURN THE SUB VALUE WHETHER USED OR NOT (RETURN NEGATIVE IF JUST FINDING ALL)	
	if(iPROPERTY == -1){iSubValue = -1;}	
	return iSubValue;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// CYCLE THROUGH ALL EQUIPPED ITEMS FOR HIGHEST SR ITEM (STORE AS AN INT ON SR ITEM)
///////////////////////////////////////////////////////////////////////////////////////////////////
int GetBestEquippedSRValue(object oCreature);
int GetBestEquippedSRValue(object oCreature)
{
	int i; 
	int iCurrentSRItem = 0;	
	int iNaturalSRValue = GetLocalInt(oCreature, "NATURALSRVALUE");
	int iCompare = 0;
    
	// ALLOW UP TO 10 ONLY AS THEY ARE THE ONLY VALID SR EQUIP TO CHECK
	for(i=0; i<11; i++)
    {
    	object oEquip = GetItemInSlot(i,oCreature);
    	
		if(GetIsObjectValid(oEquip))
        {	
			iCompare = GetLocalInt(oEquip, "PROP39_SUBPROP0");
			
			SetNoticeTextAll("ITEM NUM " + IntToString(i) + " >>>> " + IntToString(iCurrentSRItem), 1);
			
			// ONLY STORE ITEM SR VALUE IF BETTER THAN ALREADY RECORDED AND NATURAL SR ABILITY
			if(iCompare >= iCurrentSRItem && iCompare >= iNaturalSRValue){iCurrentSRItem = iCompare;}
        }
    }	
	
	// CAN RETURN ZERO
	return iCurrentSRItem;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// UPDATE CURRENT Spell Resistance (SR) FOR CREATURE
// FUNCTION FIRST CALLED AT SPAWN TO SETUP ANY NATURAL SR FOR THE CREATURE
// LATER CALLED IF A VALID SR ITEM IS EQUIPPED OR UNEQUIPPED FOR A PLAYER CONTROLLED CREATURE
// ALSO CALLED IF A PLAYER CONTROLLED COMPANION IS RAISED FROM THE DEAD (REFRESHES SR VALUES)
///////////////////////////////////////////////////////////////////////////////////////////////////
void UpdateSRCondition(object oCreature, int iRAISED = 0); 
void UpdateSRCondition(object oCreature, int iRAISED = 0)
{		
	SetNoticeText(oCreature, "UPDATING SR STATUS ON " + GetName(oCreature));
	
	// PREPARE NEW SR VALUE
	int iNEWSRValue = 0;
	
	// RETRIEVE ANY NATURAL SR VALUES - SET AT SPAWN VIA VAR (FOR COMPS) OR SKIN (FOR NPCS)
	int iNATURALSRValue = GetLocalInt(oCreature, "NATURALSRVALUE");
	
	///////////////////////////////////////////////////////////////////////////////
	// COMP/NPC SPAWNED WITH SR IN SOME WAY: SR INITIAL PERMANENT FIX	
	///////////////////////////////////////////////////////////////////////////////
	
	if(GetMainPC(oCreature) == OBJECT_INVALID && iRAISED == 0)
	{	
                // UPDATE NATURALVALUE FOR ALL CREATURES SPAWNED WITH SR SKIN
		if(GetLocalInt(oCreature, "NATURALSRVALUE") == 0)
		{
			iNATURALSRValue = GetSpellResistance(oCreature);			
		}	


                // SAFETY CHECK AGAINST BAD FUNCTION PASS
                if(iNATURALSRValue == 0){return;}
		
		// PREPARE THE SR EFFECT
		effect eSR = EffectSpellResistanceIncrease(iNATURALSRValue, -1);
		eSR = SupernaturalEffect(eSR);
	
		// APPLY THE EFFECT
		ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSR, oCreature);
		return;
	}	
	
	/////////////////////////////////////////////////////////////////////////
	// CALLED ONEQUIP OR UNEQUIP - GET HIGHEST VALID SR EQUIPPED ITEM (CAN BE ZERO)
	// IF THIS VALUE IS > 0 & NAT SR, THEN THE FEAT "ITEM SR" IS ADDED TO THE CREATURE
	/////////////////////////////////////////////////////////////////////////
	
	else{iNEWSRValue = GetBestEquippedSRValue(oCreature);}	
	
	// REMOVE THE ITEM SR FEAT REGARDLESS TO PREVENT "REDUNDANCY" EFFECT

	FeatRemove(oCreature, 2893);		
		
	// SR ITEM EQUIPPED & REQUIRES FEAT UPDATE (ITEM SR MADE PERMANENT THROUGH THE FEAT)
	if(iNEWSRValue > 0)
	{		
		SetLocalInt(oCreature, "SRUPDATE", iNEWSRValue);
		FeatAdd(oCreature, 2893, FALSE, TRUE, TRUE);
	}
	
	// RESTORE ANY NATURAL SR IF REQUIRED (NATURAL SR MADE PERMANENT HERE)
	// CALLED WHEN CREATURE RAISED FROM DEAD OR REMOVES SR ITEM
	else if(iNATURALSRValue > 0)
	{
		// PREPARE THE SR EFFECT
		effect eSR = EffectSpellResistanceIncrease(iNATURALSRValue, -1);
		eSR = SupernaturalEffect(eSR);
	
		// APPLY THE EFFECT
		ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSR, oCreature);	
	
	}		
}
 
SET UP VARIABLE VALUES ON ITEM ACQUIRED
 
// LETS TRY ADDING PROPERTY SUB-VALUES AS VARIABLES HERE
	if(GetLocalInt(oItem, "SUBPROPSDONE") == 0){LBGetItemPropertySubValue(oItem);}
  
 POTENTIAL COMPANION ONSPAWN (MUST NOT USE SKINS AS THESE CAUSE ISSUES)
 
// ADD "NATURALSRVALUE" AT TIME OF BUILD
	int iSRValue = GetLocalInt(OBJECT_SELF, "NATURALSRVALUE");
	if(iSRValue> 0){UpdateSRCondition(OBJECT_SELF);}
MONSTER ONSPAWN (USES NORMAL SKINS THAT HAVE AN SR VALUE ON THEM)



// SR - SIMPLY CHECK FOR AND MAKE ANY SR FOUND PERMANENT
        object oSKIN = GetItemInSlot(17); 
	if(GetItemHasItemProperty(oSKIN, ITEM_PROPERTY_SPELL_RESISTANCE)){UpdateSRCondition(OBJECT_SELF);}
FUNCTION MUST ALSO BE ADDED AND CALLED FROM THE RAISE DEAD OR RESURRECTION SPELLS



// RESTORE ANY NATURAL SR
	UpdateSRCondition(oTarget, 1);
FUNCTION CALLED FROM ON EQUIP



///////////////////////////////////////////////////////////////////////////////////////////////////
	// UPDATE SPELL RESISTANCE FOR PC ACCORDING TO EQUIPMENT - ONLY SR ITEMS FIRE FUNCTION
	// DELAY ALLOWS TIME FOR ANY UNEQUIPPING IF OTHER SR ITEMS AT SAME TIME
	///////////////////////////////////////////////////////////////////////////////////////////////////
	 
	if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_SPELL_RESISTANCE)){DelayCommand(0.11, UpdateSRCondition(oPC));}
	
FUNCTION CALLED FROM ON UNEQUIP



///////////////////////////////////////////////////////////////////////////////////////////////////
	// UPDATE SPELL RESISTANCE FOR PC ACCORDING TO EQUIPMENT - ONLY SR ITEMS FIRE FUNCTION	
	// NEED DELAY TO ALLOW ITEM TO UNEQUIP BEFORE THE CHECK FOR REMAINING SR ITEMS IS MADE
	///////////////////////////////////////////////////////////////////////////////////////////////////
	 
	if(GetItemHasItemProperty(oItem, ITEM_PROPERTY_SPELL_RESISTANCE)){DelayCommand(0.1, UpdateSRCondition(oPC));}
THE ITEM SR FEAT SPELL SCRIPT



// SPELL RESISTANCE FIX FOR ITEMS (BY GIVING A FEAT)
// ADD SPELL RESISTANCE VALUE ACCORDING TO THE ITEM EQUIPPED

void main()
{
	// THE OBJECT WITH SR
	object oCreature = OBJECT_SELF;
	
	// RETRIEVE THE SR VALUE TO ASSIGN
	int iSRValue = GetLocalInt(oCreature, "SRUPDATE");
	DeleteLocalInt(oCreature, "SRUPDATE");
	
	// PREPARE THE SR EFFECT
	effect eSR = EffectSpellResistanceIncrease(iSRValue, -1);
	eSR = SupernaturalEffect(eSR);
	
	// APPLY THE EFFECT
	ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSR, oCreature);	
}


#44
kevL

kevL
  • Members
  • 4 052 messages
I still don't think the previous permanent effect is removed before applying a subsequent permanent effect. Unless removing the feat from the character also removes the effect *on* the character.


i also notice this bit in UpdateSRCondition():
// UPDATE NATURALVALUE FOR ALL CREATURES SPAWNED WITH SR SKIN
    if(GetLocalInt(oCreature, "NATURALSRVALUE") == 0)
    {
        iNATURALSRValue = GetSpellResistance(oCreature);
        SetLocalInt(oCreature, "NATURALSRVALUE", iNEWSRValue);
    }
it applies iNEWSRValue to the "NATURALSRVALUE" local int. intentional? (iNEWSRValue will always be 0 at that point...)


Overall it strikes me as more complicated than it needs to be and less universal than it could be, for the sake of a few very negligible speed-ups. But if it works on Althea, that's good enough in my opinion,

#45
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

I still don't think the previous permanent effect is removed before applying a subsequent permanent effect. Unless removing the feat from the character also removes the effect *on* the character.


Hi KevL,

I believe that must be what is happening (effect removed as feat removed), as I do not notice it any other way .... as far as I can see.
 

i also notice this bit in UpdateSRCondition():




// UPDATE NATURALVALUE FOR ALL CREATURES SPAWNED WITH SR SKIN
    if(GetLocalInt(oCreature, "NATURALSRVALUE") == 0)
    {
        iNATURALSRValue = GetSpellResistance(oCreature);
        SetLocalInt(oCreature, "NATURALSRVALUE", iNEWSRValue);
    }
it applies iNEWSRValue to the "NATURALSRVALUE" local int. intentional? (iNEWSRValue will always be 0 at that point...)


This will not be zero if the creature passed was a potential companion. i.e. It is a creature with a SKIN being passed that makes it zero. It differentiates between the OnSpawn script of a normal monster and a companion with a variable. This just makes sure that creatures with skins also get the value added as a variable to work with.
 

Overall it strikes me as more complicated than it needs to be and less universal than it could be, for the sake of a few very negligible speed-ups. But if it works on Althea, that's good enough in my opinion,


Yes, I noticed that the code was becoming more module specific. Unfortunately, that is due to the "death" consideration, especially of companions who may have a natural SR and have been given equipment that is still equipped when they are raised. This is extremely important in my campaign as "raising" can be "instant" if a special item is carried and implemented.

Still, I believe this does cover all the angles now ... and does offer a template to work by, even if it needs adapting to fit specific module requirements. i.e. The principle works. :)

Cheers,
Lance.

#46
kevL

kevL
  • Members
  • 4 052 messages

This will not be zero if the creature passed was a potential companion. i.e. It is a creature with a SKIN being passed that makes it zero. It differentiates between the OnSpawn script of a normal monster and a companion with a variable. This just makes sure that creatures with skins also get the value added as a variable to work with.


void UpdateSRCondition(object oCreature, int iRAISED = 0)
{		
    int iNEWSRValue = 0;

    int iNATURALSRValue = GetLocalInt(oCreature, "NATURALSRVALUE");
    
    if(GetMainPC(oCreature) == OBJECT_INVALID && iRAISED == 0)
    {
        if(GetLocalInt(oCreature, "NATURALSRVALUE") == 0)
        {
            iNATURALSRValue = GetSpellResistance(oCreature);
            SetLocalInt(oCreature, "NATURALSRVALUE", iNEWSRValue);
            // how can iNEWSRValue be anything other than 0 there
            // It was defined as 0 at the start of the function and nothing changed it ...
        }		
        
        if(iNATURALSRValue == 0){return;}
        
        effect eSR = EffectSpellResistanceIncrease(iNATURALSRValue, -1);
        eSR = SupernaturalEffect(eSR);
    
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSR, oCreature);
        return;
    }	
    else{iNEWSRValue = GetBestEquippedSRValue(oCreature);}	
    

    if(GetHasFeatEffect(2893, oCreature) && iNEWSRValue == 0)
    {
        FeatRemove(oCreature, 2893);		
    }	
        

    if(iNEWSRValue > 0)
    {		
        SetLocalInt(oCreature, "SRUPDATE", iNEWSRValue);
        FeatAdd(oCreature, 2893, FALSE, TRUE, TRUE);
    }
    

    else if(iNATURALSRValue > 0)
    {
        effect eSR = EffectSpellResistanceIncrease(iNATURALSRValue, -1);
        eSR = SupernaturalEffect(eSR);
    
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSR, oCreature);	
    }		
}


#47
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

void UpdateSRCondition(object oCreature, int iRAISED = 0)
{		
    int iNEWSRValue = 0;

    int iNATURALSRValue = GetLocalInt(oCreature, "NATURALSRVALUE");
    
    if(GetMainPC(oCreature) == OBJECT_INVALID && iRAISED == 0)
    {
        if(GetLocalInt(oCreature, "NATURALSRVALUE") == 0)
        {
            iNATURALSRValue = GetSpellResistance(oCreature);
            SetLocalInt(oCreature, "NATURALSRVALUE", iNEWSRValue);
            // how can iNEWSRValue be anything other than 0 there
            // It was defined as 0 at the start of the function and nothing changed it ...
        }		
        
        if(iNATURALSRValue == 0){return;}
        
        effect eSR = EffectSpellResistanceIncrease(iNATURALSRValue, -1);
        eSR = SupernaturalEffect(eSR);
    
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSR, oCreature);
        return;
    }	
    else{iNEWSRValue = GetBestEquippedSRValue(oCreature);}	
    

    if(GetHasFeatEffect(2893, oCreature) && iNEWSRValue == 0)
    {
        FeatRemove(oCreature, 2893);		
    }	
        

    if(iNEWSRValue > 0)
    {		
        SetLocalInt(oCreature, "SRUPDATE", iNEWSRValue);
        FeatAdd(oCreature, 2893, FALSE, TRUE, TRUE);
    }
    

    else if(iNATURALSRValue > 0)
    {
        effect eSR = EffectSpellResistanceIncrease(iNATURALSRValue, -1);
        eSR = SupernaturalEffect(eSR);
    
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSR, oCreature);	
    }		
}


Hi KevL,

Ah! I see what you say ... Let me check my own script in case I edited and pasted the wrong version.

GOOD CATCH ... It was wrong in my own script too. It should have been "iNATURALSRValue" there. I did not see it in testing, because I never tested a monster (with SKIN) being "raised" and needing it reapplied ... which is NEVER done anyway! I'll tidy that up a bit I think, by removing the whole line, which is obviously no longer required.

I will double check again ... and hopefully there won't be anything else. Doh!

EDIT: I have corrected the original post ... and my own script. ;)

Hopefully that's it now ...

Cheers,
Lance.

#48
kevL

kevL
  • Members
  • 4 052 messages
i guess I should post a poor man's solution:

Acknowledgments:
- Kaedrin's PrC Pack
- Spell Fixes and Improvements by Reeron and Trekari (Increased Challenge add-on)
- Lance Botelle, Bard of Althea

Three events:
module event - on Player Equip
module event - on Player Unequip (delayed by 0.1 sec to give time for item to be unequipped)
These correct the item-SR bug for Party and Roster members, excluding Associates.

creature event - on Spawn (Monsters/NPCs/Associates)
This corrects the item-SR bug for creature carapices and other equipped SR-items.


call this function in the events above.
Or wherever you need it, after resurrection perhaps or explicitly equipping/unequipping/changing an SR-item on an NPC during gameplay or maybe when an NPC joins the Roster or possibly after module transitions although I think that's covered, eg.
void FixItemSR(object oCreature = OBJECT_SELF)
{
    if (GetHasSpellEffect(-4000, oCreature))
    {
        effect eEffect = GetFirstEffect(oCreature);
        while (GetIsEffectValid(eEffect))
        {
            if (GetEffectSpellId(eEffect) == -4000)
            {
                RemoveEffect(oCreature, eEffect);
                eEffect = GetFirstEffect(oCreature);
            }
            else
                eEffect = GetNextEffect(oCreature);
        }
    }


    object oItem;
    int iSR = 0;
    int
        iTest,
        iIndex;

    int iSlot;
    for (iSlot = 0; iSlot < NUM_INVENTORY_SLOTS; ++iSlot)
    {
        oItem = GetItemInSlot(iSlot, oCreature);
        if (GetIsObjectValid(oItem))
        {
            itemproperty ipProp = GetFirstItemProperty(oItem);
            while (GetIsItemPropertyValid(ipProp))
            {
                iIndex = GetItemPropertyCostTable(ipProp);
                if (iIndex == 11)
                {
                    iIndex = GetItemPropertyCostTableValue(ipProp);
                    iTest = StringToInt(Get2DAString("iprp_srcost", "Value", iIndex));

                    if (iSR < iTest)
                        iSR = iTest;
                }

                ipProp = GetNextItemProperty(oItem);
            }
        }
    }

    if (iSR > 0)
    {
        effect eSR = EffectSpellResistanceIncrease(iSR);
        eSR = SupernaturalEffect(eSR);
        eSR = SetEffectSpellId(eSR, -4000);

        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSR, oCreature);
    }
}
Some details in my descriptions may be off but I believe the code itself is pretty darn solid. Note that this fix does not apply to a pseudo-bug for racial and class SR Feats, which won't be decreased by anti-SR spells when you might think they should be. Rather, this is exclusively to fix the fact that item-granted Spell Resistance becomes broken after its first resistance check.

Note also that a proper installation of Kaedrin's PrC Pack already covers the onPlayerEquip/Unequip events. The Increased Challenge and Personal Impossibility Adjustment add-ons cover *some* of the onSpawn events ('nw_c2_default9').

#49
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

i guess I should post a poor man's solution:

Acknowledgments:
- Kaedrin's PrC Pack
- Spell Fixes and Improvements by Reeron and Trekari (Increased Challenge add-on)
- Lance Botelle, Bard of Althea

Three events:
module event - on Player Equip
module event - on Player Unequip (delayed by 0.1 sec to give time for item to be unequipped)
These correct the item-SR bug for Party and Roster members, excluding Associates.

creature event - on Spawn (Monsters/NPCs/Associates)
This corrects the item-SR bug for creature carapices and other equipped SR-items.


call this function in the events above.
Or wherever you need it, after resurrection perhaps or explicitly equipping/unequipping/changing an SR-item on an NPC during gameplay or maybe when an NPC joins the Roster or possibly after module transitions although I think that's covered, eg.



void FixItemSR(object oCreature = OBJECT_SELF)
{
    if (GetHasSpellEffect(-4000, oCreature))
    {
        effect eEffect = GetFirstEffect(oCreature);
        while (GetIsEffectValid(eEffect))
        {
            if (GetEffectSpellId(eEffect) == -4000)
            {
                RemoveEffect(oCreature, eEffect);
                eEffect = GetFirstEffect(oCreature);
            }
            else
                eEffect = GetNextEffect(oCreature);
        }
    }


    object oItem;
    int iSR = 0;
    int
        iTest,
        iIndex;

    int iSlot;
    for (iSlot = 0; iSlot < NUM_INVENTORY_SLOTS; ++iSlot)
    {
        oItem = GetItemInSlot(iSlot, oCreature);
        if (GetIsObjectValid(oItem))
        {
            itemproperty ipProp = GetFirstItemProperty(oItem);
            while (GetIsItemPropertyValid(ipProp))
            {
                iIndex = GetItemPropertyCostTable(ipProp);
                if (iIndex == 11)
                {
                    iIndex = GetItemPropertyCostTableValue(ipProp);
                    iSR = StringToInt(Get2DAString("iprp_srcost", "Value", iIndex));

                    if (iSR < iTest)
                        iSR = iTest;
                }

                ipProp = GetNextItemProperty(oItem);
            }
        }
    }

    if (iSR > 0)
    {
        effect eSR = EffectSpellResistanceIncrease(iSR);
        eSR = SupernaturalEffect(eSR);
        eSR = SetEffectSpellId(eSR, -4000);

        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSR, oCreature);
    }
}
Some details in my descriptions may be off but I believe the code itself is pretty darn solid. Note that this fix does not apply to a pseudo-bug for racial and class SR Feats, which won't be decreased by anti-SR spells when you might think they should be. Rather, this is exclusively to fix the fact that item-granted Spell Resistance becomes broken after its first resistance check.

Note also that a proper installation of Kaedrin's PrC Pack already covers the onPlayerEquip/Unequip events. The Increased Challenge and Personal Impossibility Adjustment add-ons cover *some* of the onSpawn events ('nw_c2_default9').


Hi KevL,

That looks nice and tidy. :) I see you use the dedicated spell ID .... but what is -4000? How can you have a negative value? Looks like I may be about to learn something new. ;)

Also, I recognise this is more dedicated (to SR effect search only) than my own approach here ... apart from the fact that I also had to alter some parts of mine to make it work for my module of course. ;)

Does the combination of EQUIP/UNEQUIP delays work if a PC equips an identical item but with differing SR values? e.g. PC is wearing a Cloak with SR12, and double-clicks to equip a Cloak with SR20. Does the SR update correctly? I think this was why I used the delay values I did, but that may also have been due to my own scripts doing something else as well. Just checking.

Cheers,
Lance.

#50
kevL

kevL
  • Members
  • 4 052 messages

That looks nice and tidy. :) I see you use the dedicated spell ID .... but what is -4000? How can you have a negative value? Looks like I may be about to learn something new. ;)


I sorta freaked out when i first saw a negative spell-Id also. But i've since concluded that a "spellId" is just a signed integer value (likely four bytes, allowing for values -2147483648 to 2147483647). by making it negative, Kaedrin -- it's the value used in the kPrc Pack -- guarantees there won't be a conflict with any Spells.2da entry.

To take another example of spell-Id usage: another section in my PlayerEquip/Unequip handles a reduction to Reflex Saves based on ACP (Armor Check Penalty). I use an arbitrary spell-Id of "74925" for EffectSavingThrowDecrease() ... long time before Spells.2da gets *that* big.
 

Also, I recognise this is more dedicated (to SR effect search only) than my own approach here ... apart from the fact that I also had to alter some parts of mine to make it work for my module of course. ;)


sr-effect search (but only the sr-effect applied by the fix itself) *and* converting item-SR into a dedicated effect-SR ...
 

Does the combination of EQUIP/UNEQUIP delays work if a PC equips an identical item but with differing SR values? e.g. PC is wearing a Cloak with SR12, and double-clicks to equip a Cloak with SR20. Does the SR update correctly? I think this was why I used the delay values I did, but that may also have been due to my own scripts doing something else as well. Just checking.


am pretty sure the delay is required on only the Unequip phase. Tests: the unequip event fires before the equip event, but since the unequip event is delayed all necessary item changes have occurred and the tests say SR is properly accounted for as is.




ps. Oh dang, you're getting me in the mood to work on my module again ....