/*////////////////////////////////////////////////////////////////////////////// // Script Name: pinc_henchmen //////////////////////////////////////////////////////////////////////////////// Include file for Henchmen plug in scripts for Philos Module Extentions. Database Info: Slot 0 - henchname = the save slot 1 - 8. Slots 1 - 8 define the selections: henchname = Saved character selected. image = Current character selected. */////////////////////////////////////////////////////////////////////////////// #include "0i_nui" #include "nw_inc_gff" const string HENCHMAN_DATABASE = "philos_henchman_db"; const string HENCHMAN_TABLE = "HENCHMAN_TABLE"; const string HENCHMAN_TO_EDIT = "HENCHMAN_TO_EDIT"; // Creates the table and initializes if it needs to. void CheckHenchmanDataAndInitialize(object oPC, string sSlot); // Removes a henchan from the current slot. void RemoveHenchmanDb(object oPC, string sSlot); // sDataField should be one of the data fields for that table. // sData is the string data to be saved. void SetHenchmanDbString(object oPC, string sDataField, string sData, string sSlot); // sDataField should be one of the data fields for the table. // Returns a string of the data stored. string GetHenchmanDbString(object oPC, string sDataField, string sSlot); // sDataField should be one of the data fields for that table. // jData is the json data to be saved. void SetHenchmanDbJson(object oPC, string sDataField, json jData, string sSlot); // sDataField should be one of the data fields for the table. // Returns a string of the data stored. json GetHenchmanDbJson(object oPC, string sDataField, string sSlot); // sSlot is the slot to define this object in the database for this Slot## (# Party button and #1-6). // oHenchman is the PC/Henchman to be saved. void SetHenchmanDbObject(object oPC, object oHenchman, string sSlot); // sSlot is the slot to define this object in the database for this Slot## (# Party button and #1-6). // lLocationToSpawn will spawn the object at that location. object GetHenchmanDbObject(object oPC, location lLocationToSpawn, string sSlot); // Returns TRUE if the henchman with sName can join. int GetJoinButtonActive(object oPC, string sName); // Returns a two letter alignment string. string GetAlignText(object oHenchman); // Populates the Saved character group. void AddSavedCharacterInfo(object oPC, int nToken, string sParty); // Populates the Current character group. void AddCurrentCharacterInfo(object oPC, int nToken, string sParty); // Removes a henchman from your party. void RemoveYourHenchman(object oPC, int nToken, string sParty); // Removes all henchman from the party. void RemoveWholeParty(object oPC, int nToken, string sParty); // Saves a henchman in your party to the saved party #. void SaveYourHenchman(object oPC, int nToken, string sParty); // Saves the whole party to the saved party #. void SaveWholeParty(object oPC, int nToken, string sParty); // Saves the players current party to party #. void SavedPartyJoin(object oPC, int nToken, string sParty); // Saves a character in the players party to party #. void SavedCharacterJoin(object oPC, int nToken, string sParty); // Clears the players saved party #. void SavedPartyCleared(object oPC, int nToken, string sParty); // Sets oHenchmans scripts to the current AI. void SetHenchmanScripts(object oHenchman); // If a henchman does not have a LvlStatList this will create one for them. // nLevels allows the creation of x levels for LvlStatList using the 1st class. // 0 on nLevels makes the function build it based on current levels. json CreateLevelStatList(json jHenchman, object oHenchman, object oPC, int nLevels = 0); // Resets the character to level one in the first class. object ResetCharacter(object oPC, object oHenchman); // Creates a menu to edit a characters information. void CreateCharacterEditGUIPanel(object oPC, object oAssociate); // Creates a character description menu. void CreateCharacterDescriptionNUI(object oPC, string sName, string sIcon, string sDescription); void CreateHenchmanDataTable () { sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, "CREATE TABLE IF NOT EXISTS " + HENCHMAN_TABLE + " (" + "name TEXT, " + "slot TEXT, " + "henchname TEXT, " + "image TEXT, " + "stats TEXT, " + "classes TEXT, " + "henchman TEXT, " + "PRIMARY KEY(slot));"); SqlStep (sql); } void CheckHenchmanDataAndInitialize(object oPC, string sSlot) { string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); string sQuery = "SELECT name FROM sqlite_master WHERE type ='table' AND name=@tableName;"; sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); SqlBindString(sql, "@tableName", HENCHMAN_TABLE); if(!SqlStep (sql)) CreateHenchmanDataTable(); sQuery = "SELECT slot FROM " + HENCHMAN_TABLE + " Where name = @name AND slot = @slot;"; sql = SqlPrepareQueryCampaign("philos_henchman_db", sQuery); SqlBindString(sql, "@name", sPCName); SqlBindString(sql, "@slot", sSlot); if(!SqlStep(sql)) { sQuery = "INSERT INTO " + HENCHMAN_TABLE + "(name, slot, henchname, image, stats, classes " + ", henchman) VALUES (@name, @slot, @henchname, @image, @stats, @classes, @henchman);"; sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); SqlBindString(sql, "@name", sPCName); SqlBindString(sql, "@slot", sSlot); SqlBindString(sql, "@henchname", ""); SqlBindString(sql, "@image", ""); SqlBindString(sql, "@stats", ""); SqlBindString(sql, "@classes", ""); SqlBindJson(sql, "@henchman", JsonObject()); SqlStep(sql); } } void RemoveHenchmanDb(object oPC, string sSlot) { string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); string sQuery = "DELETE FROM " + HENCHMAN_TABLE + " WHERE " + "name = @name AND slot = @slot;"; sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); SqlBindString(sql, "@name", sPCName); SqlBindString(sql, "@slot", sSlot); SqlStep(sql); } void SetHenchmanDbString(object oPC, string sDataField, string sData, string sSlot) { string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); string sQuery = "UPDATE " + HENCHMAN_TABLE + " SET " + sDataField + " = @data WHERE " + "name = @name AND slot = @slot;"; sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); SqlBindString(sql, "@data", sData); SqlBindString(sql, "@name", sPCName); SqlBindString(sql, "@slot", sSlot); SqlStep(sql); } string GetHenchmanDbString(object oPC, string sDataField, string sSlot) { string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); string sQuery = "SELECT " + sDataField + " FROM " + HENCHMAN_TABLE + " WHERE " + "name = @name AND slot = @slot;"; sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); SqlBindString(sql, "@name", sPCName); SqlBindString(sql, "@slot", sSlot); if(SqlStep (sql)) return SqlGetString(sql, 0); else return ""; } void SetHenchmanDbJson(object oPC, string sDataField, json jData, string sSlot) { string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); string sQuery = "UPDATE " + HENCHMAN_TABLE + " SET " + sDataField + " = @data WHERE name = @name AND slot = @slot;"; sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); SqlBindJson (sql, "@data", jData); SqlBindString(sql, "@name", sPCName); SqlBindString (sql, "@slot", sSlot); SqlStep (sql); } json GetHenchmanDbJson(object oPC, string sDataField, string sSlot) { string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); string sQuery = "SELECT " + sDataField + " FROM " + HENCHMAN_TABLE + " WHERE " + "name = @name AND slot = @slot;"; sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); SqlBindString(sql, "@name", sPCName); SqlBindString (sql, "@slot", sSlot); if (SqlStep (sql)) return SqlGetJson (sql, 0); else return JsonArray (); } void SetHenchmanDbObject(object oPC, object oHenchman, string sSlot) { string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); string sQuery = "UPDATE " + HENCHMAN_TABLE + " SET henchman = @henchman WHERE " + "name = @name AND slot = @slot;"; sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); SqlBindObject(sql, "@henchman", oHenchman); SqlBindString(sql, "@name", sPCName); SqlBindString(sql, "@slot", sSlot); SqlStep(sql); } object GetHenchmanDbObject(object oPC, location lLocationToSpawn, string sSlot) { string sPCName = ai_RemoveIllegalCharacters(GetPCPlayerName(oPC)); string sQuery = "SELECT henchman FROM " + HENCHMAN_TABLE + " WHERE " + "name = @name AND slot = @slot;"; sqlquery sql = SqlPrepareQueryCampaign(HENCHMAN_DATABASE, sQuery); SqlBindString(sql, "@name", sPCName); SqlBindString (sql, "@slot", sSlot); if (SqlStep (sql)) { json jHenchman = SqlGetJson(sql, 0); string sTag = JsonGetString(GffGetString(jHenchman, "Tag")); if(sTag == "") jHenchman = GffReplaceString(jHenchman, "Tag", "Hench_" + IntToString(Random(100))); return JsonToObject(jHenchman, lLocationToSpawn, OBJECT_INVALID, TRUE); } return OBJECT_INVALID; } int GetJoinButtonActive(object oPC, string sName) { if(sName == GetName(oPC)) return FALSE; // Look for a free henchman slot, and if this henchman is already joined! int nIndex = 1; object oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); while(oHenchman != OBJECT_INVALID) { if(GetName(oHenchman) == sName) return FALSE; oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, ++nIndex); } return TRUE; } string GetAlignText(object oHenchman) { string sAlign1, sAlign2; switch (GetAlignmentLawChaos(oHenchman)) { case ALIGNMENT_LAWFUL : sAlign1 = "L"; break; case ALIGNMENT_NEUTRAL : sAlign1 = "N"; break; case ALIGNMENT_CHAOTIC : sAlign1 = "C"; break; } switch (GetAlignmentGoodEvil(oHenchman)) { case ALIGNMENT_GOOD : sAlign2 = "G"; break; case ALIGNMENT_NEUTRAL : sAlign2 = "N"; break; case ALIGNMENT_EVIL : sAlign2 = "E"; break; } string sAlign = sAlign1 + sAlign2; if (sAlign == "NN") sAlign = "TN"; return sAlign; } void AddSavedCharacterInfo(object oPC, int nToken, string sParty) { string sHenchman = GetHenchmanDbString(oPC, "henchname", sParty); // Add Henchman information. if(sHenchman != "") { NuiSetBind (oPC, nToken, "btn_clear_party_event", JsonBool (TRUE)); string sText = " Clears all characters from party " + sParty + "'s list!"; NuiSetBind(oPC, nToken, "btn_clear_party_tooltip", JsonString(sText)); NuiSetBind(oPC, nToken, "btn_join_party", JsonBool (TRUE)); NuiSetBind(oPC, nToken, "btn_join_party_event", JsonBool (TRUE)); sText = " Saved characters from party " + sParty + " enter the game and join you."; NuiSetBind(oPC, nToken, "btn_join_party_tooltip", JsonString(sText)); // Setup the henchman window. string sName = GetHenchmanDbString(oPC, "henchname", sParty + sHenchman); string sImage = GetHenchmanDbString(oPC, "image", sParty + sHenchman); string sStats = GetHenchmanDbString(oPC, "stats", sParty + sHenchman); string sClasses = GetHenchmanDbString(oPC, "classes", sParty + sHenchman); NuiSetBind(oPC, nToken, "lbl_save_char_label", JsonString(sName)); NuiSetBind(oPC, nToken, "img_saved_portrait_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "img_saved_portrait_image", JsonString(sImage + "l")); NuiSetBind(oPC, nToken, "lbl_saved_stats_label", JsonString(sStats)); NuiSetBind(oPC, nToken, "lbl_saved_classes_label", JsonString(sClasses)); NuiSetBind(oPC, nToken, "btn_saved_join_label", JsonString("Join")); NuiSetBind(oPC, nToken, "btn_saved_join_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "btn_saved_remove_event", JsonBool(TRUE)); //NuiSetBind(oPC, nToken, "btn_saved_edit_event", JsonBool(TRUE)); } else { NuiSetBind(oPC, nToken, "lbl_save_char_label", JsonString("Empty Party")); NuiSetBind (oPC, nToken, "btn_clear_party_event", JsonBool (FALSE)); NuiSetBind (oPC, nToken, "btn_join_party", JsonBool (FALSE)); NuiSetBind (oPC, nToken, "btn_join_party_event", JsonBool (FALSE)); // Setup the henchman window. NuiSetBind(oPC, nToken, "img_saved_portrait_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "img_saved_portrait_image", JsonString("po_hu_m_99_l")); NuiSetBind(oPC, nToken, "lbl_saved_stats_label", JsonString("")); NuiSetBind(oPC, nToken, "lbl_saved_classes_label", JsonString("")); NuiSetBind(oPC, nToken, "btn_saved_join_event", JsonBool(FALSE)); NuiSetBind(oPC, nToken, "btn_saved_join_label", JsonString("Join")); NuiSetBind(oPC, nToken, "btn_saved_remove_event", JsonBool(FALSE)); NuiSetBind(oPC, nToken, "btn_saved_edit_event", JsonBool(FALSE)); } } void AddCurrentCharacterInfo(object oPC, int nToken, string sParty) { string sHenchman = GetHenchmanDbString(oPC, "image", sParty); if(sHenchman == "") { CheckHenchmanDataAndInitialize(oPC, sParty); SetHenchmanDbString(oPC, "image", "0", sParty); } int nHenchman = StringToInt(sHenchman); int nIndex = 0; object oCharacter; while(nIndex < AI_MAX_HENCHMAN) { if(nIndex == 0) oCharacter = oPC; else oCharacter = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); if(oCharacter == OBJECT_INVALID) { nIndex = 0; oCharacter = oPC; break; } else if(nHenchman == nIndex) break; nIndex++; } // Adjust the party buttons. int bParty = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, 1) != OBJECT_INVALID; //NuiSetBind(oPC, nToken, "btn_save_party", JsonBool (bParty)); NuiSetBind(oPC, nToken, "btn_save_party_event", JsonBool (bParty)); //NuiSetBind(oPC, nToken, "btn_remove_party", JsonBool (bParty)); NuiSetBind(oPC, nToken, "btn_remove_party_event", JsonBool (bParty)); if(bParty) { string sText = " Saves all henchman from your current party to party " + sParty + "."; NuiSetBind(oPC, nToken, "btn_save_party_tooltip", JsonString(sText)); sText = " Removes all henchman from your current party!"; NuiSetBind(oPC, nToken, "btn_remove_party_tooltip", JsonString(sText)); } // Setup the henchman window. string sName = GetName(oCharacter); string sImage = GetPortraitResRef(oCharacter); string sStats = GetAlignText(oCharacter) + " "; if(GetGender(oCharacter) == GENDER_MALE) sStats += "Male "; else sStats += "Female "; int nPosition = 1; sStats += GetStringByStrRef (StringToInt (Get2DAString ("racialtypes", "Name", GetRacialType (oCharacter)))); string sClasses = GetStringByStrRef (StringToInt (Get2DAString ("classes", "Short", GetClassByPosition (nPosition, oCharacter)))); sClasses += " " + IntToString (GetLevelByPosition (nPosition, oCharacter)); int nClass = GetClassByPosition(++nPosition, oCharacter); while(nClass != CLASS_TYPE_INVALID) { sClasses += ", " + GetStringByStrRef (StringToInt (Get2DAString ("classes", "Short", nClass))); sClasses += " " + IntToString (GetLevelByPosition (nPosition, oCharacter)); nClass = GetClassByPosition(++nPosition, oCharacter); } NuiSetBind(oPC, nToken, "lbl_game_char_label", JsonString(sName)); NuiSetBind(oPC, nToken, "img_cur_portrait_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "img_cur_portrait_image", JsonString(sImage + "l")); NuiSetBind(oPC, nToken, "lbl_cur_stats_label", JsonString(sStats)); NuiSetBind(oPC, nToken, "lbl_cur_classes_label", JsonString(sClasses)); NuiSetBind(oPC, nToken, "btn_cur_save_label", JsonString("Save")); NuiSetBind(oPC, nToken, "btn_cur_save_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "btn_cur_edit_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "btn_cur_remove_event", JsonBool(TRUE)); } object GetSelectedHenchman(object oPC, string sParty) { string sHenchman = GetHenchmanDbString(oPC, "image", sParty); if(sHenchman == "") { CheckHenchmanDataAndInitialize(oPC, sParty); SetHenchmanDbString(oPC, "image", "0", sParty); } int nHenchman = StringToInt(sHenchman); int nIndex = 0; object oCharacter; while(nIndex < AI_MAX_HENCHMAN) { if(nIndex == 0) oCharacter = oPC; else oCharacter = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); if(oCharacter == OBJECT_INVALID) { nIndex = 0; oCharacter = oPC; break; } else if(nHenchman == nIndex) break; nIndex++; } return oCharacter; } void RemoveYourHenchman(object oPC, int nToken, string sParty) { object oHenchman = GetSelectedHenchman(oPC, sParty); if(oHenchman == oPC) ai_SendMessages("You cannot remove the player from the party!", AI_COLOR_RED, oPC); else { RemoveHenchman(oPC, oHenchman); AssignCommand(oHenchman, SetIsDestroyable(TRUE, FALSE, FALSE)); NuiDestroy(oPC, NuiFindWindow(oPC, ai_GetAssociateType(oPC, oHenchman) + AI_WIDGET_NUI)); DestroyObject(oHenchman); } ai_SendMessages(GetName(oHenchman) + " has been removed from the party!", AI_COLOR_GREEN, oPC); NuiDestroy(oPC, nToken); ExecuteScript("pi_henchmen", oPC); } void RemoveWholeParty(object oPC, int nToken, string sParty) { int nIndex = AI_MAX_HENCHMAN; object oHenchman; oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); while(nIndex > 0) { if(oHenchman != OBJECT_INVALID) { ai_SendMessages(GetName(oHenchman) + " has been remove from your Party.", AI_COLOR_YELLOW, oPC); RemoveHenchman(oPC, oHenchman); AssignCommand(oHenchman, SetIsDestroyable(TRUE, FALSE, FALSE)); NuiDestroy(oPC, NuiFindWindow(oPC, ai_GetAssociateType(oPC, oHenchman) + AI_WIDGET_NUI)); DestroyObject(oHenchman); } oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, --nIndex); } ai_SendMessages("All of your henchman have been remove from the Party.", AI_COLOR_YELLOW, oPC); NuiDestroy(oPC, nToken); ExecuteScript("pi_henchmen", oPC); } void SaveYourHenchman(object oPC, int nToken, string sParty) { int bPC, nIndex, nClass, nPosition, nMaxHenchman = AI_MAX_HENCHMAN + 1; string sName, sIndex, sSlot, sStats, sClasses; object oHenchman = GetSelectedHenchman(oPC, sParty); if(oHenchman == oPC) { bPC = TRUE; oHenchman = CopyObject(oPC, GetLocation(oPC), OBJECT_INVALID, "hench_" + IntToString(Random(100)), TRUE); SetHenchmanScripts(oHenchman); } string sHenchmanName = GetName(oHenchman); while(nIndex < nMaxHenchman) { sIndex = IntToString(nIndex); sName = GetHenchmanDbString(oPC, "henchname", sParty + sIndex); if(sName == sHenchmanName || sName == "") { sSlot = sParty + sIndex; if(!bPC) RemoveHenchman(oPC, oHenchman); // Special check for Infinite Dungeon plot givers to be changed into henchman. if(GetStringLeft(GetLocalString(oHenchman, "sConversation"), 8) == "id1_plot") { DeleteLocalString(oHenchman, "sConversation"); } ChangeToStandardFaction(oHenchman, STANDARD_FACTION_DEFENDER); json jHenchman = ObjectToJson(oHenchman, TRUE); if(!bPC) AddHenchman(oPC, oHenchman); else DestroyObject(oHenchman); //string sPatch = "[{\"op\":\"replace\",\"path\":\"/FactionID/value\",\"value\":1}]"; //json jPatch = JsonParse(sPatch); //jHenchman = JsonPatch(jHenchman, jPatch); CheckHenchmanDataAndInitialize(oPC, sSlot); SetHenchmanDbString(oPC, "image", GetPortraitResRef(oHenchman), sSlot); SetHenchmanDbString(oPC, "henchname", sHenchmanName, sSlot); sStats = GetAlignText(oHenchman) + " "; if(GetGender(oHenchman) == GENDER_MALE) sStats += "Male "; else sStats += "Female "; nPosition = 1; sStats += GetStringByStrRef (StringToInt (Get2DAString ("racialtypes", "Name", GetRacialType (oHenchman)))); sClasses = GetStringByStrRef (StringToInt (Get2DAString ("classes", "Short", GetClassByPosition (nPosition, oHenchman)))); sClasses += " " + IntToString (GetLevelByPosition (nPosition, oHenchman)); nClass = GetClassByPosition(++nPosition, oHenchman); while(nClass != CLASS_TYPE_INVALID) { sClasses += ", " + GetStringByStrRef (StringToInt (Get2DAString ("classes", "Short", GetClassByPosition (nPosition, oHenchman)))); sClasses += " " + IntToString (GetLevelByPosition (nPosition, oHenchman)); nClass = GetClassByPosition(++nPosition, oHenchman); } SetHenchmanDbString(oPC, "stats", sStats, sSlot); SetHenchmanDbString(oPC, "classes", sClasses, sSlot); SetHenchmanDbJson(oPC, "henchman", jHenchman, sSlot); if(sName == "") ai_SendMessages(sHenchmanName + " has been saved to the party.", AI_COLOR_GREEN, oPC); else ai_SendMessages(sHenchmanName + " has replaced a copy of themselves in the party.", AI_COLOR_GREEN, oPC); break; } nIndex++; } if(nIndex == nMaxHenchman) ai_SendMessages("This party is full!", AI_COLOR_RED, oPC); NuiDestroy(oPC, nToken); ExecuteScript("pi_henchmen", oPC); } void SaveWholeParty(object oPC, int nToken, string sParty) { int nIndex = AI_MAX_HENCHMAN; object oHenchman; while(nIndex > 0) { oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); if(oHenchman != OBJECT_INVALID) { SetHenchmanDbString(oPC, "image", IntToString(nIndex), sParty); SaveYourHenchman(oPC, nToken, sParty); } nIndex--; } ai_SendMessages("All of your henchman have been saved to Party " + sParty + ".", AI_COLOR_YELLOW, oPC); SetHenchmanDbString(oPC, "henchname", "0", sParty); NuiDestroy(oPC, nToken); ExecuteScript("pi_henchmen", oPC); } void SavedPartyJoin(object oPC, int nToken, string sParty) { int bFound, nIndex, nDBHenchman = 0; json jHenchman; object oHenchman, oLoadedHenchman; string sDBHenchman = IntToString(nDBHenchman); string sName = GetHenchmanDbString(oPC, "henchname", sParty + sDBHenchman); while(sName != "") { bFound = FALSE; nIndex = 1; oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); while(oHenchman != OBJECT_INVALID) { if(sName == GetName(oPC) || GetName(oHenchman) == sName) { bFound = TRUE; break; } oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, ++nIndex); } if(!bFound) { ai_SendMessages(sName + " has joined your party.", AI_COLOR_GREEN, oPC); jHenchman = GetHenchmanDbJson(oPC, "henchman", sParty + sDBHenchman); oLoadedHenchman = JsonToObject(jHenchman, GetLocation(oPC), OBJECT_INVALID, TRUE); AddHenchman(oPC, oLoadedHenchman); } else ai_SendMessages(sName + " is already in your party!", AI_COLOR_RED, oPC); sDBHenchman = IntToString(++nDBHenchman); sName = GetHenchmanDbString(oPC, "henchname", sParty + sDBHenchman); } NuiDestroy(oPC, nToken); ExecuteScript("pi_henchmen", oPC); } void SavedCharacterJoin(object oPC, int nToken, string sParty) { int nIndex, bFound; object oHenchman, oLoadedHenchman; string sHenchman = GetHenchmanDbString(oPC, "henchname", sParty); string sName = GetHenchmanDbString(oPC, "henchname", sParty + sHenchman); nIndex = 1; oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex); while(oHenchman != OBJECT_INVALID) { if(sName == GetName(oPC) || GetName(oHenchman) == sName) { bFound = TRUE; break; } oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, ++nIndex); } if(!bFound) { ai_SendMessages(sName + " has joined your party!", AI_COLOR_GREEN, oPC); oLoadedHenchman = GetHenchmanDbObject(oPC, GetLocation(oPC), sParty + sHenchman); AddHenchman(oPC, oLoadedHenchman); NuiDestroy(oPC, nToken); ExecuteScript("pi_henchmen", oPC); } else ai_SendMessages(sName + " is already in your party!", AI_COLOR_RED, oPC); } void SavedPartyCleared(object oPC, int nToken, string sParty) { int nIndex, nMaxHenchman = AI_MAX_HENCHMAN + 1; object oHenchman, oLoadedHenchman; string sIndex = IntToString(nIndex); string sName = GetHenchmanDbString(oPC, "henchname", sParty + sIndex); while(nIndex < nMaxHenchman) { if(sName != "") { RemoveHenchmanDb(oPC, sParty + sIndex); ai_SendMessages(sName + " has been cleared from the saved party " + sParty + ".", AI_COLOR_YELLOW, oPC); } sIndex = IntToString(++nIndex); sName = GetHenchmanDbString(oPC, "henchname", sParty + sIndex); } SetHenchmanDbString(oPC, "henchname", "", sParty); NuiDestroy(oPC, nToken); ExecuteScript("pi_henchmen", oPC); } json CreateOptionsAlignment(object oHenchman, int nAlignType) { json jAlignNameList = JsonArray(); if(nAlignType == 0) { jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Lawful")); jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Neutral")); jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Chaotic")); } else { jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Good")); jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Neutral")); jAlignNameList = JsonArrayInsert(jAlignNameList, JsonString("Evil")); } return jAlignNameList; } json CreateOptionsClasses(object oHenchman) { int nIndex = 1, nClass; string sClassName; json jClassNameList = JsonArray(); while(nIndex < 5) { nClass = GetClassByPosition(nIndex, oHenchman); if(nClass == CLASS_TYPE_INVALID) sClassName = "Empty"; else { sClassName = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass))); sClassName += " " + IntToString(GetLevelByClass(nClass, oHenchman)); } jClassNameList = JsonArrayInsert(jClassNameList, JsonString(sClassName)); nIndex++; } return jClassNameList; } json jArrayInsertClasses() { int nIndex, nClass, nMaxClass = Get2DARowCount("classes"); string sClassName; json jClassNameCombo = JsonArray(); while(nIndex < nMaxClass) { if(Get2DAString("classes", "PlayerClass", nIndex) == "1") { sClassName = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nIndex))); jClassNameCombo = JsonArrayInsert(jClassNameCombo, NuiComboEntry(sClassName, nClass)); nClass++; } nIndex++; } return jClassNameCombo; } int GetSelectionByClass2DA(int nClass) { int nIndex, nSelection, nMaxClass = Get2DARowCount("classes"); while(nIndex < nMaxClass) { if(Get2DAString("classes", "PlayerClass", nIndex) == "1") { if(nClass == nIndex) return nSelection; nSelection++; } nIndex++; } return -1; } int GetClassBySelection2DA(int nSelection) { int nIndex, nClass, nMaxClass = Get2DARowCount("classes"); while(nClass < nMaxClass) { if(Get2DAString("classes", "PlayerClass", nClass) == "1") { if(nSelection == nIndex) return nClass; nIndex++; } nClass++; } return -1; } json ArrayInsertPackages(string sClass) { int nIndex, nPackage, nMaxPackage = Get2DARowCount("packages"); string sPackageName; json jPackageNameCombo = JsonArray(); while(nIndex < nMaxPackage) { if(Get2DAString("packages", "ClassID", nIndex) == sClass) { sPackageName = Get2DAString("packages", "Label", nIndex); //GetStringByStrRef(StringToInt(Get2DAString("packages", "Name", nIndex))); if(sPackageName != "Bad Strref" && sPackageName != "") { jPackageNameCombo = JsonArrayInsert(jPackageNameCombo, NuiComboEntry(sPackageName, nPackage)); nPackage++; } } nIndex++; } return jPackageNameCombo; } int GetSelectionByPackage2DA(string sClass, int nPackage) { int nIndex, nSelection, nMaxPackage = Get2DARowCount("packages"); string sPackageName; while(nIndex < nMaxPackage) { if(Get2DAString("packages", "ClassID", nIndex) == sClass) { sPackageName = GetStringByStrRef(StringToInt(Get2DAString("packages", "Name", nIndex))); if(sPackageName != "Bad Strref" && sPackageName != "") { if(nPackage == nIndex) return nSelection; nSelection++; } } nIndex++; } return -1; } int GetPackageBySelection2DA(string sClass, int nSelection) { int nIndex, nPackage, nMaxPackage = Get2DARowCount("packages"); while(nPackage < nMaxPackage) { if(Get2DAString("packages", "ClassID", nPackage) == sClass) { if(nSelection == nIndex) return nPackage; nIndex++; } nPackage++; } return -1; } json ArrayInsertSoundSets(object oHenchman) { int nIndex, nSoundSet, nSoundSetType, nMaxSets = Get2DARowCount("soundset"); string sGender = IntToString(GetGender(oHenchman)); string sSoundSetName, sResRef; json jSoundSetNameCombo = JsonArray(); while(nIndex < nMaxSets) { if(Get2DAString("soundset", "GENDER", nIndex) == sGender) { nSoundSetType = StringToInt(Get2DAString("soundset", "TYPE", nIndex)); if(nSoundSetType < 5) { sSoundSetName = GetStringByStrRef(StringToInt(Get2DAString("soundset", "STRREF", nIndex))); sResRef = GetStringLowerCase(Get2DAString("soundset", "RESREF", nIndex)); if(GetStringLeft(sResRef, 4) == "vs_f") sSoundSetName += " (Full)"; else if(GetStringLeft(sResRef, 4) == "vs_n") sSoundSetName += " (Part)"; jSoundSetNameCombo = JsonArrayInsert(jSoundSetNameCombo, NuiComboEntry(sSoundSetName, nSoundSet)); nSoundSet++; } } nIndex++; } return jSoundSetNameCombo; } int GetSelectionBySoundSet2DA(object oHenchman, int nSoundSet) { int nIndex, nSelection, nSoundSetType, nMaxSoundSet = Get2DARowCount("soundset"); string sGender = IntToString(GetGender(oHenchman)); while(nIndex < nMaxSoundSet) { if(Get2DAString("soundset", "GENDER", nIndex) == sGender) { nSoundSetType = StringToInt(Get2DAString("soundset", "TYPE", nIndex)); if(nSoundSetType < 5) { if(nSoundSet == nIndex) return nSelection; nSelection++; } } nIndex++; } return -1; } int GetSoundSetBySelection2DA(object oHenchman, int nSelection) { int nIndex, nSoundSet, nSoundSetType, nMaxSoundSet = Get2DARowCount("soundset"); string sGender = IntToString(GetGender(oHenchman)); while(nSoundSet < nMaxSoundSet) { if(Get2DAString("soundset", "GENDER", nSoundSet) == sGender) { nSoundSetType = StringToInt(Get2DAString("soundset", "TYPE", nSoundSet)); if(nSoundSetType < 5) { if(nSelection == nIndex) return nSoundSet; nIndex++; } } nSoundSet++; } return -1; } void SetHenchmanScripts(object oHenchman) { SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "nw_ch_ac1"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_NOTICE, "nw_ch_ac2"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "nw_ch_ac3"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "nw_ch_ac4"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "nw_ch_ac5"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "nw_ch_ac6"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_DEATH, "nw_ch_ac7"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "nw_ch_ac8"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, "nw_ch_ac9"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_RESTED, "nw_ch_aca"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "nw_ch_acb"); SetEventScript(oHenchman, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "nw_ch_ace"); } object ai_AddHenchman(object oPC, json jHenchman, location lLocation, int nFamiliar, int nCompanion) { jHenchman = GffReplaceResRef(jHenchman, "ScriptSpawn", ""); object oHenchman = JsonToObject(jHenchman, lLocation, OBJECT_INVALID, TRUE); AddHenchman(oPC, oHenchman); DeleteLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE"); string sAssociateType = ai_GetAssociateType(oPC, oHenchman); NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI)); if(nFamiliar) SummonFamiliar(oHenchman); if(nCompanion) SummonAnimalCompanion(oHenchman); return oHenchman; } json CreateLevelStatList(json jHenchman, object oHenchman, object oPC, int nLevels = 0) { int nClass = GetClassByPosition(1, oHenchman); int nHitDie = StringToInt(Get2DAString("classes", "HitDie", nClass)); SetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE", TRUE); json jSkill = JsonObject(); jSkill = GffAddByte(jSkill, "Rank", 0); jSkill = JsonObjectSet(jSkill, "__struct_id", JsonInt(0)); json jSkillArray = JsonArray(); int nNumOfSkills; for(nNumOfSkills = Get2DARowCount("skills"); nNumOfSkills > 0; nNumOfSkills--) { jSkillArray = JsonArrayInsert(jSkillArray, jSkill); } json jLevel = JsonObject(); jLevel = GffAddByte(jLevel, "EpicLevel", 0); jLevel = GffAddList(jLevel, "FeatList", JsonArray()); jLevel = GffAddByte(jLevel, "LvlStatClass", nClass); jLevel = GffAddByte(jLevel, "LvlStatHitDie", nHitDie); jLevel = GffAddList(jLevel, "SkillList", jSkillArray); jLevel = GffAddWord(jLevel, "SkillPoints", 0); jLevel = JsonObjectSet(jLevel, "__struct_id", JsonInt(0)); json jLevelArray = JsonArray(); if(nLevels == 0) nLevels = GetLevelByPosition(1, oHenchman); for(nLevels; nLevels > 0; nLevels--) { jLevelArray = JsonArrayInsert(jLevelArray, jLevel); } WriteTimestampedLogEntry("pinc_henchmen, 813, Creating LvlStatList for " + GetName(oHenchman)); return GffAddList(jHenchman, "LvlStatList", jLevelArray); } int CanSelectFeat(json jCreature, object oCreature, int nFeat, int nPosition = 1) { // Check if all classes can use. int n2DAStat = StringToInt(Get2DAString("feat", "ALLCLASSESCANUSE", nFeat)); if(n2DAStat == 0) { int bPass, nClassFeat, nRow, nClass = GetClassByPosition(nPosition, oCreature); string sClsFeat2DAName = Get2DAString("classes", "FeatsTable", nClass); int nMaxRow = Get2DARowCount(sClsFeat2DAName); while(nRow < nMaxRow) { nClassFeat = StringToInt(Get2DAString(sClsFeat2DAName, "FeatIndex", nRow)); if(nClassFeat == nFeat) { bPass = TRUE; break; } nRow++; } if(!bPass) return FALSE; } n2DAStat = StringToInt(Get2DAString("feat", "MINATTACKBONUS", nFeat)); if(JsonGetInt(GffGetByte(jCreature, "BaseAttackBonus")) < n2DAStat) return FALSE; n2DAStat = StringToInt(Get2DAString("feat", "MINSTR", nFeat)); if(JsonGetInt(GffGetByte(jCreature, "Str")) < n2DAStat) return FALSE; n2DAStat = StringToInt(Get2DAString("feat", "MINDEX", nFeat)); if(JsonGetInt(GffGetByte(jCreature, "Dex")) < n2DAStat) return FALSE; n2DAStat = StringToInt(Get2DAString("feat", "MINCON", nFeat)); if(JsonGetInt(GffGetByte(jCreature, "Con")) < n2DAStat) return FALSE; n2DAStat = StringToInt(Get2DAString("feat", "MININT", nFeat)); if(JsonGetInt(GffGetByte(jCreature, "Int")) < n2DAStat) return FALSE; n2DAStat = StringToInt(Get2DAString("feat", "MINWIS", nFeat)); if(JsonGetInt(GffGetByte(jCreature, "Wis")) < n2DAStat) return FALSE; n2DAStat = StringToInt(Get2DAString("feat", "MINCHA", nFeat)); if(JsonGetInt(GffGetByte(jCreature, "Cha")) < n2DAStat) return FALSE; n2DAStat = StringToInt(Get2DAString("feat", "MINSPELLLVL", nFeat)); int nSpellLevel = 0, nClass = GetClassByPosition(nPosition, oCreature); string s2DAName = Get2DAString("classes", "SpellGainTable", nClass); int nLevel = GetLevelByPosition(nPosition, oCreature); if(s2DAName != "") { nSpellLevel = StringToInt(Get2DAString(s2DAName, "NumSpellLevels", nLevel - 1)) - 1; } if(nSpellLevel < n2DAStat) return FALSE; n2DAStat = StringToInt(Get2DAString("feat", "PREREQFEAT1", nFeat)); if(n2DAStat > 0) { // ************************************** Add code to search jCreature's feats! if(!GetHasFeat(n2DAStat, oCreature)) return FALSE; n2DAStat = StringToInt(Get2DAString("feat", "PREREQFEAT2", nFeat)); if(!GetHasFeat(n2DAStat, oCreature)) return FALSE; } int nIndex; while(nIndex < 5) { n2DAStat = StringToInt(Get2DAString("feat", "OrReqFeat" + IntToString(nIndex), nFeat)); if(nIndex == 0 && n2DAStat == 0) break; if(GetHasFeat(n2DAStat, oCreature)) break; nIndex++; if(nIndex == 5) return FALSE; } string s2DAStat = Get2DAString("feat", "REQSKILL", nFeat); if(s2DAStat != "") { n2DAStat = StringToInt(s2DAStat); int bCanUse; if(Get2DAString("skills", "AllClassesCanUse", n2DAStat) == "1") bCanUse = TRUE; else { string sClsSkill2DA = Get2DAString("classes", "SkillsTable", nClass); int bPass, nClassSkill, nRow, nMaxRow = Get2DARowCount(sClsSkill2DA); while(nRow < nMaxRow) { nClassSkill = StringToInt(Get2DAString(sClsSkill2DA, "SkillIndex", nRow)); if(nClassSkill == n2DAStat) { bCanUse = TRUE; break; } nRow++; } } if(bCanUse) { int nSkillReq = StringToInt(Get2DAString("feat", "ReqSkillMinRanks", n2DAStat)); // ************************** Add code to check jCreatures skills. if(GetSkillRank(n2DAStat, oCreature, TRUE) < nSkillReq) return FALSE; } else return FALSE; } s2DAStat = Get2DAString("feat", "REQSKILL2", nFeat); if(s2DAStat != "") { n2DAStat = StringToInt(s2DAStat); int bCanUse; if(Get2DAString("skills", "AllClassesCanUse", n2DAStat) == "1") bCanUse = TRUE; else { string sClsSkill2DA = Get2DAString("classes", "SkillsTable", nClass); int bPass, nClassSkill, nRow, nMaxRow = Get2DARowCount(sClsSkill2DA); while(nRow < nMaxRow) { nClassSkill = StringToInt(Get2DAString(sClsSkill2DA, "SkillIndex", nRow)); if(nClassSkill == n2DAStat) { bCanUse = TRUE; break; } nRow++; } } if(bCanUse) { int nSkillReq = StringToInt(Get2DAString("feat", "ReqSkillMinRanks2", n2DAStat)); if(GetSkillRank(n2DAStat, oCreature, TRUE) < nSkillReq) return FALSE; } else return FALSE; } n2DAStat = StringToInt(Get2DAString("feat", "MinLevel", nFeat)); if(n2DAStat > 0) { int bPass, nClassPosition, nPositionClass, nPositionLevel; int nClassRequired = StringToInt(Get2DAString("feat", "MinLevelClass", nFeat)); while(nClassPosition < AI_MAX_CLASSES_PER_CHARACTER) { // ***************************** Rework to check jCreature class list instead. nPositionClass = GetClassByPosition(nClassPosition, oCreature); if(nPositionClass == nClassRequired) { nPositionLevel = GetLevelByPosition(nClassPosition, oCreature); if(nPositionLevel < n2DAStat) return FALSE; else bPass = TRUE; } nClassPosition++; } if(!bPass) return FALSE; } n2DAStat = StringToInt(Get2DAString("feat", "MinFortSave", nFeat)); if(JsonGetInt(GffGetChar(jCreature, "FortSaveThrow")) < n2DAStat) return FALSE; s2DAStat = Get2DAString("feat", "PreReqEpic", nFeat); if(s2DAStat == "1") return FALSE; return TRUE; } json ResetFeats(json jHenchman, object oHenchman) { int nLevel = 0; // We remake the Feat list if the character doesn't have a level list! json jFeatList = JsonArray(); json jFeat; int nRace = GetRacialType(oHenchman); string sRace2DAName = Get2DAString("racialtypes", "FeatsTable", nRace); // Give racial feats. WriteTimestampedLogEntry("pinc_henchmen, 972, Checking for racial feats."); int nRaceRow, nRaceFeat; int nRaceMaxRow = Get2DARowCount(sRace2DAName); while(nRaceRow < nRaceMaxRow) { nRaceFeat = StringToInt(Get2DAString(sRace2DAName, "FeatIndex", nRaceRow)); jFeat = JsonObject(); jFeat = GffAddWord(jFeat, "Feat", nRaceFeat); jFeat = JsonObjectSet(jFeat, "__struct_id", JsonInt(1)); jFeatList = JsonArrayInsert(jFeatList, jFeat); WriteTimestampedLogEntry("pinc_henchmen, 982, Adding racial feat: " + Get2DAString("feat", "LABEL", nRaceFeat)); nRaceRow++; } // Give class feats. WriteTimestampedLogEntry("pinc_henchmen, 972, Checking for class feats."); int nClass = GetClassByPosition(1, oHenchman); string sGranted, sList; string sClsFeat2DAName = Get2DAString("classes", "FeatsTable", nClass); int nClassRow, nClassFeat, nClassMaxRow = Get2DARowCount(sClsFeat2DAName); while(nClassRow < nClassMaxRow) { sGranted = Get2DAString(sClsFeat2DAName, "GrantedOnLevel", nClassRow); if(sGranted == "1") { sList = Get2DAString(sClsFeat2DAName, "List", nClassRow); if(sList == "3") { nClassFeat = StringToInt(Get2DAString(sClsFeat2DAName, "FeatIndex", nClassRow)); jFeat = JsonObject(); jFeat = GffAddWord(jFeat, "Feat", nClassFeat); jFeat = JsonObjectSet(jFeat, "__struct_id", JsonInt(1)); jFeatList = JsonArrayInsert(jFeatList, jFeat); WriteTimestampedLogEntry("pinc_henchmen, 1005, Adding class feat: " + Get2DAString("feat", "LABEL", nClassFeat)); } } nClassRow++; } // Give any bonus feats from package. WriteTimestampedLogEntry("pinc_henchmen, 1012, Checking for selectable feats."); int nPackageFeat, nPackageRow; string sBonusFeat2DAName = Get2DAString("classes", "BonusFeatsTable", nClass); int nNumOfFeats = StringToInt(Get2DAString(sBonusFeat2DAName, "Bonus", nLevel)); string sPackage2DAName = Get2DAString("packages", "FeatPref2DA", nClass); int nPackageMaxRow = Get2DARowCount(sPackage2DAName); // Give bonus feats based on the package. nPackageRow = 0; if(nNumOfFeats > 0) { while(nPackageRow < nPackageMaxRow) { nPackageFeat = StringToInt(Get2DAString(sPackage2DAName, "FeatIndex", nPackageRow)); nClassRow = 0; while(nClassRow < nClassMaxRow) { nClassFeat = StringToInt(Get2DAString(sClsFeat2DAName, "FeatIndex", nClassRow)); if(nClassFeat == nPackageFeat) { sList = Get2DAString(sClsFeat2DAName, "List", nClassRow); if((sList == "1" || sList == "2") && CanSelectFeat(jHenchman, oHenchman, nClassFeat)) { jFeat = JsonObject(); jFeat = GffAddWord(jFeat, "Feat", nClassFeat); jFeat = JsonObjectSet(jFeat, "__struct_id", JsonInt(1)); jFeatList = JsonArrayInsert(jFeatList, jFeat); WriteTimestampedLogEntry("pinc_henchmen, 1028, Adding class bonus feat: " + Get2DAString("feat", "LABEL", nPackageFeat)); nNumOfFeats--; } } nClassRow++; } if(nNumOfFeats < 1) break; nPackageRow++; } } // Give picked feats from package. WriteTimestampedLogEntry("pinc_henchmen, 972, Checking for select feats."); nNumOfFeats = 1; if(GetHasFeat(FEAT_QUICK_TO_MASTER, oHenchman)) nNumOfFeats++; nPackageRow = 0; while(nPackageRow < nPackageMaxRow || nNumOfFeats > 0) { nClassRow = 0; nPackageFeat = StringToInt(Get2DAString(sPackage2DAName, "FeatIndex", nPackageRow)); if(CanSelectFeat(jHenchman, oHenchman, nPackageFeat)) { jFeat = JsonObject(); jFeat = GffAddWord(jFeat, "Feat", nPackageFeat); jFeat = JsonObjectSet(jFeat, "__struct_id", JsonInt(1)); jFeatList = JsonArrayInsert(jFeatList, jFeat); WriteTimestampedLogEntry("pinc_henchmen, 1053, Adding character bonus feat: " + Get2DAString("feat", "LABEL", nPackageFeat)); nNumOfFeats--; } if(nNumOfFeats < 1) break; nPackageRow++; } WriteTimestampedLogEntry("pinc_henchmen, 1071, Adding feat list."); jHenchman = GffReplaceList(jHenchman, "FeatList", jFeatList); return jHenchman; } json ResetSkills(json jHenchman, object oHenchman) { // We remake the Skill List if the character doesn't have a level list! int nClass = GetClassByPosition(1, oHenchman); int nSkillPoints, nIntMod = GetAbilityModifier(ABILITY_INTELLIGENCE, oHenchman); if(nIntMod > 0) nSkillPoints = nIntMod * 4; if(GetRacialType(oHenchman) == RACIAL_TYPE_HUMAN) nSkillPoints += 4; nSkillPoints += StringToInt(Get2DAString("classes", "SkillPointBase", nClass)) * 4; int nMaxRanks = 5; json jSkillList = JsonArray(); json jSkill; // Setup the Skill List. WriteTimestampedLogEntry("pinc_henchmen, 1087, Generating skill list."); int nIndex, nSkillMaxRow = Get2DARowCount("skills"); for(nIndex = 0; nIndex < nSkillMaxRow; nIndex++) { jSkill = JsonObject(); jSkill = GffAddByte(jSkill, "Rank", 0); jSkill = JsonObjectSet(jSkill, "__struct_id", JsonInt(0)); jSkillList = JsonArrayInsert(jSkillList, jSkill); } // Give skill points based on the package. WriteTimestampedLogEntry("pinc_henchmen, 1097, Gets " + IntToString(nSkillPoints) + " skill points."); int nPackageSkill, nPackageRow, nCurrentRanks, bCrossClass, nClassRow, nNewRanks; string sPackage2DAName = Get2DAString("packages", "SkillPref2DA", nClass); int nPackageMaxRow = Get2DARowCount(sPackage2DAName); string sClass2DAName = Get2DAString("classes", "SkillsTable", nClass); int nClassMaxRow = Get2DARowCount(sClass2DAName); nPackageRow = 0; while(nPackageRow < nPackageMaxRow && nSkillPoints > 0) { nPackageSkill = StringToInt(Get2DAString(sPackage2DAName, "SkillIndex", nPackageRow)); jSkill = JsonArrayGet(jSkillList, nPackageSkill); nCurrentRanks = JsonGetInt(GffGetByte(jSkill, "Rank")); nClassRow = 0; while(nClassRow < nClassMaxRow) { if(nPackageSkill == StringToInt(Get2DAString(sClass2DAName, "SkillIndex", nClassRow))) { bCrossClass = Get2DAString(sClass2DAName, "ClassSkill", nClassRow) == "0"; break; } nClassRow++; } if(bCrossClass) nNewRanks = (nMaxRanks / 2) - nCurrentRanks; else nNewRanks = nMaxRanks - nCurrentRanks; if(nNewRanks > nSkillPoints) nNewRanks = nSkillPoints; if(nNewRanks > 0) { jSkill = GffReplaceByte(jSkill, "Rank", nCurrentRanks + nNewRanks); jSkillList = JsonArraySet(jSkillList, nPackageSkill, jSkill); WriteTimestampedLogEntry("pinc_henchmen, 1126, Adding " + IntToString(nNewRanks) + " ranks to " + Get2DAString("skills", "Label", nPackageSkill) + " CrossClass: " + IntToString(bCrossClass)); nSkillPoints -= nNewRanks; } nPackageRow++; } jHenchman = GffReplaceList(jHenchman, "SkillList", jSkillList); return jHenchman; } json ResetSpellsKnown(json jClass, object oHenchman) { WriteTimestampedLogEntry("pinc_henchmen, 1138, Checking for spells known."); int nClass = GetClassByPosition(1, oHenchman); WriteTimestampedLogEntry("pinc_henchmen, 1140, SpellCaster: " + Get2DAString("classes", "SpellCaster", nClass)); if(Get2DAString("classes", "SpellCaster", nClass) == "0") return jClass; int nLevel = 0; // We remake the Known spell list if the character doesn't have a level list! json jKnownList, jMemorizedList; json jSpell, jSpellsPerDayList; int bMemorizesSpells = StringToInt(Get2DAString("classes", "MemorizesSpells", nClass)); int bSpellBookRestricted = StringToInt(Get2DAString("classes", "SpellBookRestricted", nClass)); string sSpellKnown2DAName = Get2DAString("classes", "SpellKnownTable", nClass); string sSpellGained2DAName = Get2DAString("classes", "SpellGainTable", nClass); string sSpellTableColumn = Get2DAString("classes", "SpellTableColumn", nClass); string sSpellPackage2DAName = Get2DAString("packages", "SpellPref2DA", nClass); int nPackageSpell, nPackageRow; int nPackageMaxRow = Get2DARowCount(sSpellPackage2DAName); int nKnownSpellIndex, nSpellsKnown, nAbility, nSpellLevel = 0; string sKnownListName, sSpellLevel, sPackageSpellLevel, sAbility; // Cycle through all spell levels and reset. while(nSpellLevel < 10) { sSpellLevel = IntToString(nSpellLevel); WriteTimestampedLogEntry("pinc_henchmen, 1143, Checking Spell Level: " + sSpellLevel); // Recreate the 0th and 1st level based on the package. if(nSpellLevel < 2 && bSpellBookRestricted) { // Spellbook restricted that don't have a SpellsKnown2DAName // get to keep all 0th level spells so we skip them. Example:Wizard if(nSpellLevel != 0 || sSpellKnown2DAName != "") { // Classes that are spell book restricted but don't have a SpellKnownTable // get 3 spells + Ability Modifier worth of spells like a wizard. if(sSpellKnown2DAName == "") { sAbility = Get2DAString("classes", "SpellCastingAbil", nClass); if(sAbility == "INT") nAbility = ABILITY_INTELLIGENCE; else if(sAbility == "WIS") nAbility = ABILITY_WISDOM; else if(sAbility == "CHA") nAbility = ABILITY_CHARISMA; nSpellsKnown = 3 + GetAbilityModifier(nAbility, oHenchman); } else { nSpellsKnown = StringToInt(Get2DAString(sSpellKnown2DAName, "SpellLevel" + sSpellLevel, nLevel)); } WriteTimestampedLogEntry("pinc_henchmen, 1165, nSpellsKnown: " + IntToString(nSpellsKnown)); jKnownList = JsonArray(); nPackageRow = 0; while(nPackageRow < nPackageMaxRow && nSpellsKnown > 0) { nPackageSpell = StringToInt(Get2DAString(sSpellPackage2DAName, "SpellIndex", nPackageRow)); sPackageSpellLevel = Get2DAString("spells", sSpellTableColumn, nPackageSpell); if(sPackageSpellLevel == sSpellLevel) { jSpell = JsonObject(); jSpell = GffAddWord(jSpell, "Spell", nPackageSpell); jSpell = JsonObjectSet(jSpell, "__struct_id", JsonInt(3)); jKnownList = JsonArrayInsert(jKnownList, jSpell); WriteTimestampedLogEntry("pinc_henchmen, 1178, Adding known spell: " + Get2DAString("spells", "LABEL", nPackageSpell)); nSpellsKnown--; } nPackageRow++; } if(JsonGetLength(jKnownList) == 0) { jClass = GffRemoveList(jClass, "KnownList" + sSpellLevel); WriteTimestampedLogEntry("pinc_henchmen, 1187, Removing KnownList" + sSpellLevel); } else if(JsonGetType(GffGetList(jClass, "KnownList" + sSpellLevel)) != JSON_TYPE_NULL) { jClass = GffReplaceList(jClass, "KnownList" + sSpellLevel, jKnownList); } else jClass = GffAddList(jClass, "KnownList" + sSpellLevel, jKnownList); } } // Remove all other known spell levels and memorized levels. else { jKnownList = GffGetList(jClass, "KnownList" + sSpellLevel); if(JsonGetType(jKnownList) != JSON_TYPE_NULL) { jClass = GffRemoveList(jClass, "KnownList" + sSpellLevel); WriteTimestampedLogEntry("pinc_henchmen, 1203, Removing KnownList" + sSpellLevel); } } if(bMemorizesSpells) { jMemorizedList = GffGetList(jClass, "MemorizedList" + sSpellLevel); if(JsonGetType(jMemorizedList) != JSON_TYPE_NULL) { jClass = GffRemoveList(jClass, "MemorizedList" + sSpellLevel); WriteTimestampedLogEntry("pinc_henchmen, 1210, Removing MemorizedList" + sSpellLevel); } } else { jSpellsPerDayList = GffGetList(jClass, "SpellsPerDayList"); nSpellsKnown = StringToInt(Get2DAString(sSpellGained2DAName, "SpellLevel"+ sSpellLevel, nLevel)); jSpell = JsonArrayGet(jSpellsPerDayList, nSpellLevel); jSpell = GffReplaceByte(jSpell, "NumSpellsLeft", nSpellsKnown); jSpellsPerDayList = JsonArraySet(jSpellsPerDayList, nSpellLevel, jSpell); jClass = GffReplaceList(jClass, "SpellsPerDayList", jSpellsPerDayList); WriteTimestampedLogEntry("pinc_henchmen, 1223, Setting SpellsPerDay to " + IntToString(nSpellsKnown)); } nSpellLevel++; } return jClass; } object ResetCharacter(object oPC, object oHenchman) { SetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE", TRUE); RemoveHenchman(oPC, oHenchman); json jHenchman = ObjectToJson(oHenchman, TRUE); json jClassList = GffGetList(jHenchman, "ClassList"); json jClass = JsonArrayGet(jClassList, 0); // Set the Class list to the first class only and put at level 1. int nClass = JsonGetInt(JsonObjectGet(jClass, "Class")); jClass = GffReplaceShort(jClass, "ClassLevel", 1); // Delete extra classes. int nClassIndex = JsonGetLength(jClassList) - 1; while(nClassIndex > 0) { jClassList = JsonArrayDel(jClassList, nClassIndex--); } int nHitPoints = StringToInt(Get2DAString("classes", "HitDie", nClass)); int nMod = JsonGetInt(GffGetByte(jHenchman, "Con")); if(nMod > 9) nHitPoints += (nMod - 10) / 2; else nHitPoints += (nMod - 11) / 2; jHenchman = GffReplaceShort(jHenchman, "CurrentHitPoints", nHitPoints); jHenchman = GffReplaceShort(jHenchman, "HitPoints", nHitPoints); jHenchman = GffReplaceShort(jHenchman, "MaxHitPoints", nHitPoints); jHenchman = GffReplaceDword(jHenchman, "Experience", 0); jHenchman = GffReplaceFloat(jHenchman, "ChallengeRating", 1.0); string s2DA = Get2DAString("classes", "AttackBonusTable", nClass); int nAtk = StringToInt(Get2DAString(s2DA, "BAB", 0)); jHenchman = GffReplaceByte(jHenchman, "BaseAttackBonus", nAtk); s2DA = Get2DAString("classes", "SavingThrowTable", nClass); int nSave = StringToInt(Get2DAString(s2DA, "FortSave", 0)); jHenchman = GffReplaceChar(jHenchman, "FortSaveThrow", nSave); nSave = StringToInt(Get2DAString(s2DA, "RefSave", 0)); jHenchman = GffReplaceChar(jHenchman, "RefSaveThrow", nSave); nSave = StringToInt(Get2DAString(s2DA, "WillSave", 0)); jHenchman = GffReplaceChar(jHenchman, "WillSaveThrow", nSave); json jLvlStatList = GffGetList(jHenchman, "LvlStatList"); if(JsonGetType(jLvlStatList) != JSON_TYPE_NULL) { WriteTimestampedLogEntry("pinc_henchmen 1275, jLvlStatList: " + JsonDump(jLvlStatList, 4)); int nLevel = 1, nLevelTrack = 1; int nAbilityStatIncrease, nAbility; string sAbility; json jAbility; json jLevel = JsonArrayGet(jLvlStatList, nLevel); while(JsonGetType(jLevel) != JSON_TYPE_NULL) { WriteTimestampedLogEntry("inc_henchmen, 1297, Checking level " + IntToString(nLevelTrack)); // Remove all Ability score increases for each level from ability scores. jAbility = GffGetByte(jLevel, "LvlStatAbility"); if(JsonGetType(jAbility) != JSON_TYPE_NULL) { nAbilityStatIncrease = JsonGetInt(jAbility); if(nAbilityStatIncrease == ABILITY_STRENGTH) sAbility = "Str"; if(nAbilityStatIncrease == ABILITY_DEXTERITY) sAbility = "Dex"; if(nAbilityStatIncrease == ABILITY_CONSTITUTION) sAbility = "Con"; if(nAbilityStatIncrease == ABILITY_INTELLIGENCE) sAbility = "Int"; if(nAbilityStatIncrease == ABILITY_WISDOM) sAbility = "Wis"; if(nAbilityStatIncrease == ABILITY_CHARISMA) sAbility = "Cha"; nAbility = JsonGetInt(GffGetByte(jHenchman, sAbility)) - 1; jHenchman = GffReplaceByte(jHenchman, sAbility, nAbility); WriteTimestampedLogEntry("pinc_henchmen, 1314, Removing " + sAbility + " level bonus ability score point."); } jLvlStatList = JsonArrayDel(jLvlStatList, nLevel); // Note: nLevel is not incremented since we are removing the previous level. // there for when we get the same level again its the next level! jLevel = JsonArrayGet(jLvlStatList, nLevel); //SendMessageToPC(oPC, "jLvlStatList: " + JsonDump(jLvlStatList, 4)); nLevelTrack++; } jHenchman = GffRemoveList(jHenchman, "LvlStatList"); } jHenchman = CreateLevelStatList(jHenchman, oHenchman, oPC, 1); jHenchman = ResetSkills(jHenchman, oHenchman); jHenchman = ResetFeats(jHenchman, oHenchman); jClass = ResetSpellsKnown(jClass, oHenchman); jClassList = JsonArraySet(jClassList, 0, jClass); jHenchman = GffReplaceList(jHenchman, "ClassList", jClassList); //WriteTimestampedLogEntry("pinc_henchmen 1397, jHenchman: " + JsonDump(jHenchman, 4)); location lLocation = GetLocation(oHenchman); int nFamiliar, nCompanion; object oCompanion = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHenchman); if(oCompanion != OBJECT_INVALID) nFamiliar = TRUE; oCompanion = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oHenchman); if(oCompanion != OBJECT_INVALID) nCompanion = TRUE; AssignCommand(oHenchman, SetIsDestroyable(TRUE, FALSE, FALSE)); DestroyObject(oHenchman); oHenchman = ai_AddHenchman(oPC, jHenchman, lLocation, nFamiliar, nCompanion); return oHenchman; } // ********* New Henchman windows ********** void CreateCharacterEditGUIPanel(object oPC, object oHenchman) { // Set window to not save until it has been created. SetLocalInt(oPC, "0_No_Win_Save", TRUE); DelayCommand(0.5f, DeleteLocalInt (oPC, "0_No_Win_Save")); // Group 1 (Portrait)******************************************************* 151 / 73 // Group 1 Row 1 *********************************************************** 350 / 91 json jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); jGroupRow = CreateTextEditBox (jGroupRow, "name_placeholder", "char_name", 15, FALSE, 140.0, 20.0); jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); // Add the group row to the group column. json jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); // Group 1 Row 1 *********************************************************** 350 / 91 jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); jGroupRow = CreateTextEditBox (jGroupRow, "port_placeholder", "port_name", 15, FALSE, 140.0, 20.0, "port_tooltip"); jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); // Add the group row to the group column. jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); // Group 1 Row 2 *********************************************************** 350 / 259 jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); jGroupRow = CreateImage(jGroupRow, "", "port_resref", NUI_ASPECT_EXACTSCALED, NUI_HALIGN_CENTER, NUI_VALIGN_TOP, 140.0f, 160.0f); jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); // Add the group row to the group column. jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); // Group 1 Row 3 *********************************************************** 350 / 292 jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); jGroupRow = CreateButton (jGroupRow, "<", "btn_portrait_prev", 42.0f, 25.0f); jGroupRow = CreateButton (jGroupRow, "Set", "btn_portrait_ok", 44.0f, 25.0f); jGroupRow = CreateButton (jGroupRow, ">", "btn_portrait_next", 42.0f, 25.0f); jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); // Add group row to the group column. jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); // Group 1 Row 4 *********************************************************** 350 / 91 jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); jGroupRow = CreateLabel(jGroupRow, "Sound Set", "lbl_sound_set", 140.0, 10.0f, NUI_HALIGN_CENTER, NUI_VALIGN_BOTTOM); jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); // Add the group row to the group column. jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); // Group 1 Row 5 *********************************************************** 350 / 325 jGroupRow = JsonArrayInsert(JsonArray(), NuiSpacer()); jGroupRow = CreateCombo(jGroupRow, ArrayInsertSoundSets(oHenchman), "cmb_soundset", 140.0, 25.0); jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); // Add group row to the group column. jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); json jRow = JsonArrayInsert(JsonArray(), NuiGroup(NuiCol(jGroupCol))); // Group 2 (Stats)********************************************************** 151 / 73 // Group 2 Row 1 *********************************************************** 350 / 91 jGroupRow = CreateLabel(JsonArray(), "", "lbl_stats", 150.0, 15.0, 0, NUI_VALIGN_BOTTOM, 0.0); // Add group row to the group column. jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow)); // Group 2 Row 2 *********************************************************** 350 / 243 //json jAlign = CreateOptionsAlignment(oHenchman, 0); //jGroupRow = CreateOptions(JsonArray(), "opt_lawchaos", NUI_DIRECTION_HORIZONTAL, jAlign, 60.0, 35.0); // Add group row to the group column. //jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); // Group 2 Row 3 *********************************************************** 350 / 243 //jAlign = CreateOptionsAlignment(oHenchman, 1); //jGroupRow = CreateOptions(JsonArray(), "opt_goodevil", NUI_DIRECTION_HORIZONTAL, jAlign, 60.0, 35.0); //jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer()); // Add group row to the group column. //jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); // Group 2 Row 2 *********************************************************** 350 / 243 json jClasses = CreateOptionsClasses(oHenchman); jGroupRow = CreateOptions(JsonArray(), "opt_classes", NUI_DIRECTION_VERTICAL, jClasses, 150.0, 144.0); // Add group row to the group column. jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); // Group 2 Row 3 *********************************************************** 350 / 276 jGroupRow = CreateButton(JsonArray(), "Level Up", "btn_level_up", 150.0f, 25.0f, -1.0, "btn_level_up_tooltip"); // Add group row to the group column. jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); // Group 2 Row 4 *********************************************************** 350 / 309 jGroupRow = CreateButton (JsonArray(), "Reset Character", "btn_reset", 150.0f, 25.0f, -1.0, "btn_reset_tooltip"); // Add group row to the group column. jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); // Group 2 Row 5 *********************************************************** 350 / 342 jGroupRow = CreateCombo(JsonArray(), jArrayInsertClasses(), "cmb_class", 150.0, 25.0); // Add group row to the group column. jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); // Group 2 Row 6 *********************************************************** 350 / 375 int nClassOption = GetLocalInt(oHenchman, "CLASS_OPTION_POSITION"); int nClass = GetClassByPosition(nClassOption + 1, oHenchman); int bNoClass = FALSE; if(nClass == CLASS_TYPE_INVALID) { nClass = GetLocalInt(oHenchman, "CLASS_SELECTED_" + IntToString(nClassOption + 1)); bNoClass = TRUE; } string sClass = IntToString(nClass); jGroupRow = CreateCombo(JsonArray(), ArrayInsertPackages(sClass), "cmb_package", 150.0, 25.0); // Add group row to the group column. jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow)); jRow = JsonArrayInsert(jRow, NuiGroup(NuiCol(jGroupCol))); // Add the row to the column. json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); // Row 5 (text edit box)**************************************************** 350 / 518 jRow = CreateTextEditBox(JsonArray(), "desc_placeholder", "desc_value", 1000, TRUE, 350.0, 150.0, "desc_tooltip"); // Add the row to the column. jCol = JsonArrayInsert(jCol, NuiRow (jRow)); // Row 6 (button)*********************************************************** 350/ 546 jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); jRow = CreateButton (jRow, "Save Description", "btn_desc_save", 150.0f, 20.0f); jRow = JsonArrayInsert(jRow, NuiSpacer()); // Add row to the column. jCol = JsonArrayInsert(jCol, NuiRow (jRow)); // Set the Layout of the window. json jLayout = NuiCol (jCol); // Get the window location to restore it from the database. CheckHenchmanDataAndInitialize(oPC, "0"); json jData = GetHenchmanDbJson(oPC, "henchman", "0"); json jGeometry = JsonObjectGet(jData, "henchman_edit_nui"); float fX = JsonGetFloat(JsonObjectGet(jGeometry, "x")); float fY = JsonGetFloat(JsonObjectGet(jGeometry, "y")); if(fX == 0.0 && fY == 0.0) { fX = -1.0; fY = -1.0; } string sName = GetName(oHenchman); if(GetStringRight(sName, 1) == "s") sName = sName + "'"; else sName = sName + "'s"; int nToken = SetWindow (oPC, jLayout, "henchman_edit_nui", sName + " Character editor", fX, fY, 380.0, 588.0, FALSE, FALSE, TRUE, FALSE, TRUE, "pe_henchmen"); // Set all binds, events, and watches. int nID = GetPortraitId (oPC); NuiSetUserData(oPC, nToken, JsonInt(nID)); string sResRef = GetPortraitResRef(oHenchman); NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE); NuiSetBind(oPC, nToken, "char_name", JsonString(GetName(oHenchman))); NuiSetBindWatch(oPC, nToken, "char_name", TRUE); NuiSetBind(oPC, nToken, "char_name_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "port_name", JsonString(sResRef)); NuiSetBindWatch(oPC, nToken, "port_name", TRUE); NuiSetBind(oPC, nToken, "port_name_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "port_resref_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "port_resref_image", JsonString(sResRef + "l")); NuiSetBind(oPC, nToken, "port_tooltip", JsonString (" You may also type the portrait file name.")); // Set buttons active. NuiSetBind(oPC, nToken, "btn_portrait_prev_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "btn_portrait_next_event", JsonBool(TRUE)); int nSelection = GetSelectionBySoundSet2DA(oHenchman, GetSoundset(oHenchman)); NuiSetBind(oPC, nToken, "cmb_soundset_selected", JsonInt(nSelection)); NuiSetBindWatch(oPC, nToken, "cmb_soundset_selected", TRUE); NuiSetBind(oPC, nToken, "cmb_soundset_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "btn_desc_save_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "btn_portrait_ok_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "desc_tooltip", JsonString(" You can use color codes!")); string sDescription = GetDescription(oHenchman); NuiSetBind(oPC, nToken, "desc_value_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "desc_value", JsonString (sDescription)); // Setup the henchman window. string sStats = GetAlignText(oHenchman) + " "; if(GetGender(oHenchman) == GENDER_MALE) sStats += "Male "; else sStats += "Female "; sStats += GetStringByStrRef (StringToInt (Get2DAString ("racialtypes", "Name", GetRacialType (oHenchman)))); NuiSetBind(oPC, nToken, "lbl_stats_label", JsonString(sStats)); json jHenchman = ObjectToJson(oHenchman); NuiSetBind(oPC, nToken, "opt_classes_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "opt_classes_value", JsonInt(nClassOption)); NuiSetBind(oPC, nToken, "btn_level_up_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "btn_level_up_tooltip", JsonString(" Levels the character up by one level in selected class.")); if(ai_GetIsCharacter(oHenchman)) NuiSetBind(oPC, nToken, "btn_reset_event", JsonBool(FALSE)); else NuiSetBind(oPC, nToken, "btn_reset_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "btn_reset_tooltip", JsonString(" Resets the character to level 1.")); nSelection = GetSelectionByClass2DA(nClass); NuiSetBind(oPC, nToken, "cmb_class_selected", JsonInt(nSelection)); NuiSetBindWatch(oPC, nToken, "cmb_class_selected", bNoClass); NuiSetBind(oPC, nToken, "cmb_class_event", JsonBool(bNoClass)); int nPackage = GetLocalInt(oHenchman, "PACKAGE_SELECTED_" + IntToString(nClassOption + 1)); if(nPackage == 0) { nPackage = GetPackageBySelection2DA(sClass, 0); SetLocalInt(oHenchman, "PACKAGE_SELECTED_" + IntToString(nClassOption + 1), nPackage); } NuiSetBind(oPC, nToken, "cmb_package_selected", JsonInt(GetSelectionByPackage2DA(sClass, nPackage))); NuiSetBindWatch(oPC, nToken, "cmb_package_selected", bNoClass); NuiSetBind(oPC, nToken, "cmb_package_event", JsonBool(bNoClass)); } void CreateCharacterDescriptionNUI(object oPC, string sName, string sIcon, string sDescription) { // Row 1 ******************************************************************* 500 / 469 json jRow = CreateImage(JsonArray(), "", "char_icon", NUI_ASPECT_FIT, NUI_HALIGN_CENTER, NUI_VALIGN_MIDDLE, 40.0, 40.0); jRow = CreateTextBox(jRow, "char_text", 380.0, 400.0); // Add row to the column. json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow)); // Row 2 ******************************************************************* 500 / 522 jRow = JsonArrayInsert(JsonArray(), NuiSpacer()); jRow = CreateButton(jRow, "OK", "btn_ok", 150.0f, 45.0f); // Add row to the column. jCol = JsonArrayInsert(jCol, NuiRow(jRow)); // Set the Layout of the window. json jLayout = NuiCol(jCol); int nToken = SetWindow(oPC, jLayout, "char_description_nui", sName, -1.0, -1.0, 460.0f, 537.0 + 12.0f, FALSE, FALSE, TRUE, FALSE, TRUE, "pe_henchmen"); json jData = JsonArrayInsert(JsonArray(), JsonString(ObjectToString(oPC))); NuiSetUserData(oPC, nToken, jData); // Row 1 NuiSetBind(oPC, nToken, "char_icon_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "char_icon_image", JsonString(sIcon)); NuiSetBind(oPC, nToken, "char_text_event", JsonBool(TRUE)); NuiSetBind(oPC, nToken, "char_text", JsonString(sDescription)); // Row 2 NuiSetBind(oPC, nToken, "btn_ok_event", JsonBool(TRUE)); }