1542 lines
72 KiB
Plaintext
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));
|
|
}
|
|
|