1329 lines
63 KiB
Plaintext
1329 lines
63 KiB
Plaintext
|
/*//////////////////////////////////////////////////////////////////////////////
|
||
|
// Script Name: 0i_main
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
Include script for handling main/basic functions not defined by other includes.
|
||
|
|
||
|
Database structure: Json with indexes.
|
||
|
name (string) - The associatetype to link the data. "pc", "familiar", etc.
|
||
|
modes (jsonarray) - 0-aimodes (int), 1-magicmodes (int)
|
||
|
buttons (jsonarray) - 0-widgetbuttons (int), 1-aibuttons (int)
|
||
|
aidata (jsonarray) - 0-difficulty (int), 1-healoutcombat (int), 2-healincombat (int),
|
||
|
3-lootrange (float), 4-lockrange (float), 5-traprange (float),
|
||
|
6-Follow range (float).
|
||
|
lootfilters (jsonarray) - 0-maxweight (int), 1-lootfilters (int),
|
||
|
Item filters in min gold json array; 2-plot, 3-armor, 4-belts, 5-boots,
|
||
|
6-cloaks, 7-gems, 8-gloves, 9-headgear, 10-jewelry, 11-misc, 12-potions,
|
||
|
13-scrolls, 14-shields, 15-wands, 16-weapons, 17-arrow, 18-bolt, 19-bullet.
|
||
|
plugins (jsonarray) - 0+ (string). * Only used in the "pc" data.
|
||
|
location (jsonobject) - geometry (json), used in widgets for pc and associates.
|
||
|
*///////////////////////////////////////////////////////////////////////////////
|
||
|
const string AI_TABLE = "PEPS_TABLE";
|
||
|
const string AI_CAMPAIGN_DATABASE = "peps_database";
|
||
|
const string AI_DM_TABLE = "DM_TABLE";
|
||
|
#include "0i_constants"
|
||
|
#include "0i_messages"
|
||
|
// Sets PEPS RULES from the database to the module.
|
||
|
// Creates default rules if they do not exist.
|
||
|
void ai_SetAIRules();
|
||
|
// Returns TRUE if oCreature is controlled by a player.
|
||
|
int ai_GetIsCharacter(object oCreature);
|
||
|
// Returns TRUE if oCreature is controlled by a dungeon master.
|
||
|
int ai_GetIsDungeonMaster(object oCreature);
|
||
|
// Returns the Player of oAssociate even if oAssociate is the player.
|
||
|
// If there is no player associated with oAssociate then it returns OBJECT_INVALID.
|
||
|
object ai_GetPlayerMaster(object oAssociate);
|
||
|
// Returns the percentage of hit points oCreature has left.
|
||
|
int ai_GetPercHPLoss(object oCreature);
|
||
|
// Returns a rolled result from sDice string.
|
||
|
// Example: "1d6" will be 1-6 or "3d6" will be 3-18 or 1d6+5 will be 6-11.
|
||
|
int ai_RollDiceString(string sDice);
|
||
|
// Returns the int number of a encoded 0x00000000 hex number from a string.
|
||
|
int ai_HexStringToInt(string sString);
|
||
|
// Returns cosine of the angle between oObject1 and oObject2
|
||
|
float ai_GetCosAngleBetween(object oObject1, object oObject2);
|
||
|
// Returns a string from sString with only characters in sLegal.
|
||
|
// Used to remove illegal characters for databases.
|
||
|
string ai_RemoveIllegalCharacters(string sString, string sLegal = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
|
||
|
// Returns the total levels of oCreature.
|
||
|
int ai_GetCharacterLevels(object oCreature);
|
||
|
// Returns a string where sFind is replaced in any occurrence of sSource with sReplace.
|
||
|
string ai_StringReplaceText(string sSource, string sFind, string sReplace);
|
||
|
// Returns a string of characters between the nIndex of predefined markers of
|
||
|
// sSeperator in sText.
|
||
|
// nIndex is the number of the data we are searching for in the array.
|
||
|
// A 0 nIndex is the first item in the text array.
|
||
|
// sSeperator is the character that seperates the array(Usefull for Multiple arrays).
|
||
|
string ai_GetStringArray(string sText, int nIndex, string sSeperator = ":");
|
||
|
// Returns a string of characters between the nIndex of predefined markers of
|
||
|
// sSeperator in sText where sField has been set.
|
||
|
// sText is the text holding the array.
|
||
|
// nIndex is the array number in the data we are searching for.
|
||
|
// A 0 nIndex is the first item in the text array.
|
||
|
// sField is the field of characters to replace that index.
|
||
|
// sSeperator is the character that seperates the array(Usefull for Multiple arrays).
|
||
|
string ai_SetStringArray(string sText, int nIndex, string sField, string sSeperator = ":");
|
||
|
// Returns the number of magical properties oItem has.
|
||
|
int ai_GetNumberOfProperties(object oItem);
|
||
|
// Checks if the campaign database table has been created and initialized.
|
||
|
void ai_CheckCampaignDataAndInitialize();
|
||
|
// Checks if the dm database table and data has been created and initialized of oDM.
|
||
|
void ai_CheckDMDataAndInitialize(object oDM);
|
||
|
// Sets json to a campaign database.
|
||
|
void ai_SetCampaignDbJson(string sDataField, json jData, string sName = "PEPS_DATA", string sTable = AI_TABLE);
|
||
|
// Gets json from a campaign database.
|
||
|
json ai_GetCampaignDbJson(string sDataField, string sName = "PEPS_DATA", string sTable = AI_TABLE);
|
||
|
// Checks if oMaster has the Table created for Associate data.
|
||
|
// If no table found then the table is created and then initialized.
|
||
|
void ai_CheckAssociateDataAndInitialize(object oPlayer, string sAssociateType);
|
||
|
// Returns the associatetype int string format for oAssociate.
|
||
|
// They are pc, familar, companion, summons, henchman is the henchmans tag
|
||
|
string ai_GetAssociateType(object oPlayer, object oAssociate);
|
||
|
// Sets nData to sDataField for sAssociateType that is on oPlayer.
|
||
|
// sDataField can be modes, magicmodes, lootmodes, widgetbuttons, aibuttons, magic,
|
||
|
// healoutcombat, healincombat, mingold*.
|
||
|
void ai_SetAssociateDbInt(object oPlayer, string sAssociateType, string sDataField, int nData, string sTable = AI_TABLE);
|
||
|
// Returns nData from sDataField for sAssociateType that is on oPlayer.
|
||
|
// sDataField can be modes, magicmodes, lootmodes, widgetbuttons, aibuttons, magic,
|
||
|
// healoutcombat, healincombat, mingold*.
|
||
|
int ai_GetAssociateDbInt(object oPlayer, string sAssociateType, string sDataField, string sTable = AI_TABLE);
|
||
|
// Sets fData to sDataField for sAssociateType that is on oPlayer.
|
||
|
// sDataField can be lootrange, lockrange, traprange.
|
||
|
void ai_SetAssociateDbFloat(object oPlayer, string sAssociatetype, string sDataField, float fData, string sTable = AI_TABLE);
|
||
|
// Returns fData from sDataField for sAssociateType that is on oPlayer.
|
||
|
// sDataField can be lootrange, lockrange, traprange.
|
||
|
float ai_GetAssociateDbFloat(object oPlayer, string sAssociateType, string sDataField, string sTable = AI_TABLE);
|
||
|
// sDataField should be one of the data fields for that table.
|
||
|
// jData is the json data to be saved.
|
||
|
void ai_SetAssociateDbJson(object oPlayer, string sAssociateType, string sDataField, json jData, string sTable = AI_TABLE);
|
||
|
// sDataField should be one of the data fields for the table.
|
||
|
// Returns a string of the data stored.
|
||
|
json ai_GetAssociateDbJson(object oPlayer, string sAssociateType, string sDataField, string sTable = AI_TABLE);
|
||
|
// Saves Associate AIModes and MagicModes to the database.
|
||
|
void aiSaveAssociateModesToDb(object oPlayer, object oAssociate);
|
||
|
// Checks Associate local data and if none is found will initialize or load the
|
||
|
// correct data for oAssociate.
|
||
|
void ai_CheckAssociateData(object oPlayer, object oAssociate, string sAssociateType, int bLoad = FALSE);
|
||
|
// Checks DM's local data and if none is found will initizlize or load the
|
||
|
// correct data for oPlayer.
|
||
|
void ai_CheckDMData(object oPlayer);
|
||
|
// Adds to jPlugins functions after checking if the plugin can be installed.
|
||
|
json ai_Plugin_Add(object oPC, json jPlugins, string sPluginScript);
|
||
|
// Updates the players Plugin list and saves to the database.
|
||
|
json ai_UpdatePluginsForPC(object oPC);
|
||
|
// Updates the DM's Plugin list and saves to the database.
|
||
|
json ai_UpdatePluginsForDM (object oPC);
|
||
|
// Runs all plugins that are loaded into the database.
|
||
|
void ai_StartupPlugins(object oPC);
|
||
|
void ai_SetAIRules()
|
||
|
{
|
||
|
object oModule = GetModule();
|
||
|
ai_CheckCampaignDataAndInitialize();
|
||
|
json jRules = ai_GetCampaignDbJson("rules");
|
||
|
if(JsonGetType(JsonObjectGet(jRules, AI_RULE_MORAL_CHECKS)) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
jRules = JsonObject();
|
||
|
// Variable name set to a creatures full name to set debugging on.
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_DEBUG_CREATURE, JsonString(""));
|
||
|
// Moral checks on or off.
|
||
|
SetLocalInt(oModule, AI_RULE_MORAL_CHECKS, AI_MORAL_CHECKS);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_MORAL_CHECKS, JsonInt(AI_MORAL_CHECKS));
|
||
|
// Allows monsters to prebuff before combat starts.
|
||
|
SetLocalInt(oModule, AI_RULE_BUFF_MONSTERS, AI_PREBUFF);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_BUFF_MONSTERS, JsonInt(AI_PREBUFF));
|
||
|
// Allows monsters cast summons spells when prebuffing.
|
||
|
SetLocalInt(oModule, AI_RULE_PRESUMMON, AI_PRESUMMONS);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_PRESUMMON, JsonInt(AI_PRESUMMONS));
|
||
|
// Allows monsters to use tactical AI scripts.
|
||
|
SetLocalInt(oModule, AI_RULE_AMBUSH, AI_TACTICAL);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_AMBUSH, JsonInt(AI_TACTICAL));
|
||
|
// Enemies may summon familiars and Animal companions and will be randomized.
|
||
|
SetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS, AI_SUMMON_COMPANIONS);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_SUMMON_COMPANIONS, JsonInt(AI_SUMMON_COMPANIONS));
|
||
|
// Allow the AI to move during combat base on the situation and action taking.
|
||
|
SetLocalInt(oModule, AI_RULE_ADVANCED_MOVEMENT, AI_ADVANCED_MOVEMENT);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_ADVANCED_MOVEMENT, JsonInt(AI_ADVANCED_MOVEMENT));
|
||
|
// Follow Item Level Restrictions for monsters/associates.
|
||
|
SetLocalInt(oModule, AI_RULE_ILR, AI_ITEM_LEVEL_RESTRICTIONS);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_ILR, JsonInt(AI_ITEM_LEVEL_RESTRICTIONS));
|
||
|
// Allow the AI to use Use Magic Device.
|
||
|
SetLocalInt(oModule, AI_RULE_ALLOW_UMD, AI_USE_MAGIC_DEVICE);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_ALLOW_UMD, JsonInt(AI_USE_MAGIC_DEVICE));
|
||
|
// Allow the AI to use healing kits.
|
||
|
SetLocalInt(oModule, AI_RULE_HEALERSKITS, AI_HEALING_KITS);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_HEALERSKITS, JsonInt(AI_HEALING_KITS));
|
||
|
// Associates are permanent and don't get removed when the master dies.
|
||
|
SetLocalInt(oModule, AI_RULE_PERM_ASSOC, AI_COMPANIONS_PERMANENT);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_PERM_ASSOC, JsonInt(AI_COMPANIONS_PERMANENT));
|
||
|
// Monster AI's chance to attack the weakest target instead of the nearest.
|
||
|
SetLocalInt(oModule, AI_RULE_AI_DIFFICULTY, AI_TARGET_WEAKEST);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_AI_DIFFICULTY, JsonInt(AI_TARGET_WEAKEST));
|
||
|
// Monster AI's distance they can search for the enemy.
|
||
|
SetLocalFloat(oModule, AI_RULE_PERCEPTION_DISTANCE, AI_SEARCH_DISTANCE);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_PERCEPTION_DISTANCE, JsonFloat(AI_SEARCH_DISTANCE));
|
||
|
// Enemy corpses remain on the floor instead of dissappearing.
|
||
|
SetLocalInt(oModule, AI_RULE_CORPSES_STAY, AI_CORPSE_REMAIN);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_CORPSES_STAY, JsonInt(AI_CORPSE_REMAIN));
|
||
|
// Monsters will wander around when not in combat.
|
||
|
SetLocalInt(oModule, AI_RULE_WANDER, AI_WANDER);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_WANDER, JsonInt(AI_WANDER));
|
||
|
// Increase the number of encounter creatures.
|
||
|
SetLocalFloat(oModule, AI_INCREASE_ENC_MONSTERS, 0.0);
|
||
|
jRules = JsonObjectSet(jRules, AI_INCREASE_ENC_MONSTERS, JsonFloat(0.0));
|
||
|
// Increase all monsters hitpoints by this percentage.
|
||
|
SetLocalInt(oModule, AI_INCREASE_MONSTERS_HP, 0);
|
||
|
jRules = JsonObjectSet(jRules, AI_INCREASE_MONSTERS_HP, JsonInt(0));
|
||
|
// Monster's perception distance.
|
||
|
SetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE, AI_MONSTER_PERCEPTION);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_MON_PERC_DISTANCE, JsonInt(AI_MONSTER_PERCEPTION));
|
||
|
// Variable name set to hold the maximum number of henchman the player wants.
|
||
|
int nMaxHenchmen = GetMaxHenchmen();
|
||
|
SetLocalInt(oModule, AI_RULE_MAX_HENCHMAN, nMaxHenchmen);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_MAX_HENCHMAN, JsonInt(nMaxHenchmen));
|
||
|
// Monster AI's distance they can wander away from their spawn point.
|
||
|
SetLocalFloat(oModule, AI_RULE_WANDER_DISTANCE, AI_WANDER_DISTANCE);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_WANDER_DISTANCE, JsonFloat(AI_WANDER_DISTANCE));
|
||
|
// Monsters will open doors when wandering around and not in combat.
|
||
|
SetLocalInt(oModule, AI_RULE_OPEN_DOORS, AI_WANDER);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_OPEN_DOORS, JsonInt(AI_OPEN_DOORS));
|
||
|
// If the modules default XP has not been set then we do it here.
|
||
|
int nDefaultXP = GetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE);
|
||
|
if(nDefaultXP == 0)
|
||
|
{
|
||
|
int nValue = GetModuleXPScale();
|
||
|
if(nValue != 0) SetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE, nValue);
|
||
|
}
|
||
|
// Variable name set to allow the game to regulate experience based on party size.
|
||
|
SetLocalInt(oModule, AI_RULE_PARTY_SCALE, AI_PARTY_SCALE);
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_PARTY_SCALE, JsonInt(AI_PARTY_SCALE));
|
||
|
SetLocalJson(oModule, AI_RULE_RESTRICTED_SPELLS, JsonArray());
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_RESTRICTED_SPELLS, JsonArray());
|
||
|
// Variable name set to allow access to widget buttons for the players.
|
||
|
SetLocalInt(oModule, sDMWidgetAccessVarname, AI_DM_WIDGET_ACCESS_BUTTONS);
|
||
|
jRules = JsonObjectSet(jRules, sDMWidgetAccessVarname, JsonInt(AI_DM_WIDGET_ACCESS_BUTTONS));
|
||
|
// Variable name set to allow access to widget buttons for the players.
|
||
|
SetLocalInt(oModule, sDMAIAccessVarname, AI_DM_AI_ACCESS_BUTTONS);
|
||
|
jRules = JsonObjectSet(jRules, sDMAIAccessVarname, JsonInt(AI_DM_AI_ACCESS_BUTTONS));
|
||
|
ai_SetCampaignDbJson("rules", jRules);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Variable name set to a creatures full name to set debugging on.
|
||
|
string sValue = JsonGetString(JsonObjectGet(jRules, AI_RULE_DEBUG_CREATURE));
|
||
|
SetLocalString(oModule, AI_RULE_DEBUG_CREATURE, sValue);
|
||
|
// Moral checks on or off.
|
||
|
int bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_MORAL_CHECKS));
|
||
|
SetLocalInt(oModule, AI_RULE_MORAL_CHECKS, bValue);
|
||
|
// Allows monsters to prebuff before combat starts.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_BUFF_MONSTERS));
|
||
|
SetLocalInt(oModule, AI_RULE_BUFF_MONSTERS, bValue);
|
||
|
// Allows monsters cast summons spells when prebuffing.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_PRESUMMON));
|
||
|
SetLocalInt(oModule, AI_RULE_PRESUMMON, bValue);
|
||
|
// Allows monsters to use ambush AI scripts.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_AMBUSH));
|
||
|
SetLocalInt(oModule, AI_RULE_AMBUSH, bValue);
|
||
|
// Enemies may summon familiars and Animal companions and will be randomized.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_SUMMON_COMPANIONS));
|
||
|
SetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS, bValue);
|
||
|
// Allow the AI to move during combat base on the situation and action taking.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_ADVANCED_MOVEMENT));
|
||
|
SetLocalInt(oModule, AI_RULE_ADVANCED_MOVEMENT, bValue);
|
||
|
// Follow Item Level Restrictions for monsters/associates.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_ILR));
|
||
|
SetLocalInt(oModule, AI_RULE_ILR, bValue);
|
||
|
// Allow the AI to use Use Magic Device.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_ALLOW_UMD));
|
||
|
SetLocalInt(oModule, AI_RULE_ALLOW_UMD, bValue);
|
||
|
// Allow the AI to use healing kits.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_HEALERSKITS));
|
||
|
SetLocalInt(oModule, AI_RULE_HEALERSKITS, bValue);
|
||
|
// Associates are permanent and don't get removed when the owner dies.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_PERM_ASSOC));
|
||
|
SetLocalInt(oModule, AI_RULE_PERM_ASSOC, bValue);
|
||
|
// Monster AI's chance to attack the weakest target instead of the nearest.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_AI_DIFFICULTY));
|
||
|
SetLocalInt(oModule, AI_RULE_AI_DIFFICULTY, bValue);
|
||
|
// Monster AI's perception distance from player.
|
||
|
float fValue = JsonGetFloat(JsonObjectGet(jRules, AI_RULE_PERCEPTION_DISTANCE));
|
||
|
SetLocalFloat(oModule, AI_RULE_PERCEPTION_DISTANCE, fValue);
|
||
|
// Enemy corpses remain on the floor instead of dissappearing.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_CORPSES_STAY));
|
||
|
SetLocalInt(oModule, AI_RULE_CORPSES_STAY, bValue);
|
||
|
// Monsters will wander around when not in combat.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_WANDER));
|
||
|
SetLocalInt(oModule, AI_RULE_WANDER, bValue);
|
||
|
// Increase the number of encounter creatures.
|
||
|
fValue = JsonGetFloat(JsonObjectGet(jRules, AI_INCREASE_ENC_MONSTERS));
|
||
|
SetLocalFloat(oModule, AI_INCREASE_ENC_MONSTERS, fValue);
|
||
|
// Increase all monsters hitpoints by this percentage.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_INCREASE_MONSTERS_HP));
|
||
|
SetLocalInt(oModule, AI_INCREASE_MONSTERS_HP, bValue);
|
||
|
// Monster's perception distance.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_MON_PERC_DISTANCE));
|
||
|
if(bValue < 8 || bValue > 11) bValue = 11;
|
||
|
SetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE, bValue);
|
||
|
// Variable name set to hold the maximum number of henchman the player wants.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_MAX_HENCHMAN));
|
||
|
if(bValue == 0) bValue = GetMaxHenchmen();
|
||
|
else SetMaxHenchmen(bValue);
|
||
|
SetLocalInt(oModule, AI_RULE_MAX_HENCHMAN, bValue);
|
||
|
// Monster AI's wander distance from their spawn point.
|
||
|
fValue = JsonGetFloat(JsonObjectGet(jRules, AI_RULE_WANDER_DISTANCE));
|
||
|
SetLocalFloat(oModule, AI_RULE_WANDER_DISTANCE, fValue);
|
||
|
// Monsters will open doors while wandering around and not in combat.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_OPEN_DOORS));
|
||
|
SetLocalInt(oModule, AI_RULE_OPEN_DOORS, bValue);
|
||
|
// If the modules default XP has not been set then we do it here.
|
||
|
int nDefaultXP = GetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE);
|
||
|
if(nDefaultXP == 0)
|
||
|
{
|
||
|
bValue = GetModuleXPScale();
|
||
|
if(bValue != 0) SetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE, bValue);
|
||
|
}
|
||
|
// Variable name set to allow the game to regulate experience based on party size.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_PARTY_SCALE));
|
||
|
if(bValue)
|
||
|
{
|
||
|
int nBasePartyXP = GetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP);
|
||
|
if(nBasePartyXP == 0)
|
||
|
{
|
||
|
nDefaultXP = GetLocalInt(oModule, AI_RULE_DEFAULT_XP_SCALE);
|
||
|
SetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP, nDefaultXP);
|
||
|
}
|
||
|
}
|
||
|
SetLocalInt(oModule, AI_RULE_PARTY_SCALE, bValue);
|
||
|
json jRSpells = JsonObjectGet(jRules, AI_RULE_RESTRICTED_SPELLS);
|
||
|
if(JsonGetType(jRSpells) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
jRSpells = JsonArray();
|
||
|
jRules = JsonObjectSet(jRules, AI_RULE_RESTRICTED_SPELLS, jRSpells);
|
||
|
ai_SetCampaignDbJson("rules", jRules);
|
||
|
}
|
||
|
SetLocalJson(oModule, AI_RULE_RESTRICTED_SPELLS, jRSpells);
|
||
|
// Variable name set to allow access to widget buttons for the players.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, sDMWidgetAccessVarname));
|
||
|
SetLocalInt(oModule, sDMWidgetAccessVarname, bValue);
|
||
|
// Variable name set to allow access to widget buttons for the players.
|
||
|
bValue = JsonGetInt(JsonObjectGet(jRules, sDMAIAccessVarname));
|
||
|
SetLocalInt(oModule, sDMAIAccessVarname, bValue);
|
||
|
}
|
||
|
}
|
||
|
int ai_GetIsCharacter(object oCreature)
|
||
|
{
|
||
|
return (GetIsPC(oCreature) && !GetIsDM(oCreature) && !GetIsDMPossessed(oCreature));
|
||
|
}
|
||
|
int ai_GetIsDungeonMaster(object oCreature)
|
||
|
{
|
||
|
return (GetIsDM(oCreature) || GetIsDMPossessed(oCreature));
|
||
|
}
|
||
|
object ai_GetPlayerMaster(object oAssociate)
|
||
|
{
|
||
|
if(ai_GetIsCharacter(oAssociate)) return oAssociate;
|
||
|
object oMaster = GetMaster(oAssociate);
|
||
|
if(ai_GetIsCharacter(oMaster)) return oMaster;
|
||
|
return OBJECT_INVALID;
|
||
|
}
|
||
|
int ai_GetPercHPLoss(object oCreature)
|
||
|
{
|
||
|
int nHP = GetCurrentHitPoints(oCreature);
|
||
|
if(nHP < 1) return 0;
|
||
|
return(nHP * 100) / GetMaxHitPoints(oCreature);
|
||
|
}
|
||
|
int ai_RollDiceString(string sDice)
|
||
|
{
|
||
|
int nNegativePos, nBonus = 0;
|
||
|
string sRight = GetStringRight(sDice, GetStringLength(sDice) - FindSubString(sDice, "d") - 1);
|
||
|
int nPlusPos = FindSubString(sRight, "+");
|
||
|
if(nPlusPos != -1)
|
||
|
{
|
||
|
nBonus = StringToInt(GetStringRight(sRight, GetStringLength(sRight) - nPlusPos - 1));
|
||
|
sRight = GetStringLeft(sRight, nPlusPos);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nNegativePos = FindSubString(sRight, "-");
|
||
|
if(nNegativePos != -1)
|
||
|
{
|
||
|
nBonus = StringToInt(GetStringRight(sRight, GetStringLength(sRight) - nNegativePos - 1));
|
||
|
sRight = GetStringLeft(sRight, nNegativePos);
|
||
|
nBonus = nBonus * -1;
|
||
|
}
|
||
|
}
|
||
|
int nDie = StringToInt(sRight);
|
||
|
int nNumOfDie = StringToInt(GetStringLeft(sDice, FindSubString(sDice, "d")));
|
||
|
int nResult;
|
||
|
while(nNumOfDie > 0)
|
||
|
{
|
||
|
nResult += Random(nDie) + 1;
|
||
|
nNumOfDie --;
|
||
|
}
|
||
|
return nResult + nBonus;
|
||
|
}
|
||
|
int ai_HexStringToInt(string sString)
|
||
|
{
|
||
|
sString = GetStringLowerCase(sString);
|
||
|
int nInt = 0;
|
||
|
int nLength = GetStringLength(sString);
|
||
|
int i;
|
||
|
for(i = nLength - 1; i >= 0; i--)
|
||
|
{
|
||
|
int n = FindSubString("0123456789abcdef", GetSubString(sString, i, 1));
|
||
|
if(n == -1) return nInt;
|
||
|
nInt |= n << ((nLength - i - 1) * 4);
|
||
|
}
|
||
|
return nInt;
|
||
|
}
|
||
|
float ai_GetCosAngleBetween(object oObject1, object oObject2)
|
||
|
{
|
||
|
vector v1 = GetPositionFromLocation(GetLocation(oObject1));
|
||
|
vector v2 = GetPositionFromLocation(GetLocation(oObject2));
|
||
|
vector v3 = GetPositionFromLocation(GetLocation(OBJECT_SELF));
|
||
|
|
||
|
v1.x -= v3.x; v1.y -= v3.y; v1.z -= v3.z;
|
||
|
v2.x -= v3.x; v2.y -= v3.y; v2.z -= v3.z;
|
||
|
|
||
|
float dotproduct = v1.x*v2.x+v1.y*v2.y+v1.z*v2.z;
|
||
|
|
||
|
return dotproduct/(VectorMagnitude(v1)*VectorMagnitude(v2));
|
||
|
}
|
||
|
string ai_RemoveIllegalCharacters(string sString, string sLegal = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||
|
{
|
||
|
string sOut, sValue;
|
||
|
sString = ai_StripColorCodes(sString);
|
||
|
int nLength = GetStringLength(sString);
|
||
|
int Cnt;
|
||
|
for(Cnt = 0; Cnt != nLength; ++Cnt)
|
||
|
{
|
||
|
sValue = GetSubString(sString, Cnt, 1);
|
||
|
if(TestStringAgainstPattern("**" + sValue + "**", sLegal))
|
||
|
sOut += sValue;
|
||
|
}
|
||
|
return sOut;
|
||
|
}
|
||
|
int ai_GetCharacterLevels(object oCreature)
|
||
|
{
|
||
|
int nLevels, nPosition = 1;
|
||
|
while(nPosition <= AI_MAX_CLASSES_PER_CHARACTER)
|
||
|
{
|
||
|
nLevels += GetLevelByPosition(nPosition, oCreature);
|
||
|
nPosition++;
|
||
|
}
|
||
|
return nLevels;
|
||
|
}
|
||
|
string ai_StringReplaceText(string sSource, string sFind, string sReplace)
|
||
|
{
|
||
|
int nFindLength = GetStringLength(sFind);
|
||
|
int nPosition = 0;
|
||
|
string sReturnValue = "";
|
||
|
// Locate all occurences of sFind.
|
||
|
int nFound = FindSubString(sSource, sFind);
|
||
|
while(nFound >= 0 )
|
||
|
{
|
||
|
// Build the return string, replacing this occurence of sFind with sReplace.
|
||
|
sReturnValue += GetSubString(sSource, nPosition, nFound - nPosition) + sReplace;
|
||
|
nPosition = nFound + nFindLength;
|
||
|
nFound = FindSubString(sSource, sFind, nPosition);
|
||
|
}
|
||
|
// Tack on the end of sSource and return.
|
||
|
return sReturnValue + GetStringRight(sSource, GetStringLength(sSource) - nPosition);
|
||
|
}
|
||
|
string ai_GetStringArray(string sArray, int nIndex, string sSeperator = ":")
|
||
|
{
|
||
|
int nCnt = 0, nMark = 0, nStringLength = GetStringLength(sArray);
|
||
|
string sCharacter;
|
||
|
// Search the string.
|
||
|
while(nCnt < nStringLength)
|
||
|
{
|
||
|
sCharacter = GetSubString(sArray, nCnt, 1);
|
||
|
// Look for the mark.
|
||
|
if(sCharacter == sSeperator)
|
||
|
{
|
||
|
// If we have not found it then lets see if this mark is the one.
|
||
|
if(nMark < 1)
|
||
|
{
|
||
|
// If we are down to 0 in the index then we have found the mark.
|
||
|
if(nIndex > 0) nIndex --;
|
||
|
// Mark the start of the string we need.
|
||
|
else nMark = nCnt + 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// We have the first mark so the next mark will mean we have the string we need.
|
||
|
// Now pull it and return.
|
||
|
sArray = GetSubString(sArray, nMark, nCnt - nMark);
|
||
|
return sArray;
|
||
|
}
|
||
|
}
|
||
|
nCnt ++;
|
||
|
}
|
||
|
// If we hit the end without finding it then return "" as an error.
|
||
|
return "";
|
||
|
}
|
||
|
string ai_SetStringArray(string sArray, int nIndex, string sField, string sSeperator = ":")
|
||
|
{
|
||
|
int nCnt = 1, nMark = 1, nStringLength = GetStringLength(sArray);
|
||
|
int nIndexCounter = 0;
|
||
|
string sCharacter, sNewArray = sSeperator, sText;
|
||
|
// Check to make sure this is not a new array.
|
||
|
// If it is new then set it with 1 slot.
|
||
|
if(nStringLength < 2)
|
||
|
{
|
||
|
sArray = sSeperator + " " + sSeperator;
|
||
|
nStringLength = 3;
|
||
|
}
|
||
|
// Search the string.
|
||
|
while(nCnt <= nStringLength)
|
||
|
{
|
||
|
sCharacter = GetSubString(sArray, nCnt, 1);
|
||
|
// Look for the mark.
|
||
|
if(sCharacter == sSeperator)
|
||
|
{
|
||
|
// First check to see if this is the index we are replacing.
|
||
|
if(nIndex == nIndexCounter) sText = sField;
|
||
|
else
|
||
|
{
|
||
|
// Get the original text for this field.
|
||
|
sText = GetSubString(sArray, nMark, nCnt - nMark);
|
||
|
}
|
||
|
// Add the field to the new index.
|
||
|
sNewArray = sNewArray + sText + sSeperator;
|
||
|
// Now set the marker to the new starting point.
|
||
|
nMark = nCnt + 1;
|
||
|
// Increase the index counter as well.
|
||
|
nIndexCounter ++;
|
||
|
}
|
||
|
nCnt ++;
|
||
|
}
|
||
|
// if we are at the end of the array and still have not set the data
|
||
|
// then add blank data until we get to the correct index.
|
||
|
while(nIndexCounter <= nIndex)
|
||
|
{
|
||
|
// If they match add the field.
|
||
|
if(nIndexCounter == nIndex) sNewArray = sNewArray + sField + sSeperator;
|
||
|
// Otherwise just add a blank field.
|
||
|
else sNewArray = sNewArray + " " + sSeperator;
|
||
|
nIndexCounter ++;
|
||
|
}
|
||
|
// When done return the new array.
|
||
|
return sNewArray;
|
||
|
}
|
||
|
int ai_GetNumberOfProperties(object oItem)
|
||
|
{
|
||
|
int nNumOfProperties = 0, nPropertyType, nPropertySubType;
|
||
|
// Get first property
|
||
|
itemproperty ipProperty = GetFirstItemProperty(oItem);
|
||
|
while(GetIsItemPropertyValid(ipProperty))
|
||
|
{
|
||
|
// Ignore double type properties such as bane.
|
||
|
nPropertyType = GetItemPropertyType(ipProperty);
|
||
|
switch(nPropertyType)
|
||
|
{
|
||
|
// Skip these properties as they don't count.
|
||
|
case 8 : break; // EnhanceAlignmentGroup
|
||
|
case 44 : break; // Light
|
||
|
case 62 : break; // UseLimitationAlignmentGroup
|
||
|
case 63 : break; // UseLimitationClass
|
||
|
case 64 : break; // UseLimitationRacial
|
||
|
case 65 : break; // UseLimitationSpecificAlignment
|
||
|
case 66 : break; // UseLimitationTerrain
|
||
|
case 86 : break; // Quality
|
||
|
case 150 : break; // UseLimitationGender
|
||
|
case 15 :
|
||
|
{
|
||
|
nPropertySubType = GetItemPropertySubType(ipProperty);
|
||
|
if(nPropertySubType == IP_CONST_CASTSPELL_UNIQUE_POWER_SELF_ONLY) break;
|
||
|
if(nPropertySubType == IP_CONST_CASTSPELL_UNIQUE_POWER) break;
|
||
|
}
|
||
|
default : nNumOfProperties ++;
|
||
|
}
|
||
|
// Get the next property
|
||
|
ipProperty = GetNextItemProperty(oItem);
|
||
|
}
|
||
|
// Reduce the number of properties by one on whips.
|
||
|
if(GetBaseItemType(oItem) == BASE_ITEM_WHIP) nNumOfProperties --;
|
||
|
return nNumOfProperties;
|
||
|
}
|
||
|
void ai_CreateCampaignDataTable()
|
||
|
{
|
||
|
sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE,
|
||
|
"CREATE TABLE IF NOT EXISTS " + AI_TABLE + "(" +
|
||
|
"name TEXT, " +
|
||
|
"plugins TEXT, " +
|
||
|
"rules TEXT, " +
|
||
|
"PRIMARY KEY(name));");
|
||
|
SqlStep(sql);
|
||
|
//if(AI_DEBUG) ai_Debug("0i_main", "343", We are creating a campaign table [" +
|
||
|
// AI_TABLE + "] in the database.");
|
||
|
}
|
||
|
void ai_CheckCampaignDataTableAndCreateTable()
|
||
|
{
|
||
|
string sQuery = "SELECT name FROM sqlite_master WHERE type ='table' " +
|
||
|
"AND name =@table;";
|
||
|
sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery);
|
||
|
SqlBindString(sql, "@table", AI_TABLE);
|
||
|
if(!SqlStep(sql)) ai_CreateCampaignDataTable();
|
||
|
}
|
||
|
void ai_InitializeCampaignData()
|
||
|
{
|
||
|
string sQuery = "INSERT INTO " + AI_TABLE + "(name, plugins, rules) " +
|
||
|
"VALUES(@name, @plugins, @rules);";
|
||
|
sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery);
|
||
|
SqlBindString(sql, "@name", "PEPS_DATA");
|
||
|
SqlBindJson(sql, "@plugins", JsonArray());
|
||
|
SqlBindJson(sql, "@rules", JsonObject());
|
||
|
SqlStep(sql);
|
||
|
}
|
||
|
void ai_CheckCampaignDataAndInitialize()
|
||
|
{
|
||
|
ai_CheckCampaignDataTableAndCreateTable();
|
||
|
string sQuery = "SELECT name FROM " + AI_TABLE + " WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery);
|
||
|
SqlBindString(sql, "@name", "PEPS_DATA");
|
||
|
if(!SqlStep(sql)) ai_InitializeCampaignData();
|
||
|
}
|
||
|
void ai_CreateDMDataTable()
|
||
|
{
|
||
|
sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE,
|
||
|
"CREATE TABLE IF NOT EXISTS " + AI_DM_TABLE + "(" +
|
||
|
"name TEXT, " +
|
||
|
"buttons TEXT, " +
|
||
|
"plugins TEXT, " +
|
||
|
"locations TEXT, " +
|
||
|
"options TEXT, " +
|
||
|
"saveslots TEXT, " +
|
||
|
"PRIMARY KEY(name));");
|
||
|
SqlStep(sql);
|
||
|
}
|
||
|
void ai_CheckDMDataTableAndCreateTable()
|
||
|
{
|
||
|
string sQuery = "SELECT name FROM sqlite_master WHERE type ='table' " +
|
||
|
"AND name =@table;";
|
||
|
sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery);
|
||
|
SqlBindString(sql, "@table", AI_DM_TABLE);
|
||
|
if(!SqlStep(sql)) ai_CreateDMDataTable();
|
||
|
}
|
||
|
void ai_InitializeDMData(string sName)
|
||
|
{
|
||
|
string sQuery = "INSERT INTO " + AI_DM_TABLE + "(name, buttons, plugins, " +
|
||
|
"locations, options, saveslots) " +
|
||
|
"VALUES(@name, @buttons, @plugins, @locations, @options, @saveslots);";
|
||
|
sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery);
|
||
|
SqlBindString(sql, "@name", sName);
|
||
|
SqlBindJson(sql, "@buttons", JsonArray());
|
||
|
SqlBindJson(sql, "@plugins", JsonArray());
|
||
|
SqlBindJson(sql, "@locations", JsonObject());
|
||
|
SqlBindJson(sql, "@options", JsonObject());
|
||
|
SqlBindJson(sql, "@saveslots", JsonObject());
|
||
|
SqlStep(sql);
|
||
|
}
|
||
|
void ai_CheckDMDataAndInitialize(object oDM)
|
||
|
{
|
||
|
string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oDM)));
|
||
|
string sQuery = "SELECT name FROM " + AI_DM_TABLE + " WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery);
|
||
|
SqlBindString(sql, "@name", sName);
|
||
|
if(!SqlStep(sql))
|
||
|
{
|
||
|
ai_CheckDMDataTableAndCreateTable();
|
||
|
ai_InitializeDMData(sName);
|
||
|
}
|
||
|
}
|
||
|
void ai_SetCampaignDbJson(string sDataField, json jData, string sName = "PEPS_DATA", string sTable = AI_TABLE)
|
||
|
{
|
||
|
string sQuery = "UPDATE " + sTable + " SET " + sDataField +
|
||
|
" = @data WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery);
|
||
|
SqlBindJson(sql, "@data", jData);
|
||
|
SqlBindString(sql, "@name", sName);
|
||
|
SqlStep(sql);
|
||
|
}
|
||
|
json ai_GetCampaignDbJson(string sDataField, string sName = "PEPS_DATA", string sTable = AI_TABLE)
|
||
|
{
|
||
|
string sQuery = "SELECT " + sDataField + " FROM " + sTable + " WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryCampaign(AI_CAMPAIGN_DATABASE, sQuery);
|
||
|
SqlBindString(sql, "@name", sName);
|
||
|
json jReturn;
|
||
|
if(SqlStep(sql)) return SqlGetJson (sql, 0);
|
||
|
else return JsonArray();
|
||
|
return jReturn;
|
||
|
}
|
||
|
void ai_CreateAssociateDataTable(object oPlayer)
|
||
|
{
|
||
|
sqlquery sql = SqlPrepareQueryObject(oPlayer,
|
||
|
"CREATE TABLE IF NOT EXISTS " + AI_TABLE + "(" +
|
||
|
"name TEXT, " +
|
||
|
"modes TEXT, " +
|
||
|
"buttons TEXT, " +
|
||
|
"aidata TEXT, " +
|
||
|
"lootfilters TEXT, " +
|
||
|
"plugins TEXT, " +
|
||
|
"locations TEXT, " +
|
||
|
"PRIMARY KEY(name));");
|
||
|
SqlStep(sql);
|
||
|
//ai_Debug("0i_main", "665", GetName(oPlayer) + " is creating a table [" +
|
||
|
// AI_TABLE + "] in the database.");
|
||
|
}
|
||
|
void ai_CheckDataTableAndCreateTable(object oPlayer)
|
||
|
{
|
||
|
string sQuery = "SELECT name FROM sqlite_master WHERE type ='table' " +
|
||
|
"AND name =@table;";
|
||
|
sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery);
|
||
|
SqlBindString(sql, "@table", AI_TABLE);
|
||
|
if(!SqlStep(sql)) ai_CreateAssociateDataTable (oPlayer);
|
||
|
//else SendMessageToPC(oPlayer, "0i_main, 675, " + GetName(oPlayer) + " has a database with table [" + AI_TABLE + "].");
|
||
|
}
|
||
|
void ai_InitializeAssociateData(object oPlayer, string sAssociateType)
|
||
|
{
|
||
|
string sQuery = "INSERT INTO " + AI_TABLE + "(name, modes, buttons, " +
|
||
|
"aidata, lootfilters, plugins, locations) " +
|
||
|
"VALUES(@name, @modes, @buttons, @aidata, @lootfilters, @plugins, @locations);";
|
||
|
sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery);
|
||
|
SqlBindString(sql, "@name", sAssociateType);
|
||
|
SqlBindJson(sql, "@modes", JsonArray());
|
||
|
SqlBindJson(sql, "@buttons", JsonArray());
|
||
|
SqlBindJson(sql, "@aidata", JsonArray());
|
||
|
SqlBindJson(sql, "@lootfilters", JsonArray());
|
||
|
SqlBindJson(sql, "@plugins", JsonArray());
|
||
|
SqlBindJson(sql, "@locations", JsonObject());
|
||
|
//SendMessageToPC(oPlayer, "0i_main, 690, " + GetName(oPlayer) + " is initializing associate " +
|
||
|
// sAssociateType + " data for table [" + AI_TABLE + "].");
|
||
|
SqlStep(sql);
|
||
|
}
|
||
|
void ai_CheckAssociateDataAndInitialize(object oPlayer, string sAssociateType)
|
||
|
{
|
||
|
ai_CheckDataTableAndCreateTable(oPlayer);
|
||
|
string sQuery = "SELECT name FROM " + AI_TABLE + " WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryObject (oPlayer, sQuery);
|
||
|
SqlBindString(sql, "@name", sAssociateType);
|
||
|
if(!SqlStep(sql)) ai_InitializeAssociateData(oPlayer, sAssociateType);
|
||
|
//else SendMessageToPC(oPlayer, "0i_main, 701, sAssociateType: " + sAssociateType +
|
||
|
// " returns: " + SqlGetString(sql, 0));
|
||
|
}
|
||
|
string ai_GetAssociateType(object oPlayer, object oAssociate)
|
||
|
{
|
||
|
if(GetIsPC(oAssociate)) return "pc";
|
||
|
string sAITag = GetLocalString(oAssociate, AI_TAG);
|
||
|
if(sAITag == "")
|
||
|
{
|
||
|
int nAssociateType = GetAssociateType(oAssociate);
|
||
|
if(nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION) sAITag = "companion";
|
||
|
else if(nAssociateType == ASSOCIATE_TYPE_FAMILIAR) sAITag = "familiar";
|
||
|
else if(nAssociateType == ASSOCIATE_TYPE_SUMMONED) sAITag = "summons";
|
||
|
else if(nAssociateType == ASSOCIATE_TYPE_DOMINATED) sAITag = "dominated";
|
||
|
else if(nAssociateType == ASSOCIATE_TYPE_HENCHMAN) sAITag = GetTag(oAssociate);
|
||
|
string sCurrentAITag;
|
||
|
// Check for duplicate tags and change.
|
||
|
int nIndex;
|
||
|
object oCreature;
|
||
|
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
|
||
|
{
|
||
|
oCreature = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPlayer, nIndex);
|
||
|
if(oAssociate != oCreature && sAITag == GetTag(oCreature)) sAITag += IntToString(Random(1000));
|
||
|
}
|
||
|
for(nIndex = 2; nIndex < 6; nIndex++)
|
||
|
{
|
||
|
oCreature = GetAssociate(nIndex, oPlayer, 1);
|
||
|
if(oAssociate != oCreature && sAITag == GetTag(oCreature)) sAITag += IntToString(Random(1000));
|
||
|
}
|
||
|
SetLocalString(oAssociate, AI_TAG, sAITag);
|
||
|
}
|
||
|
return sAITag;
|
||
|
}
|
||
|
void ai_SetAssociateDbInt(object oPlayer, string sAssociatetype, string sDataField, int nData, string sTable = AI_TABLE)
|
||
|
{
|
||
|
string sQuery = "UPDATE " + sTable + " SET " + sDataField +
|
||
|
" = @data WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery);
|
||
|
SqlBindString(sql, "@name", sAssociatetype);
|
||
|
SqlBindInt(sql, "@data", nData);
|
||
|
//ai_Debug("0i_main", "368", "SETTING DATA: " + GetName(oPlayer) + " sAssociatetype: " +
|
||
|
// sAssociatetype + " sDataField: " + sDataField + " nData: " + IntToString(nData));
|
||
|
SqlStep(sql);
|
||
|
}
|
||
|
int ai_GetAssociateDbInt(object oPlayer, string sAssociatetype, string sDataField, string sTable = AI_TABLE)
|
||
|
{
|
||
|
string sQuery = "SELECT " + sDataField + " FROM " + sTable + " WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery);
|
||
|
SqlBindString(sql, "@name", sAssociatetype);
|
||
|
//ai_Debug("0i_main", "377", "GETTING DATA: " + GetName(oPlayer) + " sAssociatetype: " +
|
||
|
// sAssociatetype + " sDataField: " + sDataField);
|
||
|
if(SqlStep(sql)) return SqlGetInt(sql, 0);
|
||
|
else return 0;
|
||
|
}
|
||
|
void ai_SetAssociateDbFloat(object oPlayer, string sAssociatetype, string sDataField, float fData, string sTable = AI_TABLE)
|
||
|
{
|
||
|
string sQuery = "UPDATE " + sTable + " SET " + sDataField +
|
||
|
" = @data WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery);
|
||
|
SqlBindString(sql, "@name", sAssociatetype);
|
||
|
SqlBindFloat(sql, "@data", fData);
|
||
|
//ai_Debug("0i_main", "368", "SETTING DATA: " + GetName(oPlayer) + " sAssociatetype: " +
|
||
|
// sAssociatetype + " sDataField: " + sDataField + " fData: " + FloatToString(fData, 0, 0));
|
||
|
SqlStep(sql);
|
||
|
}
|
||
|
float ai_GetAssociateDbFloat(object oPlayer, string sAssociatetype, string sDataField, string sTable = AI_TABLE)
|
||
|
{
|
||
|
string sQuery = "SELECT " + sDataField + " FROM " + sTable + " WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery);
|
||
|
SqlBindString(sql, "@name", sAssociatetype);
|
||
|
//ai_Debug("0i_main", "377", "GETTING DATA: " + GetName(oPlayer) + " sAssociatetype: " +
|
||
|
// sAssociatetype + " sDataField: " + sDataField);
|
||
|
if(SqlStep(sql)) return SqlGetFloat(sql, 0);
|
||
|
else return 0.0;
|
||
|
}
|
||
|
void ai_SetAssociateDbJson(object oPlayer, string sAssociateType, string sDataField, json jData, string sTable = AI_TABLE)
|
||
|
{
|
||
|
//SendMessageToPC(oPlayer, "0i_main, 629, Set DbJson - sAssociateType: " + sAssociateType + " sDataField: " + sDataField + " jData: " + JsonDump(jData));
|
||
|
string sQuery = "UPDATE " + sTable + " SET " + sDataField +
|
||
|
" = @data WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery);
|
||
|
SqlBindJson(sql, "@data", jData);
|
||
|
SqlBindString(sql, "@name", sAssociateType);
|
||
|
SqlStep(sql);
|
||
|
}
|
||
|
json ai_GetAssociateDbJson(object oPlayer, string sAssociateType, string sDataField, string sTable = AI_TABLE)
|
||
|
{
|
||
|
//SendMessageToPC(oPlayer, "0i_main, 638, Get DbJson - sAssociateType: " + sAssociateType + " sDataField: " + sDataField);
|
||
|
string sQuery = "SELECT " + sDataField + " FROM " + sTable + " WHERE name = @name;";
|
||
|
sqlquery sql = SqlPrepareQueryObject(oPlayer, sQuery);
|
||
|
SqlBindString (sql, "@name", sAssociateType);
|
||
|
if(SqlStep(sql))
|
||
|
{
|
||
|
json jReturn = SqlGetJson(sql, 0);
|
||
|
//SendMessageToPC(oPlayer, "0i_main, 646 jReturn: " + JsonDump(jReturn, 1));
|
||
|
if(JsonGetType(jReturn) == JSON_TYPE_NULL) return JsonArray();
|
||
|
return jReturn;
|
||
|
}
|
||
|
else return JsonNull();
|
||
|
}
|
||
|
void aiSaveAssociateModesToDb(object oPlayer, object oAssociate)
|
||
|
{
|
||
|
string sAssociateType = ai_GetAssociateType(oPlayer, oAssociate);
|
||
|
json jModes = ai_GetAssociateDbJson(oPlayer, sAssociateType, "modes");
|
||
|
int nAIMode = GetLocalInt(oAssociate, sAIModeVarname);
|
||
|
jModes = JsonArraySet(jModes, 0, JsonInt(nAIMode));
|
||
|
int nMagicMode = GetLocalInt(oAssociate, sMagicModeVarname);
|
||
|
jModes = JsonArraySet(jModes, 1, JsonInt(nMagicMode));
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "modes", jModes);
|
||
|
}
|
||
|
void ai_SetupModes(object oPlayer, object oAssociate, string sAssociateType)
|
||
|
{
|
||
|
json jModes = JsonArray();
|
||
|
jModes = JsonArrayInsert(jModes, JsonInt(0)); // AI Modes.
|
||
|
// Set magic modes to use Normal magic, Bit 256.
|
||
|
jModes = JsonArrayInsert(jModes, JsonInt(256)); // Magic Modes.
|
||
|
SetLocalInt(oAssociate, sMagicModeVarname, 256);
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "modes", jModes, AI_TABLE);
|
||
|
}
|
||
|
void ai_SetupButtons(object oPlayer, object oAssociate, string sAssociateType)
|
||
|
{
|
||
|
json jButtons = JsonArray();
|
||
|
jButtons = JsonArrayInsert(jButtons, JsonInt(0)); // Command buttons.
|
||
|
jButtons = JsonArrayInsert(jButtons, JsonInt(0)); // AI buttons.
|
||
|
jButtons = JsonArrayInsert(jButtons, JsonInt(0)); // AI buttons 2.
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "buttons", jButtons, AI_TABLE);
|
||
|
}
|
||
|
void ai_SetupAIData(object oPlayer, object oAssociate, string sAssociateType)
|
||
|
{
|
||
|
json jAIData = JsonArray();
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonInt(0)); // 0 - Difficulty adjustment.
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonInt(70)); // 1 - Heal out of combat.
|
||
|
SetLocalInt(oAssociate, AI_HEAL_OUT_OF_COMBAT_LIMIT, 70);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonInt(50)); // 2 - Heal in combat.
|
||
|
SetLocalInt(oAssociate, AI_HEAL_IN_COMBAT_LIMIT, 50);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(20.0)); // 3 - Loot check range.
|
||
|
SetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE, 20.0);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(20.0)); // 4 - Lock check range.
|
||
|
SetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE, 20.0);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(20.0)); // 5 - Trap check range.
|
||
|
SetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE, 20.0);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(3.0)); // 6 - Associate Distance.
|
||
|
SetLocalFloat(oAssociate, AI_FOLLOW_RANGE, 3.0);
|
||
|
// This can be replaced as it is not used in the database.
|
||
|
// We keep it for now as we don't want to move other data.
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonInt(11)); // 7 - Associate Perception DistanceDistance.
|
||
|
SetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION, 11);
|
||
|
SetLocalFloat(oAssociate, AI_ASSOC_PERCEPTION_DISTANCE, 20.0);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonString("")); // 8 - Associate Combat Tactics.
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(20.0)); // 9 - Open Doors check range.
|
||
|
SetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE, 20.0);
|
||
|
json jSpells = JsonArray();
|
||
|
jAIData = JsonArrayInsert(jAIData, jSpells); // 10 - Castable spells.
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData, AI_TABLE);
|
||
|
}
|
||
|
void ai_SetupLootFilters(object oPlayer, object oAssociate, string sAssociateType)
|
||
|
{
|
||
|
json jLootFilters = JsonArray();
|
||
|
// Maximum weight to pickup an item.
|
||
|
jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(200));
|
||
|
SetLocalInt(oAssociate, AI_MAX_LOOT_WEIGHT, 200);
|
||
|
// Bitwise int for checkbox pickup filter.
|
||
|
jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(AI_LOOT_ALL_ON));
|
||
|
SetLocalInt(oAssociate, sLootFilterVarname, AI_LOOT_ALL_ON);
|
||
|
// Minimum gold value to pickup.
|
||
|
int nIndex;
|
||
|
for(nIndex = 2; nIndex < 20; nIndex++)
|
||
|
{
|
||
|
jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(0));
|
||
|
}
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "lootfilters", jLootFilters, AI_TABLE);
|
||
|
}
|
||
|
void ai_SetupLocations(object oPlayer, object oAssociate, string sAssociateType)
|
||
|
{
|
||
|
json jLocations = JsonObject();
|
||
|
json jNUI = JsonObject();
|
||
|
jNUI = JsonObjectSet(jNUI, "x", JsonFloat(-1.0));
|
||
|
jNUI = JsonObjectSet(jNUI, "y", JsonFloat(-1.0));
|
||
|
if(ai_GetIsCharacter(oAssociate))
|
||
|
{
|
||
|
jLocations = JsonObjectSet(jLocations, AI_MAIN_NUI, jNUI);
|
||
|
jLocations = JsonObjectSet(jLocations, AI_PLUGIN_NUI, jNUI);
|
||
|
}
|
||
|
jLocations = JsonObjectSet(jLocations, sAssociateType + AI_COMMAND_NUI, jNUI);
|
||
|
jLocations = JsonObjectSet(jLocations, sAssociateType + AI_NUI, jNUI);
|
||
|
jLocations = JsonObjectSet(jLocations, sAssociateType + AI_LOOTFILTER_NUI, jNUI);
|
||
|
jLocations = JsonObjectSet(jLocations, sAssociateType + AI_COPY_NUI, jNUI);
|
||
|
jLocations = JsonObjectSet(jLocations, sAssociateType + AI_QUICK_WIDGET_NUI, jNUI);
|
||
|
jLocations = JsonObjectSet(jLocations, sAssociateType + AI_SPELL_MEMORIZE_NUI, jNUI);
|
||
|
jLocations = JsonObjectSet(jLocations, sAssociateType + AI_SPELL_KNOWN_NUI, jNUI);
|
||
|
jNUI = JsonObjectSet(jNUI, "x", JsonFloat(0.0));
|
||
|
jNUI = JsonObjectSet(jNUI, "y", JsonFloat(0.0));
|
||
|
jLocations = JsonObjectSet(jLocations, sAssociateType + AI_WIDGET_NUI, jNUI);
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "locations", jLocations, AI_TABLE);
|
||
|
}
|
||
|
void ai_SetupAssociateData(object oPlayer, object oAssociate, string sAssociateType)
|
||
|
{
|
||
|
//ai_Debug("0i_main", "744", GetName(oAssociate) + " is initializing associate data.");
|
||
|
ai_CheckAssociateDataAndInitialize(oPlayer, sAssociateType);
|
||
|
// Default behavior for associates at start.
|
||
|
ai_SetupModes(oPlayer, oAssociate, sAssociateType);
|
||
|
ai_SetupButtons(oPlayer, oAssociate, sAssociateType);
|
||
|
ai_SetupAIData(oPlayer, oAssociate, sAssociateType);
|
||
|
ai_SetupLootFilters(oPlayer, oAssociate, sAssociateType);
|
||
|
// ********** Plugins ************
|
||
|
// These are pulled straight from the database.
|
||
|
ai_SetupLocations(oPlayer, oAssociate, sAssociateType);
|
||
|
}
|
||
|
void ai_RestoreDatabase(object oPlayer, object oAssociate, string sAssociateType)
|
||
|
{
|
||
|
// ********** Modes **********
|
||
|
json jModes = JsonArray();
|
||
|
// AI Modes (0).
|
||
|
int nValue = GetLocalInt(oAssociate, sAIModeVarname);
|
||
|
jModes = JsonArrayInsert(jModes, JsonInt(nValue));
|
||
|
// Magic Modes (1).
|
||
|
nValue = GetLocalInt(oAssociate, sMagicModeVarname);
|
||
|
jModes = JsonArrayInsert(jModes, JsonInt(nValue));
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "modes", jModes, AI_TABLE);
|
||
|
// ********** Buttons **********
|
||
|
json jButtons = JsonArray();
|
||
|
// Command buttons (0).
|
||
|
nValue = GetLocalInt(oAssociate, sWidgetButtonsVarname);
|
||
|
jButtons = JsonArrayInsert(jButtons, JsonInt(nValue));
|
||
|
// AI buttons Group 1 (1).
|
||
|
nValue = GetLocalInt(oAssociate, sAIButtonsVarname);
|
||
|
jButtons = JsonArrayInsert(jButtons, JsonInt(nValue));
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "buttons", jButtons, AI_TABLE);
|
||
|
// ********** AI Data **********
|
||
|
json jAIData = JsonArray();
|
||
|
nValue = GetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonInt(nValue));
|
||
|
nValue = GetLocalInt(oAssociate, AI_HEAL_OUT_OF_COMBAT_LIMIT);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonInt(nValue));
|
||
|
nValue = GetLocalInt(oAssociate, AI_HEAL_IN_COMBAT_LIMIT);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonInt(nValue));
|
||
|
float fValue = GetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue));
|
||
|
fValue = GetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue));
|
||
|
fValue = GetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue));
|
||
|
fValue = GetLocalFloat(oAssociate, AI_FOLLOW_RANGE);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue));
|
||
|
nValue = GetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonInt(nValue));
|
||
|
float fRange = 20.0;
|
||
|
if(nValue == 8) fRange = 10.0;
|
||
|
else if(nValue == 10) fRange = 35.0;
|
||
|
SetLocalFloat(oAssociate, AI_ASSOC_PERCEPTION_DISTANCE, fRange);
|
||
|
string sValue = GetLocalString(oAssociate, AI_DEFAULT_SCRIPT);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonString(sValue));
|
||
|
fValue = GetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE);
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue));
|
||
|
json jValue = GetLocalJson(oPlayer, AI_SPELLS_WIDGET);
|
||
|
if(JsonGetType(jValue) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
jValue = JsonArray();
|
||
|
jValue = JsonArrayInsert(jValue, JsonInt(1)); // 0 - Class selected.
|
||
|
jValue = JsonArrayInsert(jValue, JsonInt(10)); // 1 - Level selected.
|
||
|
jValue = JsonArrayInsert(jValue, JsonArray()); // Spell list for widget.
|
||
|
SetLocalJson(oPlayer, AI_SPELLS_WIDGET, jValue);
|
||
|
}
|
||
|
jAIData = JsonArrayInsert(jAIData, jValue);
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData);
|
||
|
// ********** LootFilters **********
|
||
|
json jLootFilters = JsonArray();
|
||
|
nValue = GetLocalInt(oAssociate, AI_MAX_LOOT_WEIGHT);
|
||
|
jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(nValue));
|
||
|
nValue = GetLocalInt(oAssociate, sLootFilterVarname);
|
||
|
jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(nValue));
|
||
|
int nIndex;
|
||
|
for(nIndex = 2; nIndex < 20; nIndex++)
|
||
|
{
|
||
|
nValue = GetLocalInt(oAssociate, AI_MIN_GOLD_ + IntToString(nIndex));
|
||
|
jLootFilters = JsonArrayInsert(jLootFilters, JsonInt(nValue));
|
||
|
}
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "lootfilters", jLootFilters, AI_TABLE);
|
||
|
// ********** Plugins ************
|
||
|
// These are pulled straight from the database.
|
||
|
// ********** Locations **********
|
||
|
// These are only in the database.
|
||
|
}
|
||
|
void ai_CheckAssociateData(object oPlayer, object oAssociate, string sAssociateType, int bLoad = FALSE)
|
||
|
{
|
||
|
//ai_Debug("0i_main", "810", "Checking data for oAssociate: " + GetName(oAssociate));
|
||
|
// Do quick check to see if they have a variable saved if so then exit.
|
||
|
if(GetLocalFloat(oAssociate, AI_ASSOC_PERCEPTION_DISTANCE) != 0.0)
|
||
|
{
|
||
|
if(!bLoad) return;
|
||
|
// If the database gets destroyed lets drop an error and restore values
|
||
|
// from the locals.
|
||
|
ai_CheckAssociateDataAndInitialize(oPlayer, sAssociateType);
|
||
|
ai_RestoreDatabase(oPlayer, oAssociate, sAssociateType);
|
||
|
return;
|
||
|
}
|
||
|
ai_CheckAssociateDataAndInitialize(oPlayer, sAssociateType);
|
||
|
// ********** Modes **********
|
||
|
json jModes = ai_GetAssociateDbJson(oPlayer, sAssociateType, "modes");
|
||
|
if(JsonGetType(JsonArrayGet(jModes, 0)) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
ai_SetupModes(oPlayer, oAssociate, sAssociateType);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetLocalInt(oAssociate, sAIModeVarname, JsonGetInt(JsonArrayGet(jModes, 0)));
|
||
|
SetLocalInt(oAssociate, sMagicModeVarname, JsonGetInt(JsonArrayGet(jModes, 1)));
|
||
|
}
|
||
|
// ********** Buttons **********
|
||
|
json jButtons = ai_GetAssociateDbJson(oPlayer, sAssociateType, "buttons");
|
||
|
if(JsonGetType(JsonArrayGet(jButtons, 0)) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
ai_SetupButtons(oPlayer, oAssociate, sAssociateType);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// ********** Associate Command Buttons **********
|
||
|
int nWidgetButtons = JsonGetInt(JsonArrayGet(jButtons, 0));
|
||
|
if(nWidgetButtons) SetLocalInt(oAssociate, sWidgetButtonsVarname, nWidgetButtons);
|
||
|
// ********** Associate AI Buttons **********
|
||
|
int nAIButtons = JsonGetInt(JsonArrayGet(jButtons, 1));
|
||
|
if(nAIButtons) SetLocalInt(oAssociate, sAIButtonsVarname, nAIButtons);
|
||
|
}
|
||
|
// ********** AI Data **********
|
||
|
json jAIData = ai_GetAssociateDbJson(oPlayer, sAssociateType, "aidata");
|
||
|
if(JsonGetType(JsonArrayGet(jAIData, 0)) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
ai_SetupAIData(oPlayer, oAssociate, sAssociateType);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT, JsonGetInt(JsonArrayGet(jAIData, 0)));
|
||
|
SetLocalInt(oAssociate, AI_HEAL_OUT_OF_COMBAT_LIMIT, JsonGetInt(JsonArrayGet(jAIData, 1)));
|
||
|
SetLocalInt(oAssociate, AI_HEAL_IN_COMBAT_LIMIT, JsonGetInt(JsonArrayGet(jAIData, 2)));
|
||
|
SetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE, JsonGetFloat(JsonArrayGet(jAIData, 3)));
|
||
|
SetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE, JsonGetFloat(JsonArrayGet(jAIData, 4)));
|
||
|
SetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE, JsonGetFloat(JsonArrayGet(jAIData, 5)));
|
||
|
SetLocalFloat(oAssociate, AI_FOLLOW_RANGE, JsonGetFloat(JsonArrayGet(jAIData, 6)));
|
||
|
int nPercRange = JsonGetInt(JsonArrayGet(jAIData, 7));
|
||
|
if(nPercRange < 8 || nPercRange > 11) nPercRange = 11;
|
||
|
SetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION, nPercRange);
|
||
|
float fRange = 20.0;
|
||
|
if(nPercRange == 8) fRange = 10.0;
|
||
|
else if(nPercRange == 10) fRange = 35.0;
|
||
|
SetLocalFloat(oAssociate, AI_ASSOC_PERCEPTION_DISTANCE, fRange);
|
||
|
string sScript = JsonGetString(JsonArrayGet(jAIData, 8));
|
||
|
if(sScript != "") SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript);
|
||
|
json jDoorRange = JsonArrayGet(jAIData, 9);
|
||
|
if(JsonGetType(jDoorRange) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
jAIData = JsonArrayInsert(jAIData, JsonFloat(20.0));
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData);
|
||
|
SetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE, 20.0);
|
||
|
}
|
||
|
else SetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE, JsonGetFloat(jDoorRange));
|
||
|
json jSpellsWidget = JsonArrayGet(jAIData, 10);
|
||
|
if(JsonGetType(jSpellsWidget) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
jSpellsWidget = JsonArray();
|
||
|
jSpellsWidget = JsonArrayInsert(jSpellsWidget, JsonInt(0)); // 0 - Class selected.
|
||
|
jSpellsWidget = JsonArrayInsert(jSpellsWidget, JsonInt(0)); // 1 - Level selected.
|
||
|
jAIData = JsonArrayInsert(jAIData, jSpellsWidget);
|
||
|
ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData);
|
||
|
SetLocalJson(oPlayer, AI_SPELLS_WIDGET, jSpellsWidget);
|
||
|
}
|
||
|
}
|
||
|
// ********** LootFilters **********
|
||
|
json jLootFilters = ai_GetAssociateDbJson(oPlayer, sAssociateType, "lootfilters");
|
||
|
if(JsonGetType(JsonArrayGet(jLootFilters, 0)) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
ai_SetupLootFilters(oPlayer, oAssociate, sAssociateType);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetLocalInt(oAssociate, AI_MAX_LOOT_WEIGHT, JsonGetInt(JsonArrayGet(jLootFilters, 0)));
|
||
|
SetLocalInt(oAssociate, sLootFilterVarname, JsonGetInt(JsonArrayGet(jLootFilters, 1)));
|
||
|
int nIndex;
|
||
|
for(nIndex = 2; nIndex < 20; nIndex++)
|
||
|
{
|
||
|
SetLocalInt(oAssociate, AI_MIN_GOLD_ + IntToString(nIndex), JsonGetInt(JsonArrayGet(jLootFilters, nIndex)));
|
||
|
}
|
||
|
}
|
||
|
// ********** Plugins ************
|
||
|
// These are pulled straight from the database.
|
||
|
// ********** Locations **********
|
||
|
json jLocations = ai_GetAssociateDbJson(oPlayer, sAssociateType, "locations");
|
||
|
if(JsonGetType(JsonObjectGet(jLocations, AI_WIDGET_NUI)) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
ai_SetupLocations(oPlayer, oAssociate, sAssociateType);
|
||
|
}
|
||
|
// They are always pulled from the database, so no copies to local variables.
|
||
|
}
|
||
|
void ai_SetupDMData(object oPlayer, string sName)
|
||
|
{
|
||
|
//ai_Debug("0i_main", "870", GetName(oPlayer) + " is initializing DM data.");
|
||
|
ai_CheckDMDataAndInitialize(oPlayer);
|
||
|
// ********** Buttons **********
|
||
|
json jButtons = JsonArray();
|
||
|
jButtons = JsonArrayInsert(jButtons, JsonInt(0)); // DM Widget Buttons.
|
||
|
ai_SetCampaignDbJson("buttons", jButtons, sName, AI_DM_TABLE);
|
||
|
// ********** Plugins ************
|
||
|
// These are pulled straight from the database.
|
||
|
json jPlugins = JsonArray();
|
||
|
ai_SetCampaignDbJson("plugins", jPlugins, sName, AI_DM_TABLE);
|
||
|
// ********** Locations **********
|
||
|
json jLocations = JsonObject();
|
||
|
json jNUI = JsonObject();
|
||
|
jNUI = JsonObjectSet(jNUI, "x", JsonFloat(-1.0));
|
||
|
jNUI = JsonObjectSet(jNUI, "y", JsonFloat(-1.0));
|
||
|
jLocations = JsonObjectSet(jLocations, AI_MAIN_NUI, jNUI);
|
||
|
jLocations = JsonObjectSet(jLocations, AI_PLUGIN_NUI, jNUI);
|
||
|
jNUI = JsonObjectSet(jLocations, "x", JsonFloat(1.0));
|
||
|
jNUI = JsonObjectSet(jLocations, "y", JsonFloat(1.0));
|
||
|
jLocations = JsonObjectSet(jLocations, AI_WIDGET_NUI, jNUI);
|
||
|
ai_SetCampaignDbJson("locations", jLocations, sName, AI_DM_TABLE);
|
||
|
// ********** Options **********
|
||
|
json jOptions = JsonArray();
|
||
|
ai_SetCampaignDbJson("options", jOptions, sName, AI_DM_TABLE);
|
||
|
// ********** SaveSlots **********
|
||
|
json jSaveSlots = JsonObject();
|
||
|
ai_SetCampaignDbJson("saveslots", jSaveSlots, sName, AI_DM_TABLE);
|
||
|
}
|
||
|
void ai_CheckDMData(object oPlayer)
|
||
|
{
|
||
|
//ai_Debug("0i_main", "898", "Checking data for DM: " + GetName(oPlayer));
|
||
|
string sName = ai_RemoveIllegalCharacters(GetName(oPlayer));
|
||
|
// ********** Buttons **********
|
||
|
json jButtons = ai_GetCampaignDbJson("buttons", sName, AI_DM_TABLE);
|
||
|
// if there is no saved AImodes then set the defaults.
|
||
|
if(JsonGetType(JsonArrayGet(jButtons, 0)) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
ai_SetupDMData(oPlayer, sName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//ai_Debug("0i_main", "909", GetName(oPlayer) + " is loading DM data from the database.");
|
||
|
// Get data from the database and place on to the associates and player.
|
||
|
// ********** Buttons **********
|
||
|
json jButtons = ai_GetCampaignDbJson("buttons", sName, AI_DM_TABLE);
|
||
|
if(JsonGetType(JsonArrayGet(jButtons, 0)) == JSON_TYPE_NULL)
|
||
|
{
|
||
|
ai_SetupDMData(oPlayer, sName);
|
||
|
}
|
||
|
SetLocalInt(oPlayer, sDMWidgetButtonVarname, JsonGetInt(JsonArrayGet(jButtons, 0)));
|
||
|
// ********** Associate Command Buttons **********
|
||
|
int nWidgetButtons = JsonGetInt(JsonArrayGet(jButtons, 0));
|
||
|
SetLocalInt(oPlayer, sDMWidgetButtonVarname, nWidgetButtons);
|
||
|
// ********** Plugins ************
|
||
|
// These are pulled straight from the database.
|
||
|
// ********** Locations **********
|
||
|
// These are pulled straight from the database.
|
||
|
// ********** Options **********
|
||
|
// ********** SaveSltos **********
|
||
|
}
|
||
|
}
|
||
|
json ai_Plugin_Add(object oPC, json jPlugins, string sPluginScript)
|
||
|
{
|
||
|
if(ResManGetAliasFor(sPluginScript, RESTYPE_NCS) == "")
|
||
|
{
|
||
|
ai_SendMessages("The script (" + sPluginScript + ") was not found by ResMan!", AI_COLOR_RED, oPC);
|
||
|
return jPlugins;
|
||
|
}
|
||
|
int nIndex;
|
||
|
json jPlugin = JsonArrayGet(jPlugins, nIndex);
|
||
|
while(JsonGetType(jPlugin) != JSON_TYPE_NULL)
|
||
|
{
|
||
|
if(JsonGetString(JsonArrayGet(jPlugin, 0)) == sPluginScript)
|
||
|
{
|
||
|
ai_SendMessages("Plugin (" + sPluginScript + ") is already installed!", AI_COLOR_RED, oPC);
|
||
|
return jPlugins;
|
||
|
}
|
||
|
jPlugin = JsonArrayGet(jPlugins, ++nIndex);
|
||
|
}
|
||
|
SetLocalInt(oPC, AI_ADD_PLUGIN, TRUE);
|
||
|
SetLocalJson(oPC, AI_JSON_PLUGINS, jPlugins);
|
||
|
ExecuteScript(sPluginScript, oPC);
|
||
|
int nPluginSet = GetLocalInt(oPC, AI_PLUGIN_SET);
|
||
|
// Setting AI_PLUGIN_SET to -1 means the plugin failed to load.
|
||
|
if(nPluginSet == -1) return jPlugins;
|
||
|
if(nPluginSet)
|
||
|
{
|
||
|
jPlugin = GetLocalJson(oPC, AI_JSON_PLUGINS);
|
||
|
jPlugins = JsonArrayInsert(jPlugins, jPlugin);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
jPlugin = JsonArray();
|
||
|
jPlugin = JsonArrayInsert(jPlugin, JsonString(sPluginScript));
|
||
|
jPlugin = JsonArrayInsert(jPlugin, JsonBool(FALSE));
|
||
|
jPlugin = JsonArrayInsert(jPlugin, JsonString(sPluginScript));
|
||
|
int nCount = JsonGetLength(jPlugins) + 1;
|
||
|
string sIcon = "is_summon" + IntToString(nCount);
|
||
|
jPlugin = JsonArrayInsert(jPlugin, JsonString(sIcon));
|
||
|
jPlugins = JsonArrayInsert(jPlugins, jPlugin);
|
||
|
}
|
||
|
DeleteLocalInt(oPC, AI_ADD_PLUGIN);
|
||
|
DeleteLocalInt(oPC, AI_PLUGIN_SET);
|
||
|
DeleteLocalJson(oPC, AI_JSON_PLUGINS);
|
||
|
return jPlugins;
|
||
|
}
|
||
|
// Temporary function to addapt old plugin json to new plugin json.
|
||
|
json ai_CheckOldPluginJson(object oPC)
|
||
|
{
|
||
|
json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins");
|
||
|
int nIndex;
|
||
|
json jPlugin = JsonArrayGet(jPlugins, nIndex);
|
||
|
// If the first array is not an array then this is the old version.
|
||
|
if(JsonGetType(jPlugin) != JSON_TYPE_ARRAY)
|
||
|
{
|
||
|
string sScript;
|
||
|
json jNewPlugins = JsonArray();
|
||
|
while(JsonGetType(jPlugin) != JSON_TYPE_NULL)
|
||
|
{
|
||
|
sScript = JsonGetString(jPlugin);
|
||
|
if(sScript != "") jNewPlugins = ai_Plugin_Add(oPC, jNewPlugins, sScript);
|
||
|
jPlugin = JsonArrayGet(jPlugins, ++nIndex);
|
||
|
|
||
|
}
|
||
|
ai_SetAssociateDbJson(oPC, "pc", "plugins", jNewPlugins);
|
||
|
return jNewPlugins;
|
||
|
}
|
||
|
return jPlugins;
|
||
|
}
|
||
|
json ai_UpdatePluginsForPC(object oPC)
|
||
|
{
|
||
|
// Check if the server is running or single player.
|
||
|
if(!AI_SERVER) return ai_CheckOldPluginJson(oPC);
|
||
|
int nJsonType, nCounter, nIndex, bWidget, bAllow;
|
||
|
string sScript, sName, sIcon;
|
||
|
json jServerPlugins = ai_GetCampaignDbJson("plugins");
|
||
|
json jPCPlugin, jPCPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins");
|
||
|
json jNewPCPlugins = JsonArray();
|
||
|
json jServerPlugin = JsonArrayGet(jServerPlugins, nIndex);
|
||
|
while(JsonGetType(jServerPlugin) != JSON_TYPE_NULL)
|
||
|
{
|
||
|
bAllow = JsonGetInt(JsonArrayGet(jServerPlugin, 1));
|
||
|
if(bAllow)
|
||
|
{
|
||
|
sName = JsonGetString(JsonArrayGet(jServerPlugin, 0));
|
||
|
nCounter = 0;
|
||
|
jPCPlugin = JsonArrayGet(jPCPlugins, nCounter);
|
||
|
nJsonType = JsonGetType(jPCPlugin);
|
||
|
while(nJsonType != JSON_TYPE_NULL)
|
||
|
{
|
||
|
if(sName == JsonGetString(JsonArrayGet(jPCPlugin, 0)))
|
||
|
{
|
||
|
// Boolean - Add to widget.
|
||
|
bWidget = JsonGetInt(JsonArrayGet(jPCPlugin, 1));
|
||
|
jServerPlugin = JsonArraySet(jServerPlugin, 1, JsonBool(bWidget));
|
||
|
break;
|
||
|
}
|
||
|
jPCPlugin = JsonArrayGet(jPCPlugins, ++nCounter);
|
||
|
nJsonType = JsonGetType(jPCPlugin);
|
||
|
}
|
||
|
if(nJsonType == JSON_TYPE_NULL)
|
||
|
{
|
||
|
jServerPlugin = JsonArraySet(jServerPlugin, 1, JsonBool(FALSE));
|
||
|
}
|
||
|
jNewPCPlugins = JsonArrayInsert(jNewPCPlugins, jServerPlugin);
|
||
|
}
|
||
|
jServerPlugin = JsonArrayGet(jServerPlugins, ++nIndex);
|
||
|
}
|
||
|
ai_SetAssociateDbJson(oPC, "pc", "plugins", jNewPCPlugins);
|
||
|
return jNewPCPlugins;
|
||
|
}
|
||
|
json ai_UpdatePluginsForDM(object oPC)
|
||
|
{
|
||
|
int nJsonType, nCounter, nIndex, bWidget, bAllow;
|
||
|
string sName, sIcon, sDbName = ai_RemoveIllegalCharacters(GetName(oPC));
|
||
|
json jServerPlugins = ai_GetCampaignDbJson("plugins");
|
||
|
ai_CheckDMDataAndInitialize(oPC);
|
||
|
json jDMPlugin, jDMPlugins = ai_GetCampaignDbJson("plugins", sDbName, AI_DM_TABLE);
|
||
|
json jNewDMPlugins = JsonArray();
|
||
|
json jServerPlugin = JsonArrayGet(jServerPlugins, nIndex);
|
||
|
while(JsonGetType(jServerPlugin) != JSON_TYPE_NULL)
|
||
|
{
|
||
|
sName = JsonGetString(JsonArrayGet(jServerPlugin, 0));
|
||
|
nCounter = 0;
|
||
|
jDMPlugin = JsonArrayGet(jDMPlugins, nCounter);
|
||
|
nJsonType = JsonGetType(jDMPlugin);
|
||
|
while(nJsonType != JSON_TYPE_NULL)
|
||
|
{
|
||
|
if(sName == JsonGetString(JsonArrayGet(jDMPlugin, 0)))
|
||
|
{
|
||
|
// Boolean - Add to widget.
|
||
|
bWidget = JsonGetInt(JsonArrayGet(jDMPlugin, 1));
|
||
|
jServerPlugin = JsonArraySet(jServerPlugin, 1, JsonBool(bWidget));
|
||
|
break;
|
||
|
}
|
||
|
jDMPlugin = JsonArrayGet(jDMPlugins, ++nCounter);
|
||
|
nJsonType = JsonGetType(jDMPlugin);
|
||
|
}
|
||
|
if(nJsonType == JSON_TYPE_NULL)
|
||
|
{
|
||
|
jServerPlugin = JsonArraySet(jServerPlugin, 1, JsonBool(FALSE));
|
||
|
}
|
||
|
jNewDMPlugins = JsonArrayInsert(jNewDMPlugins, jServerPlugin);
|
||
|
jServerPlugin = JsonArrayGet(jServerPlugins, ++nIndex);
|
||
|
}
|
||
|
ai_SetCampaignDbJson("plugins", jNewDMPlugins, sDbName, AI_DM_TABLE);
|
||
|
return jNewDMPlugins;
|
||
|
}
|
||
|
void ai_StartupPlugins(object oPC)
|
||
|
{
|
||
|
SetLocalInt(oPC, AI_STARTING_UP, TRUE);
|
||
|
int bUpdatePlugins;
|
||
|
string sScript;
|
||
|
json jPlugins;
|
||
|
if(GetIsDM(oPC)) jPlugins = ai_UpdatePluginsForDM(oPC);
|
||
|
else jPlugins = ai_UpdatePluginsForPC(oPC);
|
||
|
// We delete this so each mod can be added that legally loads.
|
||
|
DeleteLocalJson(GetModule(), AI_MONSTER_MOD_JSON);
|
||
|
int nIndex;
|
||
|
json jPlugin = JsonArrayGet(jPlugins, nIndex);
|
||
|
while(JsonGetType(jPlugin) != JSON_TYPE_NULL)
|
||
|
{
|
||
|
sScript = JsonGetString(JsonArrayGet(jPlugin, 0));
|
||
|
ExecuteScript(sScript, oPC);
|
||
|
// -1 means if failed to load so lets make sure to remove it from the list.
|
||
|
if(GetLocalInt(oPC, AI_PLUGIN_SET) == -1)
|
||
|
{
|
||
|
jPlugins = JsonArrayDel(jPlugins, nIndex);
|
||
|
bUpdatePlugins = TRUE;
|
||
|
nIndex--;
|
||
|
}
|
||
|
jPlugin = JsonArrayGet(jPlugins, ++nIndex);
|
||
|
}
|
||
|
if(bUpdatePlugins) ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins);
|
||
|
DeleteLocalInt(oPC, AI_STARTING_UP);
|
||
|
}
|