X0_SAFEREST Standard Bioware trigger

So, Im trying to create my own rest system just using marking areas as no rest and the X0_SAFEREST trigger. In the trigger’s comments it mentions that I need X1 resting enabled. I’ve never worked with the default bioware X1 resting system and in fact havent played the HotU main campaign past the start so I dont know how the rest system works other than guessing.

I can assume that I need to set the variable MODULE_SWITCH_USE_XP2_RESTSYSTEM on the module - if the X1 resting comment is the same as pointed out in this default bioware script:

//::///////////////////////////////////////////////
//:: Name: x2_onrest
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
The generic wandering monster system
*/
//:://////////////////////////////////////////////
//:: Created By: Georg Zoeller
//:: Created On: June 9/03
//:://////////////////////////////////////////////
//:: Modified By: Deva Winblood
//:: Modified Date: January 28th, 2008
//:://////////////////////////////////////////////

#include "x2_inc_restsys"
#include "x2_inc_switches"
#include "x3_inc_horse"

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

if (!GetLocalInt(GetModule(),"X3_MOUNT_NO_REST_DISMOUNT"))
{ // make sure not mounted
    /*  Deva, Jan 17, 2008
        Do not allow a mounted PC to rest
    */
    if (HorseGetIsMounted(oPC))
    { // cannot mount
        if (GetLocalInt(oPC,"X3_REST_CANCEL_MESSAGE_SENT"))
        { // cancel message already played
            DeleteLocalInt(oPC,"X3_REST_CANCEL_MESSAGE_SENT");
        } // cancel message already played
        else
        { // play cancel message
            FloatingTextStrRefOnCreature(112006,oPC,FALSE);
            SetLocalInt(oPC,"X3_REST_CANCEL_MESSAGE_SENT",TRUE); // sentinel
            // value to prevent message played a 2nd time on canceled rest
        } // play cancel message
        AssignCommand(oPC,ClearAllActions(TRUE));
        return;
    } // cannot mount
} // make sure not mounted

if (!GetLocalInt(GetModule(),"X3_MOUNT_NO_REST_DESPAWN"))
{ // if there is a paladin mount despawn it
    oMount=HorseGetPaladinMount(oPC);
    if (!GetIsObjectValid(oMount)) oMount=GetLocalObject(oPC,"oX3PaladinMount");
    if (GetIsObjectValid(oMount))
    { // paladin mount exists
        if (oMount==oPC||!GetIsObjectValid(GetMaster(oMount))) AssignCommand(oPC,HorseUnsummonPaladinMount());
        else { AssignCommand(GetMaster(oMount),HorseUnsummonPaladinMount()); }
    } // paladin mount exists
} // if there is a paladin mount despawn it

if (GetModuleSwitchValue(MODULE_SWITCH_USE_XP2_RESTSYSTEM) == TRUE)
{
    /*  Georg, August 11, 2003
        Added this code to allow the designer to specify a variable on the module
        Instead of using a OnAreaEnter script. Nice new toolset feature!
        Basically, the first time a player rests, the area is scanned for the
        encounter table string and will set it up.
    */
    object oArea = GetArea (oPC);

    string sTable = GetLocalString(oArea,"X2_WM_ENCOUNTERTABLE") ;
    if (sTable != "" )
    {
        int nDoors = GetLocalInt(oArea,"X2_WM_AREA_USEDOORS");
        int nDC = GetLocalInt(oArea,"X2_WM_AREA_LISTENCHECK");
        WMSetAreaTable(oArea,sTable,nDoors,nDC);

        //remove string to indicate we are set up
        DeleteLocalString(oArea,"X2_WM_ENCOUNTERTABLE");
    }


    /* Brent, July 2 2003
       - If you rest and are a low level character at the beginning of the module.
         You will trigger the first dream cutscene
    */
    if (GetLocalInt(GetModule(), "X2_G_LOWLEVELSTART") == 10)
    {
        AssignCommand(oPC, ClearAllActions());
        if (GetHitDice(oPC) >= 12)
        {
            ExecuteScript("bk_sleep", oPC);
            return;
        }
        else
        {
            FloatingTextStrRefOnCreature(84141 , oPC);
            return;
        }
    }

    if (GetLastRestEventType()==REST_EVENTTYPE_REST_STARTED)
    {
        if (!WMStartPlayerRest(oPC))
        {
            // The resting system has objections against resting here and now
            // Probably because there is an ambush already in progress
            FloatingTextStrRefOnCreature(84142  ,oPC);
            AssignCommand(oPC,ClearAllActions());
        }
        if (WMCheckForWanderingMonster(oPC))
        {
            //This script MUST be run or the player won't be able to rest again ...
            ExecuteScript("x2_restsys_ambus",oPC);
        }
    }
    else if (GetLastRestEventType()==REST_EVENTTYPE_REST_CANCELLED)
    {
     // No longer used but left in for the community
     // WMFinishPlayerRest(oPC,TRUE); // removes sleep effect, etc
    }
    else if (GetLastRestEventType()==REST_EVENTTYPE_REST_FINISHED)
    {
     // No longer used but left in for the community
     //   WMFinishPlayerRest(oPC); // removes sleep effect, etc
    }
}
}

The exact wording of the comment on the standard X0_SAFEREST trigger is this:
“Paint this trigger down into any XP1 area that is rest restricted. Paint it in such a way that it encloses a small room and contains one door. That door has to exist for the rest to work and be closed otherwise the player will get a “This area is not secure” messag eand be prevented from resting.”

So, do I need to do more than set the module variable and lay out the trigger as described? I’m also considering making an item called iron spikes if I can find a miscellaneous object model that looks like iron spikes, and giving them a property of increased weight to further limit resting by either using the old method of laying a trigger over a trigger to activate a trigger or directly modifiying the rest script (so that in addition to needing to find a safe room, you need iron spikes to spike the door shut like old skool DnD). I also dont plan to have ambush encounters occur, so am I correct assuming that all I need to do is not make a wandering monster table? Also, am I correct in assuming you also need to check the area as no rest? Because the way I am planning it, you can just rest as much as you like in some areas like non-dangerous wilderness and inn rooms. Its the dungeon crawls and dangerous wilderness you need to find a small room to spike shut - and well, its not smart to just nap on some city street so Im just going to keep it simple and check the no rest box.

Also, which is the default include that contains the actual switch scripting for the X1 rest system switch mentioned above?

MODULE_SWITCH_USE_XP2_RESTSYSTEM enables wandering monsters. I don’t think that’s what you are looking for. The X1 Resting System - which uses the X0_SAFEREST trigger is the rest system made for SoU.

Looking at what you need to use the X1 Rest System - will post more info shortly

1 Like

OK, all the XP1 Game Modules use X1_PlayerRest.nss as the module’s OnPlayerRest event. So you’ll want to call that as your OnPlayerRest script. You’ll see references to “safe rest triggers” and “zones” all through the comments in that script.

1 Like

Oh cool, thanks! I was trying to find the SoU version due to the diff between the X1 reference and the X2 prefix of the script but I couldnt see a prefix that made sense.

I guess, in hindsight I could have been less lazy and loaded up the SoU module. Same mental laziness is probably why I decided the x2 script was it.

Again, thank a million, youre awesome. I pretty much dont want horses anyway in my PW.

In case anyone was curious, this is what I got right now:

The modified X1_playerrest script (compiles but not tested yet) Ill probably or maybe at some time strip out the likely redundant things about gnolls and/or henchmen

//::///////////////////////////////////////////////
//:: x1_playerrest
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
This script controls what should happen when
the player rests.
*/
//:://////////////////////////////////////////////
//:: Created By:
//:: Created On:
//:://////////////////////////////////////////////
#include "x0_i0_henchman"

// * these constants copied from q3_inc_plot
// values for Q3_GNOLL_STATUS:
int GNOLL_STATUS_INIT =             0; // initial status
int GNOLL_STATUS_LEFT =             1; // all gnoll left the area
int GNOLL_STATUS_DEAD =             2; // chief is dead
int GNOLL_STATUS_SAFE_PASSAGE =     3; // gnollsgave safe passge
int GNOLL_STATUS_CONTROL_TRIBE=     4; // player has full control over the tribe

// values for Q3_GNOLL_HELP
int GNOLL_NOHELP = 0;
int GNOLL_HELP = 1;

// * Am I NOT on a safe rest trigger?
int NotOnSafeRest(object oPC);
// * Am I in a place where it is not safe to rest?
int NotSafeToRest(object oPC);

void main()
{  // SpawnScriptDebugger();
int nRest = GetLastRestEventType();
if (nRest == REST_EVENTTYPE_REST_STARTED)
{
    object oPC = GetLastPCRested();
    object oHench = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC);


    // * rest started, if I have a henchman
    // * who is dying, abort the rest
    if (GetIsObjectValid(oHench) && GetIsHenchmanDying(oHench))
    {
        AssignCommand(oPC, ClearAllActions());
        AssignCommand(oHench, ClearAllActions());
        SetCommandable(TRUE, oHench);
        // * clear previous animatioms...
        AssignCommand(oHench,
                           PlayAnimation(ANIMATION_LOOPING_PAUSE_DRUNK,
                                         1.0, 1.0));
        AssignCommand(oHench, ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT, 1.0, 
HENCHMEN_DIE_ANIM_DURATION));
        SetCommandable(TRUE, oHench);
        FloatingTextStrRefOnCreature(40051, oPC);
    }
    else
    if (NotSafeToRest(oPC) == TRUE)
    {
        if (NotOnSafeRest(oPC) == TRUE)
        {
            AssignCommand(oPC, ClearAllActions());
            AssignCommand(oHench, ClearAllActions());
            FloatingTextStrRefOnCreature(40156, oPC);
        //    AssignCommand(oPC, SpeakString("blah"));
        }
    }
}
}

//::///////////////////////////////////////////////
//:: NotSafeToRest
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Returns TRUE if this is an area that the
player is not allowed to rest in and the condition
is not achieved.
*/
//:://////////////////////////////////////////////
//:: Created By:
//:: Created On:
//:://////////////////////////////////////////////
int NotSafeToRest(object oPC)
{

// * The resting system only works on Hardcore
// * or above.
if (GetGameDifficulty() < GAME_DIFFICULTY_CORE_RULES)
{
    return FALSE;
}


 ///666 mod adjustment:
/// if the area is not checked as a no resting allowed area (ie cities)
/// the default setting is the area is not safe to rest
/// if the area is actually safe to rest in and a rest allowed zone
/// such as a non-residential area just outside city walls with few monster enccounters
// or an idyllic wilderness areas where no threats exist
// set an int variable on the area called CANRESTBOO to one
// the result of this will be the players will get the message no resting is allowed in this area in cities,
// in dungeons and dangerous wilderness, they will get the SoU its not safe to rest here message
// and in inn rooms and peaceful wilds they can rest freely
//see bottom of script for X0_SAFEREST trigger change

object oAreaRestIn = GetArea(oPC);
int iRestable = GetLocalInt(oAreaRestIn, "CANRESTBOO");
int nNotSafe = FALSE;
if (iRestable != 1)
{
 int nNotSafe = TRUE;
}


return nNotSafe;
}
//::///////////////////////////////////////////////
//:: NotOnSafeRest
 //:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
returns TRUE if the player is not in a safe
zone within an area.

RULE: There must be at least one door
      All doors must be closed

- takes player object
- finds nearest safe zone
- is player in safe zone?
   - find all doors in safe zone
    - are all doors closed?
    /// 666 mod change: does a PC in the area possess an iron spikes item
        - if YES to all the above
            is safe to rest,
                RETURN FALSE
 - otherwise give appropriate feedback and return TRUE
 */
//:://////////////////////////////////////////////
//:: Created By:
//:: Created On:
//:://////////////////////////////////////////////
int NotOnSafeRest(object oPC)
{  // SpawnScriptDebugger();
object oSafeTrigger = GetNearestObjectByTag("X0_SAFEREST", oPC);
int bAtLeastOneDoor = FALSE;
int bAllDoorsClosed = TRUE;
int bPCInTrigger = FALSE;

if (GetIsObjectValid(oSafeTrigger))
{
    if (GetObjectType(oSafeTrigger) == OBJECT_TYPE_TRIGGER)
    {

        // * cycle through trigger looking for oPC
        // * and looking for closed doors
        object oInTrig = GetFirstInPersistentObject(oSafeTrigger, OBJECT_TYPE_ALL);
        while (GetIsObjectValid(oInTrig) == TRUE)
        {
            // * rester is in trigger!
            if (oPC == oInTrig)
            {
                bPCInTrigger = TRUE;
            }
            else
            {
                // * one door found
                if (GetObjectType(oInTrig) == OBJECT_TYPE_DOOR)
                {
                    bAtLeastOneDoor = TRUE;
                    // * the door was open, exit
                    if (GetIsOpen(oInTrig) == TRUE)
                    {
                        return TRUE; //* I am no in a safe rest place because a door is open
                    }
                    if (GetLocalInt(oInTrig, "SPIKEDSHUT") == 1) return TRUE; ///666 modification - due to 
this change, saferest triggers s
                    //should ONLY be used around rooms with one door as the only exit

                }
            }
            oInTrig = GetNextInPersistentObject(oSafeTrigger, OBJECT_TYPE_ALL);
        }
    }
     }
     if (bPCInTrigger == FALSE || bAtLeastOneDoor == FALSE)
     {
    return TRUE;
}
// * You are in a safe trigger, if in a trigger, and all doors closed on that trigger.
return FALSE;
}

And here is my tagbased scripts script for the onactivate item Iron Spikes - this is the very first time Ive made one of these types of scripts, but if it works Ill probably make a similar one with a tent or bedroll for outdoor areas with no or little threat. Since it rains and junk.

// iron spike used on doors in dungons to rest  Place this
//in the module's OnActivateItem event
#include "x2_inc_switches"

void main()

{
int    nEvent = GetUserDefinedItemEventNumber(); // Which event triggered this

int nResult = X2_EXECUTE_SCRIPT_END;

    object oPC = GetItemActivator();
    object oTarget = GetItemActivatedTarget();
    if (GetObjectType( oTarget ) == OBJECT_TYPE_DOOR )
    {
       if (GetIsDoorActionPossible(oTarget, ACTION_CLOSEDOOR))
        {
        ActionCloseDoor(oTarget);
        }
       SetLocalInt(oTarget, "SPIKEDSHUT", 1);
    }

SetExecutedScriptReturnValue(nResult);

}

Like before, the above compiles but I havent tested it. In addition, when my doors are opened, they have an added line in their usual on open event that resets SPIKEDSHUT to zero. I also made copies of the standard X0_SAFEREST trigger to have an OnEnter event script that makes floaty text suggesting an iron spike would be most efficacious here:

//Saferest trigger on enter script
// when a PC enters this trigger,
  // floaty text appears to suggest they
 /// could rest here if they had iron spikes to use
// on the door

void main()
{
object oPC = GetEnteringObject();

if (GetLocalInt(oPC, "STOPSPAMMING") == 1) return; //stops the message from spamming
 SetLocalInt(oPC, "STOPSPAMMING", 1);
FloatingTextStringOnCreature("You might be able to rest here if you had iron spikes to wedge that 
door shut.", oPC, FALSE);
}