3312 lines
151 KiB
Plaintext
3312 lines
151 KiB
Plaintext
|
//============================================================================
|
||
|
//
|
||
|
// Name: CS Resting Subsystem - Main Include File
|
||
|
// File: cs_rest
|
||
|
// Author: Craig Smith (Galap) <craig@smith.dropbear.id.au>
|
||
|
//
|
||
|
// $Id: cs_rest.nss,v 1.7 2004/12/29 10:17:07 cs Exp $
|
||
|
// $Source: /local/cvs/nwn/resting/cs_rest.nss,v $
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
// This software is distributed in the hope that it will be useful. It is
|
||
|
// provided "as is" WITHOUT WARRANTY OF ANY KIND, either expressed or implied,
|
||
|
// including, but not limited to, the implied warranties of merchantability
|
||
|
// and fitness for a particular purpose. You may redistribute or modify this
|
||
|
// software for your own purposes so long as all original credit information
|
||
|
// remains intact.
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Introduction
|
||
|
// ------------
|
||
|
// The CS Resting Subsystem provides a framework for setting various popular
|
||
|
// forms of resting rules in a module, and allows these resting rules to be
|
||
|
// changed dynamically while the module is running.
|
||
|
//
|
||
|
// Installing The CS Resting Subsystem
|
||
|
// -----------------------------------
|
||
|
// To install the CS Resting Subsystem, you need to import the scripts and
|
||
|
// blueprints into your module. Open the module in the Aurora Toolset and
|
||
|
// select the File menu. Then select the Import item from the menu and
|
||
|
// navigate through your computer's directory structure until you locate
|
||
|
// the ERF file for the CS Resting Subsystem. Select the ERF file and click
|
||
|
// on the Ok button. If the toolset warns you about missing files with a .ncs
|
||
|
// extension, ignore the warning and continue--the .ncs files are compiled
|
||
|
// script files and will be created if necessary when you build your module.
|
||
|
// Once the import finishes, you have installed the CS Resting Subsystem!
|
||
|
//
|
||
|
// To use the CS Resting Subsystem in a module, you will need to change
|
||
|
// the module's OnPlayerRest event handler to be the "cs_rest_handler"
|
||
|
// script. To do this, pull down the Edit menu and select Module Properties.
|
||
|
// Select the Events tab and either drop down the list for the OnPlayerRest
|
||
|
// event to scroll through and find "cs_rest_handler", or simply delete the
|
||
|
// script name that is already there and type in "cs_rest_handler" in place.
|
||
|
// Then select the Ok button and you're done.
|
||
|
//
|
||
|
// Configuring Resting
|
||
|
// -------------------
|
||
|
// One of the design goals of the CS Resting Subsystem package is that the
|
||
|
// resting rules must be able to be managed and configured completely
|
||
|
// through the standard toolset interface *without* the need to resort to
|
||
|
// editing scripts. It is of course possible to extend the resting subsystem
|
||
|
// through writing your own resting profiles or user scripts, however if you
|
||
|
// choose to do so, you will also need to manage any configuration for your
|
||
|
// own resting extension. For most situations, however, the standard resting
|
||
|
// subsystem should be sufficient.
|
||
|
//
|
||
|
// To this end, configuration is handled through the use of a container and
|
||
|
// special items. I personally use chests but any placeable object with an
|
||
|
// inventory will work. Place the container object somewhere in your module
|
||
|
// and then change its tag to be "CS_REST_GLOBAL_CONFIG". Since this container
|
||
|
// is accessed by tag, it may be placed anywhere in the module though it
|
||
|
// should be placed somewhere that players cannot access. I recommend creating
|
||
|
// a DM room area and placing things like this global config container there.
|
||
|
//
|
||
|
// Once you have a placed the container with the correct tag, you now need
|
||
|
// to place the custom configuration items into the container, and modify
|
||
|
// any of the item tags as required for your needs. Items that represent
|
||
|
// integer values must have their tags set to the integer itself. Some other
|
||
|
// items require their tags to be set to strings such as the names of scripts.
|
||
|
//
|
||
|
// Once you have created the configuration container and put all of the desired
|
||
|
// configuration items into its inventory, the resting subsystem will function
|
||
|
// as specified by the items. This particular container is referred to as the
|
||
|
// global configuration container, but the resting subsystem allows the use of
|
||
|
// other configuration containers as well (see Other Configuration Facilities
|
||
|
// for more details). The custom configuration items are found under the
|
||
|
// "Special|Custom4" category of the Custom items palette.
|
||
|
//
|
||
|
// NOTE: If you don't place the global configuration container and set the
|
||
|
// "CS Rest: Enable" and "CS Rest: Default Profile" items as the absolute
|
||
|
// minimum configuration, the CS Resting Subsystem will *not* function and
|
||
|
// the standard Bioware default resting will remain in place.
|
||
|
//
|
||
|
// The complete list of available items, with descriptions, follows.
|
||
|
//
|
||
|
// CS Rest: Enable
|
||
|
// Default value: FALSE
|
||
|
// Enabled the resting subsystem, enforcing the rules as configured through
|
||
|
// the use of these items. The resting subsystem is *disabled* by default
|
||
|
// and one of these items *must* be placed in a configuration container
|
||
|
// before it will function. To use this item, you simply place it in the
|
||
|
// configuration container's inventory. No change to this item's tag is
|
||
|
// required. This item is the opposite of the Disable item below and only
|
||
|
// one of the two may be used at the same time.
|
||
|
// CS Rest: Disable
|
||
|
// Default value: TRUE
|
||
|
// Disable the resting subsystem, returning the player to the standard
|
||
|
// Bioware resting rules if placed in the global configuration container,
|
||
|
// or just causing an area or trigger configuration container to be
|
||
|
// ignored. To use this item, you simply place it in the configuration
|
||
|
// container's inventory. No change to this item's tag is required. This
|
||
|
// item is the opposite of the Enable item above and only one of the two
|
||
|
// may be used at the same time.
|
||
|
// CS Rest: Default Profile
|
||
|
// Default value: Not set
|
||
|
// Sets the name of the resting profile script to be executed by default
|
||
|
// when a player is not within a resting trigger. The tag of this item
|
||
|
// should be set to the name of one of the standard profile scripts:
|
||
|
// cs_rest_cnt This script disallows resting completely
|
||
|
// cs_rest_cmp This script allows resting
|
||
|
// cs_rest_rom This script only allows resting when in a room with
|
||
|
// all doors closed.
|
||
|
// One of these items *must* be placed in the global config container with
|
||
|
// its tag set correctly or the resting subsystem will fail to operate in
|
||
|
// an expected manner. It it of course possible to write your own scripts
|
||
|
// for handling resting profile. See Creating Your Own Resting Profile
|
||
|
// for further information, though please note that there is no need to
|
||
|
// create new resting profiles in most situations (and most probably *all*
|
||
|
// situations, since I can't think of any more).
|
||
|
// CS Rest: Standard HP
|
||
|
// Default value: TRUE
|
||
|
// Use the standard Bioware-style of HP regain and allow the player to
|
||
|
// regain all lost hit points after resting. To use this item, you simply
|
||
|
// place it in the configuration container's inventory. No change to this
|
||
|
// item's tag is required. This item is the opposite of the 3rd Ed Style HP
|
||
|
// item below and only one of the two may be used at the same time.
|
||
|
// CS Rest: 3rd Ed Style HP
|
||
|
// Default value: FALSE
|
||
|
// Use a style of HP gain modelled on the 3rd edition D&D manuals, wherein
|
||
|
// players regain one hit point per level each time they rest. If resting
|
||
|
// is interrupted part way through, the player will regain hit points in
|
||
|
// a pro-rata fashion, i.e. if resting was half complete, the player will
|
||
|
// regain half the number of hit points that they would have otherwise
|
||
|
// To use this item, you simply place it in the configuration container's
|
||
|
// inventory. No change to this item's tag is required. This item is the
|
||
|
// opposite of the Standard HP item above and only one of the two may be
|
||
|
// used at the same time.
|
||
|
// CS Rest: Day Only
|
||
|
// Default value: FALSE
|
||
|
// Sets the resting subsystem to allow resting only during daylight hours.
|
||
|
// To use this item, you simply place it in the configuration container's
|
||
|
// inventory. No change to this item's tag is required. Note that this
|
||
|
// item is the opposite of the Night Only item below. Only one of the two
|
||
|
// items may be used at the same time. The All Hours below item may be
|
||
|
// used to reset either Day Only or Night Only operation.
|
||
|
// CS Rest: Night Only
|
||
|
// Default value: FALSE
|
||
|
// Sets the resting subsystem to allow resting only during night hours.
|
||
|
// To use this item, you simply place it in the configuration container's
|
||
|
// inventory. No change to this item's tag is required. Note that this
|
||
|
// item is the opposite of the Night Only item above. Only one of the two
|
||
|
// items may be used at the same time. The All Hours item below may be
|
||
|
// used to reset either Day Only or Night Only operation.
|
||
|
// CS Rest: All Hours
|
||
|
// Default value: TRUE
|
||
|
// Sets the resting subsystem to allow resting at any time of the day or
|
||
|
// night. This item may be used after setting day only or night only
|
||
|
// operation to restore the resting subsystem to its default operation. To
|
||
|
// use this item, you simply place it in the configuration container's
|
||
|
// inventory. No change to this item's tag is required. Note that this
|
||
|
// item should not be used at the same time as either the Day Only or
|
||
|
// Night Only items. Remove such items from the configuration container's
|
||
|
// inventory before placing this item.
|
||
|
// CS Rest: Day Start
|
||
|
// Default value: 6
|
||
|
// Sets the hour of the day at which the resting subsystem considers "day"
|
||
|
// to begin. When the resting subsystem is operating in Day Only mode, it
|
||
|
// will only allow resting after this hour, or only before this hour if
|
||
|
// in Night Only mode. The Day Start value may be set to any integer
|
||
|
// between 0 and 22 inclusive. To use this item, you must set its
|
||
|
// tag to an integer value.
|
||
|
// CS Rest: Day End
|
||
|
// Default value: 18
|
||
|
// Sets the hour of the day at which the resting subsystem considers "day"
|
||
|
// to end. When the resting subsystem is operating in Day Only mode, it
|
||
|
// will only allow resting before this hour, or only after this hour if in
|
||
|
// Night Only mode. The Day End value may be set to any integer between
|
||
|
// 1 and 23 inclusive. To use this item, you must set its tag to an
|
||
|
// integer value.
|
||
|
// CS Rest: Armour Not Allowed
|
||
|
// Default value: FALSE
|
||
|
// Stops players from resting when then are wearing rigid armour or
|
||
|
// helmets. Armour of AC 5 or less may be worn while resting. To use
|
||
|
// this item, you simply place it in the configuration container's
|
||
|
// inventory. No change to this item's tag is required. Note that this
|
||
|
// item is the opposite of the Armour Allowed item below. Only one of the
|
||
|
// two items may be used at the same time.
|
||
|
// CS Rest: Armour Allowed
|
||
|
// Default value: TRUE
|
||
|
// Allow player to rest regardless of the armour they are wearing. To
|
||
|
// use this item, you simply place it in the configuration container's
|
||
|
// inventory. No change to this item's tag is required. Note that this
|
||
|
// item is the opposite of the Armour Not Allowed item above. Only one
|
||
|
// of the two items may be used at the same time.
|
||
|
// CS Rest: Weapons Not Allowed
|
||
|
// Default value: FALSE
|
||
|
// Stops players from resting when then are carrying weapons. To use this
|
||
|
// item, you simply place it in the configuration container's inventory.
|
||
|
// No change to this item's tag is required. Note that this item is the
|
||
|
// opposite of the Weapons Allowed item below. Only one of the two items
|
||
|
// may be used at the same time.
|
||
|
// CS Rest: Weapons Allowed
|
||
|
// Default value: TRUE
|
||
|
// Allow player to rest regardless of whether they are armed or not. To
|
||
|
// use this item, you simply place it in the configuration container's
|
||
|
// inventory. No change to this item's tag is required. Note that this
|
||
|
// item is the opposite of the Weapons Not Allowed item above. Only one
|
||
|
// of the two items may be used at the same time.
|
||
|
// CS Rest: Fade Screen
|
||
|
// Default value: FALSE
|
||
|
// Fade the player's screen display to black when resting starts, and fade
|
||
|
// back to a visible screen again when resting finishes.
|
||
|
// CS Rest: 1 Minute Limit
|
||
|
// CS Rest: 2 Minute Limit
|
||
|
// CS Rest: 3 Minute Limit
|
||
|
// CS Rest: 4 Minute Limit
|
||
|
// CS Rest: 5 Minute Limit
|
||
|
// CS Rest: 6 Minute Limit
|
||
|
// CS Rest: 7 Minute Limit
|
||
|
// CS Rest: 8 Minute Limit
|
||
|
// CS Rest: 9 Minute Limit
|
||
|
// CS Rest: 10 Minute Limit
|
||
|
// CS Rest: 12 Minute Limit
|
||
|
// CS Rest: 14 Minute Limit
|
||
|
// CS Rest: 16 Minute Limit
|
||
|
// CS Rest: 18 Minute Limit
|
||
|
// CS Rest: 20 Minute Limit
|
||
|
// CS Rest: 25 Minute Limit
|
||
|
// CS Rest: 30 Minute Limit
|
||
|
// Default Value: No Limit
|
||
|
// All of these items may be used to control how frequently players may
|
||
|
// rest. Pick the item that matches the time limit you wish to set and
|
||
|
// place it into the configuration container. No change to the item's tag
|
||
|
// is necessary. You may only use one of these items at a time, and you
|
||
|
// may not use any of these items at the same time as the Rest Time Limit
|
||
|
// or No Limit items below.
|
||
|
// CS Rest: Rest Time Limit
|
||
|
// Default Value: No Limit
|
||
|
// Use this item if you wish more fine-grained control over the time limit
|
||
|
// between resting. Place this item in a configuration container and then
|
||
|
// change its tag to an integer value representing the number of seconds
|
||
|
// that players must wait before being allowed to rest again. You may not
|
||
|
// use this item at the same time as any of the time limit items above, or
|
||
|
// the No Limit item below.
|
||
|
// CS Rest: No Limit
|
||
|
// Default value: No Limit
|
||
|
// Use this item to restore the default unlimited resting behaviour like
|
||
|
// the standard Bioware resting system. To use this item, you simply place
|
||
|
// it in the configuration container's inventory. No change to this item's
|
||
|
// tag is required. You may not use this item at the same time as any of
|
||
|
// the time limit items or the Rest Time Limit item above.
|
||
|
// CS Rest: Bedroll In Use
|
||
|
// Default value: FALSE
|
||
|
// Use bedrolls if the player has one in his or her inventory on resting.
|
||
|
// When bedrolls are in use, the player only regains full hit points, as
|
||
|
// per the regain style in use, when they have a bedroll. If they do not
|
||
|
// have a bedroll, then only half the normal number of hit points will be
|
||
|
// regained. Bedrolls are consumable items and after being used 20 times,
|
||
|
// they are destroyed. To use this item, you must place it in the
|
||
|
// configuration container's inventory and change its tag to be the same
|
||
|
// as the item that is to be used as a bedroll, e.g. if you have an item
|
||
|
// with a tag of "BEDROLL" that you intend for players to use as a bedroll,
|
||
|
// then you must set the tag of *this* item to "BEDROLL" as well. This
|
||
|
// item is the opposite of the Bedroll Not Used item below and you may
|
||
|
// not use the two items at the same time. Note that there is not yet any
|
||
|
// persistence used for storing the number of times a bedroll has been
|
||
|
// used.
|
||
|
// CS Rest: Bedroll Not Used
|
||
|
// Default value: TRUE
|
||
|
// Allow players to rest without bedrolls with no penalty to hit point
|
||
|
// regain. To use this item, you simply place it in the configuration
|
||
|
// container's inventory. No change to this item's tag is required. This
|
||
|
// item is the opposite of the Bedroll In Use item above and you may not
|
||
|
// use the two items at the same time.
|
||
|
// CS Rest: Bedroll HP multiplier
|
||
|
// Default value: 50
|
||
|
// This item sets the numerical modifier applied to hit points when
|
||
|
// bedrolls are in use and the player does not have one. If the player
|
||
|
// does not have a bedroll when resting, the hitpoints regained will be
|
||
|
// multiplied by the value set with this item to determine the final
|
||
|
// number of hit points regained. To define this value, set the item's
|
||
|
// tag to the pecentage number for the multiplier, e.g. for half hit
|
||
|
// points, use 50, for a third use 33, etc. By default, this value is 50,
|
||
|
// so players will regain half the normal hit points when resting without
|
||
|
// a bedroll. If you were to set this value to 25, then players would
|
||
|
// regain a quarter of the number of hitpoints, and setting this value to
|
||
|
// 100 would mean that bedrolls would have no effect at all (which is
|
||
|
// kind of silly but nevertheless will work). Setting this value to 0
|
||
|
// will stop players from being allowed to rest at all if they do not
|
||
|
// have a bedroll.
|
||
|
// CS Rest: HP Multiplier
|
||
|
// Default value: 100
|
||
|
// This item sets a numerical value that is used as a multiplier against
|
||
|
// the number of hit points that a player would normally regain from
|
||
|
// resting *when non-standard rest modes are in use*, i.e. the number
|
||
|
// of hitpoints is calculated first, and then multiplied by the value
|
||
|
// set with this item to determine the final number of hit points regained.
|
||
|
// To define this value, set the item's tag to the percentage number for
|
||
|
// the multiplier, e.g. for half hit points, use 50, etc. By default,
|
||
|
// this value is 100 (i.e. 100% or full hit points) and will have no effect
|
||
|
// on the hit points regained by players. If you were to set this value to
|
||
|
// 200, then players would regain twice the number of hitpoints, setting
|
||
|
// the value to 300 would give three times the normal number, and 50 will
|
||
|
// give half. Note that if you are using the standard HP regain policy,
|
||
|
// as set by the Standard HP item above (or if you set no item for HP
|
||
|
// regain at all) then this item is ignored as the standard regain policy
|
||
|
// returns the player the most hit points possible.
|
||
|
// CS Rest: Use CON Bonus
|
||
|
// Default value: FALSE
|
||
|
// Use this item to give players additional hit points equal to their CON
|
||
|
// bonus *when non-standard rest modes are in use*. Note that if you are
|
||
|
// using the standard HP regain policy, as set by the Standard HP item
|
||
|
// above (or if you set no item for HP regain at all) then this item is
|
||
|
// ignored as the standard regain policy returns the player the most hit
|
||
|
// points possible anyway. The CON bonus hit points are applied *after*
|
||
|
// the calculation of the multiplier value, so if 3rd edition style HP
|
||
|
// regain is enabled with a multipler of 2, players will receive hit
|
||
|
// points equalling (level * 2) + CON Bonus. This item is the opposite of
|
||
|
// the No CON Bonus item below and you may not use both items at the same
|
||
|
// time.
|
||
|
// CS Rest: No CON Bonus
|
||
|
// Default value: TRUE
|
||
|
// Use this item to disable the addition of CON bonus hit points when a
|
||
|
// non-standard hit point regain policy is in use. This item is the
|
||
|
// opposite of the Use CON Bonus item above and you may not use both
|
||
|
// items at the same time.
|
||
|
// CS Rest: User Script
|
||
|
// Default value: Not set
|
||
|
// Sets the name of the user script to be executed at specific points in
|
||
|
// the resting process. The tag of this item should be set to the name
|
||
|
// of the script to be executed. There are no standard user scripts
|
||
|
// provided with the CS Resting Subsystem as by definition all customised
|
||
|
// features must be provided by users of the subsystem. See Writing User
|
||
|
// Scripts for more information.
|
||
|
// CS Rest: Text Messages
|
||
|
// Default value: TRUE, with built in messages from cs_rest_text script
|
||
|
// This item will enable the display of floaty text messages, and allows
|
||
|
// the text of the messages to be changed. Once an instance of this item
|
||
|
// has been placed in the relevant configuration container, edit the item
|
||
|
// properties and click on the Description tab, then select the Variables
|
||
|
// button if you wish to change the text of the messages. The item
|
||
|
// contains all of the default messages already, so simply select the one
|
||
|
// to be changed, and change or overwrite the message that is displayed in
|
||
|
// the text field at the bottom of the dialogue box. Select the Replace
|
||
|
// button to update the message variable on the item, and then repeat
|
||
|
// for any other messages that require change. Then click Ok to save the
|
||
|
// changes to the item. The names of the variables, and explanation of
|
||
|
// when the corresponding messages are displayed, are:
|
||
|
// Variable Name Displayed When
|
||
|
// ------------- --------------
|
||
|
// cs_rest_startText A player starts resting.
|
||
|
// cs_rest_finishText A player finishes resting properly.
|
||
|
// cs_rest_cancelText A rest attempt is interrupted and
|
||
|
// so is unfinished. The player concerned
|
||
|
// will regain a portion of normal HP.
|
||
|
// cs_rest_cannotText A player may not rest due to rule
|
||
|
// restrictions.
|
||
|
// cs_rest_tooSoonText A time limit rule is in force and the
|
||
|
// player has not waited long enough.
|
||
|
// cs_rest_dayOnlyText The Day Only rest rule is in force and
|
||
|
// a player tries to rest at night.
|
||
|
// cs_rest_nightOnlyText The Night Only rest rule is in force
|
||
|
// and a player tries to rest during the
|
||
|
// day.
|
||
|
// cs_rest_noArmourText The No Armour rest rule is in force
|
||
|
// and the player is wearing armour, a
|
||
|
// helmet or carrying a shield.
|
||
|
// cs_rest_noWeaponText The no Weapons rest rule is in force
|
||
|
// and the player is carrying a weapon.
|
||
|
// cs_rest_bedrollRuinedText A bedroll is used for the last time
|
||
|
// before it becomes useless. The player
|
||
|
// gains a full rest, but must then
|
||
|
// replace the bedroll.
|
||
|
// cs_rest_notComfortable The Bedroll rest rule is in force, the
|
||
|
// player has no bedroll, but the bedroll
|
||
|
// multiplier is set to a value > 0.
|
||
|
// cs_rest_enterZoneText The player enters a Safe Camp resting
|
||
|
// trigger.
|
||
|
// cs_rest_exitZoneText The player leaves a Safe Camp resting
|
||
|
// trigger.
|
||
|
// cs_rest_unsafeText A player tries to rest within a Safe
|
||
|
// Room trigger without closing all doors.
|
||
|
// cs_rest_enterNoZoneText The player enters a No Rest resting
|
||
|
// trigger.
|
||
|
// cs_rest_exitNoZoneText The player leaves a no Rest resting
|
||
|
// trigger.
|
||
|
// cs_rest_noBedrollText The Bedroll rest rule is in force, the
|
||
|
// player has no bedroll, and the bedroll
|
||
|
// multiplier is set to 0.
|
||
|
// When a text message is displayed, any occurances of the string "<MIN>"
|
||
|
// will be replaced with the number of minutes remaining until the player
|
||
|
// will be permitted to rest again. This is really only useful in the
|
||
|
// "cs_rest_tooSoonText" variable. In addition, any variable that is set
|
||
|
// to the string "off" will not be displayed. This allows the individual
|
||
|
// messages to be controlled. This item is the opposite of the No Messages
|
||
|
// item below and you may not use both items at the same time.
|
||
|
// CS Rest: No Messages
|
||
|
// Default value: FALSE
|
||
|
// Use this item to disable the display of any floaty text messages. This
|
||
|
// item is the opposite of the Text Messages item above and you may not use
|
||
|
// both items at the same time.
|
||
|
// CS Rest: Effects
|
||
|
// Default value: FALSE
|
||
|
// Use this item to apply visual effects to resting players. Once a copy of
|
||
|
// this item has been placed in the relevant configuration container, edit
|
||
|
// the item properties and click on the Description tab, then select the
|
||
|
// Variables button to change the effects to be applied. The item already
|
||
|
// has the necessary variable, which is named "cs_rest_effects", set though
|
||
|
// with an empty value. Select the variable name in the list, and enter
|
||
|
// the numeric effect constant values desired in the text field at the
|
||
|
// bottom of the dialogue box, separated by commas. Select the Replace
|
||
|
// button to update the variable on the item, then click Ok to save the
|
||
|
// changes to the item. The numeric effect constants can be determined by
|
||
|
// opening the script named "nwscript" in the script editor and searching
|
||
|
// for "VFX". Don't forget to select the "All Resources" radio button.
|
||
|
// I'd list them all here, but there are many hundreds and most are not
|
||
|
// very useful for resting purposes. Some effects that may be quite useful
|
||
|
// for resting are:
|
||
|
// Description Constant Name Value
|
||
|
// ----------- ------------- -----
|
||
|
// Darkness VFX_DUR_DARKNESS 1
|
||
|
// Sleep VFX_IMP_SLEEP 94
|
||
|
// As an example, to set darkness and sleep effects on a player during
|
||
|
// resting, use a value of "1,94" for the "cs_rest_effects" variable
|
||
|
// on the item. Note that these are *visual* effects only, and some may
|
||
|
// run for fixed durations, finishing either before or after the resting
|
||
|
// period.
|
||
|
// CS Rest: Enable Debug
|
||
|
// Default value: FALSE
|
||
|
// Use this item to enable debug output from the resting subsystem. The
|
||
|
// debug output will be written to the message window of the player who
|
||
|
// is resting, and to server log. Debug is managed with the CS Debug
|
||
|
// subsystem, a separate package for displaying debug information. A
|
||
|
// minimal set of scripts from the CS Debug package is included with the
|
||
|
// CS Resting Subsystem.
|
||
|
//
|
||
|
// Using The Resting Triggers
|
||
|
// --------------------------
|
||
|
// The resting triggers track the entry and exit of players, and apply specific
|
||
|
// resting rules while a player is within the bounds of the trigger. The three
|
||
|
// standard triggers provided with the CS Resting Subsystem are the Camp
|
||
|
// trigger, the Room trigger and the No Rest trigger.
|
||
|
//
|
||
|
// NOTE: you do not need to use the triggers to make use of the resting
|
||
|
// subsystem, however in many instances the triggers are easier and more
|
||
|
// flexible to work with. Should you wish to block resting in most parts of
|
||
|
// an area and only allow resting at specific points, such as campsites, then
|
||
|
// using Camp triggers is the logical approach. Likewise, if you only wish to
|
||
|
// stop players from resting at specific points, such as within a boss room,
|
||
|
// then the No Rest trigger is the perfect tool.
|
||
|
//
|
||
|
// Placing a resting trigger basically involves drawing one somewhere in an
|
||
|
// area and setting any configuration necessary. The following steps provide
|
||
|
// a minimal guide to creating a Camp Trigger.
|
||
|
//
|
||
|
// 1/. Select the "CS Camp Resting Trigger" trigger from the "Generic
|
||
|
// Triggers" category of the Custom triggers palette.
|
||
|
// 2/. Draw a trigger polygon somewhere in an area, such as around a campfire
|
||
|
// tile.
|
||
|
// 3/. Edit the properties of the trigger (right click within the polygon
|
||
|
// and select "Properties" from the menu that is displayed) and change
|
||
|
// the Tag field to something sensible for your module. If you place
|
||
|
// more than one trigger with the same tag, they will all use the same
|
||
|
// configuration. This feature allows a module to have resting triggers
|
||
|
// that provide different combinations of resting rules.
|
||
|
// 4/. If you wish, create a container and place configuration items in
|
||
|
// its inventory to modify the operation of the trigger (see the section
|
||
|
// on configuring the CS Resting Subsystem for more details).
|
||
|
//
|
||
|
// You now have a functioning rest trigger. Save your module and load
|
||
|
// it up in Neverwinter Nights to see what happens, however unless you have
|
||
|
// placed a configuration container and changed the default operation, the
|
||
|
// trigger won't actually do anything different to standard Bioware resting.
|
||
|
//
|
||
|
// Other Configuration Facilities
|
||
|
// ------------------------------
|
||
|
// It is possible however to configure resting triggers differently to the
|
||
|
// global rules defined in the global configuration container. You do this
|
||
|
// by creating another container and setting its tag to match that of the
|
||
|
// trigger in question with the string "_REST_CONFIG" appended, i.e. if the
|
||
|
// trigger has a tag of "NoRestZone", the container's tag must be set to
|
||
|
// "NoRestZone_REST_CONFIG". If the tag is not set correctly, the trigger
|
||
|
// won't be able to find the container so be sure to double check this.
|
||
|
// Note that the length of the tag set on the trigger may not be more than
|
||
|
// 20 characters, since "_REST_CONFIG" is 12 characters. Tags are may a maximum
|
||
|
// of 32 characters, so 32 - 12 leaves 20 for the trigger tag.
|
||
|
//
|
||
|
// Once you create a configuration container that is specific to a trigger,
|
||
|
// any configuration items that you place in it will apply only to triggers
|
||
|
// with matching tags (and to *all* triggers with matching tags).
|
||
|
//
|
||
|
// But wait, there's more! It is also possible, in exactly the same way, to
|
||
|
// apply a set of resting rules to a specific area! Say you create an area
|
||
|
// and set its tag to be "BigBadForest". Create a container, set its tag to
|
||
|
// be "BigBadForest_REST_CONFIG" and place some configuration items in the
|
||
|
// container. This particular resting configuration will now apply to all
|
||
|
// players whenever they rest within that area. If however, there is a
|
||
|
// trigger within the area that has a different set of rules, the trigger's
|
||
|
// own rules will apply should the player rest within it.
|
||
|
//
|
||
|
// When a player rests, the resting subsystem will apply the most specific
|
||
|
// rules that it can find based on where the player actually rests. First
|
||
|
// a check is made to see if the player is within a trigger, then the area
|
||
|
// is checked for a specific config container, and finally the global config
|
||
|
// container is checked. It is important to note that this search is performed
|
||
|
// for each configuration item, not just for the configuration container itself
|
||
|
// and so if an item is not present in a trigger's configuration container,
|
||
|
// but *is* present in the global container or an area container, the resting
|
||
|
// subsystem will still apply it to the player! If you wish a specific rest
|
||
|
// rule to apply, then be careful which container you put it in.
|
||
|
//
|
||
|
// A Worked Example Of Setting Up The CS Resting Subsystem
|
||
|
// -------------------------------------------------------
|
||
|
// Ok, lets take a closer look at precisely how to make use to the CS Resting
|
||
|
// Subsystem. Let's say that you're building a module containing three areas: a
|
||
|
// city, an inn and a forest. You decide that there should be limited resting
|
||
|
// available in the forest, but no resting should be possible in the city
|
||
|
// itself since players are supposed to rest in the inn. Within the inn, full
|
||
|
// resting operates.
|
||
|
//
|
||
|
// First set the module's OnPlayerRest event script to "cs_rest_handler".
|
||
|
// Pull down the Edit menu and select Module Properties. Select the Events
|
||
|
// tab and either drop down the list for the OnPlayerRest event to scroll
|
||
|
// through and find "cs_rest_handler", or simply delete the script name
|
||
|
// that is already there and type in "cs_rest_handler" in place. Now select
|
||
|
// the Ok button and the module's rest script is set.
|
||
|
//
|
||
|
// Now create three areas and set their tags to be "TheCity", "TheInn" and
|
||
|
// "BigBadForest". Since the configuration containers for the resting subsystem
|
||
|
// should not be accessible to players, create a fourth area specifically to
|
||
|
// hold the configuration containers. DMs can jump to this area if necessary,
|
||
|
// and when editing the module in the toolset the location of the containers
|
||
|
// is irrelevant. For this module, the global resting rules will apply to the
|
||
|
// forest area while the city and inn have their own specific configuration.
|
||
|
//
|
||
|
// Create three containers and place them in the fourth area. Set their tags to
|
||
|
// be "CS_REST_GLOBAL_CONFIG", "TheCity_REST_CONFIG" and "TheInn_REST_CONFIG".
|
||
|
// Place configuration items into the three containers as indicated below:
|
||
|
//
|
||
|
// Container tagged "CS_REST_GLOBAL_CONFIG":
|
||
|
// CS Rest: Enable
|
||
|
// CS Rest: 3rd Ed Style HP
|
||
|
// CS Rest: Default Profile; set this item's tag to "cs_rest_cmp"
|
||
|
// CS Rest: 4 Minute Limit
|
||
|
//
|
||
|
// Container tagged "TheCity_REST_CONFIG":
|
||
|
// CS Rest: Default Profile; set this item's tag to "cs_rest_cnt"
|
||
|
//
|
||
|
// Container tagged "TheInn_REST_CONFIG":
|
||
|
// CS Rest: Standard HP
|
||
|
// CS Rest: Armour Not Allowed
|
||
|
// CS Rest: No Limit
|
||
|
//
|
||
|
// We're done! You now have a module configured to use the CS Resting Subsystem
|
||
|
// instead of the Bioware default resting. In the forest area, and by extension
|
||
|
// any others areas you may add to this module, players may rest once every 4
|
||
|
// minutes and will regain 1 hit point per level. No resting is permitted in
|
||
|
// the city area at all, and players may rest as often as they wish, and regain
|
||
|
// full hit points each time, in the inn but they will have to remove their
|
||
|
// armour to do it.
|
||
|
//
|
||
|
// Notice how not all configuration items need to be set in each container.
|
||
|
// When the resting subsystem is looking for a particular rule, such as whether
|
||
|
// to allow resting in armour, it looks first in any trigger-specific
|
||
|
// container that exists, then it looks in the area-specific container, and
|
||
|
// then it checks the global container. The first item found sets the rule for
|
||
|
// that resting session for that player. If no item is found, the default
|
||
|
// operation is assumed. In this example, you will see that the inn area's
|
||
|
// configuration container does not need to contain a CS Rest: Default Profile
|
||
|
// item since it can use the same script that is set in the configuration for
|
||
|
// the global container. It does however need to have the CS Rest: No Limit
|
||
|
// item to reset resting to unlimited times otherwise the 4 minute limit set
|
||
|
// in the global container would also apply.
|
||
|
//
|
||
|
// Writing User Scripts
|
||
|
// --------------------
|
||
|
// A user script can be used to add module-specific resting rules to those
|
||
|
// evaluated when determining whether a player should be permitted to rest.
|
||
|
// User scripts can also allow interoperation with other systems, such as
|
||
|
// a wandering monster system, and can be used to implement plot-specific
|
||
|
// logic that is triggered when players rest. User scripts are not required
|
||
|
// for normal use of the resting subsystem, but provide instead a powerful
|
||
|
// facility for extending the resting subsystem to meet specific module
|
||
|
// requirements. Some scripting knowledge is required to properly make use
|
||
|
// of the user scripts facility.
|
||
|
//
|
||
|
// A given user script will be executed potentially at four points during the
|
||
|
// rest cycle for a player: when rules are being evaluated to determine whether
|
||
|
// the player may rest, when the player starts to rest, when the player
|
||
|
// finishes resting, and when resting is cancelled for any reason. Only one of
|
||
|
// finish resting or cancel resting will be executed, and if a player is not
|
||
|
// permitted to rest due to not satisfying an active rest rule, then the user
|
||
|
// script will only be executed for the rule evaluation stage. User scripts
|
||
|
// are always executed with the player who is attempting to rest as the
|
||
|
// current object (i.e. OBJECT_SELF within the user script will refer to
|
||
|
// the player).
|
||
|
//
|
||
|
// When the resting subsystem is determining a player's eligibility to rest,
|
||
|
// a set of builtin rules are evaluated against the player. These rules may
|
||
|
// be enabled through configuration and are things like No Armour, Day Only,
|
||
|
// etc. Each of the rules that has been enabled will be checked and the result
|
||
|
// stored for the rest session. Once all rules have been evaluated, the player
|
||
|
// is only permitted to rest if every single rule allows it.
|
||
|
//
|
||
|
// When a user script is executed for evaluation of rest rules, the builder
|
||
|
// may add additional rules for the module. The builder may also override
|
||
|
// the evaluation of the builtin rules by performing additional checks and
|
||
|
// potentially changing the previously calculated result for a rule. For
|
||
|
// example, the No Weapons rule may be enabled, which will prevent a player
|
||
|
// from resting while holding a weapon. The module builder may however decide
|
||
|
// that daggers are small enough to be no hinderance and so would like to
|
||
|
// allow resting if the equipped weapon is a dagger. When a player rests
|
||
|
// with an equipped dagger, the resting subsystem builtin rule will fail, thus
|
||
|
// indicating that resting is not permitted. A user script may then be written
|
||
|
// that performs an additional check on the weapon to see if it is a dagger.
|
||
|
// If so, the previously calculated result of the builtin rule can be reset,
|
||
|
// allowing the player to rest. Of course, if the player fails any other
|
||
|
// rule, she will still not be allowed to rest anyway.
|
||
|
//
|
||
|
// The other execution points for the user script, i.e. when resting starts,
|
||
|
// finishes or is cancelled, are provided specifically for adding custom
|
||
|
// module-specific functionality rather than interacting with the resting
|
||
|
// subsystem itself. The user script may initiate a cutscene when resting
|
||
|
// finishes for example, or generate a random wandering monster encounter
|
||
|
// when resting starts. These execution points are provided for use by builders
|
||
|
// when integrating the resting subsystem into other aspects of a module.
|
||
|
//
|
||
|
// In structure, a user script closely resembles a standard NWN user-defined
|
||
|
// event handler script. Each execution point is numbered and the script calls
|
||
|
// a function, cs_rest_GetUserScriptState(), to determine the execution point
|
||
|
// for which it has been executed. This function will return one of the
|
||
|
// following constants:
|
||
|
// CS_REST_START_RESTING
|
||
|
// CS_REST_STOP_RESTING
|
||
|
// CS_REST_CANCEL_RESTING
|
||
|
// CS_REST_RULE_CHECK
|
||
|
//
|
||
|
// Once the execution point number has been obtained, a set of if statements
|
||
|
// or a switch statement is used to perform the necessary functionality. When
|
||
|
// the execution point number is CS_REST_RULE_CHECK, the following functions
|
||
|
// may also be used:
|
||
|
// cs_rest_GetIsRuleEnabled returns TRUE if a specific rule is
|
||
|
// enabled in configuration.
|
||
|
// cs_rest_GetRule returns TRUE if a specific rule has
|
||
|
// has been failed (i.e. the player may
|
||
|
// not rest.
|
||
|
// cs_rest_SetRule used to force a specific rule to a
|
||
|
// given state (TRUE will cause the player
|
||
|
// to be unable to rest).
|
||
|
// cs_rest_SetOverrideProfile changes the profile that will be used
|
||
|
// for the current rest session *only*.
|
||
|
// The next time the player rests, the
|
||
|
// profile will automatically revert to
|
||
|
// that which is active for the player
|
||
|
// (should the player be inside a trigger)
|
||
|
// or the default profile if the player
|
||
|
// has no profile.
|
||
|
//
|
||
|
// These functions allow the user script to control the rest rules. The rest
|
||
|
// rules are indicated by using the following constants when calling the
|
||
|
// functions above:
|
||
|
// CS_REST_RULE_LAST_REST
|
||
|
// CS_REST_RULE_DAY_ONLY
|
||
|
// CS_REST_RULE_NIGHT_ONLY
|
||
|
// CS_REST_RULE_NO_ARMOUR
|
||
|
// CS_REST_RULE_NO_WEAPONS
|
||
|
// CS_REST_RULE_NO_BEDROLL
|
||
|
// CS_REST_RULE_USER_1
|
||
|
// CS_REST_RULE_USER_2
|
||
|
// CS_REST_RULE_USER_3
|
||
|
// CS_REST_RULE_USER_4
|
||
|
// CS_REST_RULE_USER_5
|
||
|
// CS_REST_RULE_USER_6
|
||
|
// CS_REST_RULE_USER_7
|
||
|
// CS_REST_RULE_USER_8
|
||
|
// CS_REST_RULE_USER_9
|
||
|
// CS_REST_RULE_USER_10
|
||
|
// CS_REST_RULE_USER_11
|
||
|
// CS_REST_RULE_USER_12
|
||
|
// CS_REST_RULE_USER_13
|
||
|
// CS_REST_RULE_USER_14
|
||
|
// CS_REST_RULE_USER_15
|
||
|
// CS_REST_RULE_USER_16
|
||
|
//
|
||
|
// These constants identify the builtin rest rules provided by the resting
|
||
|
// subsystem, and also the 16 user rules that are available for use by builders
|
||
|
// within user scripts. The user rules will be honoured by the resting
|
||
|
// subsystem in exactly the same way as the builtin rules, with the single
|
||
|
// exception that the resting subsystem will never change the state of a user
|
||
|
// rule. All user rules are always enabled, and will always be FALSE (i.e.
|
||
|
// the player is allowed to rest) when the user script is executed. Changing
|
||
|
// any user rule to a state of TRUE through the cs_rest_SetRule() function
|
||
|
// will prevent the player from resting.
|
||
|
//
|
||
|
// When the execution point is CS_REST_START_RESTING, the following functions
|
||
|
// may also be used:
|
||
|
// cs_rest_SetAbort Causing the rest process to be aborted
|
||
|
// as if it had not started. This allows
|
||
|
// last minute decisions to be made as to
|
||
|
// whether a player may rest, despite the
|
||
|
// player having successfully satisfied all
|
||
|
// enabled rest rules.
|
||
|
// cs_rest_SetOverrideProfile changes the profile that will be used
|
||
|
// for the current rest session *only*.
|
||
|
// The next time the player rests, the
|
||
|
// profile will automatically revert to
|
||
|
// that which is active for the player
|
||
|
// (should the player be inside a trigger)
|
||
|
// or the default profile if the player
|
||
|
// has no profile.
|
||
|
//
|
||
|
// Consult the help text for each function for further details, and read
|
||
|
// through the sample code in An Example User Script. The script named
|
||
|
// cs_rest_sample is template script that may used as a starting point for
|
||
|
// user scripts. The script named cs_rest_wndmonst is a functional example
|
||
|
// that demonstrates how the Bioware HotU wandering monster system may be
|
||
|
// integrated into the resting subsystem.
|
||
|
//
|
||
|
// An Example User Script
|
||
|
// ----------------------
|
||
|
// The sample script in this section shows how to implement the example
|
||
|
// presented in Writing User Scripts.
|
||
|
//
|
||
|
// #include "cs_rest"
|
||
|
// void main() {
|
||
|
// int state = cs_rest_GetUserScriptState();
|
||
|
// if (state == CS_REST_START_RESTING) {
|
||
|
// }
|
||
|
// else if (state == CS_REST_STOP_RESTING) {
|
||
|
// }
|
||
|
// else if (state == CS_REST_CANCEL_RESTING) {
|
||
|
// }
|
||
|
// else if (state == CS_REST_RULE_CHECK) {
|
||
|
// // Has the No Weapons rule actually been enabled?
|
||
|
// if (cs_rest_GetIsRuleEnabled(CS_REST_RULE_NO_WEAPONS)) {
|
||
|
// // Retrieve the items in the resting player's hands.
|
||
|
// object right = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
|
||
|
// // If the player has a dagger in her right hand, we have to
|
||
|
// // check a little more carefully before resetting the No
|
||
|
// // Weapons rule and allowing her to rest.
|
||
|
// if ((GetBaseItemType(right) == BASE_ITEM_DAGGER) {
|
||
|
// // If the player has nothing in her left hand, or a dagger,
|
||
|
// // a shield, or a torch, she's ok to rest for this rule.
|
||
|
// // Anything else will be assumed to be another weapon
|
||
|
// // and so the resting state for the No Weapons rule will
|
||
|
// // be left unchanged.
|
||
|
// int left = GetBaseItemType(
|
||
|
// GetItemInSlot(INVENTORY_SLOT_LEFTHAND)
|
||
|
// );
|
||
|
// if ((left == BASE_ITEM_INVALID) ||
|
||
|
// (left == BASE_ITEM_TORCH) ||
|
||
|
// (left == BASE_ITEM_SMALLSHIELD) ||
|
||
|
// (left == BASE_ITEM_LARGESHIELD) ||
|
||
|
// (left == BASE_ITEM_TOWERSHIELD) ||
|
||
|
// (left == BASE_ITEM_DAGGER)
|
||
|
// ) {
|
||
|
// // The player only has a dagger or an allowed item
|
||
|
// // equipped, so the No Weapon rule can be reset.
|
||
|
// // Note that shields are checked as part of the
|
||
|
// // No Armour rule, not the No WSeapons rule.
|
||
|
// cs_rest_SetRule(CS_REST_RULE_NO_WEAPONS, FALSE);
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// Creating Your Own Resting Profile
|
||
|
// ---------------------------------
|
||
|
// A resting profile sets the fundamental operation of the resting subsystem.
|
||
|
// Resting profiles are represented by scripts that call the basic functions
|
||
|
// of the resting subsystem in response to the engine's rest events, sometimes
|
||
|
// performing additional checks (such as the safe room profile used by the
|
||
|
// CS Safe Room Trigger, which checks that all doors in a room are closed
|
||
|
// before executing the resting). The three standard profiles provided with
|
||
|
// resting subsystem are:
|
||
|
// Name Script
|
||
|
// -------------- ------
|
||
|
// Safe/Camp Rest cs_rest_cmp
|
||
|
// Safe Room Rest cs_rest_rom
|
||
|
// No Rest cs_rest_cnt
|
||
|
//
|
||
|
// Resting profiles are used in two places: when setting a default profile
|
||
|
// for the global rest configuration or in an area's rest configuration,
|
||
|
// or when creating a resting trigger. Using a resting profile from a
|
||
|
// configuration container is simply a matter of setting the profile script
|
||
|
// name using the Default Profile config item, after writing the profile
|
||
|
// script, of course. Creating a profile for use with a trigger is slightly
|
||
|
// more complex. Creating a rest profile is a task for a moderately skilled
|
||
|
// scripter with good knowledge of how the resting subsystem works.
|
||
|
//
|
||
|
// There are three components to a rest profile when it is used from a
|
||
|
// trigger: a trigger OnEnter script, a trigger OnExit script, and the
|
||
|
// resting profile script itself. The OnEnter script is a simple modification
|
||
|
// of an existing OnEnter script, since the only thing that has to change is
|
||
|
// the name of the resting profile script contained within it. The standard
|
||
|
// OnExit script provided by the resting subsystem should work for all new
|
||
|
// resting profile triggers as well, so the only real work comes about when
|
||
|
// writing the resting profile script itself.
|
||
|
//
|
||
|
// The standard resting profiles should be sufficient for most purposes, as
|
||
|
// most custom operation may be added theough the user script facility in a
|
||
|
// more elegant manner.
|
||
|
//
|
||
|
// An Example Resting Profile
|
||
|
// --------------------------
|
||
|
// To illustrate how resting profiles are created, the Safe Room Rest profile
|
||
|
// script and its corresponding trigger OnEnter script are shown here. The
|
||
|
// standard trigger OnExit script, cs_rest_trg_exit, should be sufficient
|
||
|
// for any new resting profile trigger.
|
||
|
//
|
||
|
// This is the trigger OnEnter script for the Safe Room Rest trigger. It first
|
||
|
// checks to ensure that the creature who has entered the trigger is a player,
|
||
|
// and then it sets the name of the resting profile script ("cs_rest_rom")
|
||
|
// as the player's resting profile using the cs_rest_SetProfile() function.
|
||
|
// The trigger itself is set as the object that the player has entered using
|
||
|
// the cs_rest_SetTriggeringObject() function (this is so the resting subsystem
|
||
|
// knows which configuration container to search for). Finally, a floaty text
|
||
|
// message is displayed indicating that the player has entered a rest trigger.
|
||
|
// The cs_rest_RetrieveConfig() function is used to determine whether floaty
|
||
|
// text messages are enabled (a check is performed within the function call).
|
||
|
// Basically all OnEnter scripts for resting triggers will look identical to
|
||
|
// this script except for the name of the rest profile script.
|
||
|
//
|
||
|
// #include "cs_rest"
|
||
|
// void main() {
|
||
|
// object pc = GetEnteringObject();
|
||
|
// if (GetIsPC(pc)) {
|
||
|
// // Set tracking information for this trigger.
|
||
|
// cs_rest_SetProfile(pc, "cs_rest_rom");
|
||
|
// cs_rest_SetTriggeringObject(pc, OBJECT_SELF);
|
||
|
// struct cs_rest_config cfg = cs_rest_RetrieveConfig(pc);
|
||
|
// cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_ENTER_REST);
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// This is the Safe Room Rest profile script. It retrieves the current rest
|
||
|
// session config from the player with the cs_rest_GetConfig() function (all
|
||
|
// resting configuration has by this stage been retrieved from containers and
|
||
|
// stored as local variables on the player). The specific rest event is then
|
||
|
// checked to determine whether a start, stop or cancel event is currently
|
||
|
// being processed. The stop and cancel events simply require standard rest
|
||
|
// processing so the cs_rest_StopResting() and cs_rest_CancelResting()
|
||
|
// functions are called. For a start resting event, the trigger that the
|
||
|
// player has entered is searched for doors, and the state of every door
|
||
|
// is checked to make sure it has been closed. Only if there are actually
|
||
|
// doors, and all of them are closed, is the player allowed to rest. The
|
||
|
// configuration values retrieved from the player at the start of the function
|
||
|
// are passed to most resting subsystem functions to minimise the need to
|
||
|
// continually read local variables.
|
||
|
//
|
||
|
// #include "cs_rest"
|
||
|
// void main() {
|
||
|
// object pc = GetLastPCRested();
|
||
|
// if (GetIsPC(pc)) {
|
||
|
// struct cs_rest_config cfg = cs_rest_GetConfig(pc);
|
||
|
// int restType = GetLastRestEventType();
|
||
|
// if (restType == REST_EVENTTYPE_REST_STARTED) {
|
||
|
// // Find all doors within the area of the triggering object the
|
||
|
// // PC is within.
|
||
|
// int doorsFound = 0;
|
||
|
// int openDoors = 0;
|
||
|
// if (GetIsObjectValid(cfg.trigger)) {
|
||
|
// object door = GetFirstInPersistentObject(
|
||
|
// cfg.trigger,
|
||
|
// OBJECT_TYPE_DOOR
|
||
|
// );
|
||
|
// while (GetIsObjectValid(door)) {
|
||
|
// doorsFound++;
|
||
|
// if (GetIsOpen(door)) {
|
||
|
// openDoors++;
|
||
|
// }
|
||
|
// door = GetNextInPersistentObject(
|
||
|
// cfg.trigger,
|
||
|
// OBJECT_TYPE_DOOR
|
||
|
// );
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// // Do we stop the player from resting? This is a safe room rest
|
||
|
// // check. Players may only rest if they have taken steps to
|
||
|
// // ensure their own safety, i.e. closing all doors. Resting is
|
||
|
// // not permitted if:
|
||
|
// // - there are no doors in this trigger
|
||
|
// // - a door within this trigger is open
|
||
|
// if (!doorsFound || openDoors) {
|
||
|
// cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_UNSAFE);
|
||
|
// AssignCommand(pc, ClearAllActions());
|
||
|
// }
|
||
|
// else {
|
||
|
// cs_rest_StartResting(pc, cfg);
|
||
|
// }
|
||
|
// }
|
||
|
// else if (restType == REST_EVENTTYPE_REST_FINISHED) {
|
||
|
// cs_rest_StopResting(pc, cfg);
|
||
|
// }
|
||
|
// else if (restType == REST_EVENTTYPE_REST_CANCELLED) {
|
||
|
// cs_rest_CancelResting(pc, cfg);
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// Using the CS Resting Subsystem Within A Persistent World
|
||
|
// --------------------------------------------------------
|
||
|
// In general, The CS Resting Subsystem will function correctly when used in a
|
||
|
// persistent world environment. The one thing that may cause issues is the
|
||
|
// last resting time, which must be calculated and stored each time a player
|
||
|
// rests. When a player logs in after a server restart, she will be able to
|
||
|
// rest immediately, which may not be what is desired. There are however a
|
||
|
// set of functions provided that address this situation.
|
||
|
//
|
||
|
// The cs_rest_GetState() and cs_rest_SetState() functions may be used to
|
||
|
// store the information needed to restore a player's resting situation to
|
||
|
// a specific point. The cs_rest_GetState() function may be used to retrieve
|
||
|
// resting information for a player, which may then be stored in a persistence
|
||
|
// mechanism such as a database. This resting information is returned in the
|
||
|
// form of a string for convenience. The cs_rest_SetState() function may be
|
||
|
// used to restore the resting information for when that player logs into
|
||
|
// the server again.
|
||
|
//
|
||
|
// The use of these two functions must be performed through scripting and so
|
||
|
// is not handled as part of the normal configuration of the resting subsystem.
|
||
|
// It is not necessary to use these functions in anything other than a
|
||
|
// persistent world, and not even in every one of those. Please try using the
|
||
|
// resting subsystem first before making use of these functions.
|
||
|
//
|
||
|
// Acknowledgements
|
||
|
// ----------------
|
||
|
// Many thanks go to __Abaddon__ and Elorin for being sounding boards of
|
||
|
// ideas and for telling me when I'm being stupid. Elorin finds bugs and I
|
||
|
// fix them. Sigh. Provsul has been of great assistance in providing better
|
||
|
// support for persistent worlds.
|
||
|
//
|
||
|
// To Do
|
||
|
// -----
|
||
|
// - Party-only resting.
|
||
|
// - Rations.
|
||
|
//
|
||
|
// Revision History
|
||
|
// ----------------
|
||
|
// 0.8.0dev Changed builtin resting rules to act upon a bitmapped flag
|
||
|
// integer, thus allowing all rules to operate independently.
|
||
|
// Some internal consistency tweaks, constant renaming and
|
||
|
// the like to make the code more maintainable. Added execution
|
||
|
// of user script immediately after evaluating builtin rules,
|
||
|
// and on start, stop and cancel of resting. Added User Script
|
||
|
// config item. Updated to release 1.6.0 of CS Debug. Updated
|
||
|
// documentation. Finally added support for changing the floaty
|
||
|
// text messages through the usual dynamic configuration model,
|
||
|
// and noew allow individual floaty messages to be disabled.
|
||
|
// Added the Effects config item. Added override profile.
|
||
|
// 0.7.3dev Added the Bedroll HP Multiplier config item. Changed the
|
||
|
// generation of the remaining minutes message to be more
|
||
|
// sensible.
|
||
|
// 0.7.2dev Rewrote the still dysfunctional time manipulation to use
|
||
|
// a double-int method of tracking times, thus providing more
|
||
|
// than sufficient scope for managing the DR calendar at any
|
||
|
// minutes-per-hour resolution that anyone may care to use.
|
||
|
// Shields are now considered armour with regard to resting.
|
||
|
// 0.7.1dev More debug messages. Corrected some minor issues related to
|
||
|
// time manipulation changes. Restored incorrect trigger tags.
|
||
|
// 0.7.0dev Some documentation updates. Added persistence hooks. Updated
|
||
|
// to release 1.5.0 of CS Debug. Added internal debug config
|
||
|
// support to allow debug output for the resting subsystem to
|
||
|
// be controlled through the resting subsystem configuration.
|
||
|
// Armour and weapons checks are now controlled through separate
|
||
|
// configuration items. Internal changes to time manipulation.
|
||
|
// 0.6.6dev Documentation corrections. No code change.
|
||
|
// 0.6.5dev Removed Destroy config item and associated code. The idea of
|
||
|
// destroying the config and keeping static copies of the rules
|
||
|
// as local variables never really made sense anyway. Added Use
|
||
|
// CON Bonus, No CON Bonus and HP Multiplier configuration items.
|
||
|
// 0.6.1dev Fixed No Messages configuration item so that it works.
|
||
|
// Added separate floaty messages for entering and exiting no
|
||
|
// rest zones.
|
||
|
// 0.6.0dev Major refactoring to eliminate proliferation of get/set
|
||
|
// functions and replace most with a single set of functions.
|
||
|
// Much cleaner code now. First draft of documentation. Added
|
||
|
// fade screen to black function and corresponding config item.
|
||
|
// Even more debug! Added No Messages configuration item.
|
||
|
// 0.5.0dev Added bedrolls and associated configuration items--still
|
||
|
// mostly untested. Corrected overzealous armour restrictions
|
||
|
// (forced resting naked is probably a bit over the top :).
|
||
|
// Included equipped weapons in the "armour check". Added
|
||
|
// resting never permitted function for special purposes.
|
||
|
// Added config cleanup when not destroying config containers,
|
||
|
// thus allowing defaults to re-apply the next time the container
|
||
|
// is read.
|
||
|
// 0.4.0dev Incorporated 3rd ed style resting as a configurable option
|
||
|
// for all triggers, and removed the 3rd ed trigger. Added
|
||
|
// global and area configuration facility. Added day/night
|
||
|
// only configuration items. Added armour configuration items.
|
||
|
// 0.3.0dev Added 3rd edition rules profile. Improved safe room resting
|
||
|
// by accounting for multiple doors. Rejigged framework to use
|
||
|
// two scripts per profile (enter/rest) rather than four
|
||
|
// (enter/start/stop/cancel). Added dynamic configuration.
|
||
|
// Added time limits. Added floaty text.
|
||
|
// 0.2.0dev Added profile support. Added safe room profile.
|
||
|
// 0.1.0dev Basic framework. Safe campsites.
|
||
|
//
|
||
|
//============================================================================
|
||
|
#include "cs_dbg"
|
||
|
#include "cs_token"
|
||
|
#include "cs_rest_text"
|
||
|
|
||
|
// The version numbering I use is comprised of a tripartite version number
|
||
|
// and a trailing string. The version is arranged into 1.2.3 form, where 1 is
|
||
|
// the major release number, 2 is the minor release number and 3 is the bugfix
|
||
|
// level. Each number in the version starts at 0 and increments each time a
|
||
|
// change is made to the code that classifies as that level. The trailing
|
||
|
// string is either "dev", "beta" or "final" depending upon whether the code
|
||
|
// is still under development (it will have bugs, count on it), is considered
|
||
|
// to be beta quality (i.e. technically finished but probably has bugs), or
|
||
|
// finished, tested and believed to be correctly functional. If you wish to
|
||
|
// report a bug, please include the version number with your bug report.
|
||
|
const string cs_rest_version = "0.8.0dev";
|
||
|
|
||
|
//============================================================================
|
||
|
//
|
||
|
// Data Types and Constants
|
||
|
//
|
||
|
//============================================================================
|
||
|
|
||
|
// The maximum length of tags. This is used for error validation.
|
||
|
const int CS_REST_MAX_TAG_LENGTH = 32;
|
||
|
|
||
|
// Constants for default values when using bedrolls.
|
||
|
const int CS_REST_DEF_BEDROLL_MAX_USE = 20;
|
||
|
const float CS_REST_DEF_BEDROLL_MULTIPLIER = 0.5;
|
||
|
const float CS_REST_DEF_MULTIPLIER = 1.0;
|
||
|
|
||
|
// The tag of the global rest container.
|
||
|
const string CS_REST_TAG_CONFIG = "CS_REST_GLOBAL_CONFIG";
|
||
|
|
||
|
// The suffix added to an area or trigger tag to generate the matching
|
||
|
// rest container tag.
|
||
|
const string CS_REST_TAG_CONFIG_SUFFIX = "_REST_CONFIG";
|
||
|
|
||
|
// Floaty text message IDs.
|
||
|
const int CS_REST_TXT_START = 1;
|
||
|
const int CS_REST_TXT_FINISH = 2;
|
||
|
const int CS_REST_TXT_CANCEL = 3;
|
||
|
const int CS_REST_TXT_CANNOT = 4;
|
||
|
const int CS_REST_TXT_TOO_SOON = 5;
|
||
|
const int CS_REST_TXT_DAY_ONLY = 6;
|
||
|
const int CS_REST_TXT_NIGHT_ONLY = 7;
|
||
|
const int CS_REST_TXT_NO_ARMOUR = 8;
|
||
|
const int CS_REST_TXT_NO_WEAPON = 9;
|
||
|
const int CS_REST_TXT_BEDROLL_RUINED = 10;
|
||
|
const int CS_REST_TXT_NOT_COMFORTABLE = 11;
|
||
|
const int CS_REST_TXT_ENTER_REST = 12;
|
||
|
const int CS_REST_TXT_EXIT_REST = 13;
|
||
|
const int CS_REST_TXT_UNSAFE = 14;
|
||
|
const int CS_REST_TXT_ENTER_NO_REST = 15;
|
||
|
const int CS_REST_TXT_EXIT_NO_REST = 16;
|
||
|
const int CS_REST_TXT_NO_BEDROLL = 17;
|
||
|
|
||
|
// Names of resrefs for configuration items.
|
||
|
const string CS_REST_RR_DEBUG_ON = "cs_rest_cfg_dbgo";
|
||
|
const string CS_REST_RR_ENABLE = "cs_rest_cfg_enbl";
|
||
|
const string CS_REST_RR_DISABLE = "cs_rest_cfg_dsbl";
|
||
|
const string CS_REST_RR_PROFILE = "cs_rest_cfg_prfl";
|
||
|
const string CS_REST_RR_TIME_LIMIT = "cs_rest_cfg_time";
|
||
|
const string CS_REST_RR_TIME_PREFIX = "cs_rest_cfg_tm";
|
||
|
const string CS_REST_RR_HP_3ED = "cs_rest_cfg_3ed";
|
||
|
const string CS_REST_RR_HP_STD = "cs_rest_cfg_std";
|
||
|
const string CS_REST_RR_NO_ARMOUR = "cs_rest_cfg_armn";
|
||
|
const string CS_REST_RR_YES_ARMOUR = "cs_rest_cfg_army";
|
||
|
const string CS_REST_RR_NO_WEAPONS = "cs_rest_cfg_wepn";
|
||
|
const string CS_REST_RR_YES_WEAPONS = "cs_rest_cfg_wepy";
|
||
|
const string CS_REST_RR_NO_BEDROLL = "cs_rest_cfg_bedn";
|
||
|
const string CS_REST_RR_YES_BEDROLL = "cs_rest_cfg_bedy";
|
||
|
const string CS_REST_RR_BEDROLL_MULTIPLIER = "cs_rest_cfg_bedm";
|
||
|
const string CS_REST_RR_DAY_ONLY = "cs_rest_cfg_donl";
|
||
|
const string CS_REST_RR_NIGHT_ONLY = "cs_rest_cfg_nonl";
|
||
|
const string CS_REST_RR_ALL_HOURS = "cs_rest_cfg_allh";
|
||
|
const string CS_REST_RR_DAY_START = "cs_rest_cfg_days";
|
||
|
const string CS_REST_RR_DAY_END = "cs_rest_cfg_daye";
|
||
|
const string CS_REST_RR_FADE_TO_BLACK = "cs_rest_cfg_fade";
|
||
|
const string CS_REST_RR_NO_MESSAGES = "cs_rest_cfg_nmsg";
|
||
|
const string CS_REST_RR_USE_CON_BONUS = "cs_rest_cfg_cony";
|
||
|
const string CS_REST_RR_NO_CON_BONUS = "cs_rest_cfg_conn";
|
||
|
const string CS_REST_RR_HP_MULTIPLIER = "cs_rest_cfg_hmul";
|
||
|
const string CS_REST_RR_USER_SCRIPT = "cs_rest_cfg_uscr";
|
||
|
const string CS_REST_RR_TEXT_MESSAGES = "cs_rest_cfg_text";
|
||
|
const string CS_REST_RR_EFFECTS = "cs_rest_cfg_efct";
|
||
|
|
||
|
// Names of local variables used within the resting code.
|
||
|
const string CS_REST_VAR_DEBUG = "cs_rest_debug";
|
||
|
const string CS_REST_VAR_PERMITTED = "cs_rest_permitted";
|
||
|
const string CS_REST_VAR_RULE_FLAGS = "cs_rest_ruleFlags";
|
||
|
const string CS_REST_VAR_ENABLE = "cs_rest_enable";
|
||
|
const string CS_REST_VAR_STARTED = "cs_rest_started";
|
||
|
const string CS_REST_VAR_NEVER_PERMITTED = "cs_rest_neverPermitted";
|
||
|
//const string CS_REST_VAR_PLAYER_ALLOWED = "cs_rest_playerAllowed";
|
||
|
const string CS_REST_VAR_PLAYER_PROFILE = "cs_rest_playerProfile";
|
||
|
const string CS_REST_VAR_DEFAULT_PROFILE = "cs_rest_defaultProfile";
|
||
|
const string CS_REST_VAR_OVERRIDE_PROFILE = "cs_rest_overrideProfile";
|
||
|
const string CS_REST_VAR_TIME_LIMIT = "cs_rest_timeLimit";
|
||
|
const string CS_REST_VAR_LAST_REST_DAYS = "cs_rest_lastRestDays";
|
||
|
const string CS_REST_VAR_LAST_REST_SECONDS = "cs_rest_lastRestSeconds";
|
||
|
const string CS_REST_VAR_SAVE_HP = "cs_rest_savedHP";
|
||
|
const string CS_REST_VAR_HP_3ED = "cs_rest_3ed";
|
||
|
const string CS_REST_VAR_NO_ARMOUR = "cs_rest_noArmour";
|
||
|
const string CS_REST_VAR_NO_WEAPONS = "cs_rest_noWeapons";
|
||
|
const string CS_REST_VAR_BEDROLL_IN_USE = "cs_rest_bedrollInUse";
|
||
|
const string CS_REST_VAR_BEDROLL_TAG = "cs_rest_bedrollTag";
|
||
|
const string CS_REST_VAR_BEDROLL_USE = "cs_rest_bedrollUse";
|
||
|
const string CS_REST_VAR_BEDROLL_MULTIPLIER = "cs_rest_bedrollMultiplier";
|
||
|
const string CS_REST_VAR_DAY_MODE = "cs_rest_dayMode";
|
||
|
const string CS_REST_VAR_DAY_START = "cs_rest_dayStart";
|
||
|
const string CS_REST_VAR_DAY_END = "cs_rest_dayEnd";
|
||
|
const string CS_REST_VAR_TRIGGER = "cs_rest_trigger";
|
||
|
const string CS_REST_VAR_MULTIPLIER = "cs_rest_multiplier";
|
||
|
const string CS_REST_VAR_FADE_TO_BLACK = "cs_rest_fadeToBlack";
|
||
|
const string CS_REST_VAR_FADE_DONE = "cs_rest_fadeDone";
|
||
|
const string CS_REST_VAR_NO_MESSAGES = "cs_rest_noMessages";
|
||
|
const string CS_REST_VAR_CON_BONUS = "cs_rest_conBonus";
|
||
|
const string CS_REST_VAR_NO_REST_ZONE = "cs_rest_noRestZone";
|
||
|
const string CS_REST_VAR_USER_SCRIPT = "cs_rest_userScript";
|
||
|
const string CS_REST_VAR_USER_SCRIPT_STATE = "cs_rest_userScriptState";
|
||
|
const string CS_REST_VAR_EFFECTS = "cs_rest_effects";
|
||
|
|
||
|
// Constants for indicating when resting is permitted.
|
||
|
const int CS_REST_DAY_AND_NIGHT = 0;
|
||
|
const int CS_REST_DAY_ONLY = 1;
|
||
|
const int CS_REST_NIGHT_ONLY = 2;
|
||
|
|
||
|
// Constants for state tracking whether resting actually began.
|
||
|
const int CS_REST_STARTED = 1;
|
||
|
const int CS_REST_ABORTED = 2;
|
||
|
|
||
|
// Constants for use with user hook scripts.
|
||
|
const int CS_REST_START_RESTING = 1;
|
||
|
const int CS_REST_STOP_RESTING = 2;
|
||
|
const int CS_REST_CANCEL_RESTING = 3;
|
||
|
const int CS_REST_RULE_CHECK = 4;
|
||
|
|
||
|
// Names of variables that hold floaty text message strings.
|
||
|
const string CS_REST_VAR_START_TEXT = "cs_rest_startText";
|
||
|
const string CS_REST_VAR_FINISH_TEXT = "cs_rest_finishText";
|
||
|
const string CS_REST_VAR_CANCEL_TEXT = "cs_rest_cancelText";
|
||
|
const string CS_REST_VAR_CANNOT_TEXT = "cs_rest_cannotText";
|
||
|
const string CS_REST_VAR_TOO_SOON_TEXT = "cs_rest_tooSoonText";
|
||
|
const string CS_REST_VAR_DAY_ONLY_TEXT = "cs_rest_dayOnlyText";
|
||
|
const string CS_REST_VAR_NIGHT_ONLY_TEXT = "cs_rest_nightOnlyText";
|
||
|
const string CS_REST_VAR_NO_ARMOUR_TEXT = "cs_rest_noArmourText";
|
||
|
const string CS_REST_VAR_NO_WEAPON_TEXT = "cs_rest_noWeaponText";
|
||
|
const string CS_REST_VAR_BEDROLL_RUINED_TEXT = "cs_rest_bedrollRuinedText";
|
||
|
const string CS_REST_VAR_NOT_COMFORTABLE_TEXT = "cs_rest_notComfortable";
|
||
|
const string CS_REST_VAR_ENTER_REST_TEXT = "cs_rest_enterZoneText";
|
||
|
const string CS_REST_VAR_EXIT_REST_TEXT = "cs_rest_exitZoneText";
|
||
|
const string CS_REST_VAR_UNSAFE_TEXT = "cs_rest_unsafeText";
|
||
|
const string CS_REST_VAR_ENTER_NO_REST_TEXT = "cs_rest_enterNoZoneText";
|
||
|
const string CS_REST_VAR_EXIT_NO_REST_TEXT = "cs_rest_exitNoZoneText";
|
||
|
const string CS_REST_VAR_NO_BEDROLL_TEXT = "cs_rest_noBedrollText";
|
||
|
|
||
|
// Rest rule bitmapped IDs for rule checks.
|
||
|
const int CS_REST_RULE_LAST_REST = 0x00000001;
|
||
|
const int CS_REST_RULE_DAY_ONLY = 0x00000002;
|
||
|
const int CS_REST_RULE_NIGHT_ONLY = 0x00000004;
|
||
|
const int CS_REST_RULE_NO_ARMOUR = 0x00000008;
|
||
|
const int CS_REST_RULE_NO_WEAPONS = 0x00000010;
|
||
|
const int CS_REST_RULE_NO_BEDROLL = 0x00000020;
|
||
|
const int CS_REST_RULE_RESERVED_1 = 0x00000040;
|
||
|
const int CS_REST_RULE_RESERVED_2 = 0x00000080;
|
||
|
const int CS_REST_RULE_RESERVED_3 = 0x00000100;
|
||
|
const int CS_REST_RULE_RESERVED_4 = 0x00000200;
|
||
|
const int CS_REST_RULE_RESERVED_5 = 0x00000400;
|
||
|
const int CS_REST_RULE_RESERVED_6 = 0x00000800;
|
||
|
const int CS_REST_RULE_RESERVED_7 = 0x00001000;
|
||
|
const int CS_REST_RULE_RESERVED_8 = 0x00002000;
|
||
|
const int CS_REST_RULE_RESERVED_9 = 0x00004000;
|
||
|
const int CS_REST_RULE_RESERVED_10 = 0x00008000;
|
||
|
const int CS_REST_RULE_USER_1 = 0x10000000;
|
||
|
const int CS_REST_RULE_USER_2 = 0x20000000;
|
||
|
const int CS_REST_RULE_USER_3 = 0x40000000;
|
||
|
const int CS_REST_RULE_USER_4 = 0x80000000;
|
||
|
const int CS_REST_RULE_USER_5 = 0x01000000;
|
||
|
const int CS_REST_RULE_USER_6 = 0x02000000;
|
||
|
const int CS_REST_RULE_USER_7 = 0x04000000;
|
||
|
const int CS_REST_RULE_USER_8 = 0x08000000;
|
||
|
const int CS_REST_RULE_USER_9 = 0x00100000;
|
||
|
const int CS_REST_RULE_USER_10 = 0x00200000;
|
||
|
const int CS_REST_RULE_USER_11 = 0x00400000;
|
||
|
const int CS_REST_RULE_USER_12 = 0x00800000;
|
||
|
const int CS_REST_RULE_USER_13 = 0x00010000;
|
||
|
const int CS_REST_RULE_USER_14 = 0x00020000;
|
||
|
const int CS_REST_RULE_USER_15 = 0x00040000;
|
||
|
const int CS_REST_RULE_USER_16 = 0x00080000;
|
||
|
|
||
|
// A configuration structure that tracks the operational parameters for a
|
||
|
// resting session.
|
||
|
struct cs_rest_config {
|
||
|
object debug; // The object to which debug messages are sent.
|
||
|
int permitted; // If resting is permitted for a given session.
|
||
|
int ruleFlags; // A bitmapped flag word for tracking rules.
|
||
|
int lastRestDays; // Days since start of calendar since of last rest.
|
||
|
int lastRestSeconds; // Seconds within day of last rest.
|
||
|
int savedHitPoints; // Number of HP when resting session was begin.
|
||
|
int enabled; // If this rest system is actually enabled at all.
|
||
|
int started; // If a resting session has been begun.
|
||
|
int neverPermitted; // If resting for the creature is never allowed.
|
||
|
// int allowed; // XXX Don't know. Might not be used anymore.
|
||
|
string profile; // The current profile for the player.
|
||
|
string defaultProfile; // The default profile if not otherwise set.
|
||
|
string overrideProfile; // A profile that exists only for the rest session.
|
||
|
int limit; // Number of seconds between rests.
|
||
|
int use3Ed; // Use 3rd Edition-style HP regain.
|
||
|
int noArmour; // Armour may not be equipped while resting.
|
||
|
int noWeapons; // Weapons may not be equipped while resting.
|
||
|
int useBedroll; // A bedroll must be available to rest.
|
||
|
string bedrollTag; // The tag of bedroll items.
|
||
|
float bedrollMultiplier;// A multiplier for HP regaing in bedroll resting.
|
||
|
int dayMode; // Resting may only occur during the day or night.
|
||
|
int dayStart; // The hour at which "day" starts.
|
||
|
int dayEnd; // The hour at which "day" ends.
|
||
|
object trigger; // The trigger in which the player exists.
|
||
|
float multiplier; // A multiplier for HP regain.
|
||
|
int fadeToBlack; // If the screen should fade to black while resting.
|
||
|
int noMessages; // If floating messages should be displayed.
|
||
|
int useConBonus; // If CON bonus should be added to HP regain.
|
||
|
string userScript; // Name of rule script provided by builder.
|
||
|
string effects; // A set of effect numbers to apply.
|
||
|
};
|
||
|
|
||
|
// A representation of a date and time broken down into number of days
|
||
|
// since the beginning of the calendar and a number of seconds within the
|
||
|
// current day.
|
||
|
struct cs_rest_time {
|
||
|
int days; // The number of days since the beginning of the calendar.
|
||
|
int seconds; // The number of seconds elapsed within the current day.
|
||
|
};
|
||
|
|
||
|
//============================================================================
|
||
|
//
|
||
|
// Function Prototypes and toolset IDE documentation.
|
||
|
//
|
||
|
//============================================================================
|
||
|
|
||
|
// Set the rest profile to be associated with the specified player.
|
||
|
//
|
||
|
// pc The player for whom to set the profile.
|
||
|
// profile The name of the profile to associate with the player.
|
||
|
void cs_rest_SetProfile(object pc, string profile);
|
||
|
|
||
|
// Remove any rest profile that may be associated with the specified
|
||
|
// player.
|
||
|
//
|
||
|
// pc The player from whom to remove any profile.
|
||
|
void cs_rest_DeleteProfile(object pc);
|
||
|
|
||
|
// Set the session-specific rest profile to be associated with the specified
|
||
|
// player. Session profiles are only used for the specific resting session
|
||
|
// in which they are set.
|
||
|
//
|
||
|
// pc The player for whom to set the profile.
|
||
|
// profile The name of the profile to associate with the player.
|
||
|
void cs_rest_SetOverrideProfile(object pc, string profile);
|
||
|
|
||
|
// Remove any session-specific rest profile that may be associated with the
|
||
|
// specified player. Session profiles are only used for the specific resting
|
||
|
// session in which they are set.
|
||
|
//
|
||
|
// pc The player from whom to remove any profile.
|
||
|
void cs_rest_DeleteOverrideProfile(object pc);
|
||
|
|
||
|
// Set the object that associated the rest profile with the specified player.
|
||
|
//
|
||
|
// pc The player for whom to set the triggering object.
|
||
|
// profile The triggering object.
|
||
|
void cs_rest_SetTriggeringObject(object pc, object trigger);
|
||
|
|
||
|
// Remove any triggering object that may be stored for the specified player.
|
||
|
//
|
||
|
// pc The player from whom to remove any triggering object.
|
||
|
void cs_rest_DeleteTriggeringObject(object pc);
|
||
|
|
||
|
// Set a rule flag to a specific state (i.e. TRUE or FALSE). Rule flags are
|
||
|
// used to track whether a player has satisfied a specific rule that will
|
||
|
// block resting. Resting will only be permitted if *no* rules have been
|
||
|
// satisfied and all rule flags are FALSE.
|
||
|
//
|
||
|
// cfg The current rest config for a player.
|
||
|
// rule The specific rule flag that is to be changed.
|
||
|
// value Either TRUE to set the flag or FALSE to clear it.
|
||
|
// returns The modified rest config.
|
||
|
struct cs_rest_config cs_rest_SetRuleFlag(struct cs_rest_config cfg, int rule, int value);
|
||
|
|
||
|
// Determine the state of a specific rule flag.
|
||
|
//
|
||
|
// cfg The current rest config for a player.
|
||
|
// rule The specific rule flag that is to be checked.
|
||
|
// returns TRUE if the flag is set otherwise FALSE.
|
||
|
int cs_rest_GetRuleFlag(struct cs_rest_config cfg, int rule);
|
||
|
|
||
|
// Execute the resting script associated with the rest profile that has
|
||
|
// been set for the specified player.
|
||
|
//
|
||
|
// pc The player for whom to run the script.
|
||
|
// cfg A set of configuration data for a player.
|
||
|
void cs_rest_ExecuteRestScript(object pc, struct cs_rest_config cfg);
|
||
|
|
||
|
// Return the current time as a since the beginning of the calendar.
|
||
|
//
|
||
|
// returns The current time.
|
||
|
struct cs_rest_time cs_rest_GetCurrentTime(struct cs_rest_config cfg);
|
||
|
|
||
|
// Process the configuration for the rest subsystem.
|
||
|
//
|
||
|
// pc The player for whom to process configuration.
|
||
|
// container A container object containing the configuration.
|
||
|
// cfg A set of configuration data for a player.
|
||
|
// returns The updated configuration data.
|
||
|
struct cs_rest_config cs_rest_ProcessConfig(object pc, object container, struct cs_rest_config cfg);
|
||
|
|
||
|
// Search for and compile together all of the configuration that applies to
|
||
|
// a specific player.
|
||
|
//
|
||
|
// pc The player for whom to search for configuration.
|
||
|
// returns The player's resting configuration
|
||
|
struct cs_rest_config cs_rest_RetrieveConfig(object pc);
|
||
|
|
||
|
// Read any messages that exist as variables on the specified item and set
|
||
|
// them to be used for the specified player's rest session.
|
||
|
//
|
||
|
// pc The player for whom to change messages.
|
||
|
// cfg The player's resting configuration.
|
||
|
// item The item containing message text variables.
|
||
|
void cs_rest_UpdateMessages(object pc, struct cs_rest_config cfg, object item);
|
||
|
|
||
|
// Display a floating text message on a player from those messages defined
|
||
|
// by the rest system. If floaty messages are disabled for the resting zone
|
||
|
// in which this function is invoked (i.e. cfg.noMessage is TRUE), no
|
||
|
// messages will be displayed.
|
||
|
//
|
||
|
// pc The player on whom to display the message.
|
||
|
// cfg The player's resting configuration.
|
||
|
// id The ID of the message to be displayed. This value may be one
|
||
|
// of the following constants:
|
||
|
// CS_REST_TXT_START
|
||
|
// CS_REST_TXT_FINISH
|
||
|
// CS_REST_TXT_CANCEL
|
||
|
// CS_REST_TXT_CANNOT
|
||
|
// CS_REST_TXT_TOO_SOON
|
||
|
// CS_REST_TXT_DAY_ONLY
|
||
|
// CS_REST_TXT_NIGHT_ONLY
|
||
|
// CS_REST_TXT_NO_ARMOUR
|
||
|
// CS_REST_TXT_NO_WEAPON
|
||
|
// CS_REST_TXT_BEDROLL_RUINED
|
||
|
// CS_REST_TXT_NOT_COMFORTABLE
|
||
|
// CS_REST_TXT_ENTER_REST_ZONE
|
||
|
// CS_REST_TXT_EXIT_REST_ZONE
|
||
|
// CS_REST_TXT_UNSAFE
|
||
|
// CS_REST_TXT_ENTER_NO_REST_ZONE
|
||
|
// CS_REST_TXT_EXIT_NO_REST_ZONE
|
||
|
// CS_REST_TXT_NO_BEDROLL
|
||
|
void cs_rest_ShowFloatingTextByID(object pc, struct cs_rest_config cfg, int id);
|
||
|
|
||
|
// Retrieve rest configuration from an object.
|
||
|
//
|
||
|
// returns The configuration data found.
|
||
|
struct cs_rest_config cs_rest_GetConfig(object container);
|
||
|
|
||
|
// Set current rest configuration on an object.
|
||
|
//
|
||
|
// container The object on which to set the config.
|
||
|
// cfg A set of configuration data.
|
||
|
void cs_rest_SetConfig(object container, struct cs_rest_config cfg);
|
||
|
|
||
|
// Delete rest configuration from an object.
|
||
|
//
|
||
|
// container The object from which to delete the configuration data.
|
||
|
void cs_rest_DeleteConfig(object container);
|
||
|
|
||
|
// Generate a string containing the data needed to restore the resting
|
||
|
// state of a player in the event of a system failure, or after a player
|
||
|
// logs out. This function should be called periodically while a server
|
||
|
// is running, if persistent state is being stored in such a fashion, or
|
||
|
// whenever a player logs out.
|
||
|
//
|
||
|
// NOTE: This function is not needed for the normal operation of the
|
||
|
// resting subsystem and should be used only for integration into modules
|
||
|
// that run as persistent worlds.
|
||
|
//
|
||
|
// pc The object from which to retrieve the config.
|
||
|
// returns The persistence state in string form.
|
||
|
string cs_rest_GetState(object container);
|
||
|
|
||
|
// Set the resting state for a player from a previous call to the
|
||
|
// cs_rest_GetState() function. This function should be called when
|
||
|
// a player logs into a server running as a persistent module.
|
||
|
//
|
||
|
// NOTE: This function is not needed for the normal operation of the
|
||
|
// resting subsystem and should be used only for integration into modules
|
||
|
// that run as persistent worlds.
|
||
|
//
|
||
|
// pc The object on which to set the config.
|
||
|
// state A string containing state information.
|
||
|
// timeOffset The amount of time in seconds by which the time values
|
||
|
// in the resting state should be adjusted. Adjusting the
|
||
|
// time will usually be unnecessary.
|
||
|
void cs_rest_SetState(object container, string state, int timeOffset=0);
|
||
|
|
||
|
// Set the user hook script state for a resting session.
|
||
|
//
|
||
|
// pc The player who is resting.
|
||
|
// state The state for the hook script. This should be one of the
|
||
|
// following constants:
|
||
|
// CS_REST_START_RESTING
|
||
|
// CS_REST_STOP_RESTING
|
||
|
// CS_REST_CANCEL_RESTING
|
||
|
// CS_REST_RULE_CHECK
|
||
|
void cs_rest_SetUserScriptState(object pc, int state);
|
||
|
|
||
|
// Determine the resting state for which the user hook script has been
|
||
|
// executed.
|
||
|
//
|
||
|
// pc The player who is resting. If not specified, this defaults
|
||
|
// to the current object.
|
||
|
// returns The script hook state. This will be one of the following
|
||
|
// constants:
|
||
|
// CS_REST_START_RESTING
|
||
|
// CS_REST_STOP_RESTING
|
||
|
// CS_REST_CANCEL_RESTING
|
||
|
// CS_REST_RULE_CHECK
|
||
|
int cs_rest_GetUserScriptState(object pc=OBJECT_SELF);
|
||
|
|
||
|
// Delete the user script state variable from the specified player.
|
||
|
//
|
||
|
// pc The player from which the variable is to be deleted.
|
||
|
void cs_rest_DeleteUserScriptState(object pc);
|
||
|
|
||
|
// Determine whether a specific rest rule has been enabled in the resting
|
||
|
// system configuration. Though the user rules can be checked with this
|
||
|
// function, they are always enabled.
|
||
|
//
|
||
|
// This function may only be used within the CS_REST_RULE_CHECK execution
|
||
|
// point for a user script.
|
||
|
//
|
||
|
// rule The specific rest rule that is to be checked. This value
|
||
|
// must be one of the following constants:
|
||
|
// CS_REST_RULE_LAST_REST
|
||
|
// CS_REST_RULE_DAY_ONLY
|
||
|
// CS_REST_RULE_NIGHT_ONLY
|
||
|
// CS_REST_RULE_NO_ARMOUR
|
||
|
// CS_REST_RULE_NO_WEAPONS
|
||
|
// CS_REST_RULE_NO_BEDROLL
|
||
|
// CS_REST_RULE_USER_1
|
||
|
// CS_REST_RULE_USER_2
|
||
|
// CS_REST_RULE_USER_3
|
||
|
// CS_REST_RULE_USER_4
|
||
|
// CS_REST_RULE_USER_5
|
||
|
// CS_REST_RULE_USER_6
|
||
|
// CS_REST_RULE_USER_7
|
||
|
// CS_REST_RULE_USER_8
|
||
|
// CS_REST_RULE_USER_9
|
||
|
// CS_REST_RULE_USER_10
|
||
|
// CS_REST_RULE_USER_11
|
||
|
// CS_REST_RULE_USER_12
|
||
|
// CS_REST_RULE_USER_13
|
||
|
// CS_REST_RULE_USER_14
|
||
|
// CS_REST_RULE_USER_15
|
||
|
// CS_REST_RULE_USER_16
|
||
|
// state TRUE if the rule is enabled, which means the rest subsystem
|
||
|
// will evaluate the rule when determining whether a player is
|
||
|
// allowed to rest, otherwise FALSE.
|
||
|
// pc The player who is resting. This value will default to the
|
||
|
// current object, which will always be the resting player when
|
||
|
// this function is called from a user script.
|
||
|
// returns TRUE if the specified rule has been enabled in the rest
|
||
|
// subsystem configuration, or FALSE if the rule is not enabled.
|
||
|
int cs_rest_GetIsRuleEnabled(int rule, object pc=OBJECT_SELF);
|
||
|
|
||
|
// Determine the current state of a specific rest rule, either a builtin rule
|
||
|
// or a user rule. The builtin rules are evaluated before the user script is
|
||
|
// executed. User rules are provided specifically for use by builders, will
|
||
|
// always be FALSE initially, and will never be changed by the rest subsystem.
|
||
|
//
|
||
|
// This function may only be used within the CS_REST_RULE_CHECK execution
|
||
|
// point for a user script.
|
||
|
//
|
||
|
// rule The specific rest rule that is to be checked. This value
|
||
|
// must be one of the following constants:
|
||
|
// CS_REST_RULE_LAST_REST
|
||
|
// CS_REST_RULE_DAY_ONLY
|
||
|
// CS_REST_RULE_NIGHT_ONLY
|
||
|
// CS_REST_RULE_NO_ARMOUR
|
||
|
// CS_REST_RULE_NO_WEAPONS
|
||
|
// CS_REST_RULE_NO_BEDROLL
|
||
|
// CS_REST_RULE_USER_1
|
||
|
// CS_REST_RULE_USER_2
|
||
|
// CS_REST_RULE_USER_3
|
||
|
// CS_REST_RULE_USER_4
|
||
|
// CS_REST_RULE_USER_5
|
||
|
// CS_REST_RULE_USER_6
|
||
|
// CS_REST_RULE_USER_7
|
||
|
// CS_REST_RULE_USER_8
|
||
|
// CS_REST_RULE_USER_9
|
||
|
// CS_REST_RULE_USER_10
|
||
|
// CS_REST_RULE_USER_11
|
||
|
// CS_REST_RULE_USER_12
|
||
|
// CS_REST_RULE_USER_13
|
||
|
// CS_REST_RULE_USER_14
|
||
|
// CS_REST_RULE_USER_15
|
||
|
// CS_REST_RULE_USER_16
|
||
|
// pc The player who is resting. This value will default to the
|
||
|
// current object, which will always be the resting player when
|
||
|
// this function is called from a user script.
|
||
|
// returns TRUE if the rule has been evaluated and the player does not
|
||
|
// satisfy it (which will prevent the player from resting),
|
||
|
// otherwise FALSE (which will allow the player to rest).
|
||
|
int cs_rest_GetRule(int rule, object pc=OBJECT_SELF);
|
||
|
|
||
|
// Set or clear the specified rule for a resting player. When the rule is
|
||
|
// set, i.e. the state is TRUE, the player will not be permitted to rest.
|
||
|
// If any rule at all is set to TRUE, the player will be prevented from
|
||
|
// resting. This function may be used to change the state of one of the
|
||
|
// builtin rest rules, or a user rule. User rules are provided specifically
|
||
|
// for use by builders.
|
||
|
//
|
||
|
// If a builtin rest rule is not enabled in the configuration for the resting
|
||
|
// subsystem, then changing the state of that rule will have no effect. The
|
||
|
// user rules are always considered enabled.
|
||
|
//
|
||
|
// This function may only be used within the CS_REST_RULE_CHECK execution
|
||
|
// point for a user script.
|
||
|
//
|
||
|
// rule The specific rest rule that is to be changed. This value
|
||
|
// must be one of the following constants:
|
||
|
// CS_REST_RULE_LAST_REST
|
||
|
// CS_REST_RULE_DAY_ONLY
|
||
|
// CS_REST_RULE_NIGHT_ONLY
|
||
|
// CS_REST_RULE_NO_ARMOUR
|
||
|
// CS_REST_RULE_NO_WEAPONS
|
||
|
// CS_REST_RULE_NO_BEDROLL
|
||
|
// CS_REST_RULE_USER_1
|
||
|
// CS_REST_RULE_USER_2
|
||
|
// CS_REST_RULE_USER_3
|
||
|
// CS_REST_RULE_USER_4
|
||
|
// CS_REST_RULE_USER_5
|
||
|
// CS_REST_RULE_USER_6
|
||
|
// CS_REST_RULE_USER_7
|
||
|
// CS_REST_RULE_USER_8
|
||
|
// CS_REST_RULE_USER_9
|
||
|
// CS_REST_RULE_USER_10
|
||
|
// CS_REST_RULE_USER_11
|
||
|
// CS_REST_RULE_USER_12
|
||
|
// CS_REST_RULE_USER_13
|
||
|
// CS_REST_RULE_USER_14
|
||
|
// CS_REST_RULE_USER_15
|
||
|
// CS_REST_RULE_USER_16
|
||
|
// state TRUE if the rule is to be set, which will disallow resting,
|
||
|
// otherwise FALSE to allow resting.
|
||
|
// pc The player who is resting. This value will default to the
|
||
|
// current object, which will always be the resting player when
|
||
|
// this function is called from a user script.
|
||
|
void cs_rest_SetRule(int rule, int state, object pc=OBJECT_SELF);
|
||
|
|
||
|
// Abort resting for a specific player even if that player has satisfied all
|
||
|
// enabled rest rules.
|
||
|
//
|
||
|
// This function may only be used within the CS_REST_START_RESTING execution
|
||
|
// point for a user script.
|
||
|
//
|
||
|
// pc The player who is resting. This value will default to the
|
||
|
// current object, which will always be the resting player when
|
||
|
// this function is called from a user script.
|
||
|
void cs_rest_SetAbort(object pc=OBJECT_SELF);
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Double integer precision date arithmetic support.
|
||
|
const int cs_rest_secondsPerMinute = 60;
|
||
|
int cs_rest_secondsPerHour = FloatToInt(HoursToSeconds(1));
|
||
|
const int cs_rest_hoursPerDay = 24;
|
||
|
int cs_rest_secondsPerDay = cs_rest_hoursPerDay * cs_rest_secondsPerHour;
|
||
|
const int cs_rest_daysPerMonth = 28;
|
||
|
const int cs_rest_daysPerYear = 336;
|
||
|
struct cs_rest_time cs_rest_GetCurrentTime(struct cs_rest_config cfg) {
|
||
|
struct cs_rest_time time;
|
||
|
time.days = GetCalendarYear() * cs_rest_daysPerYear;
|
||
|
time.days += GetCalendarMonth() * cs_rest_daysPerMonth;
|
||
|
time.days += GetCalendarDay();
|
||
|
time.seconds = GetTimeHour() * cs_rest_secondsPerHour;
|
||
|
time.seconds += GetTimeMinute() * cs_rest_secondsPerMinute;
|
||
|
time.seconds += GetTimeSecond();
|
||
|
return time;
|
||
|
}
|
||
|
|
||
|
// Add b to a.
|
||
|
struct cs_rest_time cs_rest_AddTime(struct cs_rest_time a, struct cs_rest_time b) {
|
||
|
a.seconds += b.seconds;
|
||
|
if (a.seconds >= cs_rest_secondsPerDay) {
|
||
|
a.seconds -= cs_rest_secondsPerDay;
|
||
|
a.days++;
|
||
|
}
|
||
|
a.days += b.days;
|
||
|
return a;
|
||
|
}
|
||
|
|
||
|
// Subtract b from a.
|
||
|
struct cs_rest_time cs_rest_SubtractTime(struct cs_rest_time a, struct cs_rest_time b) {
|
||
|
a.seconds -= b.seconds;
|
||
|
if (a.seconds < 0) {
|
||
|
a.seconds += cs_rest_secondsPerDay;
|
||
|
a.days--;
|
||
|
}
|
||
|
a.days -= b.days;
|
||
|
return a;
|
||
|
}
|
||
|
|
||
|
// Determine if a is greater than b.
|
||
|
int cs_rest_GetIsTimeGreater(struct cs_rest_time a, struct cs_rest_time b) {
|
||
|
if (a.days > b.days) return TRUE;
|
||
|
if (a.days < b.days) return FALSE;
|
||
|
if (a.seconds > b.seconds) return TRUE;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Determine if a is less than b.
|
||
|
int cs_rest_GetIsTimeLess(struct cs_rest_time a, struct cs_rest_time b) {
|
||
|
if (a.days < b.days) return TRUE;
|
||
|
if (a.days > b.days) return FALSE;
|
||
|
if (a.seconds < b.seconds) return TRUE;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Determine whether a equals b.
|
||
|
int cs_rest_GetIsTimeEqual(struct cs_rest_time a, struct cs_rest_time b) {
|
||
|
if ((a.days == b.days) && (a.seconds == b.seconds)) return TRUE;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Convert a time to a string representation.
|
||
|
string cs_rest_TimeToString(struct cs_rest_time time) {
|
||
|
return IntToString(time.days) + "." + IntToString(time.seconds);
|
||
|
}
|
||
|
|
||
|
// Construct a time value from individual values.
|
||
|
struct cs_rest_time cs_rest_Time(int days, int seconds) {
|
||
|
struct cs_rest_time time;
|
||
|
time.days = days;
|
||
|
time.seconds = seconds;
|
||
|
return time;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_ShowConfig(struct cs_rest_config cfg) {
|
||
|
if (cs_dbg_GetIsEnabled() || GetIsObjectValid(cfg.debug)) {
|
||
|
// Data generated within the rest system.
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.permitted: " + IntToString(cfg.permitted),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.ruleFlags: " + IntToString(cfg.ruleFlags),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.started: " + IntToString(cfg.started),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.savedHitPoints: " + IntToString(cfg.savedHitPoints),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.profile: " + cfg.profile,
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.overrideProfile: " + cfg.overrideProfile,
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.trigger: " + GetName(cfg.trigger),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.lastRest: " +
|
||
|
cs_rest_TimeToString(cs_rest_Time(cfg.lastRestDays, cfg.lastRestSeconds)),
|
||
|
cfg.debug
|
||
|
);
|
||
|
|
||
|
// Configuration data.
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.debug: " + ObjectToString(cfg.debug),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.enabled: " + IntToString(cfg.enabled),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.neverPermitted: " + IntToString(cfg.neverPermitted),
|
||
|
cfg.debug
|
||
|
);
|
||
|
// cs_dbg_Trace(
|
||
|
// "cfg.allowed: " + IntToString(cfg.allowed),
|
||
|
// cfg.debug
|
||
|
// );
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.defaultProfile: " + cfg.defaultProfile,
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.limit: " + IntToString(cfg.limit),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.use3Ed: " + IntToString(cfg.use3Ed),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.noArmour: " + IntToString(cfg.noArmour),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.noWeapons: " + IntToString(cfg.noWeapons),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.useBedroll: " + IntToString(cfg.useBedroll),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.bedrollTag: " + cfg.bedrollTag,
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.bedrollMultiplier: " + FloatToString(cfg.bedrollMultiplier),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.dayMode: " + IntToString(cfg.dayMode),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.dayStart: " + IntToString(cfg.dayStart),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.dayEnd: " + IntToString(cfg.dayEnd),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.multiplier: " + FloatToString(cfg.multiplier),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.fadeToBlack: " + IntToString(cfg.fadeToBlack),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.noMessages: " + IntToString(cfg.noMessages),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.useConBonus: " + IntToString(cfg.useConBonus),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.userScript: " + cfg.userScript,
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cfg.effects: " + cfg.effects,
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
struct cs_rest_config cs_rest_GetConfig(object container) {
|
||
|
struct cs_rest_config cfg;
|
||
|
cfg.debug = GetLocalObject(container, CS_REST_VAR_DEBUG);
|
||
|
|
||
|
cs_dbg_Enter("cs_rest_GetConfig(" + GetName(container) + ")", cfg.debug);
|
||
|
|
||
|
// Data generated within the rest system.
|
||
|
cfg.permitted = GetLocalInt(container, CS_REST_VAR_PERMITTED);
|
||
|
cfg.ruleFlags = GetLocalInt(container, CS_REST_VAR_RULE_FLAGS);
|
||
|
cfg.started = GetLocalInt(container, CS_REST_VAR_STARTED);
|
||
|
cfg.savedHitPoints = GetLocalInt(container, CS_REST_VAR_SAVE_HP);
|
||
|
cfg.profile = GetLocalString(container, CS_REST_VAR_PLAYER_PROFILE);
|
||
|
cfg.overrideProfile = GetLocalString(container, CS_REST_VAR_OVERRIDE_PROFILE);
|
||
|
cfg.trigger = GetLocalObject(container, CS_REST_VAR_TRIGGER);
|
||
|
cfg.lastRestDays = GetLocalInt(container, CS_REST_VAR_LAST_REST_DAYS);
|
||
|
cfg.lastRestSeconds = GetLocalInt(container, CS_REST_VAR_LAST_REST_SECONDS);
|
||
|
|
||
|
// Configuration data.
|
||
|
cfg.enabled = GetLocalInt(container, CS_REST_VAR_ENABLE);
|
||
|
cfg.neverPermitted = GetLocalInt(container, CS_REST_VAR_NEVER_PERMITTED);
|
||
|
// cfg.allowed = GetLocalInt(container, CS_REST_VAR_PLAYER_ALLOWED);
|
||
|
cfg.defaultProfile = GetLocalString(container, CS_REST_VAR_DEFAULT_PROFILE);
|
||
|
cfg.limit = GetLocalInt(container, CS_REST_VAR_TIME_LIMIT);
|
||
|
cfg.use3Ed = GetLocalInt(container, CS_REST_VAR_HP_3ED);
|
||
|
cfg.noArmour = GetLocalInt(container, CS_REST_VAR_NO_ARMOUR);
|
||
|
cfg.noWeapons = GetLocalInt(container, CS_REST_VAR_NO_WEAPONS);
|
||
|
cfg.useBedroll = GetLocalInt(container, CS_REST_VAR_BEDROLL_IN_USE);
|
||
|
cfg.bedrollTag = GetLocalString(container, CS_REST_VAR_BEDROLL_TAG);
|
||
|
cfg.bedrollMultiplier = GetLocalFloat(container, CS_REST_VAR_BEDROLL_MULTIPLIER);
|
||
|
cfg.dayMode = GetLocalInt(container, CS_REST_VAR_DAY_MODE);
|
||
|
cfg.dayStart = GetLocalInt(container, CS_REST_VAR_DAY_START);
|
||
|
cfg.dayEnd = GetLocalInt(container, CS_REST_VAR_DAY_END);
|
||
|
cfg.multiplier = GetLocalFloat(container, CS_REST_VAR_MULTIPLIER);
|
||
|
cfg.fadeToBlack = GetLocalInt(container, CS_REST_VAR_FADE_TO_BLACK);
|
||
|
cfg.noMessages = GetLocalInt(container, CS_REST_VAR_NO_MESSAGES);
|
||
|
cfg.useConBonus = GetLocalInt(container, CS_REST_VAR_CON_BONUS);
|
||
|
cfg.userScript = GetLocalString(container, CS_REST_VAR_USER_SCRIPT);
|
||
|
cfg.effects = GetLocalString(container, CS_REST_VAR_EFFECTS);
|
||
|
if (cfg.bedrollMultiplier < 0.0f) {
|
||
|
cfg.bedrollMultiplier = 0.5f;
|
||
|
}
|
||
|
if (cfg.multiplier <= 0.0f) {
|
||
|
cfg.multiplier = 1.0f;
|
||
|
}
|
||
|
|
||
|
cs_rest_ShowConfig(cfg);
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_GetConfig", cfg.debug);
|
||
|
return cfg;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_SetConfig(object container, struct cs_rest_config cfg) {
|
||
|
cs_dbg_Enter("cs_rest_SetConfig(" + GetName(container) + ")", cfg.debug);
|
||
|
|
||
|
cs_rest_ShowConfig(cfg);
|
||
|
|
||
|
if (cfg.bedrollMultiplier < 0.0f) {
|
||
|
cfg.bedrollMultiplier = 0.5f;
|
||
|
}
|
||
|
if (cfg.multiplier <= 0.0f) {
|
||
|
cfg.multiplier = 1.0f;
|
||
|
}
|
||
|
|
||
|
// Data generated within the rest system.
|
||
|
SetLocalInt(container, CS_REST_VAR_PERMITTED, cfg.permitted);
|
||
|
SetLocalInt(container, CS_REST_VAR_RULE_FLAGS, cfg.ruleFlags);
|
||
|
SetLocalInt(container, CS_REST_VAR_STARTED, cfg.started);
|
||
|
SetLocalInt(container, CS_REST_VAR_SAVE_HP, cfg.savedHitPoints);
|
||
|
SetLocalString(container, CS_REST_VAR_PLAYER_PROFILE, cfg.profile);
|
||
|
SetLocalString(container, CS_REST_VAR_OVERRIDE_PROFILE, cfg.overrideProfile);
|
||
|
SetLocalObject(container, CS_REST_VAR_TRIGGER, cfg.trigger);
|
||
|
SetLocalInt(container, CS_REST_VAR_LAST_REST_DAYS, cfg.lastRestDays);
|
||
|
SetLocalInt(container, CS_REST_VAR_LAST_REST_SECONDS, cfg.lastRestSeconds);
|
||
|
|
||
|
// Configuration data.
|
||
|
SetLocalObject(container, CS_REST_VAR_DEBUG, cfg.debug);
|
||
|
SetLocalInt(container, CS_REST_VAR_ENABLE, cfg.enabled);
|
||
|
SetLocalInt(container, CS_REST_VAR_NEVER_PERMITTED, cfg.neverPermitted);
|
||
|
// SetLocalInt(container, CS_REST_VAR_PLAYER_ALLOWED, cfg.allowed);
|
||
|
SetLocalString(container, CS_REST_VAR_DEFAULT_PROFILE, cfg.defaultProfile);
|
||
|
SetLocalInt(container, CS_REST_VAR_TIME_LIMIT, cfg.limit);
|
||
|
SetLocalInt(container, CS_REST_VAR_HP_3ED, cfg.use3Ed);
|
||
|
SetLocalInt(container, CS_REST_VAR_NO_ARMOUR, cfg.noArmour);
|
||
|
SetLocalInt(container, CS_REST_VAR_NO_WEAPONS, cfg.noWeapons);
|
||
|
SetLocalInt(container, CS_REST_VAR_BEDROLL_IN_USE, cfg.useBedroll);
|
||
|
SetLocalString(container, CS_REST_VAR_BEDROLL_TAG, cfg.bedrollTag);
|
||
|
SetLocalFloat(container, CS_REST_VAR_BEDROLL_MULTIPLIER, cfg.bedrollMultiplier);
|
||
|
SetLocalInt(container, CS_REST_VAR_DAY_MODE, cfg.dayMode);
|
||
|
SetLocalInt(container, CS_REST_VAR_DAY_START, cfg.dayStart);
|
||
|
SetLocalInt(container, CS_REST_VAR_DAY_END, cfg.dayEnd);
|
||
|
SetLocalFloat(container, CS_REST_VAR_MULTIPLIER, cfg.multiplier);
|
||
|
SetLocalInt(container, CS_REST_VAR_FADE_TO_BLACK, cfg.fadeToBlack);
|
||
|
SetLocalInt(container, CS_REST_VAR_NO_MESSAGES, cfg.noMessages);
|
||
|
SetLocalInt(container, CS_REST_VAR_CON_BONUS, cfg.useConBonus);
|
||
|
SetLocalString(container, CS_REST_VAR_USER_SCRIPT, cfg.userScript);
|
||
|
SetLocalString(container, CS_REST_VAR_EFFECTS, cfg.effects);
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_SetConfig", cfg.debug);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_DeleteConfig(object container) {
|
||
|
object debug = GetLocalObject(container, CS_REST_VAR_DEBUG);
|
||
|
|
||
|
cs_dbg_Enter("cs_rest_DeleteConfig(" + GetName(container) + ")", debug);
|
||
|
|
||
|
// Data generated within the rest system and used only when a player is
|
||
|
// actually resting. It is not necessary to store this data within a
|
||
|
// persistence mechanism since should either a player log out or the
|
||
|
// server crash, the player won't be resting anymore and so this data
|
||
|
// will be superfluous.
|
||
|
DeleteLocalInt(container, CS_REST_VAR_PERMITTED);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_RULE_FLAGS);
|
||
|
DeleteLocalString(container, CS_REST_VAR_OVERRIDE_PROFILE);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_STARTED);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_SAVE_HP);
|
||
|
|
||
|
// These variables are used by the resting system to track the current
|
||
|
// state of the player with regard to resting policies, however since
|
||
|
// the values are set through trigger scripts, it is not necessary to
|
||
|
// store the data in a persistence mechanism as it will simply be
|
||
|
// recreated when the player logs in again and reenters the trigger.
|
||
|
// The following variables are deleted elsewhere and are listed
|
||
|
// here merely for completion. These deletions should not be
|
||
|
// uncommented.
|
||
|
// DeleteLocalString(container, CS_REST_VAR_PLAYER_PROFILE);
|
||
|
// DeleteLocalObject(container, CS_REST_VAR_TRIGGER);
|
||
|
|
||
|
// These variables are maintained across rests and constitute the
|
||
|
// persistent data within the resting subsystem. Should full persistence
|
||
|
// be desired, this data should be stored for each player and restored
|
||
|
// to each player when they log in. The following variables are deleted
|
||
|
// elsewhere if necessary and are listed here merely for completion.
|
||
|
// These deletions should not be uncommented.
|
||
|
// DeleteLocalInt(container, CS_REST_VAR_LAST_REST_DAYS);
|
||
|
// DeleteLocalInt(container, CS_REST_VAR_LAST_REST_SECONDS);
|
||
|
|
||
|
// Configuration data. This data is generated from the configuration
|
||
|
// containers each time a player rests and so it is not necessary for
|
||
|
// any of this data to be stored in a persistence mechanism.
|
||
|
DeleteLocalObject(container, CS_REST_VAR_DEBUG);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_ENABLE);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_NEVER_PERMITTED);
|
||
|
// DeleteLocalInt(container, CS_REST_VAR_PLAYER_ALLOWED);
|
||
|
DeleteLocalString(container, CS_REST_VAR_DEFAULT_PROFILE);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_TIME_LIMIT);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_HP_3ED);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_NO_ARMOUR);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_NO_WEAPONS);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_BEDROLL_IN_USE);
|
||
|
DeleteLocalString(container, CS_REST_VAR_BEDROLL_TAG);
|
||
|
DeleteLocalFloat(container, CS_REST_VAR_BEDROLL_MULTIPLIER);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_DAY_MODE);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_DAY_START);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_DAY_END);
|
||
|
DeleteLocalFloat(container, CS_REST_VAR_MULTIPLIER);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_FADE_TO_BLACK);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_NO_MESSAGES);
|
||
|
DeleteLocalInt(container, CS_REST_VAR_CON_BONUS);
|
||
|
DeleteLocalString(container, CS_REST_VAR_USER_SCRIPT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_EFFECTS);
|
||
|
|
||
|
// Custom text messages.
|
||
|
DeleteLocalString(container, CS_REST_VAR_START_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_FINISH_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_CANCEL_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_CANNOT_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_TOO_SOON_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_DAY_ONLY_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_NIGHT_ONLY_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_NO_ARMOUR_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_NO_WEAPON_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_BEDROLL_RUINED_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_NOT_COMFORTABLE_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_ENTER_REST_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_EXIT_REST_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_UNSAFE_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_ENTER_NO_REST_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_EXIT_NO_REST_TEXT);
|
||
|
DeleteLocalString(container, CS_REST_VAR_NO_BEDROLL_TEXT);
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_DeleteConfig", debug);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
string cs_rest_GetProfile(object pc) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
string profile = GetLocalString(pc, CS_REST_VAR_PLAYER_PROFILE);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetProfile(" + GetName(pc) + "): " + profile,
|
||
|
debug
|
||
|
);
|
||
|
return profile;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_SetProfile(object pc, string profile) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_SetProfile(" + GetName(pc) + "): " + profile,
|
||
|
debug
|
||
|
);
|
||
|
SetLocalString(pc, CS_REST_VAR_PLAYER_PROFILE, profile);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
string cs_rest_GetOverrideProfile(object pc) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
string profile = GetLocalString(pc, CS_REST_VAR_OVERRIDE_PROFILE);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetOverrideProfile(" + GetName(pc) + "): " + profile,
|
||
|
debug
|
||
|
);
|
||
|
return profile;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_SetOverrideProfile(object pc, string profile) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_SetOverrideProfile(" + GetName(pc) + "): " + profile,
|
||
|
debug
|
||
|
);
|
||
|
SetLocalString(pc, CS_REST_VAR_OVERRIDE_PROFILE, profile);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_DeleteProfile(object pc) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_DeleteProfile(" + GetName(pc) + ")",
|
||
|
debug
|
||
|
);
|
||
|
DeleteLocalString(pc, CS_REST_VAR_PLAYER_PROFILE);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_SetUserScriptState(object pc, int state) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_SetUserScriptState(" + GetName(pc) + ", " + IntToString(state) + ")",
|
||
|
debug
|
||
|
);
|
||
|
SetLocalInt(pc, CS_REST_VAR_USER_SCRIPT_STATE, state);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int cs_rest_GetUserScriptState(object pc=OBJECT_SELF) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
int state = GetLocalInt(pc, CS_REST_VAR_USER_SCRIPT_STATE);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetUserScriptState(" + GetName(pc) + "): " + IntToString(state),
|
||
|
debug
|
||
|
);
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_DeleteUserScriptState(object pc) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_DeleteUserScriptState(" + GetName(pc) + ")",
|
||
|
debug
|
||
|
);
|
||
|
DeleteLocalString(pc, CS_REST_VAR_USER_SCRIPT_STATE);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int cs_rest_GetIsRuleEnabled(int rule, object pc=OBJECT_SELF) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
int state = TRUE;
|
||
|
switch(rule) {
|
||
|
case CS_REST_RULE_LAST_REST:
|
||
|
state = (GetLocalInt(pc, CS_REST_VAR_TIME_LIMIT) > 0);
|
||
|
break;
|
||
|
case CS_REST_RULE_DAY_ONLY:
|
||
|
state = (GetLocalInt(pc, CS_REST_VAR_DAY_MODE) == CS_REST_DAY_ONLY);
|
||
|
break;
|
||
|
case CS_REST_RULE_NIGHT_ONLY:
|
||
|
state = (GetLocalInt(pc, CS_REST_VAR_DAY_MODE) == CS_REST_NIGHT_ONLY);
|
||
|
break;
|
||
|
case CS_REST_RULE_NO_ARMOUR:
|
||
|
state = GetLocalInt(pc, CS_REST_VAR_NO_ARMOUR);
|
||
|
break;
|
||
|
case CS_REST_RULE_NO_WEAPONS:
|
||
|
state = GetLocalInt(pc, CS_REST_VAR_NO_WEAPONS);
|
||
|
break;
|
||
|
case CS_REST_RULE_NO_BEDROLL:
|
||
|
state = GetLocalInt(pc, CS_REST_VAR_BEDROLL_IN_USE);
|
||
|
break;
|
||
|
}
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetIsRuleEnabled(" +
|
||
|
IntToString(rule) + ", " +
|
||
|
GetName(pc) + "): " +
|
||
|
IntToString(state),
|
||
|
debug
|
||
|
);
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int cs_rest_GetRule(int rule, object pc=OBJECT_SELF) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
int flags = GetLocalInt(pc, CS_REST_VAR_RULE_FLAGS);
|
||
|
int state = flags & rule;
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetRule(" +
|
||
|
IntToString(rule) + ", " +
|
||
|
GetName(pc) + "): " +
|
||
|
IntToString(state),
|
||
|
debug
|
||
|
);
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_SetRule(int rule, int state, object pc=OBJECT_SELF) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Enter(
|
||
|
"cs_rest_SetRule(" +
|
||
|
IntToString(rule) + ", " +
|
||
|
IntToString(state) + ", " +
|
||
|
GetName(pc) + ")",
|
||
|
debug
|
||
|
);
|
||
|
if (cs_rest_GetIsRuleEnabled(rule, pc)) {
|
||
|
int flags = GetLocalInt(pc, CS_REST_VAR_RULE_FLAGS);
|
||
|
cs_dbg_Trace("flags before: " + IntToHexString(flags));
|
||
|
if (state) {
|
||
|
// We want to set the flag.
|
||
|
flags |= rule;
|
||
|
}
|
||
|
else {
|
||
|
// We want to clear the flag.
|
||
|
flags &= ~rule;
|
||
|
}
|
||
|
cs_dbg_Trace("flags after: " + IntToHexString(flags));
|
||
|
SetLocalInt(pc, CS_REST_VAR_RULE_FLAGS, flags);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace("disabled rule");
|
||
|
}
|
||
|
cs_dbg_Exit("cs_rest_SetRule", debug);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_SetAbort(object pc=OBJECT_SELF) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_SetAbort(" +
|
||
|
GetName(pc) + ")",
|
||
|
debug
|
||
|
);
|
||
|
SetLocalInt(pc, CS_REST_VAR_PERMITTED, FALSE);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
struct cs_rest_time cs_rest_GetLastRestTime(object pc) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
struct cs_rest_time time = cs_rest_Time(
|
||
|
GetLocalInt(pc, CS_REST_VAR_LAST_REST_DAYS),
|
||
|
GetLocalInt(pc, CS_REST_VAR_LAST_REST_SECONDS)
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetLastRestTime(" + GetName(pc) + "): " +
|
||
|
cs_rest_TimeToString(time),
|
||
|
debug
|
||
|
);
|
||
|
return time;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_SetLastRestTime(object pc, struct cs_rest_time time) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_SetLastRestTime(" + GetName(pc) + "): " +
|
||
|
cs_rest_TimeToString(time),
|
||
|
debug
|
||
|
);
|
||
|
SetLocalInt(pc, CS_REST_VAR_LAST_REST_DAYS, time.days);
|
||
|
SetLocalInt(pc, CS_REST_VAR_LAST_REST_SECONDS, time.seconds);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
object cs_rest_GetTriggeringObject(object pc) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
object trigger = GetLocalObject(pc, CS_REST_VAR_TRIGGER);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetTriggeringObject(" + GetName(pc) + "): " +
|
||
|
GetName(trigger),
|
||
|
debug
|
||
|
);
|
||
|
return trigger;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_SetTriggeringObject(object pc, object trigger) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_SetTriggeringObject(" + GetName(pc) + "): " +
|
||
|
GetName(trigger),
|
||
|
debug
|
||
|
);
|
||
|
SetLocalObject(pc, CS_REST_VAR_TRIGGER, trigger);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_DeleteTriggeringObject(object pc) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_DeleteTriggeringObject(" + GetName(pc) + ")",
|
||
|
debug
|
||
|
);
|
||
|
DeleteLocalObject(pc, CS_REST_VAR_TRIGGER);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
string cs_rest_GetState(object pc) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
string state = "";
|
||
|
struct cs_rest_time lastRest = cs_rest_GetLastRestTime(pc);
|
||
|
state += IntToString(lastRest.days);
|
||
|
state += ":";
|
||
|
state += IntToString(lastRest.seconds);
|
||
|
cs_dbg_Trace("cs_rest_GetState: " + state, debug);
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_SetState(object pc, string state, int timeOffset=0) {
|
||
|
object debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_SetState(" +
|
||
|
GetName(pc) + ", " +
|
||
|
state + ", " +
|
||
|
IntToString(timeOffset) + ")",
|
||
|
debug
|
||
|
);
|
||
|
cs_tkn_SetTokenString(state, ":");
|
||
|
int lastRestDays = StringToInt(cs_tkn_GetNextToken());
|
||
|
int lastRestSeconds = StringToInt(cs_tkn_GetNextToken());
|
||
|
struct cs_rest_time lastRest = cs_rest_Time(lastRestDays, lastRestSeconds);
|
||
|
if (timeOffset != 0) {
|
||
|
lastRest = cs_rest_AddTime(lastRest, cs_rest_Time(0, timeOffset));
|
||
|
}
|
||
|
cs_rest_SetLastRestTime(pc, lastRest);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int cs_rest_GetIsWearingHelm(object pc, struct cs_rest_config cfg) {
|
||
|
int result = FALSE;
|
||
|
int head = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_HEAD, pc));
|
||
|
if (head == BASE_ITEM_HELMET) {
|
||
|
result = TRUE;
|
||
|
}
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetIsWearingHelm(" + GetName(pc) + "): " +
|
||
|
IntToString(result),
|
||
|
cfg.debug
|
||
|
);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int cs_rest_GetIsWearingArmour(object pc, struct cs_rest_config cfg) {
|
||
|
int result = FALSE;
|
||
|
object armour = GetItemInSlot(INVENTORY_SLOT_CHEST, pc);
|
||
|
if (GetItemACValue(armour) > 5) {
|
||
|
result = TRUE;
|
||
|
}
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetIsWearingArmour(" + GetName(pc) + "): " +
|
||
|
IntToString(result),
|
||
|
cfg.debug
|
||
|
);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int cs_rest_GetIsArmed(object pc, struct cs_rest_config cfg) {
|
||
|
int result = 0;
|
||
|
if (GetIsObjectValid(pc)) {
|
||
|
int hand1 = GetBaseItemType(
|
||
|
GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, pc)
|
||
|
);
|
||
|
if (hand1 != BASE_ITEM_INVALID) {
|
||
|
result++;
|
||
|
}
|
||
|
int hand2 = GetBaseItemType(
|
||
|
GetItemInSlot(INVENTORY_SLOT_LEFTHAND, pc)
|
||
|
);
|
||
|
if (!((hand2 == BASE_ITEM_INVALID) ||
|
||
|
(hand2 == BASE_ITEM_TORCH) ||
|
||
|
(hand2 == BASE_ITEM_SMALLSHIELD) ||
|
||
|
(hand2 == BASE_ITEM_LARGESHIELD) ||
|
||
|
(hand2 == BASE_ITEM_TOWERSHIELD))
|
||
|
) {
|
||
|
result++;
|
||
|
}
|
||
|
}
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetIsArmed(" + GetName(pc) + "): " + IntToString(result),
|
||
|
cfg.debug
|
||
|
);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int cs_rest_GetIsShieldEquipped(object pc, struct cs_rest_config cfg) {
|
||
|
int result = 0;
|
||
|
if (GetIsObjectValid(pc)) {
|
||
|
int hand2 = GetBaseItemType(
|
||
|
GetItemInSlot(INVENTORY_SLOT_LEFTHAND, pc)
|
||
|
);
|
||
|
if ((hand2 == BASE_ITEM_SMALLSHIELD) ||
|
||
|
(hand2 == BASE_ITEM_LARGESHIELD) ||
|
||
|
(hand2 == BASE_ITEM_TOWERSHIELD)
|
||
|
) {
|
||
|
result = TRUE;
|
||
|
}
|
||
|
}
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetIsShieldEquipped(" + GetName(pc) + "): " +
|
||
|
IntToString(result),
|
||
|
cfg.debug
|
||
|
);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
struct cs_rest_config cs_rest_SetRuleFlag(struct cs_rest_config cfg, int rule, int value) {
|
||
|
cs_dbg_Enter(
|
||
|
"cs_rest_SetRuleFlag(" +
|
||
|
IntToString(rule) + ", " +
|
||
|
IntToString(value) + ")",
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace("before flags: " + IntToString(cfg.ruleFlags));
|
||
|
if (value) {
|
||
|
// We want to set the flag.
|
||
|
cfg.ruleFlags |= rule;
|
||
|
}
|
||
|
else {
|
||
|
// We want to clear the flag.
|
||
|
cfg.ruleFlags &= ~rule;
|
||
|
}
|
||
|
cs_dbg_Trace("after flags: " + IntToString(cfg.ruleFlags));
|
||
|
cs_dbg_Exit("cs_rest_SetRuleFlag");
|
||
|
return cfg;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
int cs_rest_GetRuleFlag(struct cs_rest_config cfg, int rule) {
|
||
|
int flag = cfg.ruleFlags &= rule;
|
||
|
cs_dbg_Trace("cs_rest_GetRuleFlag(" + IntToString(rule) +"): " + IntToString(flag));
|
||
|
return flag;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
struct cs_rest_config cs_rest_GetIsRestPermitted(
|
||
|
object pc,
|
||
|
struct cs_rest_config cfg
|
||
|
) {
|
||
|
// By default, resting is permitted and no rule flags are set.
|
||
|
cfg.permitted = TRUE;
|
||
|
cfg.ruleFlags = 0;
|
||
|
|
||
|
// Check whether this creature is ever allowed to rest at all.
|
||
|
if (cfg.neverPermitted) {
|
||
|
cfg.permitted = FALSE;
|
||
|
}
|
||
|
|
||
|
// Check for a rest time limit.
|
||
|
if (cfg.permitted && (cfg.limit > 0)) {
|
||
|
// Determine the current time.
|
||
|
struct cs_rest_time currentTime = cs_rest_GetCurrentTime(cfg);
|
||
|
|
||
|
// Determine the time at which resting is next available by adding
|
||
|
// the current rest limit to the last rest time.
|
||
|
struct cs_rest_time nextRest = cs_rest_Time(
|
||
|
cfg.lastRestDays,
|
||
|
cfg.lastRestSeconds
|
||
|
);
|
||
|
nextRest = cs_rest_AddTime(nextRest, cs_rest_Time(0, cfg.limit));
|
||
|
cs_dbg_Trace(
|
||
|
"current time: " + cs_rest_TimeToString(currentTime),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"Next rest time: " + cs_rest_TimeToString(nextRest),
|
||
|
cfg.debug
|
||
|
);
|
||
|
|
||
|
if (cs_rest_GetIsTimeLess(currentTime, nextRest)) {
|
||
|
// The required time period has not passed so the player
|
||
|
// may not rest yet.
|
||
|
cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_TOO_SOON);
|
||
|
cfg = cs_rest_SetRuleFlag(cfg, CS_REST_RULE_LAST_REST, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check for day only resting.
|
||
|
if (cfg.permitted && (cfg.dayMode == CS_REST_DAY_ONLY)) {
|
||
|
int hour = GetTimeHour();
|
||
|
if ((hour < cfg.dayStart) || (hour >= cfg.dayEnd)) {
|
||
|
cs_dbg_Trace("Day-only set and it is not day", cfg.debug);
|
||
|
cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_DAY_ONLY);
|
||
|
cfg = cs_rest_SetRuleFlag(cfg, CS_REST_RULE_DAY_ONLY, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check for night only resting.
|
||
|
if (cfg.permitted && (cfg.dayMode == CS_REST_NIGHT_ONLY)) {
|
||
|
int hour = GetTimeHour();
|
||
|
if ((hour >= cfg.dayStart) && (hour < cfg.dayEnd)) {
|
||
|
cs_dbg_Trace("Night-only set and it is not night", cfg.debug);
|
||
|
cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_NIGHT_ONLY);
|
||
|
cfg = cs_rest_SetRuleFlag(cfg, CS_REST_RULE_NIGHT_ONLY, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check if wearing armour.
|
||
|
if (cfg.permitted && cfg.noArmour) {
|
||
|
if (cs_rest_GetIsWearingHelm(pc, cfg) ||
|
||
|
cs_rest_GetIsShieldEquipped(pc, cfg) ||
|
||
|
cs_rest_GetIsWearingArmour(pc, cfg)
|
||
|
) {
|
||
|
cs_dbg_Trace("Armour is not permitted while resting", cfg.debug);
|
||
|
cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_NO_ARMOUR);
|
||
|
cfg = cs_rest_SetRuleFlag(cfg, CS_REST_RULE_NO_ARMOUR, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check if carrying weapons.
|
||
|
if (cfg.permitted && cfg.noWeapons) {
|
||
|
if (cs_rest_GetIsArmed(pc, cfg)) {
|
||
|
cs_dbg_Trace("Arms are not permitted while resting", cfg.debug);
|
||
|
cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_NO_WEAPON);
|
||
|
cfg = cs_rest_SetRuleFlag(cfg, CS_REST_RULE_NO_WEAPONS, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check if carrying a bedroll.
|
||
|
if (cfg.permitted && cfg.useBedroll) {
|
||
|
object item = GetItemPossessedBy(pc, cfg.bedrollTag);
|
||
|
if (GetIsObjectValid(item)) {
|
||
|
// Increment a usage count on the bedroll.
|
||
|
// XXX This may need to be persistent.
|
||
|
int used = GetLocalInt(item, CS_REST_VAR_BEDROLL_USE);
|
||
|
used++;
|
||
|
if (used > CS_REST_DEF_BEDROLL_MAX_USE) {
|
||
|
cs_dbg_Trace("Bedroll has been destroyed through use", cfg.debug);
|
||
|
DestroyObject(item);
|
||
|
cs_rest_ShowFloatingTextByID(pc,cfg,CS_REST_TXT_BEDROLL_RUINED);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace("Incrementing bedroll use count", cfg.debug);
|
||
|
SetLocalInt(item, CS_REST_VAR_BEDROLL_USE, used);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// Is there hit point regain without a bedroll?
|
||
|
if (cfg.bedrollMultiplier > 0.0) {
|
||
|
// No bedroll means only partial hit points regained.
|
||
|
cs_dbg_Trace("Resting without a bedroll reduces regain", cfg.debug);
|
||
|
cfg.multiplier = cfg.multiplier * cfg.bedrollMultiplier;
|
||
|
cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_NOT_COMFORTABLE);
|
||
|
}
|
||
|
else {
|
||
|
// No bedroll means no rest allowed at all.
|
||
|
cs_dbg_Trace("Resting without a bedroll not permitted", cfg.debug);
|
||
|
cfg = cs_rest_SetRuleFlag(cfg, CS_REST_RULE_NO_BEDROLL, TRUE);
|
||
|
cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_NO_BEDROLL);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Execute external script hook for rest rule evaluation. We don't even
|
||
|
// bother executing the user script if the never permitted flag is set,
|
||
|
// since by definition the player will not be permitted to rest no matter
|
||
|
// what.
|
||
|
if ((cfg.userScript != "") && !cfg.neverPermitted) {
|
||
|
cs_rest_SetConfig(pc, cfg);
|
||
|
cs_rest_SetUserScriptState(pc, CS_REST_RULE_CHECK);
|
||
|
ExecuteScript(cfg.userScript, pc);
|
||
|
cs_rest_DeleteUserScriptState(pc);
|
||
|
cfg = cs_rest_GetConfig(pc);
|
||
|
}
|
||
|
|
||
|
if (cfg.permitted) {
|
||
|
// If resting is still permitted at this point, check whether any
|
||
|
// of the rules should disallow it. Any rule that is set will cause
|
||
|
// resting to be not permitted.
|
||
|
cs_dbg_Trace("Checking rule evaluation", cfg.debug);
|
||
|
cfg.permitted = (cfg.ruleFlags == 0);
|
||
|
cs_dbg_Trace(
|
||
|
"Permitted after rule evaluation: " + IntToString(cfg.permitted),
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
|
||
|
cs_dbg_Trace(
|
||
|
"cs_rest_GetIsRestPermitted(" + GetName(pc) + "): " +
|
||
|
IntToString(cfg.permitted),
|
||
|
cfg.debug
|
||
|
);
|
||
|
return cfg;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_ExecuteRestScript(object pc, struct cs_rest_config cfg) {
|
||
|
cs_dbg_Enter("cs_rest_ExecuteRestScript(" + GetName(pc) + ")", cfg.debug);
|
||
|
|
||
|
// Make sure that we have a rest profile.
|
||
|
string profile = cfg.profile;
|
||
|
if (profile == "") {
|
||
|
// No configured profile so fall back on the default.
|
||
|
profile = cfg.defaultProfile;
|
||
|
cs_dbg_Trace("No profile, assuming default: " + profile, cfg.debug);
|
||
|
}
|
||
|
if (cfg.overrideProfile != "") {
|
||
|
// There's an override so use that instead.
|
||
|
profile = cfg.overrideProfile;
|
||
|
cs_dbg_Trace("Using override profile instead: " + profile, cfg.debug);
|
||
|
}
|
||
|
|
||
|
cs_dbg_Trace("Running rest script: " + profile, cfg.debug);
|
||
|
ExecuteScript(profile, GetModule());
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_ExecuteRestScript", cfg.debug);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
struct cs_rest_config cs_rest_ProcessConfig(
|
||
|
object pc,
|
||
|
object container,
|
||
|
struct cs_rest_config cfg
|
||
|
) {
|
||
|
cs_dbg_Enter("cs_rest_ProcessConfig(" + GetTag(container) + ")", cfg.debug);
|
||
|
|
||
|
// Do we have a valid object from which to configure?
|
||
|
if (GetIsObjectValid(container) && GetHasInventory(container)) {
|
||
|
cs_dbg_Trace(
|
||
|
"Valid configuration object: " + GetResRef(container),
|
||
|
cfg.debug
|
||
|
);
|
||
|
|
||
|
// Sort through all items in the configuration object's inventory,
|
||
|
// checking each one to see if it is something that we recognise.
|
||
|
object item = GetFirstItemInInventory(container);
|
||
|
while (GetIsObjectValid(item)) {
|
||
|
string resref = GetResRef(item);
|
||
|
if (resref == CS_REST_RR_DEBUG_ON) {
|
||
|
// Found a debug on value. The presence of this item is
|
||
|
// enough to indicate that debugging should be enabled.
|
||
|
// When debug is enabled, messages are sent to the player
|
||
|
// current resting.
|
||
|
cfg.debug = pc;
|
||
|
cs_dbg_EnableDestination(CS_DBG_ALL);
|
||
|
cs_dbg_Trace("Enabling debugging", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_ENABLE) {
|
||
|
// Found an enable value. The presence of this item is
|
||
|
// enough to indicate that the rest system is active.
|
||
|
cfg.enabled = TRUE;
|
||
|
cs_dbg_Trace("Enabling resting", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_DISABLE) {
|
||
|
// Found a disable value. The presence of this item is
|
||
|
// enough to indicate that the rest system is inactive.
|
||
|
cfg.enabled = FALSE;
|
||
|
cs_dbg_Trace("Disabling resting", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_HP_3ED) {
|
||
|
// Found a 3ed HP value. The presence of this item is
|
||
|
// enough to indicate that the rest system should use 3rd
|
||
|
// edition style hit point rules.
|
||
|
cfg.use3Ed = TRUE;
|
||
|
cs_dbg_Trace("Using 3rd Ed Style HP", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_HP_STD) {
|
||
|
// Found a standard HP value. The presence of this item is
|
||
|
// enough to indicate that the rest system should use normal
|
||
|
// hit point rules.
|
||
|
cfg.use3Ed = FALSE;
|
||
|
cs_dbg_Trace("Using standard HP", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_PROFILE) {
|
||
|
// Found a profile value. Set the default profile to be
|
||
|
// a script the same name as this item's tag.
|
||
|
string profile = GetStringLowerCase(GetTag(item));
|
||
|
cfg.defaultProfile = profile;
|
||
|
cs_dbg_Trace("Default profile is " + profile, cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_DAY_ONLY) {
|
||
|
// Found a day-only value. The presence of this item is
|
||
|
// enough to indicate that resting should only be permitted
|
||
|
// during daylight hours.
|
||
|
cfg.dayMode = CS_REST_DAY_ONLY;
|
||
|
cs_dbg_Trace("Setting day only mode", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_NIGHT_ONLY) {
|
||
|
// Found a night-only value. The presence of this item is
|
||
|
// enough to indicate that resting should only be permitted
|
||
|
// during night hours.
|
||
|
cfg.dayMode = CS_REST_NIGHT_ONLY;
|
||
|
cs_dbg_Trace("Setting night only mode", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_ALL_HOURS) {
|
||
|
// Found an all-hours value. The presence of this item is
|
||
|
// enough to indicate that resting is permitted at all
|
||
|
// times during the day and night.
|
||
|
cfg.dayMode = CS_REST_DAY_AND_NIGHT;
|
||
|
cs_dbg_Trace("Setting resting for all hours", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_DAY_START) {
|
||
|
// Found a start of day value. Convert the item's tag into an
|
||
|
// integer and use it as the starting hour for the "day".
|
||
|
int hour = StringToInt(GetTag(item));
|
||
|
if ((hour >= 0) && (hour < 23)) {
|
||
|
cfg.dayStart = hour;
|
||
|
cs_dbg_Trace(
|
||
|
"Setting day start: " + IntToString(hour),
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_DAY_END) {
|
||
|
// Found an end of day value. Convert the item's tag into an
|
||
|
// integer and use it as the ending hour for the "day".
|
||
|
int hour = StringToInt(GetTag(item));
|
||
|
if ((hour > 0) && (hour <= 23)) {
|
||
|
cfg.dayEnd = hour;
|
||
|
cs_dbg_Trace(
|
||
|
"Setting day end: " + IntToString(hour),
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_NO_ARMOUR) {
|
||
|
// Found a no armour value. The presence of this item is
|
||
|
// enough to indicate that resting is not permitted while
|
||
|
// wearing armour.
|
||
|
cfg.noArmour = TRUE;
|
||
|
cs_dbg_Trace("Setting no armour mode", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_YES_ARMOUR) {
|
||
|
// Found an armour allowed value. The presence of this item
|
||
|
// is enough to indicate that resting is permitted even while
|
||
|
// armour is being worn.
|
||
|
cfg.noArmour = FALSE;
|
||
|
cs_dbg_Trace("Setting armour allowed mode", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_NO_WEAPONS) {
|
||
|
// Found a no weapons value. The presence of this item is
|
||
|
// enough to indicate that resting is not permitted while
|
||
|
// weapons are equipped.
|
||
|
cfg.noWeapons = TRUE;
|
||
|
cs_dbg_Trace("Setting no weapons mode", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_YES_WEAPONS) {
|
||
|
// Found a weapons allowed value. The presence of this item
|
||
|
// is enough to indicate that resting is permitted even while
|
||
|
// weapons are equipped.
|
||
|
cfg.noWeapons = FALSE;
|
||
|
cs_dbg_Trace("Setting weapons allowed mode", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_NO_BEDROLL) {
|
||
|
// Found a no bedroll value. The presence of this item is
|
||
|
// enough to indicate that bedrolls are ignored completely
|
||
|
// for purposes of calculating hit point regain.
|
||
|
cfg.useBedroll = FALSE;
|
||
|
cs_dbg_Trace("Setting no bedroll mode", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_YES_BEDROLL) {
|
||
|
// Found a bedroll in use value. The presence of this item
|
||
|
// is enough to indicate that bedrolls are used to determine
|
||
|
// the number of hit points regained while resting, while
|
||
|
// its tag contains the tag of the item that is to considered
|
||
|
// to be a bedroll.
|
||
|
cfg.useBedroll = TRUE;
|
||
|
cfg.bedrollTag = GetTag(item);
|
||
|
cs_dbg_Trace("Setting bedroll mode: " + GetTag(item), cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_BEDROLL_MULTIPLIER) {
|
||
|
// Found a bedroll HP multiplier value. The tag of this item
|
||
|
// provides a multiplier for hit points regained by players
|
||
|
// when bedrolls are in effect and no bedroll is present.
|
||
|
float multiplier = StringToInt(GetTag(item))/100.0;
|
||
|
if ((multiplier < 0.0) && (multiplier >= 100.0)) {
|
||
|
multiplier = CS_REST_DEF_BEDROLL_MULTIPLIER;
|
||
|
cs_dbg_Trace(
|
||
|
"Invalid Bedroll HP multiplier: " + GetTag(item),
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
cfg.bedrollMultiplier = multiplier;
|
||
|
if (multiplier > 0.0) {
|
||
|
cs_dbg_Trace(
|
||
|
"Bedroll HP multiplier is " + FloatToString(cfg.multiplier),
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace(
|
||
|
"Resting without a bedroll is disabled",
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
else if ((resref == CS_REST_RR_TIME_LIMIT) ||
|
||
|
(GetStringLeft(resref, 14) == CS_REST_RR_TIME_PREFIX)){
|
||
|
// Found a time limit value. Set the resting time limit to be
|
||
|
// an integer taken from this item's tag.
|
||
|
if (GetStringLowerCase(GetTag(item)) != "none") {
|
||
|
int limit = StringToInt(GetTag(item));
|
||
|
cfg.limit = limit;
|
||
|
cs_dbg_Trace(
|
||
|
"Time limit is " + IntToString(limit) + " seconds",
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace("Time limit does not apply", cfg.debug);
|
||
|
}
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_FADE_TO_BLACK) {
|
||
|
// Found a fade to black value. The presence of this item
|
||
|
// is enough to indicate that the screen should fade to black
|
||
|
// when a player rests.
|
||
|
cfg.fadeToBlack = TRUE;
|
||
|
cs_dbg_Trace("The screen will fade to black", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_NO_MESSAGES) {
|
||
|
// Found a no messages value. The presence of this item
|
||
|
// is enough to indicate the display of messages should be
|
||
|
// suppressed.
|
||
|
cfg.noMessages = TRUE;
|
||
|
cs_dbg_Trace("No floaty messages will be displayed", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_USE_CON_BONUS) {
|
||
|
// Found a use CON bonus value. The presence of this item
|
||
|
// is enough to indicate that players should receive their
|
||
|
// CON bonus as hit points when resting.
|
||
|
cfg.useConBonus = TRUE;
|
||
|
cs_dbg_Trace("CON bonus will be used", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_NO_CON_BONUS) {
|
||
|
// Found a no CON bonus value. The presence of this item
|
||
|
// is enough to indicate that players should not receive their
|
||
|
// CON bonus as hit points when resting.
|
||
|
cfg.useConBonus = FALSE;
|
||
|
cs_dbg_Trace("CON bonus will be not used", cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_HP_MULTIPLIER) {
|
||
|
// Found a HP multiplier value. The tag of this item provides
|
||
|
// a multiplier for hit points regained by players.
|
||
|
float multiplier = StringToInt(GetTag(item))/100.0;
|
||
|
if ((multiplier <= 0.0) && (multiplier >= 100.0)) {
|
||
|
multiplier = CS_REST_DEF_MULTIPLIER;
|
||
|
cs_dbg_Trace(
|
||
|
"Invalid HP multiplier: " + GetTag(item),
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
cfg.multiplier = multiplier;
|
||
|
cs_dbg_Trace(
|
||
|
"HP multiplier is " + FloatToString(cfg.multiplier),
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_USER_SCRIPT) {
|
||
|
// Found a user script value. The tag of this item provides
|
||
|
// the name of a script to be executed at user hook points.
|
||
|
cfg.userScript = GetStringLowerCase(GetTag(item));
|
||
|
cs_dbg_Trace("User script is " + cfg.userScript, cfg.debug);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_TEXT_MESSAGES) {
|
||
|
// Found a container item for text messages. A set of
|
||
|
// variables on this item may override the default messages.
|
||
|
cs_dbg_Trace("Floaty messages will be displayed", cfg.debug);
|
||
|
cfg.noMessages = FALSE;
|
||
|
cs_rest_UpdateMessages(pc, cfg, item);
|
||
|
}
|
||
|
else if (resref == CS_REST_RR_EFFECTS) {
|
||
|
// Found an effects value. A set of effects may be applied
|
||
|
// to a player when resting, derived from the value of a
|
||
|
// variable on this item.
|
||
|
cs_dbg_Trace("Effects will be applied", cfg.debug);
|
||
|
cfg.effects = GetLocalString(item, CS_REST_VAR_EFFECTS);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace("Unrecognised item: " + resref, cfg.debug);
|
||
|
}
|
||
|
item = GetNextItemInInventory(container);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace(
|
||
|
"Not a valid configuration object: " + GetResRef(container),
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Validate and override hour settings if they are obviously screwy.
|
||
|
if ((cfg.dayStart < 1) || (cfg.dayStart > cfg.dayEnd)) {
|
||
|
cfg.dayStart = 6;
|
||
|
}
|
||
|
if ((cfg.dayEnd > 23) || (cfg.dayEnd < cfg.dayStart)) {
|
||
|
cfg.dayEnd = 18;
|
||
|
}
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_ProcessConfig", cfg.debug);
|
||
|
return cfg;
|
||
|
}
|
||
|
//----------------------------------------------------------------------------
|
||
|
// Find our configuration. First we find a global configuration object,
|
||
|
// then an area-specific one for the area that the player is in, and
|
||
|
// if there is a profile set for the resting player we look for a profile
|
||
|
// configuration object.
|
||
|
struct cs_rest_config cs_rest_RetrieveConfig(object pc) {
|
||
|
struct cs_rest_config cfg;
|
||
|
cfg.debug = GetLocalObject(pc, CS_REST_VAR_DEBUG);
|
||
|
cs_dbg_Enter("cs_rest_RetrieveConfig(" + GetName(pc) + ")", cfg.debug);
|
||
|
|
||
|
// Initialise default values.
|
||
|
cfg.bedrollMultiplier = CS_REST_DEF_BEDROLL_MULTIPLIER;
|
||
|
cfg.multiplier = CS_REST_DEF_MULTIPLIER;
|
||
|
|
||
|
// Pull in internal state from the PC if any.
|
||
|
cfg.profile = cs_rest_GetProfile(pc);
|
||
|
cfg.overrideProfile = cs_rest_GetOverrideProfile(pc);
|
||
|
cfg.trigger = cs_rest_GetTriggeringObject(pc);
|
||
|
cfg.permitted = GetLocalInt(pc, CS_REST_VAR_PERMITTED);
|
||
|
cfg.ruleFlags = GetLocalInt(pc, CS_REST_VAR_RULE_FLAGS);
|
||
|
cfg.started = GetLocalInt(pc, CS_REST_VAR_STARTED);
|
||
|
cfg.savedHitPoints = GetLocalInt(pc, CS_REST_VAR_SAVE_HP);
|
||
|
struct cs_rest_time time = cs_rest_GetLastRestTime(pc);
|
||
|
cfg.lastRestDays = time.days;
|
||
|
cfg.lastRestSeconds = time.seconds;
|
||
|
|
||
|
// Find the global config container.
|
||
|
cs_dbg_Trace("Searching global config: " + CS_REST_TAG_CONFIG, cfg.debug);
|
||
|
object container = GetObjectByTag(CS_REST_TAG_CONFIG);
|
||
|
if (!GetIsObjectValid(container)) {
|
||
|
// Try again in lowercase just to be sure.
|
||
|
container = GetObjectByTag(GetStringLowerCase(CS_REST_TAG_CONFIG));
|
||
|
}
|
||
|
if (GetIsObjectValid(container)) {
|
||
|
cs_dbg_Trace("Global config found", cfg.debug);
|
||
|
cfg = cs_rest_ProcessConfig(pc, container, cfg);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace("Global config not found", cfg.debug);
|
||
|
}
|
||
|
|
||
|
// Find any area config container.
|
||
|
string tag = GetTag(GetArea(pc)) + CS_REST_TAG_CONFIG_SUFFIX;
|
||
|
cs_dbg_Trace("Searching area config: " + tag, cfg.debug);
|
||
|
if (GetStringLength(tag) > CS_REST_MAX_TAG_LENGTH) {
|
||
|
cs_dbg_Trace(
|
||
|
"Rest config tag > " +
|
||
|
IntToString(CS_REST_MAX_TAG_LENGTH) +
|
||
|
" characters. This will cause problems.",
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
container = GetObjectByTag(tag);
|
||
|
if (!GetIsObjectValid(container)) {
|
||
|
// Try again in lowercase just to be sure.
|
||
|
container = GetObjectByTag(GetStringLowerCase(tag));
|
||
|
}
|
||
|
if (GetIsObjectValid(container)) {
|
||
|
cs_dbg_Trace("Area config found", cfg.debug);
|
||
|
cfg = cs_rest_ProcessConfig(pc, container, cfg);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace("Area config not found", cfg.debug);
|
||
|
}
|
||
|
|
||
|
// Find a trigger config container if any.
|
||
|
container = cfg.trigger;
|
||
|
if (GetIsObjectValid(container)) {
|
||
|
tag = GetTag(container) + CS_REST_TAG_CONFIG_SUFFIX;
|
||
|
cs_dbg_Trace("Searching trigger config: " + tag, cfg.debug);
|
||
|
if (GetStringLength(tag) > CS_REST_MAX_TAG_LENGTH) {
|
||
|
cs_dbg_Trace(
|
||
|
"Rest config tag > " +
|
||
|
IntToString(CS_REST_MAX_TAG_LENGTH) +
|
||
|
" characters. This will cause problems.",
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
container = GetObjectByTag(tag);
|
||
|
if (!GetIsObjectValid(container)) {
|
||
|
// Try again in lowercase just to be sure.
|
||
|
container = GetObjectByTag(GetStringLowerCase(tag));
|
||
|
}
|
||
|
if (GetIsObjectValid(container)) {
|
||
|
cs_dbg_Trace("Trigger config found", cfg.debug);
|
||
|
cfg = cs_rest_ProcessConfig(pc, container, cfg);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace("Trigger config not found", cfg.debug);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace("Searching trigger config: not inside a trigger", cfg.debug);
|
||
|
}
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_RetrieveConfig", cfg.debug);
|
||
|
return cfg;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_UpdateMessages(object pc, struct cs_rest_config cfg, object item) {
|
||
|
SetLocalString(pc, CS_REST_VAR_START_TEXT, GetLocalString(item, CS_REST_VAR_START_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_FINISH_TEXT, GetLocalString(item, CS_REST_VAR_FINISH_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_CANCEL_TEXT, GetLocalString(item, CS_REST_VAR_CANCEL_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_CANNOT_TEXT, GetLocalString(item, CS_REST_VAR_CANNOT_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_TOO_SOON_TEXT, GetLocalString(item, CS_REST_VAR_TOO_SOON_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_DAY_ONLY_TEXT, GetLocalString(item, CS_REST_VAR_DAY_ONLY_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_NIGHT_ONLY_TEXT, GetLocalString(item, CS_REST_VAR_NIGHT_ONLY_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_NO_ARMOUR_TEXT, GetLocalString(item, CS_REST_VAR_NO_ARMOUR_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_NO_WEAPON_TEXT, GetLocalString(item, CS_REST_VAR_NO_WEAPON_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_BEDROLL_RUINED_TEXT, GetLocalString(item, CS_REST_VAR_BEDROLL_RUINED_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_NOT_COMFORTABLE_TEXT, GetLocalString(item, CS_REST_VAR_NOT_COMFORTABLE_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_ENTER_REST_TEXT, GetLocalString(item, CS_REST_VAR_ENTER_REST_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_EXIT_REST_TEXT, GetLocalString(item, CS_REST_VAR_EXIT_REST_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_UNSAFE_TEXT, GetLocalString(item, CS_REST_VAR_UNSAFE_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_ENTER_NO_REST_TEXT, GetLocalString(item, CS_REST_VAR_ENTER_NO_REST_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_EXIT_NO_REST_TEXT, GetLocalString(item, CS_REST_VAR_EXIT_NO_REST_TEXT));
|
||
|
SetLocalString(pc, CS_REST_VAR_NO_BEDROLL_TEXT, GetLocalString(item, CS_REST_VAR_NO_BEDROLL_TEXT));
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_ShowFloatingTextByID(object pc, struct cs_rest_config cfg, int id){
|
||
|
cs_dbg_Enter(
|
||
|
"cs_rest_ShowFloatingTextByID(" +
|
||
|
GetName(pc) + ", " +
|
||
|
IntToString(id) + ")",
|
||
|
cfg.debug
|
||
|
);
|
||
|
|
||
|
if (cfg.noMessages) {
|
||
|
// Bail out if messages are turned off.
|
||
|
cs_dbg_Trace("message display is disabled");
|
||
|
cs_dbg_Exit("cs_rest_ShowFloatingTextByID", cfg.debug);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// object mod = GetModule();
|
||
|
string text = "";
|
||
|
cs_dbg_Trace("Message ID: " + IntToString(id), cfg.debug);
|
||
|
switch (id) {
|
||
|
case CS_REST_TXT_START:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_START_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_START;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_FINISH:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_FINISH_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_FINISH;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_CANCEL:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_CANCEL_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_CANCEL;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_CANNOT:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_CANNOT_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_CANNOT;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_TOO_SOON:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_TOO_SOON_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_TOO_SOON;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_DAY_ONLY:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_DAY_ONLY_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_DAY_ONLY;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_NIGHT_ONLY:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_NIGHT_ONLY_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_NIGHT_ONLY;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_NO_ARMOUR:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_NO_ARMOUR_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_NO_ARMOUR;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_NO_WEAPON:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_NO_WEAPON_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_NO_WEAPON;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_BEDROLL_RUINED:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_BEDROLL_RUINED_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_BEDROLL_RUINED;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_NOT_COMFORTABLE:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_NOT_COMFORTABLE_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_NOT_COMFORTABLE;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_ENTER_REST:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_ENTER_REST_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_ENTER_REST;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_EXIT_REST:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_EXIT_REST_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_EXIT_REST;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_UNSAFE:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_UNSAFE_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_UNSAFE;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_ENTER_NO_REST:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_ENTER_NO_REST_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_ENTER_NO_REST;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_EXIT_NO_REST:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_EXIT_NO_REST_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_EXIT_NO_REST;
|
||
|
}
|
||
|
break;
|
||
|
case CS_REST_TXT_NO_BEDROLL:
|
||
|
text = GetLocalString(pc, CS_REST_VAR_NO_BEDROLL_TEXT);
|
||
|
if (text == "") {
|
||
|
text = CS_REST_MSG_NO_BEDROLL;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
cs_dbg_Trace("Message ID not recognised", cfg.debug);
|
||
|
break;
|
||
|
}
|
||
|
if (text != "") {
|
||
|
if (text == "off") {
|
||
|
cs_dbg_Trace("message is disabled");
|
||
|
}
|
||
|
else {
|
||
|
// Expand references in the string.
|
||
|
cs_dbg_Trace("Expanding embedded references", cfg.debug);
|
||
|
int pos = FindSubString(text, "<MIN>");
|
||
|
if (pos > 0) {
|
||
|
// Number of minutes before next rest.
|
||
|
struct cs_rest_time currentTime = cs_rest_GetCurrentTime(cfg);
|
||
|
struct cs_rest_time nextRest = cs_rest_Time(
|
||
|
cfg.lastRestDays,
|
||
|
cfg.lastRestSeconds
|
||
|
);
|
||
|
nextRest = cs_rest_AddTime(nextRest, cs_rest_Time(0, cfg.limit));
|
||
|
cs_dbg_Trace(
|
||
|
"current time: " + cs_rest_TimeToString(currentTime),
|
||
|
cfg.debug
|
||
|
);
|
||
|
cs_dbg_Trace(
|
||
|
"Next rest time: " + cs_rest_TimeToString(nextRest),
|
||
|
cfg.debug
|
||
|
);
|
||
|
struct cs_rest_time left = cs_rest_SubtractTime(nextRest, currentTime);
|
||
|
int minutes = (left.seconds / cs_rest_secondsPerMinute);
|
||
|
string replace = "";
|
||
|
if (minutes == 0) {
|
||
|
replace = "less than a minute";
|
||
|
}
|
||
|
else {
|
||
|
replace = IntToString(minutes) + " minute";
|
||
|
if (minutes > 1) {
|
||
|
replace += "s";
|
||
|
}
|
||
|
}
|
||
|
text =
|
||
|
GetStringLeft(text, pos) +
|
||
|
replace +
|
||
|
GetStringRight(text, GetStringLength(text) - pos - 5);
|
||
|
}
|
||
|
FloatingTextStringOnCreature(text, pc, FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_ShowFloatingTextByID", cfg.debug);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_ApplyEffects(object pc, struct cs_rest_config cfg) {
|
||
|
cs_dbg_Enter("cs_rest_ApplyEffects(" + GetName(pc) + ")", cfg.debug);
|
||
|
|
||
|
cs_dbg_Trace("effects to apply: " + cfg.effects);
|
||
|
cs_tkn_SetTokenString(cfg.effects);
|
||
|
while(!cs_tkn_GetIsLastToken()) {
|
||
|
string token = cs_tkn_GetNextToken();
|
||
|
int effectID = StringToInt(token);
|
||
|
if (effectID > 0) {
|
||
|
cs_dbg_Trace("applying effect: " + token);
|
||
|
effect eff = EffectVisualEffect(effectID);
|
||
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eff, pc, 22.0);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace("effect failed to parse: " + token);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_ApplyEffects", cfg.debug);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// This function is used as a failsafe if, for whatever reason, the resting
|
||
|
// fails to stop and so the screen remains faded to black. Leaving players
|
||
|
// with a black screen is not friendly.
|
||
|
void cs_rest_fadeUpFallback(object pc, object debug) {
|
||
|
cs_dbg_Enter("cs_rest_fadeUpFallback(" + GetName(pc) + ")", debug);
|
||
|
|
||
|
if (!GetLocalInt(pc, CS_REST_VAR_FADE_DONE)) {
|
||
|
cs_dbg_Trace("Fade up failed! Fallback kicked in.", debug);
|
||
|
FadeFromBlack(pc);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace("Fade up worked ok.", debug);
|
||
|
}
|
||
|
DeleteLocalInt(pc, CS_REST_VAR_FADE_DONE);
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_fadeUpFallback", debug);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_StartResting(object pc, struct cs_rest_config cfg) {
|
||
|
cs_dbg_Enter("cs_rest_StartResting(" + GetName(pc) + ")", cfg.debug);
|
||
|
|
||
|
cfg.savedHitPoints = GetCurrentHitPoints(pc);
|
||
|
cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_START);
|
||
|
|
||
|
// If we're configured to fade the screen to black, do so here.
|
||
|
if (cfg.fadeToBlack) {
|
||
|
cs_dbg_Trace("Fading to black", cfg.debug);
|
||
|
FadeToBlack(pc);
|
||
|
// Failsafe fade just in case resting is aborted somehow.
|
||
|
// Yeah yeah, I'm paranoid. I know.
|
||
|
DelayCommand(25.0, cs_rest_fadeUpFallback(pc, cfg.debug));
|
||
|
}
|
||
|
|
||
|
// Apply any effects indicated by the user.
|
||
|
cs_rest_ApplyEffects(pc, cfg);
|
||
|
|
||
|
cs_rest_SetConfig(pc, cfg);
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_StartResting", cfg.debug);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_StopResting(object pc, struct cs_rest_config cfg) {
|
||
|
cs_dbg_Enter("cs_rest_StopResting(" + GetName(pc) + ")", cfg.debug);
|
||
|
|
||
|
// Did the rest system actually kick in?
|
||
|
if (cfg.started == CS_REST_STARTED) {
|
||
|
cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_FINISH);
|
||
|
|
||
|
if (cfg.use3Ed) {
|
||
|
// Reduce player's HP back to stored value + level.
|
||
|
int oldHP = cfg.savedHitPoints;
|
||
|
if (oldHP > 0) {
|
||
|
// Determine how many HP the PC regains.
|
||
|
int gained = GetHitDice(pc);
|
||
|
gained = FloatToInt(IntToFloat(gained) * cfg.multiplier);
|
||
|
if (cfg.useConBonus) {
|
||
|
gained += GetAbilityModifier(ABILITY_CONSTITUTION, pc);
|
||
|
}
|
||
|
if (gained < 1) {
|
||
|
// Player always regains at least 1 HP.
|
||
|
gained = 1;
|
||
|
}
|
||
|
cs_dbg_Trace("gained: " + IntToString(gained), cfg.debug);
|
||
|
|
||
|
// Determine the number of HP the PC should now have.
|
||
|
int newHP = oldHP + gained;
|
||
|
|
||
|
// If the new HP value is less than full HP, we need to reduce
|
||
|
// the PC's HP down again.
|
||
|
if (newHP < GetMaxHitPoints(pc)) {
|
||
|
effect damage = EffectDamage(
|
||
|
GetCurrentHitPoints(pc) - newHP,
|
||
|
DAMAGE_TYPE_MAGICAL,
|
||
|
DAMAGE_POWER_PLUS_FIVE
|
||
|
);
|
||
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, damage, pc);
|
||
|
|
||
|
// Calculate display value.
|
||
|
newHP = newHP - oldHP;
|
||
|
}
|
||
|
else {
|
||
|
// Calculate display value.
|
||
|
newHP = GetMaxHitPoints(pc) - oldHP;
|
||
|
}
|
||
|
cs_dbg_Trace(
|
||
|
GetName(pc) + " regained " +
|
||
|
IntToString(newHP) + " hit points",
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace(
|
||
|
GetName(pc) + " has 0 hit points! This is bad...",
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set config that we actually want to keep for next time.
|
||
|
cs_rest_SetLastRestTime(pc, cs_rest_GetCurrentTime(cfg));
|
||
|
|
||
|
// If we faded the screen to black, fade back up again.
|
||
|
if (cfg.fadeToBlack) {
|
||
|
cs_dbg_Trace("Fading screen up", cfg.debug);
|
||
|
FadeFromBlack(pc);
|
||
|
SetLocalInt(pc, CS_REST_VAR_FADE_DONE, TRUE);
|
||
|
}
|
||
|
}
|
||
|
else if (cfg.started != CS_REST_ABORTED) {
|
||
|
cs_dbg_Trace(
|
||
|
GetName(pc) + ": resting stopped after never starting!",
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_StopResting", cfg.debug);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
void cs_rest_CancelResting(object pc, struct cs_rest_config cfg) {
|
||
|
cs_dbg_Enter("cs_rest_CancelResting(" + GetName(pc) + ")", cfg.debug);
|
||
|
|
||
|
// Did the rest system actually kick in?
|
||
|
if (cfg.started == CS_REST_STARTED) {
|
||
|
cs_rest_ShowFloatingTextByID(pc, cfg, CS_REST_TXT_CANCEL);
|
||
|
|
||
|
if (cfg.use3Ed) {
|
||
|
// Reduce player's HP to stored value + proportion of level, i.e.
|
||
|
// if the player rests for half a normal rest period, he gets half
|
||
|
// his level in HP. If the player is only slightly injured, i.e.
|
||
|
// less than his level in damage, then the normal resting is left
|
||
|
// alone which results in slower healing if interrupted close to
|
||
|
// full hit points. Ah well.
|
||
|
int oldHP = cfg.savedHitPoints;
|
||
|
if (oldHP > 0) {
|
||
|
int maxHP = GetMaxHitPoints(pc);
|
||
|
if (oldHP != maxHP) {
|
||
|
// Determine how many HP the PC regains.
|
||
|
int currentHP = GetCurrentHitPoints(pc);
|
||
|
int gained = FloatToInt(IntToFloat(GetHitDice(pc)) *
|
||
|
((IntToFloat(currentHP - oldHP)) /
|
||
|
(IntToFloat(maxHP - oldHP))));
|
||
|
gained = FloatToInt(IntToFloat(gained) * cfg.multiplier);
|
||
|
if (cfg.useConBonus) {
|
||
|
gained += GetAbilityModifier(ABILITY_CONSTITUTION, pc);
|
||
|
}
|
||
|
if (gained < 1) {
|
||
|
// Player always regains at least 1 HP.
|
||
|
gained = 1;
|
||
|
}
|
||
|
cs_dbg_Trace("gained: " + IntToString(gained), cfg.debug);
|
||
|
|
||
|
// Determine the number of HP the PC should now have.
|
||
|
int newHP = oldHP + gained;
|
||
|
|
||
|
// If the PC has more HP than he should, we need to reduce
|
||
|
// the PC's HP down again.
|
||
|
if (currentHP > newHP) {
|
||
|
effect damage = EffectDamage(
|
||
|
currentHP - newHP,
|
||
|
DAMAGE_TYPE_MAGICAL,
|
||
|
DAMAGE_POWER_PLUS_FIVE
|
||
|
);
|
||
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, damage, pc);
|
||
|
}
|
||
|
else {
|
||
|
gained = currentHP - oldHP;
|
||
|
}
|
||
|
cs_dbg_Trace(
|
||
|
GetName(pc) + " regained " +
|
||
|
IntToString(gained) + " hit points",
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
cs_dbg_Trace(
|
||
|
GetName(pc) + " has 0 hit points! This is bad...",
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set config that we actually want to keep for next time.
|
||
|
cs_rest_SetLastRestTime(pc, cs_rest_GetCurrentTime(cfg));
|
||
|
|
||
|
// If we faded the screen to black, fade back up again.
|
||
|
if (cfg.fadeToBlack) {
|
||
|
cs_dbg_Trace("Fading screen up", cfg.debug);
|
||
|
FadeFromBlack(pc);
|
||
|
SetLocalInt(pc, CS_REST_VAR_FADE_DONE, TRUE);
|
||
|
}
|
||
|
}
|
||
|
else if (cfg.started != CS_REST_ABORTED) {
|
||
|
cs_dbg_Trace(
|
||
|
GetName(pc) + ": resting cancelled after never starting!",
|
||
|
cfg.debug
|
||
|
);
|
||
|
}
|
||
|
|
||
|
cs_dbg_Exit("cs_rest_CancelResting", cfg.debug);
|
||
|
}
|