MMD_PRC8/_module/nss/pinc_henchmen.nss
Jaysyn904 6b49325c35 2025/07/20 Update
Updated PEPS AI.
2025-07-20 11:58:23 -04:00

1542 lines
72 KiB
Plaintext

/*//////////////////////////////////////////////////////////////////////////////
// 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));
}