// Created By: Zunath on 6/21/2011 // Description: Allows items placed inside of containers to be persistently stored in the database. // The item limit must be set as a variable on the placeable. The name of the variable can be // found below, named "PSS_SOFT_ITEM_CAP". // // Changes from MZS2's version: Replaced Bioware database usage with MySQL database usage. // Removed code references to "weight limit". // Renamed functions to be more clear. // Wrote descriptions for function prototypes // Cleaned up code. // Basically, I rewrote the system. :X #include "aps_include" #include "colors_inc" /////////////// // CONSTANTS // /////////////// // Name of the table which stores all information regarding items stored in a chest const string PSS_MYSQL_TABLE = "zst_storage"; // The hard limit on the number of items able to be stored in a single chest // Default is 100. I don't recommend raising this any higher though. const int PSS_HARD_ITEM_CAP = 100; // Name of the variable stored on a chest which determines the number of items able to be placed inside // the chest. Note that if this amount is higher than PSS_HARD_ITEM_CAP, only that amount will be able to be placed // inside. const string PSS_SOFT_ITEM_CAP = "ZST_ITEM_LIMIT"; //////////////// // PROTOTYPES // //////////////// // Call this on the chest's OnOpen event. void PSS_OnChestOpen(); // Call this on the chest's OnDisturbed event. // When an item is added or removed from a chest, the database information is updated. // If the item count in a chest goes over the limit specified for the chest, the item(s) is/are returned to the player void PSS_OnChestDisturbed(); /////////////// // FUNCTIONS // /////////////// void PSS_OnChestOpen() { object oChest = OBJECT_SELF; object oArea = GetArea(oChest); string sLoadedVar = "PSS_CHEST_LOADED"; string sTag = "'" + GetTag(oChest) + "'"; string sAreaTag = "'" + SQLEncodeSpecialChars(GetTag(oArea)) + "'"; int bChestLoaded = GetLocalInt(oChest, sLoadedVar); int iMaxItems = GetLocalInt(oChest, PSS_SOFT_ITEM_CAP); // Chest has already been loaded. No need to load it again. Quit here. if(bChestLoaded) return; // Chest hasn't been loaded yet. We need to load all of the items from the database to // the chest's inventory. else { int iCurItem = 1; // Mark this chest as loaded. SetLocalInt(oChest, sLoadedVar, TRUE); while(iCurItem <= iMaxItems) { // I couldn't figure out a less confusing way to retrieve objects from the database. string sSQL = "SELECT Item" + IntToString(iCurItem) + " FROM " + PSS_MYSQL_TABLE + " WHERE Tag=" + sTag +" AND AreaTag=" + sAreaTag + ";"; SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL); object oItem = RetrieveCampaignObject ("NWNX", "-", GetLocation(oChest), oChest); // No need to keep checking the table - there are no more items being stored at the moment if(!GetIsObjectValid(oItem)){break;} // Prevent duplication of items in containers if(GetHasInventory(oItem)) { object oCycle = GetFirstItemInInventory(oItem); while(GetIsObjectValid(oCycle)) { DestroyObject(oCycle); oCycle = GetNextItemInInventory(oItem); } } iCurItem = iCurItem + 1; } } } void PSS_OnChestDisturbed() { object oChest = OBJECT_SELF; object oPC = GetLastDisturbed(); object oArea = GetArea(oChest); string sTag = "'" + GetTag(oChest) + "'"; string sAreaName = "'" + SQLEncodeSpecialChars(GetName(oArea)) + "'"; string sAreaTag = "'" + SQLEncodeSpecialChars(GetTag(oArea)) + "'"; int iType = GetInventoryDisturbType(); // In order to avoid having to constantly check to make sure there's no dead space in // the row fields, we just delete the row outright and then insert a new one with the current items. // This probably isn't the most efficient way, but I don't have a way to sort data sets in NWScript. string sSQL = "DELETE FROM " + PSS_MYSQL_TABLE + " WHERE Tag=" + sTag + " AND AreaTag=" + sAreaTag + ";"; SQLExecDirect(sSQL); // Now we're ready to store the items again. int iMaxItems = GetLocalInt(oChest, PSS_SOFT_ITEM_CAP); sSQL = "INSERT INTO " + PSS_MYSQL_TABLE + "(Tag, AreaTag, AreaName) VALUES (" + sTag + "," + sAreaTag + "," + sAreaName + ")"; int iCurItem = 1; int iReachedLimit = FALSE; // Cycle through bank inventory and store items object oItem = GetFirstItemInInventory(oChest); while(GetIsObjectValid(oItem)) { // Haven't reached the limit yet. if(iMaxItems >= iCurItem) { // Create a new row using their ID, if this is the first item in the bank if(iCurItem == 1) { SQLExecDirect(sSQL); } sSQL = "UPDATE " + PSS_MYSQL_TABLE + " SET Item" + IntToString(iCurItem) + "=%s WHERE Tag=" + sTag + " AND AreaTag=" + sAreaTag + ";"; SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL); StoreCampaignObject ("NWNX", "-", oItem); } // Reached the limit - return the item else { AssignCommand(oChest, ActionGiveItem(oItem, oPC)); iReachedLimit = TRUE; } // Add one to the tally and move to the next item in bank's inventory iCurItem = iCurItem + 1; oItem = GetNextItemInInventory(oChest); } // Reached the limit. Inform player. if(iReachedLimit == TRUE) { SendMessageToPC(oPC, ColorTokenRed() + "No more items can be placed inside." + ColorTokenEnd()); } // Haven't reached the limit. Read out the current item limit. else { SendMessageToPC(oPC, ColorTokenWhite() + "Item Limit: " + IntToString(iCurItem-1) + " / " + ColorTokenRed() + IntToString(iMaxItems)); } } // Error checking //void main(){}