Need Help With a Script!

SKIP DOWN TO Can This Be Simplified? - Neverwinter Nights 1 / Toolset, Scripting, NWNX - Neverwinter Vault

I’m thinking this block of code can be simplified. It supposed to limit regaining spells/feat uses to once in 24 hours on hardcore or higher difficultly (I omitted the difficulty check).

// Check time since last rest
nFirstRest = GetLocalInt(oPC, "FIRST_REST");
nDay = GetCalendarDay();
nTimeHour = GetTimeHour();

if (nFirstRest == 0) //First time resting in module
{
    SetLocalInt(oPC, "FIRST_REST", 1);
    SetLocalInt(oPC, "REST_DAY", nDay);
    SetLocalInt(oPC, "REST_HOUR", nTimeHour);
}
else
{
    nRestDay = GetLocalInt(oPC, "REST_DAY");
    nRestHour = GetLocalInt(oPC, "REST_HOUR");

    if (nRestDay == 28 && nDay == 1) //* Bugfix for calendar change over
    {
        if (nRestHour <= nTimeHour)
        {
            SetLocalInt(oPC, "REST_DAY", nDay);
            SetLocalInt(oPC, "REST_HOUR", nTimeHour);
        }
     }
     else
     {
        if (nRestDay < nDay)
        {
            if (nRestHour <= nTimeHour)
            {
                SetLocalInt(oPC, "REST_DAY", nDay);
                SetLocalInt(oPC, "REST_HOUR", nTimeHour);
            }
        }
        else
        {
            bDoNot = TRUE;
            SendMessageToPC(oPC, "It is too soon after your last rest to regain feats or spells.");
        }
    }
}

Not by that much but here is a quick try on it -

// Check time since last rest

nDay = GetCalendarDay();
nTimeHour = GetTimeHour();

if (!(GetLocalInt(oPC, "FIRST_REST"))) //First time resting in module
{
    SetLocalInt(oPC, "FIRST_REST", 1);
    SetLocalInt(oPC, "REST_DAY", nDay);
    SetLocalInt(oPC, "REST_HOUR", nTimeHour);
}
else
{
    nRestDay = GetLocalInt(oPC, "REST_DAY");
    nRestHour = GetLocalInt(oPC, "REST_HOUR");

    if (nRestDay == 28 && nDay == 1) //* Bugfix for calendar change over
    {
        if (nRestHour <= nTimeHour)
        {
            SetLocalInt(oPC, "REST_DAY", nDay);
            SetLocalInt(oPC, "REST_HOUR", nTimeHour);
        }
     }
     else
     {
        if ((nRestDay < nDay) && (nRestHour <= nTimeHour))
        {
            SetLocalInt(oPC, "REST_DAY", nDay);
            SetLocalInt(oPC, "REST_HOUR", nTimeHour);
        }
        else
        {
            bDoNot = TRUE;
            SendMessageToPC(oPC, "It is too soon after your last rest to regain feats or spells.");
        }
    }
}

TR

What happens if a player does not rest for a month?

Instead of doing this ‘bugfix’ thing you should properly convert date+time into a float (maybe hours since module start) and then it’s just simple float arithmetic and no need for ‘bugfixes’:

fRest = GetLocalFloat(oPC, "REST_DATETIME");
fCurrent = GetCurrentDateTimeAsFloat();
if (fCurrent - fRest > 24)
{
   SetLocalFloat(oPC, "REST_DATETIME", fCurrent);
}
else
{
   bDoNot = TRUE;
   SendMessageToPC(...);
}

with an appropriate GetCurrentDateTimeAsFloat() function. It’s not difficult to write one but perhaps someone did that alreay and it’s on the vault…

If you are only going down hours don’t bother with a float. It’s an integer value anyway.

Completely rethinking how I’m doing this. Its been a decade + since I originally designed / bashed this spell/feat gain blocker together and I’ve been from NWN scripting for so long that I can’t make heads or tails of it.

What I want to do is check each time the PC rests to see if 24 hours has passed since their last rest. If NOT, I want to prevent them from regaining spell and feat uses.

Is there some way to track hours passed without having to check the day, hour, etc. I imagine I could set an integer on the PC or module when the PC ends a rest and use the module heartbeat to index it +1 everytime an hour passes. When the count reaches 24, I delete the integer.

My question is how many module heartbeats are in 24 game hours? If, I’m reading the wiki right, its 480 heartbeats?

TBH, it is so much more efficient (too many heartbeat scripts == lag) to just test for the passage of time when the PC attempts to rest.

TR

Your heartbeat idea might work, but personally I wouldn’t add stuff to heartbeats if you can do it any other way, especially if it’s something simple like this.

If you set REST_DAY to -99 when oPC first materializes into existence (either through a trigger or with OnModuleLoad if it’s a single player module), you can trim the entire FIRST_REST thingy. The current day is always going to be greater than -99, yes?
Furthermore, you can roll both REST_DAY and REST_HOUR into one variable.

int timeLast 	= GetLocalInt(oPC, "REST_LAST");
int timeCurrent = GetTimeHour() + (GetCalendarDay() * 24);
int timeDiff;

if(timeCurrent > timeLast)	timeDiff = timeCurrent - timeLast; 
else 						timeDiff = 672 - timeLast + timeCurrent; // 672 = 24 * 28, one nwn month

if(timeDiff < 24)
{
	bDoNot = TRUE;
    SendMessageToPC(oPC, "It is too soon after your last rest to regain feats or spells.");
}
else SetLocalInt(oPC, "REST_LAST", timeCurrent);

The only problem with this method is if oPC skips resting for a month and then rests around the same day as last time.

Alternatively, you can do what I do for time in my module:

const int DAY           = 24;
const int MONTH         = 672;      //28 days * 24 hours
const int YEAR          = 8064;     //336 days * 24 hours, remove this part if your module lasts less than a year

int TimeGetCurrent()
{
    return  GetCalendarYear() * YEAR + GetCalendarMonth() * MONTH + GetCalendarDay() * DAY + GetTimeHour();
}

On successful rest, do
SetLocalInt(oPC, "LAST_REST", TimeGetCurrent())
To see whether 24 hours passed since last rest, simply check if
TimeGetCurrent() - GetLocalInt(oPC, "LAST_REST") >= 24
You don’t even need to set LAST_REST to anything for the first rest… unless your module starts at the beginning of the calendar.

This is the script so far. Now I just have to work out how to actually block the spell and feat regain. I have a system right now I stole from HCR 2.0 years ago, but its kind of cumbersome.

/*
    Module OnPlayerRest script

*/

#include "x3_inc_horse"
#include "_inc_time"
#include "_inc_debug"
#include "_inc_rest"

void ps_RestTimerPseudoHB();


void main()
{
    object oPC = GetLastPCRested();
    object oMount;

//---------------------------- BIOWARE CRAP ------------------------------------

    if (!GetLocalInt(GetModule(),"X3_MOUNT_NO_REST_DISMOUNT"))
    {
        if (HorseGetIsMounted(oPC))
        {
            if (GetLocalInt(oPC,"X3_REST_CANCEL_MESSAGE_SENT"))
            {
                DeleteLocalInt(oPC,"X3_REST_CANCEL_MESSAGE_SENT");
            }
            else
            {
                FloatingTextStrRefOnCreature(112006,oPC,FALSE);
                SetLocalInt(oPC,"X3_REST_CANCEL_MESSAGE_SENT",TRUE);
            }
            AssignCommand(oPC,ClearAllActions(TRUE));
            return;
        }
    }

    if (!GetLocalInt(GetModule(),"X3_MOUNT_NO_REST_DESPAWN"))
    {
        oMount=HorseGetPaladinMount(oPC);
        if (!GetIsObjectValid(oMount)) oMount=GetLocalObject(oPC,"oX3PaladinMount");
        if (GetIsObjectValid(oMount))
        {
            if (oMount==oPC||!GetIsObjectValid(GetMaster(oMount))) AssignCommand(oPC,HorseUnsummonPaladinMount());
            else { AssignCommand(GetMaster(oMount),HorseUnsummonPaladinMount()); }
        }
    }

//------------------------------------------------------------------------------

    int nRestTimer = GetLocalInt(GetModule(), "REST_TIMER");
    SendDebugMessageToPC(oPC, "INITIAL REST TIMER = " +IntToString(nRestTimer));

    int nTimePassed;

    if (GetLastRestEventType() == REST_EVENTTYPE_REST_STARTED )
    {
        // Set all regain status to TRUE
        SetLocalInt(GetModule(), "WIZARD_REGAIN", TRUE);
        SetLocalInt(GetModule(), "DIVINE_REGAIN", TRUE);
        SetLocalInt(GetModule(), "FEAT_REGAIN", TRUE);

        // Check for spellbook
        if (GetLevelByClass(CLASS_TYPE_WIZARD, oPC) > 0)
        {
            if (!HasItem(oPC, "IT_SPELLBOOK") )
            {
                SetLocalInt(GetModule(), "WIZARD_REGAIN", FALSE);
                SendMessageToPC(oPC, "You need a spellbook to regain spells.");
            }
        }

        // Check for divine symbol
        if (GetLevelByClass(CLASS_TYPE_CLERIC, oPC) > 0 ||
            GetLevelByClass(CLASS_TYPE_DRUID, oPC) > 0 ||
            GetLevelByClass(CLASS_TYPE_PALADIN, oPC) > 0 ||
            GetLevelByClass(CLASS_TYPE_RANGER, oPC) > 0 )
        {
            if (!HasItem(oPC, "IT_SYMBOL") )
            {
                SetLocalInt(GetModule(), "DIVINE_REGAIN", FALSE);
                SendMessageToPC(oPC, "You need a divine symbol to regain spells.");
            }
        }

        if (GetGameDifficulty() >= GAME_DIFFICULTY_CORE_RULES )
        {
            // Check if 24 hours have passed for the PC
            if (!nRestTimer )
            {
                // OK to regain - do nothing
            }
            else
            {
                // Too soon - no feat or spell regain
                SetLocalInt(GetModule(), "WIZARD_REGAIN", FALSE);
                SetLocalInt(GetModule(), "DIVINE_REGAIN", FALSE);
                SendMessageToPC(oPC, "You cannot regain spells until 24 hours have passed.");

                SetLocalInt(GetModule(), "FEAT_REGAIN", FALSE);
                SendMessageToPC(oPC, "You cannot regain feats until 24 hours have passed.");
            }
        }
    }
    else if (GetLastRestEventType() == REST_EVENTTYPE_REST_CANCELLED )
    {
        // Advance game clock
        nTimePassed = d8();
        ps_AdvanceGameClock(nTimePassed);
        SendMessageToPC(oPC, ps_IntToText(nTimePassed)+" hours have passed while you rested.");

        // If a rest cycle has already started, index the cycle by the time passed
        if (!nRestTimer)
        {
            SetLocalInt(GetModule(), "REST_TIMER", nRestTimer+nTimePassed);
        }
    }
    else if (GetLastRestEventType() == REST_EVENTTYPE_REST_FINISHED )
    {
        // Regain
        SendDebugMessageToPC(oPC, "ARCANE REGAIN = " +IntToString(GetLocalInt(GetModule(), "nWizSpellRegain")));
        SendDebugMessageToPC(oPC, "DIVINE REGAIN = " +IntToString(GetLocalInt(GetModule(), "nDivSpellRegain")));
        SendDebugMessageToPC(oPC, "FEAT REGAIN = " +IntToString(GetLocalInt(GetModule(), "nFeatRegain")));

        if (GetLocalInt(GetModule(), "WIZARD_REGAIN") > 0 )
        {
            // OK to regain, do nothing
            SendDebugMessageToPC(oPC, "SPELLS REGAINED");
        }
        else
        {
            // Too soon to regain
            SendDebugMessageToPC(oPC, "SPELLS NOT REGAINED");
        }

        if (GetLocalInt(GetModule(), "DIVINE_REGAIN") > 0 )
        {
            // OK to regain, do nothing
            SendDebugMessageToPC(oPC, "SPELLS REGAINED");
        }
        else
        {
            // Too soon to regain
            SendDebugMessageToPC(oPC, "SPELLS NOT REGAINED");
        }

        if (GetLocalInt(GetModule(), "FEAT_REGAIN") > 0 )
        {
            // OK to regain, do nothing
            SendDebugMessageToPC(oPC, "FEATS REGAINED");
        }
        else
        {
            // Too soon to regain
            SendDebugMessageToPC(oPC, "FEATS NOT REGAINED");
        }

        // Advance game clock
        ps_AdvanceGameClock(8);
        SendMessageToPC(oPC, "Eight hours have passed while you rested.");

        // If this was the first time resting, start the regain interval timer
        if (!nRestTimer)
        {
            SetLocalInt(GetModule(), "REST_TIMER", 1);
            DelayCommand(6.0, ps_RestTimerPseudoHB());
        }
        else // Index the rest cycle by the time passed
        {
            SetLocalInt(GetModule(), "REST_TIMER", nRestTimer+8);
        }

        SendDebugMessageToPC(oPC, "REST TIMER = " +IntToString(GetLocalInt(GetModule(), "REST_TIMER")));
    }
}


void ps_RestTimerPseudoHB()
{
    int nTime = GetLocalInt(GetModule(), "REST_TIMER");
    if (nTime < 480)
    {
        nTime++;
        SetLocalInt(GetModule(), "REST_TIMER", nTime);
        DelayCommand(6.0, ps_RestTimerPseudoHB());
    }
    else
    {
        DeleteLocalInt(GetModule(), "REST_TIMER");
    }
}

_inc_debug


const string PUBLIC_CDKEY = "UP7GTJDE";


// Sends a debug message to the module builder
void SendDebugMessageToPC(object oPC, string sMessage);



void SendDebugMessageToPC(object oPC, string sMessage)
{
    if (GetPCPublicCDKey(oPC, TRUE) == PUBLIC_CDKEY) // Change the string to match the PublicCDKey of the module Builder
    {
        SendMessageToPC(oPC, sMessage);
    }
}

_inc_time

/*
    Time Functions library

*/

//---------------------- FUNCTION DEFINITIONS ----------------------------------

// Advance the game clock by the time specified (hours, minutes, seconds, milliseconds)
void ps_AdvanceGameClock(int nHr = 0, int nMin = 0, int nSec = 0, int nMil = 0);

// Convert nTime to its text equivalent
string ps_IntToText(int nTime);


//---------------------- FUNCTION IMPLEMENTATION -------------------------------

void ps_AdvanceGameClock(int nHr = 0, int nMin = 0, int nSec = 0, int nMil = 0)
{
    int nHour         = GetTimeHour()        + nHr;
    int nMinute       = GetTimeMinute()      + nMin;
    int nSecond       = GetTimeSecond()      + nSec;
    int nMillisecond  = GetTimeMillisecond() + nMil;
    SetTime(nHour, nMinute, nSecond, nMillisecond);
}

string ps_IntToText(int nTime)
{
    string sTime;
    if (nTime < 9)
    {
        switch (nTime)
        {
            case 1: sTime = "One"; break;
            case 2: sTime = "Two"; break;
            case 3: sTime = "Three"; break;
            case 4: sTime = "Four"; break;
            case 5: sTime = "Five"; break;
            case 6: sTime = "Six"; break;
            case 7: sTime = "Seven"; break;
            case 8: sTime = "Eight"; break;
            case 9: sTime = "Nine"; break;
        }
    }
    else
    {
        sTime = IntToString(nTime);
    }

    return sTime;
}

The problem with recursive pseudo-heartbeats is that advancing time only speeds DelayCommands in progress. If the pseudo-heartbeat’s trigger interval is less than the time advanced, the rest won’t be triggered properly. Don’t use them if you need a reliable counter.
If you want to see for yourself, try making a placeable that advances time by an hour OnClick add make ps_RestTimerPseudoHB SendMessageToPC with the current timer.

e.g.
ps_RestTimerPseudoHB should be called 20 times per hour. But if you call ps_AdvanceGameClock(1) to skip an hour, although the ps_RestTimerPseudoHB that is currently being delayed will trigger immediately, the rest won’t. The resulting timer is 19 less than it should be.
If I’m reading ps_RestTimerPseudoHB right, this means your players will have to wait approx 48 minutes REAL-TIME (480 * 6 seconds) between rests if they want their spells back, and that’s AFTER the time skip from their last rest.

To account for it, you’d have to bake a REST_TIMER increase into your ps_AdvanceGameClock function (20 per hour, one per 6 seconds). I see you tried to do that in your rest script, but you forgot to multiply nTimePassed by 20. You’ll also have to be careful with any plot/travel-related timeskips.
In addition, you can’t change your module’s Minutes/Hour setting without breaking the script.

There’s really no need to complicate things. Just have your rest script check the last in-game time the PC rested.

EDIT: TIMER IS WORKING - ty Bhon

The script looks like this now…

/*
    Module OnPlayerRest script

*/

#include "x3_inc_horse"
#include "_inc_time"
#include "_inc_debug"

//void ps_RestTimerPseudoHB();


void main()
{
    object oPC = GetLastPCRested();
    object oMount;

//--------------------------- BIOWARE STUFF ------------------------------------

    if (!GetLocalInt(GetModule(),"X3_MOUNT_NO_REST_DISMOUNT"))
    {
        if (HorseGetIsMounted(oPC))
        {
            if (GetLocalInt(oPC,"X3_REST_CANCEL_MESSAGE_SENT"))
            {
                DeleteLocalInt(oPC,"X3_REST_CANCEL_MESSAGE_SENT");
            }
            else
            {
                FloatingTextStrRefOnCreature(112006,oPC,FALSE);
                SetLocalInt(oPC,"X3_REST_CANCEL_MESSAGE_SENT",TRUE);
            }
            AssignCommand(oPC,ClearAllActions(TRUE));
            return;
        }
    }

    if (!GetLocalInt(oPC,"X3_MOUNT_NO_REST_DESPAWN"))
    {
        oMount=HorseGetPaladinMount(oPC);
        if (!GetIsObjectValid(oMount)) oMount=GetLocalObject(oPC,"oX3PaladinMount");
        if (GetIsObjectValid(oMount))
        {
            if (oMount==oPC||!GetIsObjectValid(GetMaster(oMount))) AssignCommand(oPC,HorseUnsummonPaladinMount());
            else { AssignCommand(GetMaster(oMount),HorseUnsummonPaladinMount()); }
        }
    }

//------------------------------------------------------------------------------

//    int nRestTimer = GetLocalInt(oPC, "REST_TIMER");
//    SendDebugMessageToPC(oPC, "INITIAL REST TIMER = " +IntToString(nRestTimer));

    int nTimePassed;

    if (GetLastRestEventType() == REST_EVENTTYPE_REST_STARTED )
    {
        // Set all regain status to TRUE
        SetLocalInt(oPC, "WIZARD_REGAIN", TRUE);
        SetLocalInt(oPC, "DIVINE_REGAIN", TRUE);
        SetLocalInt(oPC, "FEAT_REGAIN", TRUE);

        // Check for spellbook
        if (GetLevelByClass(CLASS_TYPE_WIZARD, oPC) > 0)
        {
            if (!HasItem(oPC, "IT_SPELLBOOK") )
            {
                SetLocalInt(oPC, "WIZARD_REGAIN", FALSE);
                SendMessageToPC(oPC, "You need a spellbook to regain spells.");
            }
        }

        // Check for divine symbol
        if (GetLevelByClass(CLASS_TYPE_CLERIC, oPC) > 0 ||
            GetLevelByClass(CLASS_TYPE_DRUID, oPC) > 0 ||
            GetLevelByClass(CLASS_TYPE_PALADIN, oPC) > 0 ||
            GetLevelByClass(CLASS_TYPE_RANGER, oPC) > 0 )
        {
            if (!HasItem(oPC, "IT_SYMBOL") )
            {
                SetLocalInt(oPC, "DIVINE_REGAIN", FALSE);
                SendMessageToPC(oPC, "You need a divine symbol to regain spells.");
            }
        }

        if (GetGameDifficulty() >= GAME_DIFFICULTY_CORE_RULES )
        {
            if (!GetLocalInt(oPC, "LAST_REST") )
            {
                // Do nothing - first time resting
            }
            else if (ps_GetCurrentTime() - GetLocalInt(oPC, "LAST_REST") <= 24 )
            {
                // Too soon - no feat or spell regain
                SetLocalInt(oPC, "WIZARD_REGAIN", FALSE);
                SetLocalInt(oPC, "DIVINE_REGAIN", FALSE);
                SendMessageToPC(oPC, "You cannot regain spells until 24 hours have passed.");

                SetLocalInt(oPC, "FEAT_REGAIN", FALSE);
                SendMessageToPC(oPC, "You cannot regain feats until 24 hours have passed.");
            }
        }
    }
    else if (GetLastRestEventType() == REST_EVENTTYPE_REST_CANCELLED )
    {
        // Advance game clock
        nTimePassed = d8();
        ps_AdvanceGameClock(nTimePassed);
        SendMessageToPC(oPC, ps_IntToText(nTimePassed)+" hours have passed while you rested.");
    }
    else if (GetLastRestEventType() == REST_EVENTTYPE_REST_FINISHED )
    {
        // Regain
        SendDebugMessageToPC(oPC, "WIZARD REGAIN = " +IntToString(GetLocalInt(oPC, "WIZARD_REGAIN")));
        SendDebugMessageToPC(oPC, "DIVINE REGAIN = " +IntToString(GetLocalInt(oPC, "DIVINE_REGAIN")));
        SendDebugMessageToPC(oPC, "FEAT REGAIN = " +IntToString(GetLocalInt(oPC, "FEAT_REGAIN")));

        if (GetLocalInt(oPC, "WIZARD_REGAIN") > 0 )
        {
            // OK to regain, do nothing
            SendDebugMessageToPC(oPC, "SPELLS REGAINED");
        }
        else
        {
            // Too soon to regain
            SendDebugMessageToPC(oPC, "SPELLS NOT REGAINED");
        }

        if (GetLocalInt(oPC, "DIVINE_REGAIN") > 0 )
        {
            // OK to regain, do nothing
            SendDebugMessageToPC(oPC, "SPELLS REGAINED");
        }
        else
        {
            // Too soon to regain
            SendDebugMessageToPC(oPC, "SPELLS NOT REGAINED");
        }

        if (GetLocalInt(oPC, "FEAT_REGAIN") > 0 )
        {
            // OK to regain, do nothing
            SendDebugMessageToPC(oPC, "FEATS REGAINED");
        }
        else
        {
            // Too soon to regain
            SendDebugMessageToPC(oPC, "FEATS NOT REGAINED");
        }

        // Advance game clock
        ps_AdvanceGameClock(8);
        SendMessageToPC(oPC, "Eight hours have passed while you rested.");

        SetLocalInt(oPC, "LAST_REST", ps_GetCurrentTime());
    }
}

I think I understand what you’re saying here after seeing your example above. Your method is a lot cleaner and doesn’t rely on any form of recursive function. Speaking of which, I still have to work my expendable torches into the rest script.

I’m going to give your second example a try and see how that works. Hopefully I can figure out how to set it up into what I’ve already got so far without too much trouble.

No problem. You can trim the time check even further.
If ps_GetCurrentTime is the same as TimeGetCurrent from my post, you can remove this part:

if (!GetLocalInt(oPC, "LAST_REST") )
{
	// Do nothing - first time resting
}

GetLocalInt returns 0 if the local var wasn’t set to anything. This means that TimeGetCurrent will ALWAYS return a number that’s at least 24 greater than GetLocalInt(oPC, “LAST_REST”) on first rest, unless your module starts on the day the calendar was invented (year 0, month 0, day 0).
e.g.
If the year is 1300 (the toolset’s default starting year is around there), TimeGetCurrent will return at least 10,483,200 (1300 * 8064). On first rest, GetLocalInt(oPC, “LAST_REST”) will return 0. (10,483,200 - 0) is not less than or equal to 24, and oPC will get their spells back.

Also, wouldn’t this need at least 25 hours to pass for a successful rest?
if(ps_GetCurrentTime() - GetLocalInt(oPC, "LAST_REST") <= 24)
If that’s not your intention, turn <= into <.

One more thing, you’re always sending players two messages if less than 24 hours have passed. You can merge them into
SendMessageToPC(oPC, "You cannot regain spells or feats until 24 hours have passed.");
And maybe mention that it’s 24 hours since the last time spells were restored.

So the check would look something like:

if (GetGameDifficulty() >= GAME_DIFFICULTY_CORE_RULES)
{
	if(ps_GetCurrentTime() - GetLocalInt(oPC, "LAST_REST") < 24)//could merge this with the previous if, but it's a bit long
	{
		// Too soon - no feat or spell regain
		SetLocalInt(oPC, "WIZARD_REGAIN", FALSE);
		SetLocalInt(oPC, "DIVINE_REGAIN", FALSE);
		SetLocalInt(oPC, "FEAT_REGAIN", FALSE);
		SendMessageToPC(oPC, "You cannot regain spells or feats until 24 hours have passed since your last good rest.");    
	}	
}

I don’t know if there’s a way to prevent spells/feats from restoring on rest, though.
If you need help with torches, I have a pseudo-heartbeat script that runs OnEquip and gradually weakens them until they’re extinguished.

Ty again. Yeah, I had this system from years back that used to reset feats and spells but I can’t find the original and what got put into and later modified by someone else in Q doesn’t work. Thus, I’m scrapping that part and just going to bail before rest is complete if it hasn’t been 24 hours.

What if on rest start you get

(((((CalendarYear * 12) + CalendarMonth) * 28) + CalendarDay) * 24) + GetHour

That gives you a big Int that is the current hour value in the mod

If that var doesn’t exist on PC just allow rest and stamp it on it.

If that var exists on PC and is < to current hour value - 24 then allow rest and stamp New time.

Sorry about the lack of syntax but I’m on the cellphone.

B.

Thanks for all the info. Jasperre over on Discord set me up with a pretty slim system that does everything I’m looking for.