Temporary Hit Points Script

I need a script for a passive feat that adds temporary hit points to the character that has the feat only once (and does not stack the temporary hit points.) Also I need it so if more than one character has this feat that both characters get the right number of hit points and not the highlighted character get all of the temporary hit points while the other gest none.

I have this script thus far;
#include “X0_I0_SPELLS”
#include “nwn2_inc_spells”

void main()
{
object oPC = GetLastPCRested();
object oTarget = OBJECT_SELF;
int iSWhisp = GetLevelByClass(64, oTarget);
int iSWarr = GetLevelByClass(67, oTarget);
int iCaster = iSWhisp+iSWarr;
int iWis = GetAbilityModifier(ABILITY_WISDOM, oTarget);
int iBonus = (iWis)*3;
int iTempHP = (iCaster+iBonus);

RemoveTempHitPoints();

effect eEFF = EffectTemporaryHitpoints(iTempHP);
eEFF = SupernaturalEffect(eEFF);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEFF, oTarget, HoursToSeconds(72));
SendMessageToPC(GetFirstPC(), “Youthful vigor active!”);
SetEffectSpellId(eEFF, 716416);
}

? so the effect refreshes only on successful rest?

Yes, the feat is fired and resets on rest.

This is the line on the rest script that fires this script;

if(GetHasFeat(2813, oTarget))
{
RemoveEffectsFromSpell(oTarget, 716416);
ExecuteScript(“spirit_youth”, oTarget);
}

1 Like

is your feat flagged IsPersistent in Feat.2da ? If so it should fire automatically, without having to call ExecuteScript() …

( i think this could be a problem in a few ways )

 
Or are you going with NOT IsPersistent ?

It is IsPersistent

If the feat is persistent and properly set up with a correct association to the spells.2da this script should be its impact spellscript, and it should work with the following:

void main()
{
	object oPC = OBJECT_SELF;
	if (GetHasSpellEffect(GetSpellId(), oPC) == TRUE) return;
	
	int nSWHISP = GetLevelByClass(64, oPC);
	int nSWARR = GetLevelByClass(67, oPC);
	int nWIS = GetAbilityModifier(ABILITY_WISDOM, oPC);
	if (nWIS < 0) nWIS = 0;
	int nHP = nSWHISP + nSWARR + nWIS * 3;
	
	effect eFX = EffectTemporaryHitpoints(nHP);
	eFX = ExtraordinaryEffect(eFX);
	ApplyEffectToObject(DURATION_TYPE_PERMANENT, eFX, oPC);
	SendMessageToPC(oPC, "Youthful vigor active!");
}

Now that I think about it, though, I’m not sure if using temporary hit points for this is a good idea, the effect would reapply itself as soon as those temporary hit points are removed via damage (after area transition, or reload), perhaps it would be better to change them to BonusHitPoints, the effect would be roughly the same, but it would not be removed by damage.

Thanks, I will try both to see which one actually works the way the feat was intended.

I also found a small workaround to keep the script more similar to your original idea, with temporary hps that last for 72 hours instead of being permanent, the little “downside” is that I had to add an additional permanent effect that grants 2 (not 1 because odd numbers are gross :stuck_out_tongue: ) max hp and reduce the amount of temporary hp by 2, it makes almost no difference in terms of gameplay, but it’s needed to avoid the double stacking without recurring to local variables and a modified rest script.

void main()
{
	object oPC = OBJECT_SELF;
	if (GetHasSpellEffect(GetSpellId(), oPC) == TRUE) return;
	
	SendMessageToPC(oPC, "Youthful vigor active!");
	
	int nSWHISP = GetLevelByClass(64, oPC);
	int nSWARR = GetLevelByClass(67, oPC);
	int nWIS = GetAbilityModifier(ABILITY_WISDOM, oPC);
	int nHP = nSWHISP + nSWARR + nWIS * 3;
	
	effect ePERM = EffectBonusHitpoints(2);
	ePERM = ExtraordinaryEffect(ePERM);
	ApplyEffectToObject(DURATION_TYPE_PERMANENT, ePERM, oPC);
	
	if (nHP <= 2) return;
	effect eTEMP = EffectTemporaryHitpoints(nHP - 2);
	eTEMP = ExtraordinaryEffect(eTEMP);
	ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eTEMP, oPC, HoursToSeconds(72));
}

The probl i see with a Persistent feat is that it’s going to fire on more events than just the OnRested event.

(the benefit to Persistent is that it could fire in any module that uses your Spells and Feat 2das)

But since you seem okay with modifying the (module-level) OnRested script … i’d suggest removing the IsPersistent flag from the feat, and doing this in the REST_EVENTTYPE_REST_FINISHED section of your OnRested:

if (GetHasFeat(2813, oRested))
    ExecuteScript("spirit_youth", oRested);

That is, there’d no longer be a spell or spellscript. The feat becomes merely an utterly passive feat. Until a character with the feat rests, that is …

the script should then remove any temporary HP, re-apply its effect, and it doesn’t need a custom ID if you go this route

 
ALTERNATELY, you could keep the feat as a spellability, with its spellscript, but set a variable in the OnRested script, that allows the spellscript to run its code on the rested character, then clear the variable in the spellscript … the result would be that any other event that fires your Persistent feat’s spellscript bypasses the body of its code

I removed the IsPersistent = 1 with the OnRest script firing the script and now it is not firing at all.

all the scripts posted in this topic are for a persistent feat, obviously they wont fire properly if called from OnRest, because OBJECT_SELF in that case, is the module, not the feat target.

For a OnRest event (which I wouldn’t recommend), you would need different scripts.

try it with debugging code in your module’s OnRested script

    object oRested = GetLastPCRested();
    SendMessageToPC(GetFirstPC(FALSE), "checking for feat #2813");
    if (GetHasFeat(2813, oRested))
    {
        SendMessageToPC(GetFirstPC(FALSE), ". feat found fire spirit_youth");
        ExecuteScript("spirit_youth", oRested);
    }

do the messages appear in chat?

the second parameter of ExecuteScript() becomes OBJECT_SELF in the executed script …

Ah, that’s right I didn’t see that part on the fourth post, I just looked at the original script and I saw GetLastPCrested (which, by the way, is defined and never called again?), so I assumed it was used like that on the rest script.
Still, I don’t see handling the resting type of event (if started, cancelled, finished) anywhere and I still think that handling via the OnRest event is more trouble than worth, especially if the OP has already set up a persistent feat that fired at least.
Also, the OnRest event won’t handle the feat when obtained on level up, you’d have to modify the On Level up script as well, whereas the persistent feat handles all possible types of events (except resurrection) and you just need to use a trick to avoid the double stacking.

EDIT: No wait.

if(GetHasFeat(2813, oTarget))
{
RemoveEffectsFromSpell(oTarget, 716416);
ExecuteScript(“spirit_youth”, oTarget);
}

We don’t know how he has defined oTarget there, if it’s OBJECT_SELF, then he’s running that script on the module, and we’re back to square one, it won’t fire at all.

well that’s the thing, i don’t favor mucking about with module-level events either. But it seems to me that’s got to happen if darin wants to exclude other events (ie, not OnRested events) from handling the SpiritYouth feat, whether he flags the feat as IsPersistent or not. unfortunately …

in either case, i got it to work fine here, without Active/Persistent set. I (temporarily) repurposed ChannelMuse (as not Active, not Persistent). used this for an OnRested script

// 'k_mod_player_rest'

void main()
{
    switch (GetLastRestEventType())
    {
        case REST_EVENTTYPE_REST_STARTED:
            break;

        case REST_EVENTTYPE_REST_FINISHED:
        {
            object oRested = GetLastPCRested();
            SendMessageToPC(GetFirstPC(FALSE), "checking for feat #9020");
            if (GetHasFeat(9020, oRested)) //2813
            {
                SendMessageToPC(GetFirstPC(FALSE), ". feat found fire spirit_youth");
                ExecuteScript("spirit_youth", oRested);
            }
            break;
        }

        case REST_EVENTTYPE_REST_CANCELLED:
            break;
    }
}

and this for the pseudo-spellscript

// 'spirit_youth'

#include "nw_i0_spells"

void main()
{
    RemoveTempHitPoints();

    object oTarget = OBJECT_SELF;

//  int iSWhisp = GetLevelByClass(64, oTarget);
//  int iSWarr  = GetLevelByClass(67, oTarget);
//  int iCaster = iSWhisp + iSWarr;
    int iCaster = GetTotalLevels(oTarget, FALSE);

    int iWis   = GetAbilityModifier(ABILITY_WISDOM, oTarget);
    int iBonus = iWis * 3;
    int iHp    = iCaster + iBonus;

    effect e = EffectTemporaryHitpoints(iHp);
           e = SupernaturalEffect(e);

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, e, oTarget, HoursToSeconds(72));

    SendMessageToPC(GetFirstPC(), "Youthful vigor active!");
}

and it just went click click bang

ironically – or not, considering this is Nwn2 – there are still issues.

this is the best i could do on the script. Note that as an ExtraordinaryEffect it gets removed by resting automatically. The extra hitpoints appear on the character sheet, but not on the PC’s portrait.

// 'spirit_youth'

void main()
{
    object oTarget = OBJECT_SELF;

    SendMessageToPC(oTarget, "Youthful vigor active!");

//  int iSWhisp = GetLevelByClass(64, oTarget);
//  int iSWarr  = GetLevelByClass(67, oTarget);
//  int iCaster = iSWhisp + iSWarr;
    int iCaster = GetTotalLevels(oTarget, FALSE);

    int iWis   = GetAbilityModifier(ABILITY_WISDOM, oTarget);
    int iBonus = iWis * 3;
    int iHp    = iCaster + iBonus;

    effect e = EffectTemporaryHitpoints(iHp);
    e = ExtraordinaryEffect(e);

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, e, oTarget, HoursToSeconds(72));
}

i also tried EffectBonusHitpoints() but after 2+ rests it wants to stay at double extra HP …

I am getting double extra HP with both bonus hit points and temporary hit points. All I do is click between different character portraits and it behaves correctly for the first click on the character but doubles by the time I click on another portrait and return to the original. Bonus hit points still require the character to heal themselves up to the “bonus maximum,” so I am still confused on this one.

Thanks anyway.

construct and apply EffectHeal(GetMaxHitPoints()) right after adding bonus hp and that part of it should be taken care of

 
 
ps. i should point out that buggy extra HP is a known fact about the nwn2 engine: Kaedrin went to great lengths to try a fix for it in his PrC Pack … but i don’t think it has yet been truly/reliably worked around – although, I’m not sure what the bug is exactly or if it’s applicable here …

I’d say, all in all, if you get it working reasonably to your liking yer doin ok