/************************************************************************ * script name : socket_inc * created by : eyesolated * date : 2019/3/21 * * description : Central include script for Socketing * * changes : 2019/3/21 - eyesolated - Initial creation ************************************************************************/ #include "socket_cfg" #include "ip_inc" #include "util_inc" #include "nwnx_itemprop" #include "prc_misc_const" /******************************************************************************* * FUNCTION DECLARATION ******************************************************************************/ // Creates the database tables used for Socketing void socket_CreateTables(); // Returns FALSE if any of the required Socketing Tables is missing int socket_GetTablesExist(); // Drops all Socketing Tables void socket_DropTables(); // Adds information about a socketable item to the database void socket_AddSocketableItem(string sResRef, int nItemCategory, int nItemProperty, int nItemSubProperty = -1); // Returns the resref of a socketable item string socket_GetSocketableItem(); // Retrieves socket information for sSocket // Return Values: Socket does not exist - RETURN.* will be "" / 0 / OBJECT_INVALID depending on variable type // Socket is empty - RETURN.Item_Socketed_ResRef will be SOCKET_SOCKETED_NONE // Socketed - RETURN will hold all information struct SOCKET_STRUCT_SOCKET_INFO socket_GetSocketInfo(object oItem, int nSocket = 1); // Get the first empty socket of oItem // Returns -1 if there is no empty socket available int socket_GetEmptySocket(object oItem); // Retrieves the itemproperty associated with oSocketableItem if socketed in oItem itemproperty socket_GetProperty(object oItem, object oSocketableItem); // Returns the Item Category (SOCKET_ITEMCATEGORY_*) int socket_GetItemCategory(object oItem); // (re)Sets the Description of oItem to include Socket information void socket_SetDescription(object oItem); // Inserts oItemToSocket into oItem and informs oPC about the result // Returns TRUE on success, FALSE on failure int socket_InsertSocketableItem(object oPC, object oItem, object oItemToSocket); // Creates a new socket in the given position // Returns FALSE if the socket couldn't be created, TRUE if it was created successfully int socket_CreateSocket(object oItem, int nSocket = 1); // Tries to create nCount Sockets in oItem (Maximum of 3). // Returns the nubmer of new sockets created. int socket_CreateSockets(object oItem, int nCount); /******************************************************************************* * FUNCTION IMPLEMENTATION ******************************************************************************/ int socket_GetTablesExist() { int nExists_Base = NWNX_SQL_ExecuteQuery("DESCRIBE " + SOCKET_TABLE_BASE); return (nExists_Base); } void socket_DropTables() { NWNX_SQL_ExecuteQuery("DROP TABLE " + SOCKET_TABLE_BASE); } void socket_CreateTables() { // Base Table string Table_Base = SOCKET_TABLE_BASE + " (" + "ResRef varchar(16) NOT NULL," + "ItemCategory int NOT NULL," + "ItemProperty_ID int NOT NULL," + "ItemSubProperty_ID int NOT NULL DEFAULT -1" + ")"; NWNX_SQL_ExecuteQuery("CREATE TABLE IF NOT EXISTS " + Table_Base); } void socket_AddSocketableItem(string sResRef, int nItemCategory, int nItemProperty, int nItemSubProperty = -1) { string sSQL = "INSERT INTO " + SOCKET_TABLE_BASE + " (ResRef, ItemCategory, ItemProperty_ID, ItemSubProperty_ID) "; sSQL += "VALUES (?, ?, ?, ?)"; NWNX_SQL_PrepareQuery(sSQL); NWNX_SQL_PreparedString(0, sResRef); NWNX_SQL_PreparedInt(1, nItemCategory); NWNX_SQL_PreparedInt(2, nItemProperty); NWNX_SQL_PreparedInt(3, nItemSubProperty); NWNX_SQL_ExecutePreparedQuery(); } string socket_GetSocketableItem() { string sSQL = "SELECT DISCTINCT ResRef FROM " + SOCKET_TABLE_BASE + " ORDER BY RAND() LIMIT 1"; NWNX_SQL_ExecuteQuery(sSQL); if (NWNX_SQL_ReadyToReadNextRow()) { NWNX_SQL_ReadNextRow(); return NWNX_SQL_ReadDataInActiveRow(0); } return ""; } struct SOCKET_STRUCT_SOCKET_INFO socket_GetSocketInfo(object oItem, int nSocket = 1) { struct SOCKET_STRUCT_SOCKET_INFO SocketInfo; SocketInfo.Item_Socketed_ResRef = GetLocalString(oItem, SOCKET_VAR_SOCKET_RESREF + "_" + IntToString(nSocket)); // If there is no ResRef or is an empty socket, return right away if (SocketInfo.Item_Socketed_ResRef == "" || SocketInfo.Item_Socketed_ResRef == SOCKET_SOCKETED_NONE) return SocketInfo; // Read the other variables SocketInfo.Item_Socketed_Tag = GetLocalString(oItem, SOCKET_VAR_SOCKET_TAG + "_" + IntToString(nSocket)); SocketInfo.Item_Socketed_Name = GetLocalString(oItem, SOCKET_VAR_SOCKET_NAME + "_" + IntToString(nSocket)); return SocketInfo; } int socket_GetEmptySocket(object oItem) { int nSocket; string ResRef; for (nSocket = 1; nSocket <= SOCKET_MAXIMUM; nSocket++) { ResRef = GetLocalString(oItem, SOCKET_VAR_SOCKET_RESREF + "_" + IntToString(nSocket)); if (ResRef == "") return -1; else if (ResRef == SOCKET_SOCKETED_NONE) return nSocket; } return -1; } itemproperty socket_GetProperty(object oItem, object oSocketableItem) { itemproperty Result; int nItemCategory = socket_GetItemCategory(oItem); if (nItemCategory == SOCKET_ITEMCATEGORY_UNKNOWN) return Result; string sItemToSocket_ResRef = GetResRef(oSocketableItem); string sQuery; sQuery = "SELECT A.ItemSubProperty_ID" + ", B." +CS_IP_ID + ", B." + CS_IP_VARONE + ", B." + CS_IP_VARTWO + ", B." + CS_IP_VARTHREE + " FROM " + SOCKET_TABLE_BASE + " A" + " JOIN " + CS_IP_TABLE + " B ON A.ItemProperty_ID = B." + CS_IP_ID + " WHERE A.ResRef = ? AND (A.ItemCategory & ?) != 0 AND B." + CS_IP_LEVEL + " = ?"; NWNX_SQL_PrepareQuery(sQuery); NWNX_SQL_PreparedString(0, sItemToSocket_ResRef); NWNX_SQL_PreparedInt(1, nItemCategory); NWNX_SQL_PreparedInt(2, GetLocalInt(oSocketableItem, SOCKET_VAR_ITEM_LEVEL)); NWNX_SQL_ExecutePreparedQuery(); if (NWNX_SQL_ReadyToReadNextRow()) { NWNX_SQL_ReadNextRow(); int IP_SubProperty = StringToInt(NWNX_SQL_ReadDataInActiveRow(0)); int IP_ID = StringToInt(NWNX_SQL_ReadDataInActiveRow(1)); int IP_VarOne = StringToInt(NWNX_SQL_ReadDataInActiveRow(2)); int IP_VarTwo = StringToInt(NWNX_SQL_ReadDataInActiveRow(3)); int IP_VarThree = StringToInt(NWNX_SQL_ReadDataInActiveRow(4)); struct STRUCT_IP_PropertyDetails ip = ip_GetSpecificProperty(GetBaseItemType(oSocketableItem), IP_ID, IP_VarOne, IP_VarTwo, IP_VarThree); Result = ip.IP; // Force specific Property if there is one if (IP_SubProperty != -1) { struct NWNX_IPUnpacked IPU = NWNX_ItemProperty_UnpackIP(Result); IPU.nSubType = IP_SubProperty; Result = NWNX_ItemProperty_PackIP(IPU); } } else { WriteTimestampedLogEntry("SOCKET: Failed to retrieve DB values for [" + sItemToSocket_ResRef + "]"); } return Result; } int socket_GetItemCategory(object oItem) { int nBaseItemType = GetBaseItemType(oItem); switch (nBaseItemType) { case BASE_ITEM_AMULET: return SOCKET_ITEMCATEGORY_JEWELRY_AMULET; case BASE_ITEM_ARMOR: return SOCKET_ITEMCATEGORY_ARMOR; case BASE_ITEM_BELT: return SOCKET_ITEMCATEGORY_BELT; case BASE_ITEM_BOOTS: return SOCKET_ITEMCATEGORY_BOOTS; case BASE_ITEM_BRACER: case BASE_ITEM_BRACER_SHIELD: return SOCKET_ITEMCATEGORY_BRACERS; case BASE_ITEM_CLOAK: return SOCKET_ITEMCATEGORY_CLOAK; case BASE_ITEM_GLOVES: return SOCKET_ITEMCATEGORY_GLOVES; case BASE_ITEM_HELMET: return SOCKET_ITEMCATEGORY_HELMET; case BASE_ITEM_RING: return SOCKET_ITEMCATEGORY_JEWELRY_RING; case BASE_ITEM_SMALLSHIELD: case BASE_ITEM_LARGESHIELD: case BASE_ITEM_TOWERSHIELD: return SOCKET_ITEMCATEGORY_SHIELD; case BASE_ITEM_LIGHTCROSSBOW: case BASE_ITEM_HEAVYCROSSBOW: return SOCKET_ITEMCATEGORY_RANGED_CROSSBOW; case BASE_ITEM_SHORTBOW: case BASE_ITEM_LONGBOW: return SOCKET_ITEMCATEGORY_RANGED_BOW; case BASE_ITEM_SHORTSWORD: case BASE_ITEM_LONGSWORD: case BASE_ITEM_BATTLEAXE: case BASE_ITEM_BASTARDSWORD: case BASE_ITEM_LIGHTFLAIL: case BASE_ITEM_WARHAMMER: case BASE_ITEM_LIGHTMACE: case BASE_ITEM_HALBERD: case BASE_ITEM_TWOBLADEDSWORD: case BASE_ITEM_GREATSWORD: case BASE_ITEM_GREATAXE: case BASE_ITEM_DAGGER: case BASE_ITEM_CLUB: case BASE_ITEM_DART: case BASE_ITEM_DIREMACE: case BASE_ITEM_DOUBLEAXE: case BASE_ITEM_HEAVYFLAIL: case BASE_ITEM_LIGHTHAMMER: case BASE_ITEM_HANDAXE: case BASE_ITEM_KAMA: case BASE_ITEM_KATANA: case BASE_ITEM_KUKRI: case BASE_ITEM_MORNINGSTAR: case BASE_ITEM_QUARTERSTAFF: case BASE_ITEM_RAPIER: case BASE_ITEM_SCYTHE: case BASE_ITEM_SHORTSPEAR: case BASE_ITEM_SHURIKEN: case BASE_ITEM_SICKLE: case BASE_ITEM_SCIMITAR: case BASE_ITEM_SLING: case BASE_ITEM_DWARVENWARAXE: case BASE_ITEM_WHIP: case BASE_ITEM_GRENADE: case BASE_ITEM_TRIDENT: case BASE_ITEM_THROWINGAXE: case BASE_ITEM_CSLASHWEAPON: case BASE_ITEM_CPIERCWEAPON: case BASE_ITEM_CBLUDGWEAPON: case BASE_ITEM_CSLSHPRCWEAP: //:: PRC Weapons case BASE_ITEM_LIGHT_LANCE: case BASE_ITEM_HEAVY_PICK: case BASE_ITEM_LIGHT_PICK: case BASE_ITEM_SAI: case BASE_ITEM_NUNCHAKU: case BASE_ITEM_FALCHION: case BASE_ITEM_SAP: case BASE_ITEM_KATAR: case BASE_ITEM_HEAVY_MACE: case BASE_ITEM_MAUL: case BASE_ITEM_DOUBLE_SCIMITAR: case BASE_ITEM_GOAD: case BASE_ITEM_EAGLE_CLAW: case BASE_ITEM_ELVEN_LIGHTBLADE: case BASE_ITEM_ELVEN_THINBLADE: case BASE_ITEM_ELVEN_COURTBLADE: // CEP weapons: case 300: // trident_1h case 301: // heavypick case 302: // lightpick case 303: // sai case 304: // nunchaku case 305: // falchion case 308: // sap case 309: // daggerassn case 310: // katar case 312: // lightmace2 case 313: // kukri2 case 316: // falchion_2 case 317: // heavy_mace case 318: // maul case 319: // mercurial_longsword case 320: // mercurial_greatsword case 321: // scimitar_double case 322: // goad case 323: // windfirewheel case 324: // maugdoublesword case 327: // Flowers_Crystal case 329: // tool_2handed case 330: // Longsword_2 return SOCKET_ITEMCATEGORY_MELEE; } return SOCKET_ITEMCATEGORY_UNKNOWN; } void socket_SetDescription(object oItem) { string sSaved = GetLocalString(oItem, SOCKET_VAR_ITEM_DESCRIPTION); string sDescription = GetDescription(oItem); string sSocketDescription = "\n"; int n; struct SOCKET_STRUCT_SOCKET_INFO socketInfo; for (n = 1; n <= SOCKET_MAXIMUM; n++) { socketInfo = socket_GetSocketInfo(oItem, n); if (socketInfo.Item_Socketed_ResRef == "") break; else if (socketInfo.Item_Socketed_ResRef == SOCKET_SOCKETED_NONE) sSocketDescription += "\n" + SOCKET_DESCRIPTION_SOCKET + SOCKET_DESCRIPTION_SOCKET_EMPTY; else sSocketDescription += "\n" + SOCKET_DESCRIPTION_SOCKET + GetLocalString(oItem, SOCKET_VAR_SOCKET_NAME + "_" + IntToString(n)); } // If there is no socket description, return right away if (sSocketDescription == "\n") return; // If saved is empty or the retrieved description shows no signs of socketing texts, // save the "original/pre-Socketing" description and append sSocketDescription if (sSaved == "" || FindSubString(sDescription, SOCKET_DESCRIPTION_SOCKET) == -1) { SetLocalString(oItem, SOCKET_VAR_ITEM_DESCRIPTION, sDescription); sDescription += sSocketDescription; } // otherwise, use the saved "original/pre-Socketing" description and append there else sDescription = sSaved + sSocketDescription; SetDescription(oItem, sDescription); } int socket_InsertSocketableItem(object oPC, object oItem, object oItemToSocket) { string sItemToSocket_ResRef = GetResRef(oItemToSocket); // If this is the Socket Creator, create a socket if (GetIsDM(oPC) && sItemToSocket_ResRef == "socket_creator") { socket_CreateSockets(oItem, 1); return FALSE; } string sItemToSocket_Name = GetName(oItemToSocket); // Find out if there's an empty socket int nSocket = socket_GetEmptySocket(oItem); if (nSocket == -1) { SendMessageToPC(oPC, "There is no empty socket available on " + GetName(oItem)); return FALSE; } else { // Find out if this item is already socketed int n = 1; while (n < nSocket) { if (GetLocalString(oItem, SOCKET_VAR_SOCKET_RESREF + "_" + IntToString(n)) == sItemToSocket_ResRef) { SendMessageToPC(oPC, "A socket already contains " + sItemToSocket_Name); return FALSE; } n++; } } // Retrieve information about the socketed item from Database itemproperty IP = socket_GetProperty(oItem, oItemToSocket); if (!GetIsItemPropertyValid(IP)) return FALSE; // Add the identified item property to the item IPSafeAddItemProperty(oItem, IP, 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING); // Set the local strings for the sockets on the item SetLocalString(oItem, SOCKET_VAR_SOCKET_RESREF + "_" + IntToString(nSocket), sItemToSocket_ResRef); SetLocalString(oItem, SOCKET_VAR_SOCKET_TAG + "_" + IntToString(nSocket), GetTag(oItemToSocket)); SetLocalString(oItem, SOCKET_VAR_SOCKET_NAME + "_" + IntToString(nSocket), sItemToSocket_Name); // Destory the now socketed item DestroyObject(oItemToSocket); // Set the new description socket_SetDescription(oItem); // Tell the player he successfully socketed the item SendMessageToPC(oPC, "You successfully socketed " + sItemToSocket_Name + " into " + GetName(oItem)); return TRUE; } int socket_CreateSocket(object oItem, int nSocket = 1) { // Only items of known Categories are able to get Sockets if (socket_GetItemCategory(oItem) == SOCKET_ITEMCATEGORY_UNKNOWN) return FALSE; string sExisting = GetLocalString(oItem, SOCKET_VAR_SOCKET_RESREF + "_" + IntToString(nSocket)); // If the Socket already exists, return FALSE if (sExisting != "") return FALSE; else { SetLocalString(oItem, SOCKET_VAR_SOCKET_RESREF + "_" + IntToString(nSocket), SOCKET_SOCKETED_NONE); return TRUE; } } int socket_CreateSockets(object oItem, int nCount) { // Only items of known Categories are able to get Sockets if (socket_GetItemCategory(oItem) == SOCKET_ITEMCATEGORY_UNKNOWN) return FALSE; // Reduce nCount if needed if (nCount > SOCKET_MAXIMUM) nCount = SOCKET_MAXIMUM; int nCreated = 0; int n; for (n = 1; n <= SOCKET_MAXIMUM; n++) { if (socket_CreateSocket(oItem, n)) nCreated++; if (nCreated == nCount) break; } if (nCreated > 0) socket_SetDescription(oItem); return nCreated; } void socket_CreateSocketableItem(object oTarget, int nLevel = -1) { // Select an item string sResRef = socket_GetSocketableItem(); // Create selected item in oTarget's inventory object oItem = CreateItemOnObject(sResRef, oTarget); // Set Name of item (recoloring based on level/rarity // Set level on item SetLocalInt(oItem, SOCKET_VAR_ITEM_LEVEL, nLevel); }