@Shadooow
That is what I do/have done. I just thought I had found a solution to avoid having to use GetIsImmune in the function (for poison), but had not. i.e. A fail save ended up being checked twice, so I reverted to simply using a GetIsImmune to bypass other checks and let the default functions do their job.
Anyway, I believe that is as much as I am able to do here, and at least it serves the purpose I aimed for … Ref poison, you do need to ensure you send the POISON subtype, or else it will still not report correctly on a fail save still … but hopefully a builder who might use the function will add that when required.
On a positive note, curses do not appear to be an issue and work with the function fine, because there is no “immunity” for curses as such. And even though we can get immunities to ability decreases, I am content that they do not qualify in this case. i.e. The effect is a curse specifically, and the results of that are not considered as independent effects that can be “immunized” against. Spell resistance does still work though, and as I do not intend to alter the spell in this instance, it’s irrelevant anyway. However, I have tested a curse via another source and it appeared to work fine.
So, here it is, as far as I am going to take it … The only real addition is the GetIsImmune versus a POISON save effect that required extra attention. As you say, I may not have covered everything, but I will check it as time goes by to see if other effects that use it require any extra attention.
It has been tested with a few effects, but should be good with all. Just double check results to be sure you are happy with them.
NB: Can be used with all effect types, but care should be taken when asking for a poison save check - MUST pass the SAVING_THROW_TYPE_POISON.
//////////////////////////////////////////////////////////////////////////////////
// SAVING THROW WITH VFX DEPENDING UPON IMMUNE OR RESISTED OR FAILED (LANCE BOTELLE)
// SIMPLY RETURNS 0 ON SAVE FAIL, RETURNS 1 ON SAVE MADE, RETURNS 2 ON IMMUNE (WITH VFXs)
// NB 1: ANY POISON SAVE IGNORES ANY DC PASSED & USES THE POISON.2DA REF INSTEAD (iSupMess IS MADE 1 IF NOT IMMUNE)
// NB 2: Reports integer only. Any result from that (like death) must be handled seperately.
// NB 3: This does not test for spell cast timings between effect and requirement.
// Therefore, the moment this function is called, the check is made with VFX.
// oTarget is the PC or creature making the saving throw.
// iSAVETYPE CAN BE: SAVING_THROW_FORT, SAVING_THROW_REFLEX OR SAVING_THROW_WILL
// iSUBTYPE IS SAVING_THROW_TYPE_XXXX FORMAT (SAVING_THROW_TYPE_ALL IS DEFAULT)
// iDC IS THE DC TO SAVE AGAINST (DEFAULT 15) USE iSupMess = 1 IF USING SPECIFIC FEEDBACK.
// According to official source: If using with an area of effect script (On Enter
// On Exit or On Heartbeat) wemust pass GetAreaOfEffectCreator into oSaveVersus.
//////////////////////////////////////////////////////////////////////////////////
int LBSavingThrowResult(int iSAVETYPE, object oTarget, int iDC = 15, int iSUBTYPE = SAVING_THROW_TYPE_ALL, object oSaveVersus = OBJECT_SELF, int iSupMess = 0);
int LBSavingThrowResult(int iSAVETYPE, object oTarget, int iDC = 15, int iSUBTYPE = SAVING_THROW_TYPE_ALL, object oSaveVersus = OBJECT_SELF, int iSupMess = 0)
{
// LIMIT THE DC
if (iDC<1){iDC = 1;}else if (iDC > 255){iDC = 255;}
// NOT A PLAYER SPELL INTERCEPT
int iRESULT = ResistSpell(oSaveVersus, oTarget);
// NOW CHECK FOR OTHER IMMUNITIES/RESISTANCES OR SAVES
if(iRESULT < 1)
{
// POISON HAS TO BE HANDLED VIA HARD-CODE IF NO IMMUNITY
if(iSUBTYPE == SAVING_THROW_TYPE_POISON)
{
if(GetIsImmune(oTarget, IMMUNITY_TYPE_POISON, oSaveVersus)){iRESULT = 2;}
else{iSupMess = 1;}
}
// DETERMINE HOW PC SAVES FIRST (DOUBLE CHECK ANY IMMUNITY VIA SPELL AFTER ANY DEFAULT)
else if(iSAVETYPE == SAVING_THROW_FORT){iRESULT = FortitudeSave(oTarget, iDC, iSUBTYPE, oSaveVersus);}
else if(iSAVETYPE == SAVING_THROW_REFLEX){iRESULT = ReflexSave(oTarget, iDC, iSUBTYPE, oSaveVersus);}
else if(iSAVETYPE == SAVING_THROW_WILL){iRESULT = WillSave(oTarget, iDC, iSUBTYPE, oSaveVersus);}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// PLAY A VFX ACCORDING TO RESULT
//////////////////////////////////////////////////////////////////////////////////////////////////
// PC SAVES
if(iRESULT == 1)
{
effect eSR = EffectVisualEffect( VFX_DUR_SPELL_SPELL_RESISTANCE ); // uses NWN2 VFX
ApplyEffectToObject(DURATION_TYPE_INSTANT, eSR, oTarget);
if(iSupMess == 0)
{
SendMessageToPC(GetFirstPC(FALSE), "<i>" + GetName(oTarget) + " shakes off the effect!</i>");
}
}
// PC IMMUNE
else if(iRESULT == 2)
{
// BRIEF INDICATION
effect eGlobe = EffectVisualEffect( VFX_DUR_SPELL_GLOBE_INV_LESS ); // uses NWN2 VFX
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eGlobe, oTarget, 0.5);
if(iSupMess == 0)
{
SendMessageToPC(GetFirstPC(FALSE), "<i>" + GetName(oTarget) + " is immune to the effect!</i>");
}
}
// PC FAILS
else
{
effect eSR = EffectVisualEffect( VFX_DUR_MIND_AFFECTING_FEAR ); // uses NWN2 VFX
ApplyEffectToObject(DURATION_TYPE_INSTANT, eSR, oTarget);
if(iSupMess == 0)
{
SendMessageToPC(GetFirstPC(FALSE), "<i>" + GetName(oTarget) + " succumbs to the effect!</i>");
}
}
// INFORM RESULT
return iRESULT;
}
Thanks, I will take a closer look at that! 
Just a quick example of what I am trying to illustrate is that where you have additional GetIsImmune checks, I currently do not require them (as far as I can see) because the basic Save functions appear to consider them correctly. Only the POISON check I could not get to report as I hoped.
e.g. If a PC has a ring of fear immunity, my function will pass back that the PC is immune when ever they make a saving throw roll versus a FEAR subtype without the need to specifically add GetIsImmune - even if the resultant effect does not use EffectFrightened, which it seemed to me the functions required before the immunity checks would fire.
This was an important consideration for me because of (as you say) spell alterations where a different final effect may be resultant from a spell that simply uses a save versus x. E.g. I alter the result of EffectFrightened to simply an attack penalty on lower settings. Using the official scripts, if a player had a ring immune to fear, then they would not gain the benefits of said ring against a save versus fear because the final effect applied was different to “fear” expected and so they had to make a save when one should not have been required. Where you use GetIsImmune prior to the checks, I simply make use of the official functions that do return the correct result for the save type checked, rather than the final result applied.