Added (2) Castle Interior overrides, continued making static NPCs & stores dynamic. added more DMFI language tokens, started working on mod onEnter scripting, got NPCs to fire emotes while walking around.
286 lines
10 KiB
Plaintext
286 lines
10 KiB
Plaintext
//::////////////////////////////////////////////////////////////////////////////
|
|
//:: Store Open Script
|
|
//:: ar_st_general
|
|
//:: For slightly faster store restocking
|
|
//:: -DM Heatstroke
|
|
//::////////////////////////////////////////////////////////////////////////////
|
|
/*
|
|
This script will allow stores to partially reset
|
|
themselves to their original state after some
|
|
time has passed.
|
|
|
|
Intended for persistent worlds.
|
|
*/
|
|
//::////////////////////////////////////////////////////////////////////////////
|
|
//:: Created By: The Krit
|
|
//:: Created On: 3/2/07
|
|
//:: Replaces the "do-nothing" BioWare script.
|
|
//::////////////////////////////////////////////////////////////////////////////
|
|
//::////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This script will cause a store's finite inventory
|
|
// and limited gold to be (partially) replenished
|
|
// after a certain amount of time passes. It will also
|
|
// clean out new items and excess gold. I call this
|
|
// restocking.
|
|
//
|
|
// The timer starts when the store is first opened
|
|
// after server rest or the last restock. The time
|
|
// is random, but will be at least RESTOCK_TIME_FIXED
|
|
// real-time hours. The random component of the time
|
|
// is added to this minimum, and will range from 0
|
|
// to RESTOCK_TIME_VARIABLE minutes.
|
|
//
|
|
// Items are only replaced if all of that type have
|
|
// been sold (and not bought back). The chance for an
|
|
// item to be replaced is RESTOCK_CHANCE.
|
|
//
|
|
// Items not in the store's original inventory have a
|
|
// chance to be removed (sold to unspecified NPC's, if
|
|
// you will) when the store restocks. This chance is
|
|
// UNSTOCK_CHANCE.
|
|
//
|
|
// After the store restocks, the store's gold supply -- if
|
|
// limited -- will be no more than GOLD_MAX_FRACTION times
|
|
// its starting value.
|
|
//
|
|
// After the store restocks, the store's gold supply -- if
|
|
// limited -- will be no less than GOLD_MIN_FRACTION times
|
|
// its starting value.
|
|
//
|
|
// If you try to mess with things and make GOLD_MAX_FRACTION
|
|
// less than GOLD_MIN_FRACTION, you deserve whatever happens.
|
|
// You may also smack yourself for making trouble. :)
|
|
//
|
|
//::////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// The variables mentioned above are set globally below.
|
|
// In addition, you can change the value for a particular
|
|
// store by setting a local variable of the same name
|
|
// (and type) on the store.
|
|
// NOTE: These variables must be set on the *store*, not
|
|
// the merchant.
|
|
//
|
|
//::////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This script will (likely) break if you switch a
|
|
// store from unlimited gold to limited gold through
|
|
// scripting. Don't do that. There would be no
|
|
// original gold level to refer to when restocking.
|
|
//
|
|
//::////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// The following is the minimum number of real-time (not
|
|
// game-time) hours that elapse before a store gets
|
|
// restocked.
|
|
const int RESTOCK_TIME_FIXED = 2;
|
|
|
|
// The following is the maximum number of minutes (not
|
|
// hours) that a restock might be delayed beyond the
|
|
// above minimum number of hours.
|
|
const int RESTOCK_TIME_VARIABLE = 30;
|
|
|
|
// The following is the chance (percentage) that a depleted
|
|
// item will be replaced when the restocking occurs. Each
|
|
// item rolls this percentage individually.
|
|
const int RESTOCK_CHANCE = 75;
|
|
|
|
// The following is the chance (percentage) that an item
|
|
// not in the store's original inventory will be removed
|
|
// when a restocking occurs.
|
|
const int UNSTOCK_CHANCE = 5;
|
|
|
|
// The following is the fraction (floating point) of the
|
|
// stores original gold that is the most a store can have
|
|
// after restocking.
|
|
// (No effect on stores with unlimited gold.)
|
|
const float GOLD_MAX_FRACTION = 2.20;
|
|
|
|
// The following is the fraction (floating point) of the
|
|
// stores original gold that is the least a store can have
|
|
// after restocking.
|
|
// (No effect on stores with unlimited gold.)
|
|
const float GOLD_MIN_FRACTION = 0.80;
|
|
|
|
|
|
// The following are names of local variables used by
|
|
// this script.
|
|
const string STORE_GOLD = "TK_STORE_STARTING_GOLD";
|
|
const string ORIG_INVENTORY = "TK_STORE_STARTING_INVENTORY_";
|
|
const string CUR_INVENTORY = "TK_STORE_CURRENT_INVENTORY_";
|
|
const string INVENTORY_STACK = "TK_STORE_INVENTORY_STACK_LIST_";
|
|
const string INVENTORY_LIST = "TK_STORE_INVENTORY_LIST_";
|
|
const string INVENTORY_SIZE = "TK_STORE_INVENTORY_SIZE";
|
|
const string INVENTORIED = "TK_STORE_DID_INVENTORY";
|
|
const string RESTOCK_ORDERED = "TK_STORE_DID_DELAY";
|
|
|
|
|
|
// Records the store's current (starting) inventory.
|
|
void DoInventory();
|
|
|
|
// Restocks the store.
|
|
void Restock();
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
// main()
|
|
//
|
|
// Intended for a store's OnOpenStore event, replacing the BioWare default.
|
|
//
|
|
void main()
|
|
{
|
|
// See if the store's original inventory has been recorded.
|
|
if ( !GetLocalInt(OBJECT_SELF, INVENTORIED) )
|
|
{
|
|
// Record the current inventory.
|
|
DoInventory();
|
|
SetLocalInt(OBJECT_SELF, INVENTORIED, TRUE);
|
|
}
|
|
|
|
// See if a restock is currently on delay.
|
|
if ( !GetLocalInt(OBJECT_SELF, RESTOCK_ORDERED) )
|
|
{
|
|
// Determine the restock times (possibly stored locally).
|
|
int nRestockHours = GetLocalInt(OBJECT_SELF, "RESTOCK_TIME_FIXED");
|
|
if ( nRestockHours == 0 )
|
|
nRestockHours = RESTOCK_TIME_FIXED;
|
|
int nRestockMinutes = GetLocalInt(OBJECT_SELF, "RESTOCK_TIME_VARIABLE");
|
|
if ( nRestockMinutes == 0 )
|
|
nRestockMinutes = RESTOCK_TIME_VARIABLE;
|
|
|
|
// Order (delay) a restock.
|
|
DelayCommand( TurnsToSeconds(60*nRestockHours + Random(nRestockMinutes+1)),
|
|
Restock());
|
|
SetLocalInt(OBJECT_SELF, RESTOCK_ORDERED, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
// DoInventory()
|
|
//
|
|
// Records the store's current (starting) inventory.
|
|
//
|
|
void DoInventory()
|
|
{
|
|
// Record the store's current gold.
|
|
SetLocalInt(OBJECT_SELF, STORE_GOLD, GetStoreGold(OBJECT_SELF));
|
|
|
|
// Record the store's current inventory.
|
|
int nCount = 0;
|
|
object oItem = GetFirstItemInInventory();
|
|
while ( oItem != OBJECT_INVALID )
|
|
{
|
|
// We are only concerned with items in finite supply.
|
|
if ( !GetInfiniteFlag(oItem) )
|
|
{
|
|
string sResRef = GetResRef(oItem);
|
|
// Set a boolean flag based on the blueprint name.
|
|
SetLocalInt(OBJECT_SELF, ORIG_INVENTORY + sResRef, TRUE);
|
|
// Add sResRef to the list of blueprints.
|
|
SetLocalString(OBJECT_SELF, INVENTORY_LIST + IntToString(nCount), sResRef);
|
|
// Record the stack size.
|
|
SetLocalInt(OBJECT_SELF, INVENTORY_STACK + IntToString(nCount), GetItemStackSize(oItem));
|
|
// Update the count.
|
|
nCount++;
|
|
}
|
|
// Next item.
|
|
oItem = GetNextItemInInventory();
|
|
}
|
|
|
|
// Record the length of the list of blueprints.
|
|
SetLocalInt(OBJECT_SELF, INVENTORY_SIZE, nCount);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
// Restock()
|
|
//
|
|
// Restocks the store.
|
|
//
|
|
void Restock()
|
|
{
|
|
// Check the store's gold.
|
|
int nCurGold = GetStoreGold(OBJECT_SELF);
|
|
|
|
// We are only concerned if the store has limited gold.
|
|
if ( nCurGold > -1 )
|
|
{
|
|
// Determine the min and max gold fractions (possibly stored locally).
|
|
float fGoldMin = GetLocalFloat(OBJECT_SELF, "GOLD_MIN_FRACTION");
|
|
if ( fGoldMin == 0.0 )
|
|
fGoldMin = GOLD_MIN_FRACTION;
|
|
float fGoldMax = GetLocalFloat(OBJECT_SELF, "GOLD_MAX_FRACTION");
|
|
if ( fGoldMax == 0.0 )
|
|
fGoldMax = GOLD_MAX_FRACTION;
|
|
|
|
// Calculate the minimum and maximum gold levels.
|
|
int nOrigGold = GetLocalInt(OBJECT_SELF, STORE_GOLD);
|
|
int nMinGold = FloatToInt(IntToFloat(nOrigGold) * fGoldMin);
|
|
int nMaxGold = FloatToInt(IntToFloat(nOrigGold) * fGoldMax);
|
|
|
|
// Check for too little gold.
|
|
if ( nCurGold < nMinGold )
|
|
SetStoreGold(OBJECT_SELF, nMinGold);
|
|
// Check for too much gold.
|
|
else if ( nCurGold > nMaxGold )
|
|
SetStoreGold(OBJECT_SELF, nMaxGold);
|
|
}
|
|
|
|
// Determine the unstock chance (possibly stored locally).
|
|
int nUnstockChance = GetLocalInt(OBJECT_SELF, "UNSTOCK_CHANCE");
|
|
if ( nUnstockChance == 0 )
|
|
nUnstockChance = UNSTOCK_CHANCE;
|
|
|
|
// Scan the store's current inventory.
|
|
// Record which original items are still around.
|
|
// Possibly remove non-original items.
|
|
object oItem = GetFirstItemInInventory();
|
|
while ( oItem != OBJECT_INVALID )
|
|
{
|
|
// We are only concerned with items in finite supply.
|
|
if ( !GetInfiniteFlag(oItem) )
|
|
{
|
|
string sResRef = GetResRef(oItem);
|
|
|
|
// See if this item is an original item.
|
|
if ( GetLocalInt(OBJECT_SELF, ORIG_INVENTORY + sResRef) )
|
|
{
|
|
// Set a boolean flag (temporarily) based on the blueprint name.
|
|
SetLocalInt(OBJECT_SELF, CUR_INVENTORY + sResRef, TRUE);
|
|
DelayCommand(0.0, DeleteLocalInt(OBJECT_SELF, CUR_INVENTORY + sResRef));
|
|
}
|
|
// See if this (not original) item should be removed.
|
|
else if ( d100() <= nUnstockChance )
|
|
// Delete this item.
|
|
DestroyObject(oItem);
|
|
}
|
|
// Next item.
|
|
oItem = GetNextItemInInventory();
|
|
}
|
|
|
|
// Determine the restock chance (possibly stored locally).
|
|
int nRestockChance = GetLocalInt(OBJECT_SELF, "RESTOCK_CHANCE");
|
|
if ( nRestockChance == 0 )
|
|
nRestockChance = RESTOCK_CHANCE;
|
|
|
|
// Loop through the list of items that might be restored.
|
|
int nCount = GetLocalInt(OBJECT_SELF, INVENTORY_SIZE);
|
|
while ( nCount-- > 0 )
|
|
{
|
|
string sResRef = GetLocalString(OBJECT_SELF, INVENTORY_LIST + IntToString(nCount));
|
|
|
|
// Make sure no items of this type are in the store's inventory (before this loop).
|
|
if ( !GetLocalInt(OBJECT_SELF, CUR_INVENTORY + sResRef) )
|
|
// See if this item should be restocked.
|
|
if ( d100() <= nRestockChance )
|
|
// Add this item to the store.
|
|
CreateItemOnObject(sResRef, OBJECT_SELF,
|
|
GetLocalInt(OBJECT_SELF, INVENTORY_STACK + IntToString(nCount)));
|
|
}
|
|
|
|
// Restocking is no longer in progress.
|
|
SetLocalInt(OBJECT_SELF, RESTOCK_ORDERED, FALSE);
|
|
}
|