Author Topic: Need help with scripting problem  (Read 717 times)

Legacy_DeadeyeDevie

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Need help with scripting problem
« on: April 13, 2016, 12:39:32 am »


               

Hi guys n girls,


 


Got the urge to build more onto a module i have had lying around for years, and i have hit on an issue. im trying to mearge 2 scripts to make 1 rest script, but cant get my head round how to do it.


 


the 2 scripts are:-


 


rest-campfire V2.0


http://148.251.86.81...st-campfire-v20


 


and


 


on_resting_by_the_dungeon_master


http://neverwinterva...ll-requirements


 


what im trying to achieve is a resting system where a bedroll and rations are needed after a campfire has been put down, thus adding a money sink into rest, and lowering the amount of space for hoarding loot. Also requiring forward planning on logistics for long group (or solo) dungeon crawls. this also needs to have a time limit between rests, so rest cant be spammed.


 


i have had a look around for a good system, but cant find one im happy with, hence trying to mix these 2 together.


 


if anyone can help, or can point me in the direction of a script that fits my needs, i will be sooo happy, and be able to move past this stumbling block.


 


thank you all in advance for any helpful posts.


 


 



               
               

               
            

Legacy_DeadeyeDevie

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Need help with scripting problem
« Reply #1 on: April 21, 2016, 10:55:57 pm »


               

bumped, as i still cant get my head round how to put the 2 scripts together.


 


These are the scripts i cant work out how to put together. i constantly get errors that im having isssues resolving.


 


first the main rest script, with bedroll, timing, and rations:-


 



 


object oResting=GetLastPCRested();

int nRestingCounter=GetLocalInt(oResting, "nRestingCounterPC");

int nRoundsUntilRest;

int nMinUntilRest;

int nRoundsBetweenRests=100; // change number of rounds between rest

string sOutput;

 

 

void main()

{

  object oPC = GetLastPCRested();

  int iHostileRange = 30;

  object oProvisions = GetItemPossessedBy(oPC, "Rations");

  object oBedroll = GetItemPossessedBy(oPC, "Bedroll");

  int nStacked = GetNumStackedItems(oProvisions);

 

 

 

  // checks time for rest

 

        if (GetIsObjectValid(oResting) && nRestingCounter<nRoundsBetweenRests && GetLastRestEventType() == REST_EVENTTYPE_REST_STARTED)

            {

              AssignCommand(oResting, ClearAllActions());

              nRoundsUntilRest = nRoundsBetweenRests-nRestingCounter;

              nMinUntilRest = nRoundsUntilRest/20; // gives time left in min value. Approx.

              sOutput="You cannot rest again so soon! You may rest again in about ("+IntToString(nMinUntilRest)+" Minutes).";

              AssignCommand(oResting, SpeakString(sOutput));

            }

            else if (GetLastRestEventType() == REST_EVENTTYPE_REST_FINISHED)

             {

               SetLocalInt(oResting, "nRestingCounterPC", 0);

              }

            else

 

 

//  checks for Bedroll and Rations

 

if (GetLastRestEventType() == REST_EVENTTYPE_REST_STARTED)

    {

             // Check if the PC has Rations, AND if it's a valid PC doing the resting

 

             if (oProvisions == OBJECT_INVALID && oPC != OBJECT_INVALID)

             {

                // didn't have Rations and is a valid PC

 

                AssignCommand (oPC, ClearAllActions());

                FloatingTextStringOnCreature ("You need provisions to rest", oPC);

             }

 

             else // player has Rations

 

              // Check if the PC has Bedroll, AND if it's a valid PC doing the resting

 

             if (oBedroll == OBJECT_INVALID && oPC != OBJECT_INVALID)

             {

                // didn't have Bedroll and is a valid PC

 

                AssignCommand (oPC, ClearAllActions());

                FloatingTextStringOnCreature ("You need a Bedroll to rest", oPC);

             }

 

             else // player has Bedroll

 

             {

 

                // nearest creature check proximity, hostility.

 

                object oCreature = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);

 

                    if (iHostileRange == 0 || (iHostileRange != 0 && GetDistanceToObject(oCreature) <= IntToFloat(iHostileRange)))

                    {

                        // Initiate Resting, make bedroll and sleepy zz's

 

                        object oRestbedroll = CreateObject (OBJECT_TYPE_PLACEABLE, "plc_bedrolls", GetLocation (oPC), FALSE);

                        SetLocalObject (oPC, "o_PL_Bedrollrest", oRestbedroll);

                        effect eVis = EffectVisualEffect(VFX_IMP_SLEEP, VFX_IMP_BLIND_DEAF_M);

                        ApplyEffectToObject( DURATION_TYPE_TEMPORARY, eVis, oPC);

 

                        // delete 1 rest provision

 

                        nStacked = nStacked -1;

                        DestroyObject(oProvisions);

                        CreateItemOnObject("rations", oPC, nStacked);

 

                     }

 

                    else // Monsters too close to rest

                    {

                        AssignCommand (oPC, ClearAllActions());

                        FloatingTextStringOnCreature ("Their are monsters nearby!", oPC);

                    }

            }

    }

 

 

    // Resting Done

    if ((GetLastRestEventType() == REST_EVENTTYPE_REST_FINISHED || GetLastRestEventType() == REST_EVENTTYPE_REST_CANCELLED) && GetIsObjectValid(GetLocalObject (oPC, "o_PL_Bedrollrest")))

    {

        DestroyObject (GetLocalObject (oPC, "o_PL_Bedrollrest"), 0.0f);

        DeleteLocalObject (oPC, "o_PL_Bedrollrest");

 

 

 

    }

 

 

}

 



 

 

 

im trying to integate this script, to make a campfire placeable needed too


 



void CreateCampSite(object oPC){

    object oCampSite = CreateObject(OBJECT_TYPE_PLACEABLE,"restcampfire",Location(GetArea(oPC),GetPosition(oPC)+AngleToVector(GetFacing(oPC)),0.f));

    DelayCommand(0.1f,SetPlaceableIllumination(oCampSite, FALSE));

    DelayCommand(0.2f,RecomputeStaticLighting(GetArea(oPC)));

}

 

void main()

{

    object oPC = GetLastPCRested();

    int eRestEvent = GetLastRestEventType();

 

    object oCampSite;

    float oDist;

    //Change tags and/or add more checks for "free" rest areas

    if(GetTag(GetArea(oPC))=="InsideTent" || GetTag(GetArea(oPC))=="InnRoom"){

        //if you want them to bust out bedrolls or do something special, put it here

        return;

    }

    //for areas that need campsites...

    if(eRestEvent == REST_EVENTTYPE_REST_STARTED){

        oCampSite=GetNearestObjectByTag("RestCampfire",oPC);

        //must be within 5 feet of lit campfire

        if(!GetIsObjectValid(oCampSite) || GetDistanceBetween(oPC,oCampSite) > 5.f){

            //no campfire, check for invisable rest area

            oCampSite=GetNearestObjectByTag("RestArea",oPC);

            if(GetIsObjectValid(oCampSite) && GetDistanceBetween(oPC,oCampSite) <= 5.f){

                //free rest area near invisible object

                return;

            }

            //no close campsite

            object oCampSiteKit=GetItemPossessedBy(oPC,"CampsiteKit");

            if(GetIsObjectValid(oCampSiteKit)){

                //player builds campsite

                SendMessageToPC(oPC,"Preparing a camp site...");

                AssignCommand(oPC,ClearAllActions());

                AssignCommand(oPC,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0f,2.0f));

                DelayCommand(1.0f,CreateCampSite(oPC));

                DestroyObject(oCampSiteKit,1.0f);

            }else{

                //can't rest

                SendMessageToPC(oPC,"You must rest near a camp site.");

                AssignCommand(oPC,ClearAllActions());

            }

        }else if(!GetPlaceableIllumination(oCampSite)){

            //not lit...

                SendMessageToPC(oPC,"You must light the campfire first.");

                AssignCommand(oPC,ClearAllActions());

        }else{

            //rest

            SetLocalObject(oPC,"Campsite",oCampSite);

        }

    }else if(eRestEvent == REST_EVENTTYPE_REST_FINISHED){

        oCampSite=GetLocalObject(oPC,"Campsite");

        //must be within 5 feet of fire

        if(GetIsObjectValid(oCampSite) && GetDistanceBetween(oPC,oCampSite) <= 6.f){

            DestroyObject(oCampSite);

        }

    }

}


 

 

 



 



 


 


the plan is,(as far as i see it in my head) the player must put down a campfire to rest out in the field. once that is down they can rest, but only if they have a bedroll and rations.


 


i like the animations in these scripts, but if you guys know of one that does the same, then please tell me.



               
               

               
            

Legacy_Proleric

  • Hero Member
  • *****
  • Posts: 1750
  • Karma: +0/-0
Need help with scripting problem
« Reply #2 on: April 22, 2016, 08:42:43 am »


               Can you break the problem down for us a little?

There's a lot of code to read through there, with little information on the expected results, or on how the actual results differ.
               
               

               
            

Legacy_DeadeyeDevie

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Need help with scripting problem
« Reply #3 on: April 22, 2016, 09:15:44 am »


               Yes. The second code is one for a campfire placeable object that the player creates with an item in the inventory. Then on resting,  they need a bed roll and rations ( 1st big code).


Whenever I try and put them together, it comes out with compile errors, such as duplicate action instances or missing brackets. And I'm big enough to stare I have no clue where to put the brackets or fix the duplicates (it also breaks when I remove what they ask me too)!
               
               

               
            

Legacy_LoA_Tristan

  • Jr. Member
  • **
  • Posts: 64
  • Karma: +0/-0
Need help with scripting problem
« Reply #4 on: April 23, 2016, 12:17:27 am »


               I think you would need to lay some groundwork first to get help with the script. I have no idea where you are in this.

The second script looks useless of itself because it doesn't catch canceled rests. Provided you have all the resources set up in the toolset to implement the script, you can just walk around building campsites that will never go away, since the local object can be overwritten, possibly even set up blockades with them (a badass thing to do, but I am not sure if it's the intended purpose of the script).

Looks like the bulk of the work here is toolsetting. On the scripting side there needs to be a module heartbeat to decrement "nRestingCounterPC" on each PC, and a few scripts to implement the provisions etc. The OnRest event has to catch three eventualities.
 

REST_EVENTTYPE_REST_STARTED
REST_EVENTTYPE_REST_CANCELLED
REST_EVENTTYPE_REST_FINISHED


The first script seems OK for this, but you will have to decide whether you're the sort of person who can look at something and modify it to do exactly what you want, or whether you need to actually write from scratch to understand it - the heuristic approach.

You might want to check out two bioware resources for implementation of the rest items.

x0_skill_ctrap - the radial craft menu conversation, for assembling camping stuff out of raw material
x2_inc_compon - involved in the OnDeath event of placeables, doors, and certain creatures so they drop these raw materials (in the OC, it happens when your crafting skills are good)


               
               

               
            

Legacy_KMdS!

  • Sr. Member
  • ****
  • Posts: 364
  • Karma: +0/-0
Need help with scripting problem
« Reply #5 on: April 28, 2016, 05:41:02 am »


               

Hmmm.....I have a food system in place modified from the HCR project that sounds like what you are looking for.


 


Basically, it is an HTF, Hunger/Thirst/Fatigue, system that initiates and tracks a players hunger and thirst requiring a player to eat and or drink as required determined by time. Variables for modification of the time required before hunger and or thirst occurs can be set to .emulate climate, exertion, etc. Players can suffer negative effects or even die from hunger, thirst, diseased or poisoned of food or water. Intoxication is supported with encumbant effects upon abilities, even total blackouts. Thre are canteens that can be filled with whatever defined drinks you enable, water, alcohol, poison, etc.


 



Fest requires a bedroll, but does not require a campfire, though it could be implemented.


 


I have added the CNR foods to the system. You can add items to the system as well.


 


I use a MySQL database to track the HTF values. Without some persistent method of tracking the values will be reset every mod reset.


 


I can see about modifying and pulling it if you think it might be what your looking for.


 


Here is the main include file.


 


/*::////////////////////////////////////////////////////////////////////////////
//:: Name: KMdS PNP Hard Core Rule Set 1.0
//:: System: KMdS D&D 3nd ed Hunger Food and Thirst (KMdS HTF)
//:: FileName: HC_Inc_HTF
//:: Copyright: (c) 2004 Michael Careaga
//::////////////////////////////////////////////////////////////////////////////
 
    This is the heart of the HTF system.  All HTF related Constants and Functions
    are located here.  All functions are fully documented.  For info on using the
    system, look in About_KMdS_HTF.
 
 
    CREATING FOOD AND DRINKS FOR THE SYSTEM.
 
    To make a new food or drink item compatable with the KMdS HTF system, you will
    need to add it to the list in hc_htf_foods.  Look in that script for info on how
    to add foods to the system.
 
 
    FILES INCLUDED IN THIS SYSTEM
 
    hc_inc_htf              hc_inc_stageday
    hchtf_enterwater        hchtf_exitwater
    hchtf_fooddrinkp
 
 
    See hc_inc_htf.nss for more info on all scripts in the KMdS D&D 3nd ed Hunger
    Food and Thirst package.
 
//::////////////////////////////////////////////////////////////////////////////
//:: Created By: Kilr Mik d Spik
//:: Created On: 08/15/2004
//:://////////////////////////////////////////////////////////////////////////*/
 
//  ----------------------------------------------------------------------------
//  LIBRARIES
//  ----------------------------------------------------------------------------
 
#include "hc_inc_stageday"
#include "hcff_include"
 
 
//  ----------------------------------------------------------------------------
//  CONSTANTS
//  ----------------------------------------------------------------------------
 
//The initial levels of virtual hunger/thirst/fatigue Hitpoints
//that all PCs start with.
const int INITHUNGERLEVEL = 1800;
const int INITTHIRSTLEVEL = 720;
const int INITFATIGUELEVEL = 960;
 
//Amount the PC's current HTF levels can go above the initial levels
//This gives them a bit of a buffer zone before venturing into a place where
//food and water get scarce.
const float buffer = 0.2;
 
//The rate of "damage" to the above levels a PC takes every time
//the system performs an htf check.
//Note that these values can be modified with a multiplier based on the
//area the PC is in at the time the check is performed.
//See the function SetAreaConsumeRates in hc_inc_htf, and set it in the file
//hc_setareavars.
const int DEFHUNGERCONSUMERATE = 10;
const int DEFTHIRSTCONSUMERATE = 10;
const int DEFFATIGUECONSUMERATE = 10;
 
/* The following are the HTF values of food and drink.  The foods listed in
hc_htf_food refer to these values
 
"RICH", "NORM", and "POOR" indicate what quality of hunger satisfaction
a Food item gives to the PC (see values below). Those values are added
to the PC's current hunger level when the food is eaten. Likewise,
"HIGH", "MED", and "LOW" indicate the same for thirst levels for Drink items.
If quality is not specified in either case, the default is NORM and MED.
 
"Alcohol1" thru "Alcohol5" will produce alcoholic effects on a drink item.
The number indicates the level of intelligence loss. See the function
ApplyAlcoholEffectToPC.
 
"POISON1" thru "POISON5" on a Food or Drink Item will poison the PC.
"DISEASE1 thru "DISEASE5" on a Food or Drink Item will give the PC a disease.
POISON and DISEASE are mutually exclusive and DISEASE will override POISON.
You cannot stack effects either, only the highest one in number will be used.
Making an item poisoned or diseased will also nullify any positive effects
the item might have had so, dont even bother including them in the tag.
If you want to change the disease or poison types see the functions,
ApplyPoisonToPC and ApplyDiseaseToPC.
 
"ENERGY1", "ENERGY2", "ENERGY3" will add to the PC's current fatigue level HPs by the
amount specified. (for coffee-like food/drink items)
 
"HPBONUS1" thru "HPBONUS5" will add hit points to the PC of the amounts indicated
in the below variables. (use this wisely!)*/
 
// Food value constants
const int RICH = 450;
const int NORM = 300;
const int POOR = 150;
 
// Drink value constants
const int HIGH = 180;
const int MED = 120;
const int LOW = 60;
const int VERYLOW = 30;
const int NON = 0;
 
 
// Other food and drink value constants
const int ENERGY3 = 144;
const int ENERGY2 = 96;
const int ENERGY1 = 48;
const int HPBONUS5 = 5;
const int HPBONUS4 = 4;
const int HPBONUS3 = 3;
const int HPBONUS2 = 2;
const int HPBONUS1 = 1;
const int POISONTYPE5 = POISON_HUGE_SPIDER_VENOM;
const int POISONTYPE4 = POISON_LARGE_SPIDER_VENOM;
const int POISONTYPE3 = POISON_MEDIUM_SPIDER_VENOM;
const int POISONTYPE2 = POISON_SMALL_SPIDER_VENOM;
const int POISONTYPE1 = POISON_TINY_SPIDER_VENOM;
const int DISEASETYPE5 = DISEASE_BLINDING_SICKNESS;
const int DISEASETYPE4 = DISEASE_BURROW_MAGGOTS;
const int DISEASETYPE3 = DISEASE_FILTH_FEVER;
const int DISEASETYPE2 = DISEASE_RED_ACHE;
const int DISEASETYPE1 = DISEASE_SHAKES;
 
//Set this to 1 to allow automatic eating and drinking.
//Set it to 0 to force PCs to manually eat and drink all the time.
const int AUTOEATDRINK = 1;
 
//This only applies if AUTOEATDRINK = 1.
//Sets when automatic eating and drink is performed in relation to the current
//hunger and thirst levels of the PC.
//A value of 1 will auto eat/drink when PC is at 80% of maximum levels.
//A value of 2 will auto eat/drink when PC is at 60% of maximum levels.
//A value of 3 will auto eat/drink when PC is at 40% of maximum levels.
//A value of 4 will auto eat/drink when PC is at 20% of maximum levels.
const int AUTOEATDRINKRATE = 1;
 
//This determines at what percentage of the maximum hunger and thirst levels
//a PC is unable to rest becuase of hunger and/or thirst.
//The PC cannot rest if their current levels are below the given percentage.
const float RESTRESTRICTIONPERCENT = 0.6;
 
//The next two variables determines what base AC level will cause additonal fatigue
//loss and at what bonus multiplier the extra loss will occur at.
//(see DEFFATIGUECONSUMERATE above) Note that this multiplier will be
//stacked WITH any area based multiplier already in effect.
//For example if your Desert area has a Fatigue multiplier of 3, and the
//Default consume rate is 10, every fatigue check will result in a loss of
//fatigue leves by 3 * 10 on 30 points.  If the PC is wearing Armor with
//AC >= FATIGUEARMORPEN, then it would be 30 multiplied by the
//FATIGUEARMORPENMULTIPLIER as well. If that was equal to 1.5, in the example
//that PC would lose 30 * 1.5, or 45 fatigue level points per check.
//Thus a good lesson to PCs will be if the area environment makes you tired to
//begin with, dont make yourself extra tired by wearing heavy armor all the time.
const int FATIGUEARMORPEN = 6;
const float FATIGUEARMORPENMULTIPLIER = 1.5;
 
//Change the below value to increase or decrease the amount of changes the
//water canteen item can hold.
const int MAXCANTEENCHARGES = 5;
 
//Text string constants for thirst
const string TOOTHIRSTY0 = "You feel a little thirsty.";
const string TOOTHIRSTY1 = "You are very thirsty.";
const string TOOTHIRSTY2 = "Your throat is parched! You need something to drink!";
const string TOOTHIRSTY3 = "You are dehydrated and feel very faint.";
const string TOOTHIRSTY4 = "Water, must find water...";
 
//Text string constants for hunger
const string TOOHUNGRY0 = "You feel a little hungry.";
const string TOOHUNGRY1 = "You are very hungry.";
const string TOOHUNGRY2 = "You are famished! You need something to eat!";
const string TOOHUNGRY3 = "You are starving and feel very weak.";
const string TOOHUNGRY4 = "Wasting away, no food anywhere...";
 
//Text string constants for extreme hunger or thirst
const string THIRSTYMSG = "* looks parched *";
const string HUNGRYGROWL = "* stomach growls loudly *";
 
//Text string constants for drinking and eating
const string BURP = "*Burp.....Ahhhhhh*";
const string GULP = "*Gulp*";
const string GULPDRINK = "You gulp down the drink.";
 
//Text string constants for death by starvation
const string FORTSAVEVSSTARVATION ="Fortitute save succuess vs. death by starvation.";
const string DEATHBYSTARVATION ="You have starved to death.";
 
//Text string constants for death from thirst
const string FORTSAVEVSDEHYDRATION ="Fortitute save succuess vs. death by dehydration.";
const string DEATHBYDEHYDRATION ="You have died of dehydration.";
 
//Text string constants for fatige from hunger
const string LACKOFFOOD1 ="You have become fatigued from lack of eating!";
const string LACKOFFOOD2 ="You have become exhausted from  going so long without food!";
 
//Text string constants for fatigue from thirst
const string LACKOFWATER1 ="You have become fatigued from lack of water!";
const string LACKOFWATER2 ="You have become exhausted from  going so long without water!";
 
//Text string constants for having filled up on fod or water
const string STUFFED = "You manage to eat the food, but you are stuffed.";
const string FULLYHYDRATED = "You manage to finish off the drink, but are no longer thirsty.";
 
//Text string constants for consuming food or drink
const string CONSUMEITEM = "You consume the item.";
const string TAKEABITE = "You take a bite.";
const string TAKEADRINK = "You take a drink.";
 
//Text string constants for being to full of food and water to eat or drink
const string NOTHUNGRY = "You are too full to consume that.";
const string NOTTHIRSTY = "You are not thirsty enough to drink that.";
 
//Text string constants for searching for food or drink
const string SEARCHFOOD = "You rummage through your pack looking for something to eat.";
const string SEARCHDRINK = "You rummage through your pack looking for something to drink.";
const string FAILEDTOFINDCONSUMABLE = "You fail to find anything.";
const string DONOTCONSUME = "This looks foul and you decide not to consume it.";
 
//Text string constants for fatigue
const string TOOTIRED0 = "You feel a little tired.";
const string TOOTIRED1 = "You are getting sleepy.";
const string TOOTIRED2 = "You are very tired you need to rest!";
const string TOOTIRED3 = "You are so tired you can barely stand, you should rest now!";
const string TOOTIRED4 = "You are so exhausted you are in danger of collapsing where you stand.";
const string YAWN = "*yawns*";
const string NOTENOUGHREST1 = "You have become fatigued due to lack of rest.";
const string NOTENOUGHREST2 = "You have become exhausted due to lack of rest.";
 
//Text string constants for collapsing from exhaustion
const string FORTSAVEVSCOLLAPSE ="Fortitute save succuess vs. collapse from exhaustion.";
const string COLLAPSEFROMEXHAUSTION = "You have collapsed from exhaustion.";
 
//Text string constants for canteen use
const string EMPTYCANTEEN = "This canteen is empty, you should fill it from a source of water.";
const string CANTEENBADTARGET = "Target yourself to drink from the canteen, or a source of water to refill it.";
const string INVALIDWATERSOURCE = "That is not a valid source of water.";
const string FOULWATER = "That water was foul! You empty your canteen.";
const string EMPTYWATERSOURCE = "The container is empty!";
 
//Text string constants for other misc.
const string MOVECLOSERTOOBJ = "You need to move closer.";
const string NOWATERHERE = "There is no body of water in your immediate area that is adequate for consumption.";
const string CANTEENFULL = "Your canteen is already full.";
const string FILLCANTEEN = "You fill the canteen.";
const string CANTEENSPOT = "You could fill a canteen here.";
const string POISON = "The water looks poisoned.";
const string DISEASE="The water looks diseased.";
const string CANFILLCANTEEN="You may fill your canteen anywhere in the world you find water, whether it is drinkable is another matter.";
const string REFRESHING="The water looks very refreshing.";
 
//  ----------------------------------------------------------------------------
//  PROTOTYPES
//  ----------------------------------------------------------------------------
 
//This function is used by the SetAreaConsumeRates function to set an areas consume rates.
//Use a multiplier of 0 for default rates, and -1 to turn it off. Positive values multiply the
//consumption rate by the given value.
void SetAreaConsumeRateByVarName(object oArea, string VarName, float Multiplier, int DefRate);
 
//Use this function to set an area's consume rate based on the stage of day.  Stageofday may be
//set to 1 for DAWN, 2 for DUSK, 3 for NIGHT, default is 0 for DAY.  fHRMultiplier is for hunger,
//fTRMultiplier is for thirst, fFRMultiplier is for fatigue.  Set any of the multipliers 0 for
//default rates, -1 to turn it off, and a positive value to add the multiple to the base rate.
void SetAreaConsumeRates(object oArea, int stageofday, float fHRMultiplier, float fTRMultiplier, float fFRMultiplier);
 
//Use this function to set all consumtion rates for hunger, thirst and fatigue in an area for
//all stages of the day.  Use this function as an example of how to set consume rates by stage
//of day and consume rate modifier.  DayH = Day Hunger rate multiplier, DayT = Day Thirst rate
//multiplier, DayF= Day Fatigue rate multiplier.  Set to -1.0 to disable HTF in any area or set
//to any float above 0 to increase the default rate by whatever amount you decide, as an example
// a value of 1.0 would double the default rate, 2.0 would triple it, 3.0 would quadruple it.
void SetAllStagesAndHTFConsumeRates(object oArea, float DayH = 0.0, float DayT = 0.0, float DayF = 0.0, float DawnH = 0.0, float DawnT = 0.0, float DawnF = 0.0, float DuskH = 0.0, float DuskT = 0.0, float DuskF = 0.0, float NightH = 0.0, float NightT = 0.0, float NightF = 0.0);
 
//This function initializes a players HTF values if they are not found in the database storing them into
//the database.  If values for a PC are found in the database, nothing is done.
void InitPCHTFValues(object oPC);
 
//This Integer is used to determine if the PC is hungry = 1, thirsty = 2, hungry and thirsty = 3,
//or not hungry or thirsty = 0.
int IsPCVeryHungryOrThirsty(object oPC);
 
//Use this function to reset a PC's HTF levels to initial levels.
void ResetHTFLevels(object oPC);
 
//Use this to reset fatigue levels to starting values.
void ResetFatigueLevels(object oPC);
 
//Used by UseFoodOrDrinkItem Integer to set a PC's hunger level when "food" is consumed.
//This could also be used as an effect triggerd by anything a mod developer might be able to imagime.
void ApplyHungerBonus(string sItemTag, object oPC);
 
//Used by UseFoodOrDrinkItem Integer to apply an alcohol effect to a PC when alcohol is consumed.
//This could also be used as an effect triggerd by anything a mod developer might be able to imagine.
//The function also determines how long the effect lasts based on the strenght of the alcohol.
void ApplyAlcoholEffectToPC(string sItemTag, object oPC);
 
//Used by UseFoodOrDrinkItem Integer to set a PC's thirst level when "drink" is consumed.
//This could also be used as an effect triggerd by anything a mod developer might be able to imagime.
void ApplyThirstBonus(string sItemTag, object oPC);
 
//Used by UseFoodOrDrinkItem Integer to set a PC's fatigue level when certain "food or drink" is consumed.
//This could also be used as an effect triggerd by anything a mod developer might be able to imagime.
void ApplyEnergyBonus(string sItemTag, object oPC);
 
//Used by UseFoodOrDrinkItem Integer to heal various amounts of hp's on a PC when certain "food or drink" is consumed.
//This could also be used as an effect triggerd by anything a mod developer might be able to imagime.
void ApplyHPBonus(string sItemTag, object oPC);
 
//Used by UseFoodOrDrinkItem Integer to apply various poison effects on a PC when certain "food or drink" is consumed.
//This could also be used as an effect triggerd by anything a mod developer might be able to imagime.
void ApplyPoisonEffectToPC(object oPC, string sItemTag);
 
//Used by UseFoodOrDrinkItem Integer to apply various disease effects on a PC when certain "food or drink" is consumed.
//This could also be used as an effect triggerd by anything a mod developer might be able to imagime.
void ApplyDiseaseEffectToPC(object oPC, string sItemTag);
 
//Call this function to actually attempt to consume an item.  If "food" or "drink" is found the int will return 1
//and then call the apropriate sub function to apply the appropriate effect, otherwise the int returned is 0 and exits.
//ie ApplyHungerBonus, ApplyAlcoholEffectToPC, ApplyThirstBonus, ApplyEnergyBonus, ApplyHPBonus, ApplyPoisonEffectToPC
//and ApplyDiseaseEffectToPC.
int UseFoodOrDrinkItem(object oPC, object oItem, string sItemTag = "");
 
//This function is called by the UseWaterCanteen function on succesfull use of a water canteen.
void UseCanteenCharge(object oPC, object oCanteen);
 
//This function is called by the UseWaterCanteen function on succesfull use of a water canteen on a water source.
void ReFillCanteen(object oPC, object oCanteen, object oTarget, string sItemTag = "");
 
//This function is called on use of a water canteen to determine whether to refill, use to drink (and so use one charge)
void UseWaterCanteen(object oPC,object oCanteen, object oTarget, location loc);
 
//This function is called whenever a PC's hunger or thirst reaches specific levels based on switches in hc_inc_vars.
//It causes the PC to search for any food or drink in their inventory and consume it if found.
void DoAutoEatDrink(object oPC, string itemtype);
 
//This function is called by DoHungerChkOnPC and does a check on a player whenever a PC's hunger reaches specific levels
//based on switches in hc_inc_vars.  Should a player fail the check they DIE!
void DoDeathByStarvation(object oPC);
 
//This function is called by the PCHTFSystemChk function and does a check on a pc to determine which of the 5 hunger states
//the PC is at as well as applying damage to the initial hunger level int.  If a PC becomes extremely hungry their stage
//of fatigue will increase.
void DoHungerChkOnPC(object oPC);
 
//This function is called by DoThirstChkOnPC and does a check on a player whenever a PC's hunger reaches specific levels
//based on switches in hc_inc_vars.  Should a player fail the check they DIE!
void DoDeathByDehydration(object oPC);
 
//This function is called by the PCHTFSystemChk function and does a check on a pc to determine which of the 5 thirst states
//the PC is at as well as applying damage to the initial thirst level int.  If a PC becomes extremely thirsty their stage
//of fatigue will increase.
void DoThirstChkOnPC(object oPC);
 
//This function is called by the PCHTFSystemChk function and does a check on a pc to determine which of the 5 fatigue states
//the PC is at as well as applying damage to the initial fatigue level int.  As fatige stages increase STR and CON are
//decreased by a proportional amount for each stage.  If a PC should reach the 5th stage of fatigue the PC makes a check to
//see if they pass out from exhaustion.
void DoFatigueChkOnPC(object oPC);
 
//Use this function on a fixed timed loop to trigger a check of a PC's HTF levels and to apply whatever damage to the PC's
//initial HTF levels.
void PCHTFSystemChk();
 
// Applies the effects of fatigue to a PC, but only if they are not already fatigued or exhausted.
// Strength loss = 2, Dexterity loss = 2, Movement speed reduction of 60%.
// The effects can be removed by resting.
// Sends whatever message you select above the PC.  Default is no message.
void MakePlayerFatigued(object oPC, string message = "");
 
// Removes any effects of fatigue and applies the effects of exhaustion to a PC,
// but only if they are not already exhausted.
// Strength loss = 6, Dexterity loss = 6, Movement speed reduction of 80%.
// The effects can be removed by resting.
// Sends whatever message you select above the PC.  Default is no message.
void MakePlayerExhausted(object oPC, string message = "");
 
// Makes a player collapse from exhaustion and removes any ExtraordinaryEffect
// a player may have upon them.  The function applies temporary blindness and sleep effects.
// The effects are not dispellable.
// Sends whatever message you select above the PC.  Default is no message.
void MakePlayerCollapse(object oPC, string message = "");
 
// Applies effects from intoxication.
// Int IntLoss is the loss of intelligence a temporarily PC suffers.
// The default duration of the effect is ONE_HOUR_TO_FLOAT_SECONDS which can be set in the hc_inc_globals.nss script,
// or set whatever amount of time you want manually in the function.
// Sends whatever message you select above the PC.  Default is no message.
void MakePCDrunk(object oPC, int IntLoss, string message = "", float fDuration = ONE_HOUR_TO_FLOAT_SECONDS);
 
// Use this to retrieve an objects HTF food and drink values from the database.  If the value is not found,
// sItemOriginalTag is returned as a default value.  Besure to declare sItemOriginalTag equal to the objects tag.
string GetHTFFoodAndDrinkValues(string sItemOriginalTag);
 
// This is used by InitFoodValues to store a foods Hunger and Thirst quenching values into the database where
// they can be retrieved upon the comsumption of that food or drink.
void SetHTFFoodAndDrinkValues(string sTag, string sHTFValue);
 
// Use this function to initiate Food values for any edible foodstuff.  Add any food items you want to use as
// an edible or drinkable here.  Place a call to this function from the OnModuleLoad event for your module.
// You may use the same tag naming structure and apply it to placeable objects and triggers.  If you place
// the function hchtf_fooddrinkp into the placeable's OnUsed event, the PC will use the object as if he or had
// she consumed an item of the same tag type. (of course without actually consuming the placeable).  You could
// use this method to make things such as water fountains, etc.  Another possibility is to create a trigger
// around a body of water using the naming conventions above. Then be sure to add hchtf_enterwater to the
// trigger's OnEnter, and hchtf_exitwater on it OnExit events.  This will enable the PC to target their empty
// water canteen on the ground, and if they are standing inside the trigger, it will fill the canteen with the
// item type described by the trigger's tag.
void InitFoodValues();
 
//  ----------------------------------------------------------------------------
//  FUNCTIONS
//  ----------------------------------------------------------------------------
 
void SetAreaConsumeRateByVarName(object oArea, string VarName, float Multiplier, int DefRate)
{
    if (Multiplier < 0.0)
        SetLocalInt(oArea, VarName, -1);
    else if (Multiplier > 0.0)
        SetLocalInt(oArea, VarName, FloatToInt(DefRate * Multiplier));
}
 
void SetAreaConsumeRates(object oArea, int stageofday, float fHRMultiplier, float fTRMultiplier, float fFRMultiplier)
{
    string time_suffix = GetStageOfDaySuffix(stageofday);
    SetAreaConsumeRateByVarName(oArea, "HUNGERCONSUMERATE"  + time_suffix, fHRMultiplier, DEFHUNGERCONSUMERATE);
    SetAreaConsumeRateByVarName(oArea, "THIRSTCONSUMERATE"  + time_suffix, fTRMultiplier, DEFTHIRSTCONSUMERATE);
    SetAreaConsumeRateByVarName(oArea, "FATIGUECONSUMERATE" + time_suffix, fFRMultiplier, DEFFATIGUECONSUMERATE);
}
 
void SetAllStagesAndHTFConsumeRates(object oArea, float DayH = 0.0, float DayT = 0.0, float DayF = 0.0,
                                                  float DawnH = 0.0, float DawnT = 0.0, float DawnF = 0.0,
                                                  float DuskH = 0.0, float DuskT = 0.0, float DuskF = 0.0,
                                                  float NightH = 0.0, float NightT = 0.0, float NightF = 0.0)
{
    SetAreaConsumeRates(oArea,DAY,DayH,DayT,DayF);
    SetAreaConsumeRates(oArea,DAWN,DawnH,DawnT,DawnF);
    SetAreaConsumeRates(oArea,DUSK,DuskH,DuskT,DuskF);
    SetAreaConsumeRates(oArea,NIGHT,NightH,NightT,NightF);
}
 
void InitPCHTFValues(object oPC)
{
    //Get the players unique id# as set by FF-NWN
    string sId = GetLocalString(oPC, "PWId");
    if (sId == "" || !GetIsObjectValid(oPC))//Not a valid player.
        return;
    int iHtf = SQLExecAndFetchDirect("SELECT Hunger,Thirst,Fatigue FROM htf_values WHERE Id="+sId);
    if (iHtf != SQL_SUCCESS) // This player's HTF levels don't exist yet, set up the initial values.  Otherwise do nothing.
        SQLExecDirect("INSERT INTO htf_values (Id,Hunger,Thirst,Fatigue) VALUES("+
        sId+","+IntToString(INITHUNGERLEVEL)+","+IntToString(INITTHIRSTLEVEL)+","+IntToString(INITFATIGUELEVEL)+")");
}
 
int IsPCVeryHungryOrThirsty(object oPC)
{
    if (!GetIsPC(oPC)) return 0;
    string sId = GetLocalString(oPC, "PWId");
    int iHTlevel = SQLLocalExecAndFetchDirect("SELECT Hunger,Thirst FROM htf_values WHERE Id="+sId);
    float fHungerRating = SQLLocalEatDataFloat();
    float fThirstRating = SQLLocalEatDataFloat();
    if ((fHungerRating <= INITHUNGERLEVEL * RESTRESTRICTIONPERCENT)&&
    (fThirstRating <= INITTHIRSTLEVEL * RESTRESTRICTIONPERCENT)) return 3;
    if (fThirstRating <= INITTHIRSTLEVEL * RESTRESTRICTIONPERCENT) return 2;
    if (fHungerRating <= INITHUNGERLEVEL * RESTRESTRICTIONPERCENT) return 1;
    return 0;
}
 
void ResetHTFLevels(object oPC)
{
    if (!GetIsPC(oPC)) return ;
    string sId = GetLocalString(oPC, "PWId");
    if (!GetIsPC(oPC)) return;
        SQLExecDirect("UPDATE htf_values SET Hunger="+IntToString(INITHUNGERLEVEL)+
        ",Thirst="+IntToString(INITTHIRSTLEVEL)+", Fatigue="+IntToString(INITFATIGUELEVEL)+" WHERE Id="+sId);
 
}
 
void ResetFatigueLevels(object oPC)
{
    string sId = GetLocalString(oPC, "PWId");
    if (!GetIsPC(oPC)) return;
        SQLExecDirect("UPDATE htf_values SET Fatigue="+IntToString(INITFATIGUELEVEL)+" WHERE Id="+sId);
 
}
void ApplyHungerBonus(string sItemTag, object oPC)
{
    string sId = GetLocalString(oPC, "PWId");
    if (FindSubString(sItemTag,"FOOD") == -1)
        return;
    int oldlevel = SQLExecAndFetchSingleInt("SELECT Hunger FROM htf_values WHERE Id="+sId);
    int newlevel = oldlevel + NORM;
    if (FindSubString(sItemTag,"RICH") != -1)
        newlevel = oldlevel + RICH;
    else if (FindSubString(sItemTag,"POOR") != -1)
        newlevel = oldlevel + POOR;
 
    if (newlevel > FloatToInt(INITHUNGERLEVEL * (1.0 + buffer)))
    {
        newlevel = FloatToInt(INITHUNGERLEVEL * (1.0 + buffer));
        SendMessageToPC(oPC,STUFFED);
    }
    SQLExecDirect("UPDATE htf_values SET Hunger="+IntToString(newlevel)+" WHERE Id="+sId);
}
 
void ApplyAlcoholEffectToPC(string sItemTag, object oPC)
{
    if(GetTag(GetArea(oPC))!="TheFuguePlane"){
        int IntLoss, nSaveResult, i, nDuration;
 
        if (FindSubString(sItemTag,"ALCOHOL10")!=-1)
            IntLoss = 10;
        else if (FindSubString(sItemTag,"ALCOHOL5")!=-1)
            IntLoss = 5;
        else if (FindSubString(sItemTag,"ALCOHOL4")!=-1)
            IntLoss = 4;
        else if (FindSubString(sItemTag,"ALCOHOL3")!=-1)
            IntLoss = 3;
        else if (FindSubString(sItemTag,"ALCOHOL2")!=-1)
            IntLoss = 2;
        else
            IntLoss = 1;
 
        nSaveResult = FortitudeSave(oPC, 12+(IntLoss*2), SAVING_THROW_TYPE_POISON);
        if(!nSaveResult)
        {
            nDuration++;
            i=1;
            do
            {
                 nSaveResult = FortitudeSave(oPC, 12-i+(IntLoss*2), SAVING_THROW_TYPE_POISON);
                 i++;
                 if(!nSaveResult)
                    nDuration++;
            } while (!nSaveResult);
            SetLocalInt(oPC, "DrunkLevel", nDuration + GetLocalInt(oPC, "DrunkLevel"));
            MakePCDrunk(oPC,IntLoss,BURP,IntToFloat(nDuration)* ONE_HOUR_TO_FLOAT_SECONDS);
        }
        else FloatingTextStringOnCreature(BURP, oPC, FALSE);
    }
}
 
void ApplyThirstBonus(string sItemTag, object oPC)
{
    string sId = GetLocalString(oPC, "PWId");
    if (FindSubString(sItemTag,"DRINK") == -1)
        return;
    if (FindSubString(sItemTag,"ALCOHOL") != -1)
        ApplyAlcoholEffectToPC(sItemTag, oPC);
    int oldlevel = SQLExecAndFetchSingleInt("SELECT Thirst FROM htf_values WHERE Id="+sId);
    int newlevel = oldlevel + NON;
    if (FindSubString(sItemTag,"HIGH") != -1)
        newlevel = oldlevel + HIGH;
    else if (FindSubString(sItemTag,"MED") != -1)
        newlevel = oldlevel + MED;
    else if (FindSubString(sItemTag,"LOW") != -1)
        newlevel = oldlevel + LOW;
    else if (FindSubString(sItemTag,"VERYLOW") != -1)
        newlevel = oldlevel + VERYLOW;
    if (newlevel > FloatToInt(INITTHIRSTLEVEL * (1.0 + buffer))) {
        newlevel = FloatToInt(INITTHIRSTLEVEL * (1.0 + buffer));
        SendMessageToPC(oPC,FULLYHYDRATED);
    }
    SQLExecDirect("UPDATE htf_values SET Thirst="+IntToString(newlevel)+" WHERE Id="+sId);
}
 
void ApplyEnergyBonus(string sItemTag, object oPC)
{
    string sId = GetLocalString(oPC, "PWId");
    int oldlevel = SQLExecAndFetchSingleInt("SELECT Fatigue FROM htf_values WHERE Id="+sId);
    int newlevel = oldlevel;
    if (FindSubString(sItemTag,"ENERGY3") != -1)
        newlevel = oldlevel + ENERGY3;
    else if (FindSubString(sItemTag,"ENERGY2") != -1)
        newlevel = oldlevel + ENERGY2;
    else if (FindSubString(sItemTag,"ENERGY1") != -1)
        newlevel = oldlevel + ENERGY1;
    if (newlevel > INITFATIGUELEVEL)
        newlevel = INITFATIGUELEVEL;
    if (newlevel > oldlevel)
        SQLExecDirect("UPDATE htf_values SET Fatigue="+IntToString(newlevel)+" WHERE Id="+sId);
}
 
void ApplyHPBonus(string sItemTag, object oPC)
{
    int HPBONUS = 0;
    if (FindSubString(sItemTag,"HPBONUS5") != -1)
        HPBONUS = HPBONUS5;
    else if (FindSubString(sItemTag,"HPBONUS4") != -1)
        HPBONUS = HPBONUS4;
    else if (FindSubString(sItemTag,"HPBONUS3") != -1)
        HPBONUS = HPBONUS3;
    else if (FindSubString(sItemTag,"HPBONUS2") != -1)
        HPBONUS = HPBONUS2;
    else if (FindSubString(sItemTag,"HPBONUS1") != -1)
        HPBONUS = HPBONUS1;
    if (HPBONUS > 0) {
        effect eVis = EffectVisualEffect(VFX_IMP_HEALING_S);
        effect eHeal = EffectHeal(HPBONUS);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oPC);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);
    }
}
 
void ApplyPoisonEffectToPC(object oPC, string sItemTag)
{
    int poisontype;
    if (FindSubString(sItemTag,"POISON5")!=-1)
        poisontype = POISONTYPE5;
    else if (FindSubString(sItemTag,"POISON4")!=-1)
        poisontype = POISONTYPE4;
    else if (FindSubString(sItemTag,"POISON3")!=-1)
        poisontype = POISONTYPE3;
    else if (FindSubString(sItemTag,"POISON2")!=-1)
        poisontype = POISONTYPE2;
    else
        poisontype = POISONTYPE1;
 
    effect ePoison = EffectPoison(poisontype);
    effect eVis = EffectVisualEffect(VFX_IMP_POISON_S);
    ApplyEffectToObject(DURATION_TYPE_INSTANT, ePoison, oPC);
    ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);
}
 
void ApplyDiseaseEffectToPC(object oPC, string sItemTag)
{
    int diseasetype;
    if (FindSubString(sItemTag,"DISEASE5")!=-1)
        diseasetype = DISEASETYPE5;
    else if (FindSubString(sItemTag,"DISEASE4")!=-1)
        diseasetype = DISEASETYPE4;
    else if (FindSubString(sItemTag,"DISEASE3")!=-1)
        diseasetype = DISEASETYPE3;
    else if (FindSubString(sItemTag,"DISEASE2")!=-1)
        diseasetype = DISEASETYPE2;
    else
        diseasetype = DISEASETYPE1;
    effect eDisease = EffectDisease(diseasetype);
    effect eVis = EffectVisualEffect(VFX_IMP_DISEASE_S);
    ApplyEffectToObject(DURATION_TYPE_INSTANT, eDisease, oPC);
    ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);
}
 
int UseFoodOrDrinkItem(object oPC, object oItem, string sItemTag = "")
{
    string sId = GetLocalString(oPC, "PWId");
    if (oItem != OBJECT_INVALID)
        sItemTag = GetHTFFoodAndDrinkValues(GetTag(oItem));
    sItemTag = GetStringUpperCase(sItemTag);
    int iPOISON = FindSubString(sItemTag,"POISON") != -1;
    int iDISEASE = FindSubString(sItemTag,"DISEASE") != -1;
    int isFood = FindSubString(sItemTag,"FOOD") != -1;
    int isDrink = FindSubString(sItemTag,"DRINK") != -1;
    int bIsAlcohol = FindSubString(sItemTag,"ALCOHOL") != -1;
 
    if (!iPOISON && !iDISEASE)
    {
        int htlevels = SQLLocalExecAndFetchDirect("SELECT Hunger,Thirst FROM htf_values WHERE Id="+sId);
        if (htlevels = SQL_SUCCESS)
        {
 
            int hlevel = SQLLocalEatDataInt();
            int tlevel = SQLLocalEatDataInt();
            if (isDrink && isFood)
            {
                if ((hlevel == FloatToInt(INITHUNGERLEVEL * (1.0 + buffer))) &&
                (tlevel == FloatToInt(INITTHIRSTLEVEL * (1.0 + buffer))))
                {
                    SendMessageToPC(oPC,NOTHUNGRY);
                    return 0;
                }
                else{
                    AssignCommand(oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
                    ApplyHungerBonus(sItemTag, oPC);
                    ApplyThirstBonus(sItemTag, oPC);
                    ApplyEnergyBonus(sItemTag, oPC);
                    ApplyHPBonus(sItemTag, oPC);
                }
            }
            else if (isFood)
            {
                if (hlevel == FloatToInt(INITHUNGERLEVEL * (1.0 + buffer)))
                {
                    SendMessageToPC(oPC,NOTHUNGRY);
                    return 0;
                }
                else{
                    ApplyHungerBonus(sItemTag, oPC);
                    ApplyEnergyBonus(sItemTag, oPC);
                    ApplyHPBonus(sItemTag, oPC);
                }
            }
            else if (isDrink)
            {
                if (tlevel == FloatToInt(INITTHIRSTLEVEL * (1.0 + buffer)))
                {
                    if (bIsAlcohol){
                        AssignCommand(oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
                        ApplyAlcoholEffectToPC(sItemTag, oPC);
                    }
                    else{
                        SendMessageToPC(oPC,NOTTHIRSTY);
                        return 0;
                    }
                }
                else{
                    AssignCommand(oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
                    ApplyThirstBonus(sItemTag, oPC);
                    ApplyEnergyBonus(sItemTag, oPC);
                    ApplyHPBonus(sItemTag, oPC);
                }
            }
            else
                return 0;
            if (oItem != OBJECT_INVALID)
            {
                int nStackCount = GetItemStackSize(oItem);
                if(nStackCount < 2)
                    DestroyObject(oItem);
            }
            if (FindSubString(sItemTag,"FOOD") != -1) SendMessageToPC(oPC,TAKEABITE);
            else if (FindSubString(sItemTag,"DRINK") != -1) SendMessageToPC(oPC,TAKEADRINK);
        }
    }
    else if (isFood || isDrink)
    {
        if(GetLevelByClass(CLASS_TYPE_RANGER,oPC)||GetLevelByClass(CLASS_TYPE_DRUID,oPC))
        {
            SendMessageToPC(oPC,DONOTCONSUME);
            return -1;
        }
        if (!iDISEASE)
        {
            ApplyPoisonEffectToPC(oPC, sItemTag);
            if(isDrink)
                AssignCommand(oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
        }
        else
        {
            ApplyDiseaseEffectToPC(oPC, sItemTag);
            if(isDrink)
                AssignCommand(oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
        }
        if (oItem != OBJECT_INVALID)
            DestroyObject(oItem);
        return -1;
    }
    else
        return 0;
 
    return 1;
}
 
void UseCanteenCharge(object oPC, object oCanteen)
{
    string srctag = GetLocalString(oCanteen,"SRCTAG");
    srctag = GetHTFFoodAndDrinkValues(srctag);
 
    int charges = GetLocalInt(oCanteen,"CHARGES");
    int usecharge = UseFoodOrDrinkItem(oPC,OBJECT_INVALID,srctag);
    if (usecharge == 1)
    {
        SetLocalInt(oCanteen,"CHARGES",charges - 1);
        DelayCommand(1.5,FloatingTextStringOnCreature(GULP, oPC));
    }
    else if (usecharge == -1)
    {
        AssignCommand(oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK));
        SendMessageToPC(oPC,FOULWATER);
        SetLocalInt(oCanteen,"CHARGES",0);
        SetLocalString(oCanteen,"SRCTAG","");
    }
    else if (FindSubString(GetStringUpperCase(srctag),"DRINK")==-1)
    {
        SendMessageToPC(oPC, "Invalid water source tag '" + srctag + "' assigned to canteen, inform DM");
        SendMessageToPC(oPC, "Resetting Canteen.");
        SetLocalInt(oCanteen,"CHARGES",0);
        SetLocalString(oCanteen,"SRCTAG","");
    }
}
 
void ReFillCanteen(object oPC, object oCanteen, object oTarget, string sItemTag = "")
{
    int charges = GetLocalInt(oCanteen,"CHARGES");
    if (charges == MAXCANTEENCHARGES)
    {
        SendMessageToPC(oPC,CANTEENFULL);
        return;
    }
    if (oTarget != OBJECT_INVALID)
    {
        sItemTag = GetTag(oTarget);
        if (GetDistanceBetween(oPC,oTarget) > 3.0)
        {
            SendMessageToPC(oPC,MOVECLOSERTOOBJ);
            return;
        }
    }
    else
        AssignCommand(oPC,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,3.0));
 
    SetLocalInt(oCanteen,"CHARGES",MAXCANTEENCHARGES);
    SetLocalString(oCanteen,"SRCTAG",sItemTag);
    SendMessageToPC(oPC,FILLCANTEEN);
}
 
void UseWaterCanteen(object oPC,object oCanteen, object oTarget, location loc)
{
    int Charges = GetLocalInt(oCanteen,"CHARGES");
    string srctag = GetLocalString(oCanteen,"SRCTAG");
 
    if (oTarget==OBJECT_INVALID)
    {
        if (GetDistanceBetweenLocations(loc,GetLocation(oPC)) > 3.0)
            SendMessageToPC(oPC,MOVECLOSERTOOBJ);
        else
        {
            string watersource = GetLocalString(oPC,"WATERSOURCE");
            if (FindSubString(GetStringUpperCase(watersource),"DRINK")==-1)
                SendMessageToPC(oPC,NOWATERHERE);
            else
                ReFillCanteen(oPC,oCanteen,OBJECT_INVALID,watersource);
        }
    }
    else
    {
        if (GetObjectType(oTarget)==OBJECT_TYPE_CREATURE)
        {
            if (oTarget==oPC)
            {
                if (Charges)
                    UseCanteenCharge(oPC,oCanteen);
                else
                    SendMessageToPC(oPC,EMPTYCANTEEN);
            }
            else
                SendMessageToPC(oPC,CANTEENBADTARGET);
        }
        if (GetObjectType(oTarget)==OBJECT_TYPE_PLACEABLE)
        {
            int nDrinksLeft = GetLocalInt(oTarget,"Charges");
            if (FindSubString(GetStringUpperCase(GetHTFFoodAndDrinkValues(GetTag(oTarget))),"DRINK")!=-1)
            {
                if(nDrinksLeft >= 1)
                {
                    if(srctag==GetTag(oTarget))
                        SetLocalInt(oTarget,"Charges",nDrinksLeft - Charges);
                    else
                    {
                        SetLocalInt(oTarget,"Charges",nDrinksLeft - MAXCANTEENCHARGES);
                        SetLocalInt(oCanteen,"CHARGES",0);
                    }
                    ReFillCanteen(oPC,oCanteen,oTarget);
                }
                else
                    SendMessageToPC(oPC,EMPTYWATERSOURCE);
            }
            else
                SendMessageToPC(oPC,INVALIDWATERSOURCE);
        }
    }
}
 
void DoAutoEatDrink(object oPC, string itemtype)
{
    object oEquip = GetFirstItemInInventory(oPC);
    itemtype = GetStringUpperCase(itemtype);
    if (itemtype == "FOOD")
        SendMessageToPC(oPC,SEARCHFOOD);
 
    if (itemtype == "DRINK")
        SendMessageToPC(oPC,SEARCHDRINK);
    while(GetIsObjectValid(oEquip))
    {
        if ((FindSubString(GetStringUpperCase(GetHTFFoodAndDrinkValues(GetTag(oEquip))),
        itemtype)!= -1) || (itemtype == "DRINK" && (GetTag(oEquip)) == "WaterCanteen" && GetLocalInt
        (oEquip,"CHARGES") > 0))
            break;
        oEquip = GetNextItemInInventory(oPC);
    }
    int founditem = 0;
    if (GetIsObjectValid(oEquip)){
        if (GetTag(oEquip)!="WaterCanteen")
            founditem = UseFoodOrDrinkItem(oPC, oEquip);
        else {
            if (GetLocalInt(oEquip,"CHARGES") > 0){
                UseCanteenCharge(oPC, oEquip);
                founditem = TRUE;
            }
        }
    }
    if (!founditem)
        SendMessageToPC(oPC,FAILEDTOFINDCONSUMABLE);
}
 
void DoDeathByStarvation(object oPC)
{
    string sId = GetLocalString(oPC, "PWId");
    int iHP = GetCurrentHitPoints(oPC);
    effect eKillPC = EffectDamage(iHP + 11);
    ApplyEffectToObject(DURATION_TYPE_INSTANT,eKillPC,oPC);
    SQLExecDirect("DELETE from pcdata WHERE VarName='STARVATIONSAVES' AND Id="+sId);
    ResetHTFLevels(oPC);
    SendMessageToPC(oPC, DEATHBYSTARVATION);
}
 
void DoHungerChkOnPC(object oPC)
{
    if (!GetIsPC(oPC)) return;
    string sId = GetLocalString(oPC, "PWId");
    int consumerate = GetLocalInt(GetArea(oPC),"HUNGERCONSUMERATE" + GetStageOfDaySuffix(GetStageOfDay()));
    if (consumerate==0) consumerate = DEFHUNGERCONSUMERATE;
    if (consumerate < 0) return;
 
    int oldlevel = SQLExecAndFetchSingleInt("SELECT Hunger FROM htf_values WHERE Id="+sId);
    int newlevel = oldlevel - consumerate;
    if (newlevel < 1) newlevel = 1;
 
    SQLExecDirect("UPDATE htf_values SET Hunger="+IntToString(newlevel)+" WHERE Id="+sId);
    if ((IntToFloat(newlevel) <= (INITHUNGERLEVEL*0.8)) && (IntToFloat(newlevel) > INITHUNGERLEVEL*0.6)){
        SendMessageToPC(oPC, TOOHUNGRY0);
        if (AUTOEATDRINK && (AUTOEATDRINKRATE == 1))
            DoAutoEatDrink(oPC,"Food");
    }
    if ((IntToFloat(newlevel) <= (INITHUNGERLEVEL*0.6)) && (IntToFloat(newlevel) > INITHUNGERLEVEL*0.4)){
        FloatingTextStringOnCreature (HUNGRYGROWL, oPC);
        SendMessageToPC(oPC, TOOHUNGRY1);
        if (AUTOEATDRINK && (AUTOEATDRINKRATE <= 2))
            DoAutoEatDrink(oPC,"Food");
    }
    if ((IntToFloat(newlevel) <= (INITHUNGERLEVEL*0.4)) && (IntToFloat(newlevel) > INITHUNGERLEVEL*0.2)) {
        FloatingTextStringOnCreature (HUNGRYGROWL, oPC);
        SendMessageToPC(oPC, TOOHUNGRY2);
        if (AUTOEATDRINK && (AUTOEATDRINKRATE <= 3))
            DoAutoEatDrink(oPC,"Food");
    }
    if ((IntToFloat(newlevel) <= (INITHUNGERLEVEL*0.2)) && (newlevel > 1)) {
        FloatingTextStringOnCreature (HUNGRYGROWL, oPC);
        SendMessageToPC(oPC, TOOHUNGRY3);
        MakePlayerFatigued(oPC, LACKOFFOOD1);
        if (AUTOEATDRINK)
            DoAutoEatDrink(oPC,"Food");
    }
    if (newlevel == 1) {
        FloatingTextStringOnCreature (HUNGRYGROWL, oPC);
        SendMessageToPC(oPC, TOOHUNGRY4);
        int iStarvationSaves = SQLExecAndFetchSingleInt("SELECT Value FROM pcdata WHERE Id="+
        sId+" AND VarName='STARVATIONSAVES'");
        if (iStarvationSaves!=SQL_SUCCESS)
            SQLExecDirect("INSERT INTO pcdata (VarName,Id,Value) VALUES ('STARVATIONSAVES',"+sId+",0)");
        int iFortSave = FortitudeSave(oPC,iStarvationSaves);
        MakePlayerExhausted(oPC,LACKOFFOOD2);
        if (iFortSave) {
            SendMessageToPC(oPC, FORTSAVEVSSTARVATION);
            SQLExecDirect("UPDATE pcdata SET VarName='STARVATIONSAVES',Value="+IntToString(iStarvationSaves + 5)+
            " WHERE Id="+sId);
            if (AUTOEATDRINK)
                DoAutoEatDrink(oPC,"Food");
        }
        else
           DoDeathByStarvation(oPC);
    }
}
 
void DoDeathByDehydration(object oPC)
{
    int iHP = GetCurrentHitPoints(oPC);
    string sId = GetLocalString(oPC, "PWId");
    effect eKillPC = EffectDamage(iHP + 11);
    ApplyEffectToObject(DURATION_TYPE_INSTANT,eKillPC,oPC);
    SQLExecDirect("DELETE from pcdata WHERE VarName='DEHYDRATIONSAVES' AND Id="+sId);
    ResetHTFLevels(oPC);
    SendMessageToPC(oPC, DEATHBYDEHYDRATION);
}
 
void DoThirstChkOnPC(object oPC)
{
    if (!GetIsPC(oPC)) return;
    string sId = GetLocalString(oPC, "PWId");
    int consumerate = GetLocalInt(GetArea(oPC),"THIRSTCONSUMERATE" + GetStageOfDaySuffix(GetStageOfDay()));
    if (consumerate==0) consumerate = DEFTHIRSTCONSUMERATE;
    if (consumerate < 0) return;
 
    int oldlevel = SQLExecAndFetchSingleInt("SELECT Thirst FROM htf_values WHERE Id="+sId);
    int newlevel = oldlevel - consumerate;
    if (newlevel < 1) newlevel = 1;
 
    SQLExecDirect("UPDATE htf_values SET Thirst="+IntToString(newlevel)+" WHERE Id="+sId);
    if ((IntToFloat(newlevel) <= (INITTHIRSTLEVEL*0.8)) && (IntToFloat(newlevel) > INITTHIRSTLEVEL*0.6)) {
        SendMessageToPC(oPC, TOOTHIRSTY0);
        if (AUTOEATDRINK && (AUTOEATDRINKRATE == 1))
            DoAutoEatDrink(oPC,"Drink");
    }
    if ((IntToFloat(newlevel) <= (INITTHIRSTLEVEL*0.6)) && (IntToFloat(newlevel) > INITTHIRSTLEVEL*0.4)) {
        SendMessageToPC(oPC, TOOTHIRSTY1);
        if (AUTOEATDRINK && (AUTOEATDRINKRATE <= 2))
            DoAutoEatDrink(oPC,"Drink");
    }
    if ((IntToFloat(newlevel) <= (INITTHIRSTLEVEL*0.4)) && (IntToFloat(newlevel) > INITTHIRSTLEVEL*0.2)) {
        FloatingTextStringOnCreature (THIRSTYMSG, oPC);
        SendMessageToPC(oPC, TOOTHIRSTY2);
        if (AUTOEATDRINK && (AUTOEATDRINKRATE <= 3))
            DoAutoEatDrink(oPC,"Drink");
    }
    if ((IntToFloat(newlevel) <= (INITTHIRSTLEVEL*0.2)) && (newlevel > 1)) {
        FloatingTextStringOnCreature (THIRSTYMSG, oPC);
        SendMessageToPC(oPC, TOOTHIRSTY3);
        MakePlayerFatigued(oPC, LACKOFWATER1);
        if (AUTOEATDRINK)
            DoAutoEatDrink(oPC,"Drink");
    }
    if (newlevel == 1) {
        FloatingTextStringOnCreature (THIRSTYMSG, oPC);
        SendMessageToPC(oPC, TOOTHIRSTY4);
        int iDehydrationSaves = SQLExecAndFetchSingleInt("SELECT Value FROM pcdata WHERE Id="+
        sId+" AND VarName='DEHYDRATIONSAVES'");
        if (iDehydrationSaves!=SQL_SUCCESS)
            SQLExecDirect("INSERT INTO pcdata (VarName,Id,Value) VALUES ('DEHYDRATIONSAVES',"+sId+",0)");
        int iFortSave = FortitudeSave(oPC,iDehydrationSaves);
        MakePlayerExhausted(oPC,LACKOFWATER2);
        if (iFortSave) {
            SendMessageToPC(oPC, FORTSAVEVSDEHYDRATION);
            SQLExecDirect("UPDATE pcdata SET VarName='DEHYDRATIONSAVES',Value="+IntToString(iDehydrationSaves +
            5)+" WHERE Id="+sId);
            if (AUTOEATDRINK)
                DoAutoEatDrink(oPC,"Drink");
        }
        else
           DoDeathByDehydration(oPC);
    }
}
 
void DoFatigueChkOnPC(object oPC)
{
    if (!GetIsPC(oPC)) return;
    string sId = GetLocalString(oPC, "PWId");
    int consumerate = GetLocalInt(GetArea(oPC),"FATIGUECONSUMERATE" + GetStageOfDaySuffix(GetStageOfDay()));
    if (consumerate==0) consumerate = DEFFATIGUECONSUMERATE;
    if (consumerate < 0) return;
 
    object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC);
    if (GetItemACValue(oArmor) >= FATIGUEARMORPEN)
        consumerate  = FloatToInt(consumerate * FATIGUEARMORPENMULTIPLIER);
 
 
    int oldlevel = SQLExecAndFetchSingleInt("SELECT Fatigue FROM htf_values WHERE Id="+sId);
    int newlevel = oldlevel - consumerate;
    if (newlevel < 1) newlevel = 1;
 
    SQLExecDirect("UPDATE htf_values SET Fatigue="+IntToString(newlevel)+" WHERE Id="+sId);
    if ((IntToFloat(newlevel) <= (INITFATIGUELEVEL*0.8)) && (IntToFloat(newlevel) > INITFATIGUELEVEL*0.6))
        SendMessageToPC(oPC, TOOTIRED0);
    if ((IntToFloat(newlevel) <= (INITFATIGUELEVEL*0.6)) && (IntToFloat(newlevel) > INITFATIGUELEVEL*0.4)) {
        FloatingTextStringOnCreature (YAWN, oPC);
        SendMessageToPC(oPC, TOOTIRED1);
        AssignCommand (oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_BORED));
    }
    if ((IntToFloat(newlevel) <= (INITFATIGUELEVEL*0.4)) && (IntToFloat(newlevel) > INITFATIGUELEVEL*0.2)) {
        FloatingTextStringOnCreature (YAWN, oPC);
        SendMessageToPC(oPC, TOOTIRED2);
        AssignCommand (oPC,ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_TIRED));
    }
    if ((IntToFloat(newlevel) <= (INITFATIGUELEVEL*0.2)) && (newlevel > 1)) {
        SendMessageToPC(oPC, TOOTIRED3);
        AssignCommand (oPC,ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_TIRED));
        AssignCommand (oPC,PlayVoiceChat(VOICE_CHAT_REST,oPC));
        MakePlayerFatigued(oPC, NOTENOUGHREST1);
    }
    if (newlevel == 1) {
        SendMessageToPC(oPC, TOOTIRED4);
        int iCollapseSaves = SQLExecAndFetchSingleInt("SELECT Value FROM pcdata WHERE Id="+
        sId+" AND VarName='FATIGUECOLLAPSESAVES'");
        if (iCollapseSaves < 1)
            KMdS_SetPCPersistentStringInternal(oPC, "FATIGUECOLLAPSESAVES", "0");
        int iFortSave = FortitudeSave(oPC,iCollapseSaves);
        MakePlayerExhausted(oPC,NOTENOUGHREST2);
        if (iFortSave) {
            SendMessageToPC(oPC, FORTSAVEVSCOLLAPSE);
            KMdS_SetPCPersistentStringInternal(oPC, "FATIGUECOLLAPSESAVES", IntToString(iCollapseSaves+5));
            AssignCommand (oPC,ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_TIRED));
            AssignCommand (oPC,PlayVoiceChat(VOICE_CHAT_REST,oPC));
        }
        else {
            MakePlayerCollapse(oPC,COLLAPSEFROMEXHAUSTION);
            KMdS_SetPCPersistentStringInternal(oPC, "FATIGUECOLLAPSESAVES", "0");
            SQLExecDirect("UPDATE htf_values SET Fatigue="+IntToString(FloatToInt(INITFATIGUELEVEL*0.25))+" WHERE Id="+sId);
        }
    }
}
 
void PCHTFSystemChk()
{
    if (GetIsPC(OBJECT_SELF))
    {
        if (!GetIsDM(OBJECT_SELF) && !GetIsDead(OBJECT_SELF))
        {
            if (!GetLocalInt(OBJECT_SELF,"DYING") || !GetLocalInt(OBJECT_SELF, "CLEAR_IOUN"))
            {
                DoHungerChkOnPC(OBJECT_SELF);
                DoThirstChkOnPC(OBJECT_SELF);
                DoFatigueChkOnPC(OBJECT_SELF);
            }
        }
    }
}
 
object HTFEffectCreator(string sTag = "HTF")
{
    object oHTFEffectCreator = GetLocalObject(GetModule(), sTag);
    if(oHTFEffectCreator == OBJECT_INVALID)
    {
        oHTFEffectCreator = GetObjectByTag(sTag);
        SetLocalObject(GetModule(), sTag, oHTFEffectCreator);
    }
    return oHTFEffectCreator;
}
 
void MakePlayerFatigued(object oPC, string message = "")
{
    if (!GetIsPC(oPC))
        return;
 
    int bFatigued = GetLocalInt(oPC, "bFatigued");
    int bExhausted = GetLocalInt(oPC, "bExhausted");
    if (bFatigued || bExhausted)
        return;
 
    SetLocalInt(oPC,"bFatigued",TRUE);
    object oHTFEffectCreator = HTFEffectCreator();
    SetLocalObject(oHTFEffectCreator, "PC", oPC);
    ExecuteScript("fatigue_player", oHTFEffectCreator);
 
    if (message!="") FloatingTextStringOnCreature(message, oPC, FALSE);
 
}
 
void MakePlayerExhausted(object oPC, string message = "")
{
    if (!GetIsPC(oPC))
        return;
    object oHTFEffectCreator = HTFEffectCreator();
    int bFatigued = GetLocalInt(oPC, "bFatigued");
    int bExhausted = GetLocalInt(oPC, "bExhausted");
    if (bExhausted)
        return;
 
    else if (bFatigued)
    {
 
        effect eLoop=GetFirstEffect(oPC);
        while (GetIsEffectValid(eLoop))
        {
            if(GetEffectCreator(eLoop) == oHTFEffectCreator &&
              (GetEffectType(eLoop) == EFFECT_TYPE_ABILITY_DECREASE ||
               GetEffectType(eLoop) == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE) &&
                GetEffectDurationType(eLoop) == DURATION_TYPE_PERMANENT
                )
                 RemoveEffect(oPC, eLoop);
            eLoop=GetNextEffect(oPC);
        }
        SetLocalInt(oPC,"bFatigued",FALSE);
    }
 
    SetLocalInt(oPC,"bExhausted",TRUE);
    SetLocalObject(oHTFEffectCreator, "PC", oPC);
    ExecuteScript("fatigue_player", oHTFEffectCreator);
    if (message!="") FloatingTextStringOnCreature( message, oPC, FALSE);
 
}
 
void MakePlayerCollapse(object oPC, string message = "")
{
    if (!GetIsPC(oPC))
        return;
 
    effect eSnore = EffectVisualEffect(VFX_IMP_SLEEP);
    effect eBlind =  SupernaturalEffect(EffectBlindness());
    effect eCollapse = SupernaturalEffect(EffectSleep());
 
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCollapse, oPC, 30.0);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSnore, oPC, 7.0);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBlind, oPC, 29.0);
 
    DelayCommand(7.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSnore, oPC, 7.0));
 
    if (message!="") FloatingTextStringOnCreature(message, oPC, FALSE);
}
 
void MakePCDrunk(object oPC, int IntLoss, string message = "", float fDuration = ONE_HOUR_TO_FLOAT_SECONDS)
{
    if (!GetIsPC(oPC))
        return;
 
    if (Random(100) + 1 < 40)
        AssignCommand(oPC, ActionPlayAnimation(ANIMATION_LOOPING_TALK_LAUGHING));
    else
        AssignCommand(oPC, ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_DRUNK));
 
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(EffectAbilityDecrease( ABILITY_INTELLIGENCE, IntLoss)), oPC, fDuration);
 
    if (message!="") FloatingTextStringOnCreature(message, oPC, TRUE);
 
    int nConst = GetAbilityScore(oPC,ABILITY_CONSTITUTION);
    int nDrunkLevel = GetLocalInt(oPC, "DrunkLevel");
    if (nDrunkLevel > nConst)
        {
            AssignCommand(oPC, ClearAllActions(TRUE));
            FadeToBlack(oPC);
            DelayCommand(30.0f, FadeFromBlack(oPC));
            AssignCommand(oPC, ActionPlayAnimation( ANIMATION_LOOPING_DEAD_FRONT, 1.0, 30.0));
            DelayCommand(30.0f, SetLocalInt(oPC, "DrunkLevel", nConst));
            DelayCommand(4.0f, SetCommandable(FALSE, oPC));
            DelayCommand(34.0f, SetCommandable(TRUE, oPC));
        }
}
 
string GetHTFFoodAndDrinkValues(string sItemOriginalTag)
{
    string sItemTag = SQLExecAndFetchSingle("SELECT val FROM foods WHERE name='FoodProperty_"+
    sItemOriginalTag+"_HCHTF_TAG'",sItemOriginalTag);
    return sItemTag;
}
 
void SetHTFFoodAndDrinkValues(string sTag, string sHTFValue)
{
    string sSQL = "REPLACE foods SET val='"+sHTFValue+"', name='FoodProperty_" + sTag + "_" + "HCHTF_TAG'";
    SetLocalString(GetWaypointByTag("NWN_MySQL_WP"), "NWNX!ODBC!EXEC", sSQL);
}
 
void InitFoodValues()
{
    if(UPDATE_FOODS)
    {
        // Beers
        SetHTFFoodAndDrinkValues("cnrbBrokenKnuckle",   "Drink_VERYLOW_Alcohol1");
        SetHTFFoodAndDrinkValues("cnrbGreenForest",     "Drink_VERYLOW_Alcohol1");
        SetHTFFoodAndDrinkValues("cnrbAxeHead",         "Drink_LOW_Alcohol1");
        SetHTFFoodAndDrinkValues("cnrbBigRock",         "Drink_NON_Alcohol1");
        SetHTFFoodAndDrinkValues("cnrbBlackHorse",      "Drink_LOW_Alcohol2");
        SetHTFFoodAndDrinkValues("cnrbCherryRiver",     "Drink_LOW_Alcohol2");
        SetHTFFoodAndDrinkValues("cnrbDeadOrc",         "Drink_NON_Alcohol2");
        SetHTFFoodAndDrinkValues("cnrbFireWood",        "Drink_LOW_Alcohol2");
        SetHTFFoodAndDrinkValues("cnrbCrackedSkull",    "Drink_LOW_Alcohol3");
        SetHTFFoodAndDrinkValues("cnrbBlackKnight",     "Drink_LOW_Alcohol3");
        SetHTFFoodAndDrinkValues("cnrbBlueSword",       "Drink_LOW_Alcohol3");
        SetHTFFoodAndDrinkValues("cnrbJumpinJuniper",   "Drink_LOW_Alcohol3");
        SetHTFFoodAndDrinkValues("cnrbPigsEar",         "Drink_LOW_Alcohol3");
        SetHTFFoodAndDrinkValues("cnrbRedCrow",         "Drink_LOW_Alcohol3");
        SetHTFFoodAndDrinkValues("cnrbSilverBuckle",    "Drink_LOW_Alcohol3");
        SetHTFFoodAndDrinkValues("cnrbTowerMalt",       "Drink_LOW_Alcohol3");
        SetHTFFoodAndDrinkValues("cnrbIronHammer",      "Drink_MED_Alcohol3");
        SetHTFFoodAndDrinkValues("cnrbDwarfsSledge",    "Drink_MED_Alcohol3");
        SetHTFFoodAndDrinkValues("cnrbWizardsWheat",    "Drink_HIGH_Alcohol4");
        SetHTFFoodAndDrinkValues("cnrbWilloWhiskey",    "Drink_LOW_Alcohol5");
        SetHTFFoodAndDrinkValues("cnrbDarkDragon",      "Drink_HIGH_Alcohol5");
        SetHTFFoodAndDrinkValues("cnrbBlackBlood",      "Drink_HIGH_Alcohol10");
 
        // Juices
        SetHTFFoodAndDrinkValues("cnrAppleJuice",       "Drink_MED");
        SetHTFFoodAndDrinkValues("cnrBlkberryJuice",    "Drink_MED");
        SetHTFFoodAndDrinkValues("cnrBluberryJuice",    "Drink_MED");
        SetHTFFoodAndDrinkValues("cnrCherryJuice",      "Drink_MED");
        SetHTFFoodAndDrinkValues("cnrCrnberryJuice",    "Drink_MED");
        SetHTFFoodAndDrinkValues("cnrEldberryJuice",    "Drink_MED");
        SetHTFFoodAndDrinkValues("cnrGrapeJuice",       "Drink_MED");
        SetHTFFoodAndDrinkValues("cnrJuniperJuice",     "Drink_MED");
        SetHTFFoodAndDrinkValues("cnrPearJuice",        "Drink_MED");
        SetHTFFoodAndDrinkValues("cnrRspberryJuice",    "Drink_MED");
 
        // Breads
        SetHTFFoodAndDrinkValues("cnrCornBread",        "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrOatBread",         "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrRiceBread",        "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrRyeBread",         "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrWheatBread",       "Food_POOR");
 
        // Pie's
        SetHTFFoodAndDrinkValues("cnrApplePie",         "Food_RICH");
        SetHTFFoodAndDrinkValues("cnrBlkberryPie",      "Food_RICH");
        SetHTFFoodAndDrinkValues("cnrBluberryPie",      "Food_RICH");
        SetHTFFoodAndDrinkValues("cnrCherryPie",        "Food_RICH");
        SetHTFFoodAndDrinkValues("cnrPecanPie",         "Food_RICH");
 
        // Fruits
        SetHTFFoodAndDrinkValues("cnrAppleFruit",       "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrBlkberryFruit",    "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrBluberryFruit",    "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrCherryFruit",      "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrCrnberryFruit",    "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrEldberryFruit",    "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrGrapeFruit",       "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrJuniperFruit",     "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrPearFruit",        "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrRspberryFruit",    "Food_POOR");
 
        // Nuts
        SetHTFFoodAndDrinkValues("cnrAlmondFruit",      "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrChestnutFruit",    "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrHazelnutFruit",    "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrPecanFruit",       "Food_POOR");
        SetHTFFoodAndDrinkValues("cnrWalnutFruit",      "Food_POOR");
 
        // Other Food
        SetHTFFoodAndDrinkValues("cnrHoney",            "Food_POOR"); // Honey
        SetHTFFoodAndDrinkValues("cnrMapleSyrup",       "Food_POOR"); // MapleSyrup
        SetHTFFoodAndDrinkValues("cnrChickenEgg",       "Food_POOR"); // Raw chicken egg
        SetHTFFoodAndDrinkValues("cnrCornFlakes",       "Food_POOR"); // Corn flakes
        SetHTFFoodAndDrinkValues("FoodRation",          "Food_POOR");
        SetHTFFoodAndDrinkValues("CookedEgg",           "Food_POOR");
        SetHTFFoodAndDrinkValues("CookedMeat",          "Food_NORM");
        SetHTFFoodAndDrinkValues("CookedSteak",         "Food_NORM");
        SetHTFFoodAndDrinkValues("CookedFish",          "Food_NORM");
        SetHTFFoodAndDrinkValues("cnrCowsMilk",         "Drink_MED_Food_POOR");
 
        // Raw foods that need cooking
        SetHTFFoodAndDrinkValues("cnrAnimalMeat",       "Meat_Raw"); // Bear etc raw meat
        SetHTFFoodAndDrinkValues("cnrAnimalMeat",       "Fish_Raw"); // Raw fish
    }
    // Placeables
 
}

               
               

               
            

Legacy_DeadeyeDevie

  • Newbie
  • *
  • Posts: 14
  • Karma: +0/-0
Need help with scripting problem
« Reply #6 on: April 29, 2016, 09:19:15 pm »


               Thanks for the suggestion, but that's a bit too extreme. The plan is to make the players have to plan thier rests ahead of time when they are going on extended journeys. The bed roll and fire was to add a touch of realism without the constraints of micromanaging scheduled,forced breaks.



What I'm basically looking for is a rest script that does the following, perhaps scripted I  this order.


-rest only allowed every 4 game hours or so


-before resting, you need to place a campfire down


-when resting it checks for a bedroll and food. 1 piece of food is used up on rest.


The animations I have seen of the bed roll being placed to sit/lie on, and the screen going black are great touches, but I THINK I can work that bit out myself.


A placeable that resets the rest timer, and ignores the bedroll and food part would always be good, for inns and such.