//:://///////////////////////////////////////////// //:: Persistent Container OnOpen Script //:: Copyright (c) 2001 Bioware Corp. //::////////////////////////////////////////////// /* usage: attach this script to the OnOpen event of a container info: you can customize several parameters: specify maximum capacity using WillSafe property choose object TAG for ID generation (ReflexSafe = 0) !! use this to share inventories !! use this for moving inventories (like creatures) choose automatic ID generation for stationary containers (ReflexSafe = 1). !! probably the best, coz container does not need a specific tag use player for ID generation (ReflexSafe = 2) !! use this for player vaults. each player gets his own inventory !! from the same container you can easily map those properties to something else, in case you use this include file for creature/merchant inventory.. - added watchdog to catch chest "stuck open" events - added fix to prevent action-spam exploit */ //::////////////////////////////////////////////// //:: Created By: Knat //:: Created On: 28.6.03 //::////////////////////////////////////////////// #include "PINV_inc" // this watchdog only exists to watch for a "stuck open" bug // it then resets the object to a proper null-state // watchdog is only active during PC<->object interaction void Watchdog(object oPC) { if( GetDistanceToObject(oPC) > 2.0 && GetLocalInt(OBJECT_SELF,"IMBUSY!")) { // simulate onClose event int nID = (GetReflexSavingThrow(OBJECT_SELF) == 2) ? PINV_GetID(oPC,2) : PINV_GetID(OBJECT_SELF,GetReflexSavingThrow(OBJECT_SELF)); if( PINV_StoreInventory(nID, OBJECT_SELF, oPC, GetWillSavingThrow(OBJECT_SELF)) == -1 ) SendMessageToPC(oPC, "Warning: items are not stored persistently. Your name contains malicious characters..."); // unlock container SetLocalInt(OBJECT_SELF,"IMBUSY!",FALSE); SetLocked(OBJECT_SELF,FALSE); // reset object to stable null state // we use the most brute force way to ensure it works 100% // no matter what the engine thinks.. // // create a new clone CreateObject(GetObjectType(OBJECT_SELF),GetResRef(OBJECT_SELF),GetLocation(OBJECT_SELF)); // destroy old sporked object DestroyObject(OBJECT_SELF); ActionPlayAnimation(ANIMATION_PLACEABLE_CLOSE); } else { if(GetLocalInt(OBJECT_SELF,"IMBUSY!")) DelayCommand(1.0,Watchdog(oPC)); } } void main() { // this will fix a dangerous action-spam exploit // finally some use for GetTimeMillisecond int nThisTime = GetTimeMillisecond(); int nLastTime = GetLocalInt(OBJECT_SELF,"EVT_LASTTIME"); SetLocalInt(OBJECT_SELF,"EVT_LASTTIME",nThisTime); if(nThisTime != nLastTime) // proceed only if internal time moved forward { object oUser = GetLastOpenedBy(); if(!GetIsPC(oUser)) return; // one time initialization if(!GetLocalInt(OBJECT_SELF,"INIT")) { // reject items with "NODROP" anywhere in the tag PINV_BlockItemByFilter("**NODROP**"); SetLocalInt(OBJECT_SELF,"INIT",TRUE); } if(!GetLocalInt(OBJECT_SELF,"IMBUSY!")) { // lock container FloatingTextStringOnCreature("Please walk away to close container",oUser,FALSE); SetLocalInt(OBJECT_SELF,"IMBUSY!",TRUE); SetLocked(OBJECT_SELF, TRUE); DelayCommand(1.0,Watchdog(oUser)); // create inventory from DB // "Reflex Safe" serves as ID_FLAG // reflex = 0 // non unique container ID. it will just use the placeable tag as container index // multiple containers can share the same space this way // reflex = 1 // unique container ID. area-tag + location used as container index. each container gets // his own space, tag is irrelevant. // placeable must be stationary !!!! // reflex = 2 // ID based on GetPCPlayerName() and GetName() // container inventory depends on opener // this is useful for player vaults int nID = (GetReflexSavingThrow(OBJECT_SELF) == 2) ? PINV_GetID(oUser,2) : PINV_GetID(OBJECT_SELF,GetReflexSavingThrow(OBJECT_SELF)); if( PINV_RetrieveInventory(nID, OBJECT_SELF) == -1 ) SendMessageToPC(oUser, "You can't retrieve items from this container. Your name contains malicious characters..."); } else SendMessageToPC(oUser,"Container is busy, try again later..."); } }