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.) && (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.) && (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.) && (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
}