2025/12/15 Update

Updated PEPS.
Updated nim tools.
This commit is contained in:
Jaysyn904
2025-12-15 18:59:42 -05:00
parent 9fdd96653e
commit f9067172a6
415 changed files with 12995 additions and 9415 deletions

View File

@@ -17,10 +17,21 @@ void main()
// Scout ahead is done int 0e_ch_1_hb (heartbeat script).
if(sAction == "Scout")
{
ai_ClearCreatureActions();
ai_HaveCreatureSpeak(oAssociate, 4, ":29:35:46:");
ai_SetAIMode(oAssociate, AI_MODE_SCOUT_AHEAD, TRUE);
ai_ScoutAhead(oAssociate);
if(ai_GetAIMode(oAssociate, AI_MODE_SCOUT_AHEAD))
{
ai_ClearCreatureActions();
ai_HaveCreatureSpeak(oAssociate, 6, ":29:35:46:10");
ai_SetAIMode(oAssociate, AI_MODE_SCOUT_AHEAD, FALSE);
ai_SendMessages(GetName(oAssociate) + " has stopped patrolling ahead.", AI_COLOR_YELLOW, oPC);
}
else
{
ai_ClearCreatureActions();
ai_HaveCreatureSpeak(oAssociate, 6, ":29:35:46:22:");
ai_SetAIMode(oAssociate, AI_MODE_SCOUT_AHEAD, TRUE);
ai_SendMessages(GetName(oAssociate) + " is now patrolling ahead.", AI_COLOR_YELLOW, oPC);
ai_ScoutAhead(oAssociate);
}
}
else if(sAction == "BasicTactics")
{
@@ -168,5 +179,22 @@ void main()
}
return;
}
else if(sAction == "GetHenchTokens")
{
int nCount, nCntr = 1;
object oHenchman = GetHenchman(oPC, nCntr);
while(oHenchman != OBJECT_INVALID && nCntr <= AI_MAX_HENCHMAN)
{
if(oHenchman == OBJECT_INVALID) break;
if(oHenchman != oAssociate)
{
SetCustomToken(77101 + nCount, GetName(oHenchman));
nCount++;
}
oHenchman = GetHenchman(oPC, ++nCntr);
}
ai_SetupAllyTargets(oAssociate, oPC);
return;
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}

View File

@@ -10,9 +10,6 @@ void main()
{
object oHenchman = OBJECT_SELF;
int nSpell = StringToInt (GetScriptParam ("nSpell"));
// Save the original form so we can check when we turn back (Add 1 so we don't save a 0!).
SetLocalInt (oHenchman, AI_NORMAL_FORM, GetAppearanceType (oHenchman) + 1);
SetLocalString (oHenchman, AI_COMBAT_SCRIPT, "ai_a_polymorphed");
ActionCastSpellAtObject (nSpell, oHenchman, 255, TRUE);
}

View File

@@ -9,8 +9,10 @@
Allows use of ai_conversation for henchman in other modules.
*///////////////////////////////////////////////////////////////////////////////
#include "0i_actions"
#include "nw_inc_gff"
void BeginOriginalHenchmanConversation(string sDialog, object oPC)
{
if(AI_DEBUG) ai_Debug("0c_get_convo", "14", "sDialog: (" + sDialog + ")");
BeginConversation(sDialog, oPC);
}
void main()

View File

@@ -32,6 +32,7 @@ void main()
{
ai_ClearCreatureActions();
object oTarget = GetLocalObject(oCreature, "AI_ALLY_TARGET_" + IntToString(nTarget));
if(AI_DEBUG) ai_Debug("0c_henchmenspell", "36", " nTarget: " + IntToString(nTarget) + " oTarget: " + GetName(oTarget));
if(oTarget != OBJECT_INVALID && ai_CheckAndCastSpell(oCreature, nSpell, 0, 0.0f, oTarget, oPC))
{
DeleteLocalInt(oCreature, "0_SPELL_TO_CAST");

View File

@@ -68,7 +68,7 @@ int StartingConditional()
{
string sHealingIn = IntToString(GetLocalInt(oAssociate, AI_HEAL_IN_COMBAT_LIMIT)) + "%";
string sHealingOut = IntToString(GetLocalInt(oAssociate, AI_HEAL_OUT_OF_COMBAT_LIMIT)) + "%";
SetCustomToken(AI_BASE_CUSTOM_TOKEN + 5, "I'm healing our allies if they go below " +
SetCustomToken(AI_BASE_CUSTOM_TOKEN + 4, "I'm healing our allies if they go below " +
sHealingIn + " health in combat and " + sHealingOut + " out of combat.");
}
else if(sParam == "Spells")

View File

@@ -0,0 +1,16 @@
/*//////////////////////////////////////////////////////////////////////////////
Script: 0c_if_assoc_mode
Programmer: Philos
////////////////////////////////////////////////////////////////////////////////
Text Appears When script that checks to see the ally targets have been set for
this number target.
nTarget (INT) : 0 = ALL, 1 PC, 2 Caster, 3-6 = oPC's Henchman, 7 = PC's Familiar
8 = PC's Animal Companion, 9 = PC's Summon.
Param:
nTarget - The target to check and see if they are set.
*///////////////////////////////////////////////////////////////////////////////
int StartingConditional()
{
string sTarget = GetScriptParam("nTarget");
return GetIsObjectValid(GetLocalObject(OBJECT_SELF, "AI_ALLY_TARGET_" + sTarget));
}

View File

@@ -5,7 +5,11 @@
Text Appears When script that checks if the speaker is the master of this
henchman.
*///////////////////////////////////////////////////////////////////////////////
#include "0i_constants"
int StartingConditional()
{
return !GetIsObjectValid(GetMaster());
string sInput = GetScriptParam("sInput");
if(sInput == "Can_Hire_Henchman" && AI_ALLOW_TAKING_HENCHMAN) return !GetIsObjectValid(GetMaster());
else if(sInput == "Cannot_Hire_Henchman") return !GetIsObjectValid(GetMaster());
return FALSE;
}

View File

@@ -3,9 +3,14 @@
Programmer: Philos
////////////////////////////////////////////////////////////////////////////////
Text Appears When script that check if scouting is activated on this server.
Script Param: nTRUE -
if set to 1 then it will pass TRUE if they are in scout mode.
if set to 0 then it will pass TRUE if they are NOT in scout mode.
*///////////////////////////////////////////////////////////////////////////////
#include "0i_associates"
int StartingConditional()
{
return AI_SCOUT_AHEAD_ON;
int nTRUE = StringToInt(GetScriptParam("nTRUE"));
return AI_SCOUT_AHEAD_ON && ai_GetAIMode(OBJECT_SELF, AI_MODE_SCOUT_AHEAD) == nTRUE;
}

View File

@@ -0,0 +1,26 @@
/*//////////////////////////////////////////////////////////////////////////////
Script: 0e_animations
Programmer: Philos
////////////////////////////////////////////////////////////////////////////////
Monster Ambient Animations and Walk Waypoint code.
This code uses the Bioware systems, but can be rewritten to use what ever you
want!
This is called in the nw_c2_default1 - monster heartbeat script.
*///////////////////////////////////////////////////////////////////////////////
#include "x0_i0_anims"
#include "0i_actions"
void main()
{
if(!IsInConversation (OBJECT_SELF))
{
if(GetWalkCondition(NW_WALK_FLAG_CONSTANT)) WalkWayPoints();
if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS)) PlayMobileAmbientAnimations_NonAvian();
else if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN)) PlayMobileAmbientAnimations_Avian();
else if(GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS)) PlayImmobileAmbientAnimations();
else if(GetLocalInt(GetModule(), AI_RULE_WANDER) && GetStandardFactionReputation(STANDARD_FACTION_HOSTILE) > 89)
{
ai_AmbientAnimations();
}
}
}

View File

@@ -10,8 +10,7 @@ void main()
{
object oCreature = OBJECT_SELF;
// Added code to allow for permanent associates in the battle!
if(AI_DEBUG) ai_Debug("0e_ch_7_ondeath", "13", GetName(oCreature) + " has died!" +
" AI_RULE_PERM_ASSOC: " + IntToString(GetLocalInt(GetModule(), AI_RULE_PERM_ASSOC)));
if(AI_DEBUG) ai_Debug("0e_ch_7_ondeath", "13", GetName(oCreature) + " has died!");
object oModule = GetModule();
if(GetLocalInt(oModule, AI_RULE_PERM_ASSOC))
{
@@ -22,6 +21,7 @@ void main()
oAssociate = GetAssociate(nIndex, oCreature);
if(oAssociate != OBJECT_INVALID)
{
if(AI_DEBUG) ai_Debug("0e_ch_7_ondeath", "24", GetName(oAssociate) + " being set to permanent!");
SetIsDestroyable(FALSE, FALSE, FALSE, oAssociate);
DelayCommand(0.1, ChangeToStandardFaction(oAssociate, STANDARD_FACTION_HOSTILE));
DelayCommand(3.0, SetIsDestroyable(TRUE, FALSE, FALSE, oAssociate));
@@ -31,12 +31,15 @@ void main()
// Remove the widget!
object oPC = GetMaster(oCreature);
if(oPC != OBJECT_INVALID)
{
{
if(AI_DEBUG) ai_Debug("0e_ch_7_ondeath", "35", GetName(oPC) + " Removing associates widget!");
NuiDestroy(oPC, NuiFindWindow(oPC, ai_GetAssociateType(oPC, oCreature) + AI_WIDGET_NUI));
DelayCommand(0.5, ai_CheckXPPartyScale(oCreature));
DelayCommand(2.0, ai_ClearCreatureActions(TRUE));
}
DelayCommand(2.0, ai_ClearCombatState(oCreature));
ExecuteScript(GetLocalString(oCreature, "AI_ON_DEATH"));
ChangeToStandardFaction(oCreature, STANDARD_FACTION_DEFENDER);
if(AI_DEBUG) ai_Debug("0e_ch_7_ondeath", "42", "Execute second OnDeath script: " + GetLocalString(oCreature, "AI_ON_DEATH"));
ExecuteScript(GetLocalString(oCreature, "AI_ON_DEATH"), oCreature);
}

View File

@@ -8,6 +8,7 @@
#include "nw_inc_gff"
#include "x0_i0_assoc"
#include "0i_menus"
#include "0i_module"
#include "0i_player_target"
// Save a window ID to the database.
void ai_SaveWindowLocation(object oPC, int nToken, string sAssociateType, string sWindowID);
@@ -32,10 +33,6 @@ void ai_RulePercDistInc(object oPC, object oModule, int nIncrement, int nToken);
// Adds a spell to a json AI restricted spell list then returns jRules.
// bRestrict = TRUE will add to the list FALSE will remove it from the list.
json ai_AddRestrictedSpell(json jRules, int nSpell, int bRestrict = TRUE);
// Turns on oAssociate AI, Setting all event scripts.
void ai_TurnOn(object oPC, object oAssociate, string sAssociateType);
// Turns off oAssociate AI, Setting all event scripts.
void ai_TurnOff(object oPC, object oAssociate, string sAssociateType);
// Adds a henchman back into the players party.
object ai_AddHenchman(object oPC, json jHenchman, location lLocation, int nFamiliar, int nCompanion);
@@ -94,10 +91,20 @@ void main()
json jData = NuiGetUserData(oPC, nToken);
object oAssociate = StringToObject(JsonGetString(JsonArrayGet(jData, 0)));
string sAssociateType = ai_GetAssociateType(oPC, oAssociate);
if(ai_GetIsDungeonMaster(oPC))
{
if(!NuiFindWindow(oPC, "dm" + AI_WIDGET_NUI))
{
ai_SendMessages(GetName(oPC) + " is now a Dungeon Master! Loading Dungeon Master widget.", AI_COLOR_YELLOW, oPC);
ai_CheckDMStart(oPC);
}
DelayCommand(0.0, NuiDestroy(oPC, nToken));
return;
}
if(!ai_GetIsCharacter(oAssociate) && !GetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE") &&
(oAssociate == OBJECT_INVALID || GetMaster(oAssociate) != oPC))
{
ai_SendMessages("This creature is no longer in your party!", AI_COLOR_RED, oPC);
ai_SendMessages(GetName(oAssociate) + " is no longer in your party!", AI_COLOR_RED, oPC);
DelayCommand(0.0, NuiDestroy(oPC, nToken));
return;
}
@@ -196,57 +203,6 @@ void main()
aiSaveAssociateModesToDb(oPC, oPC);
}
}
else if(sElem == "btn_toggle_assoc_widget")
{
int bWidgetOff = !ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oPC, "pc");
string sAssocType;
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oPC, "pc", bWidgetOff);
object oAssoc = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
oAssoc = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
oAssoc = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
oAssoc = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
int nIndex;
object oHenchman;
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oHenchman != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oHenchman);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oHenchman, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oHenchman);
}
}
}
else if(sElem == "btn_effect_icon")
{
if(ai_GetMagicMode(oPC, AI_MAGIC_EFFECT_ICON_REPORT))
@@ -280,10 +236,10 @@ void main()
{
int nMaxHenchmen = StringToInt(sText);
if(nMaxHenchmen < 1) nMaxHenchmen = 1;
if(nMaxHenchmen > 12)
if(nMaxHenchmen > AI_MAX_HENCHMAN)
{
nMaxHenchmen = 12;
ai_SendMessages("The maximum henchmen for this mod is 12!", AI_COLOR_RED, oPC);
nMaxHenchmen = AI_MAX_HENCHMAN;
ai_SendMessages("The maximum henchmen for this mod is " + IntToString(AI_MAX_HENCHMAN) + "!", AI_COLOR_RED, oPC);
}
SetMaxHenchmen(nMaxHenchmen);
SetLocalInt(oModule, AI_RULE_MAX_HENCHMAN, nMaxHenchmen);
@@ -318,7 +274,7 @@ void main()
{
int nNumber = StringToInt(sText);
if(nNumber < 0) nNumber = 0;
else if(nNumber > 100) nNumber = 100;
else if(nNumber > 500) nNumber = 500;
SetLocalInt(oModule, AI_INCREASE_MONSTERS_HP, nNumber);
jRules = JsonObjectSet(jRules, AI_INCREASE_MONSTERS_HP, JsonInt(nNumber));
}
@@ -354,6 +310,12 @@ void main()
{
SetLocalInt(oModule, AI_RULE_BUFF_MONSTERS, bCheck);
jRules = JsonObjectSet(jRules, AI_RULE_BUFF_MONSTERS, JsonInt(bCheck));
NuiSetBind(oPC, nToken, "chbx_full_buff_event", JsonBool(bCheck));
}
else if(sElem == "chbx_full_buff_check")
{
SetLocalInt(oModule, AI_RULE_FULL_BUFF_MONSTERS, bCheck);
jRules = JsonObjectSet(jRules, AI_RULE_FULL_BUFF_MONSTERS, JsonInt(bCheck));
}
else if(sElem == "chbx_buff_summons_check")
{
@@ -579,6 +541,60 @@ void main()
else if(sElem == "btn_familiar_name") ai_SetCompanionName(oPC, oAssociate, nToken, ASSOCIATE_TYPE_FAMILIAR);
else if(sElem == "btn_companion_name") ai_SetCompanionName(oPC, oAssociate, nToken, ASSOCIATE_TYPE_ANIMALCOMPANION);
else if(GetStringLeft(sElem, 11) == "btn_plugin_") ai_Plugin_Execute(oPC, sElem);
else if(sElem == "btn_toggle_assoc_widget")
{
int bWidgetOff = !ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oPC, "pc");
string sAssocType, sText;
if(bWidgetOff) sText = " Associate Widgets [Off]";
else sText = " Associate Widgets [On]";
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_toggle_assoc_widget_tooltip", sText);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oPC, "pc", bWidgetOff);
object oAssoc = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
oAssoc = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
oAssoc = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
oAssoc = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
int nIndex;
object oHenchman;
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oHenchman != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oHenchman);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oHenchman, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oHenchman);
}
}
}
}
else if(sEvent == "watch")
{
@@ -597,10 +613,14 @@ void main()
jPlugin = JsonArraySet(jPlugin, 1, JsonBool(bCheck));
jPlugins = JsonArraySet(jPlugins, nIndex, jPlugin);
ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins);
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC));
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC));
}
}
else if(sElem == "chbx_buff_rest_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_BUFF_REST, oAssociate, sAssociateType, nToken, sElem);
else if(sElem == "chbx_toggle_assoc_widget_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_ASSOC_WIDGETS_OFF, oAssociate, sAssociateType, nToken, sElem);
else if(sElem == "chbx_cmd_action_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_ACTION, oAssociate, sAssociateType, nToken, sElem);
else if(sElem == "chbx_cmd_guard_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_GUARD, oAssociate, sAssociateType, nToken, sElem);
else if(sElem == "chbx_cmd_hold_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_HOLD, oAssociate, sAssociateType, nToken, sElem);
@@ -623,8 +643,11 @@ void main()
else if(sElem == "chbx_companion_check") ai_SetWidgetButtonToCheckbox(oPC, BTN_CMD_COMPANION, oAssociate, sAssociateType, nToken, sElem);
else if(sElem == "cmb_familiar_selected") ai_SetCompanionType(oPC, oAssociate, nToken, ASSOCIATE_TYPE_FAMILIAR);
else if(sElem == "cmb_companion_selected") ai_SetCompanionType(oPC, oAssociate, nToken, ASSOCIATE_TYPE_ANIMALCOMPANION);
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
}
}
else if(sEvent == "mousescroll")
{
@@ -635,6 +658,9 @@ void main()
if(sElem == "btn_cmd_follow" &&
oPC != oAssociate) ai_FollowIncrement(oPC, oAssociate, 1.0, sAssociateType);
else if(sElem == "btn_follow_target") ai_FollowIncrement(oPC, oAssociate, 1.0, sAssociateType);
else if(sElem == "btn_buff_long") ai_DelaySpellSpeed(oPC, oAssociate, 0.1, sAssociateType);
else if(sElem == "btn_buff_short") ai_DelaySpellSpeed(oPC, oAssociate, 0.1, sAssociateType);
else if(sElem == "btn_buff_all") ai_DelaySpellSpeed(oPC, oAssociate, 0.1, sAssociateType);
}
else if(nMouseScroll == -1.0) // Scroll down
{
@@ -642,6 +668,9 @@ void main()
if(sElem == "btn_cmd_follow" &&
oPC != oAssociate) ai_FollowIncrement(oPC, oAssociate, -1.0, sAssociateType);
else if(sElem == "btn_follow_target") ai_FollowIncrement(oPC, oAssociate, -1.0, sAssociateType);
else if(sElem == "btn_buff_long") ai_DelaySpellSpeed(oPC, oAssociate, -0.1, sAssociateType);
else if(sElem == "btn_buff_short") ai_DelaySpellSpeed(oPC, oAssociate, -0.1, sAssociateType);
else if(sElem == "btn_buff_all") ai_DelaySpellSpeed(oPC, oAssociate, -0.1, sAssociateType);
}
}
return;
@@ -722,8 +751,11 @@ void main()
else if(sElem == "chbx_ignore_traps_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_IGNORE_TRAPS, oAssociate, sAssociateType, nToken, sElem);
else if(sElem == "chbx_perc_range_check") ai_SetAIButtonToCheckbox(oPC, BTN_AI_PERC_RANGE, oAssociate, sAssociateType, nToken, sElem);
else if(sElem == "cmb_ai_script_selected") ai_SetAIScript(oPC, oAssociate, nToken);
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, sAssociateType + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
}
}
else if(sEvent == "mousescroll")
{
@@ -863,6 +895,60 @@ void main()
else if(sElem == "btn_update_widget") ai_UpdateAssociateWidget(oPC, oAssociate);
else if(GetStringLeft(sElem, 15) == "btn_exe_plugin_") ai_Plugin_Execute(oPC, sElem);
else if(GetStringLeft(sElem, 11) == "btn_widget_") ai_SelectWidgetSpellTarget(oPC, oAssociate, sElem);
else if(sElem == "btn_toggle_assoc_widget")
{
int bWidgetOff = !ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oPC, "pc");
string sAssocType, sText;
if(bWidgetOff) sText = "Associate Widgets [Off]";
else sText = "Associate Widgets [On]";
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_toggle_assoc_widget_tooltip", sText);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oPC, "pc", bWidgetOff);
object oAssoc = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
oAssoc = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
oAssoc = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
oAssoc = GetAssociate(ASSOCIATE_TYPE_DOMINATED, oPC);
if(oAssoc != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oAssoc);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oAssoc, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oAssoc);
}
int nIndex;
object oHenchman;
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oHenchman = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oHenchman != OBJECT_INVALID)
{
sAssocType = ai_GetAssociateType(oPC, oHenchman);
ai_SetWidgetButton(oPC, BTN_WIDGET_OFF, oHenchman, sAssocType, bWidgetOff);
if(bWidgetOff) IsWindowClosed(oPC, sAssocType + AI_WIDGET_NUI);
else ai_CreateWidgetNUI(oPC, oHenchman);
}
}
}
}
if(sEvent == "mousescroll")
{
@@ -881,6 +967,9 @@ void main()
else if(sElem == "btn_heal_in") ai_Heal_Button(oPC, oAssociate, 5, AI_HEAL_IN_COMBAT_LIMIT, sAssociateType);
else if(sElem == "btn_loot") ai_LootRangeIncrement(oPC, oAssociate, 1.0, sAssociateType);
else if(sElem == "btn_perc_range") ai_PercRangeIncrement(oPC, oAssociate, 1, sAssociateType, -1);
else if(sElem == "btn_buff_long") ai_DelaySpellSpeed(oPC, oAssociate, 0.1, sAssociateType);
else if(sElem == "btn_buff_short") ai_DelaySpellSpeed(oPC, oAssociate, 0.1, sAssociateType);
else if(sElem == "btn_buff_all") ai_DelaySpellSpeed(oPC, oAssociate, 0.1, sAssociateType);
}
if(nMouseScroll == -1.0) // Scroll down
{
@@ -897,6 +986,9 @@ void main()
else if(sElem == "btn_heal_in") ai_Heal_Button(oPC, oAssociate, -5, AI_HEAL_IN_COMBAT_LIMIT, sAssociateType);
else if(sElem == "btn_loot") ai_LootRangeIncrement(oPC, oAssociate, -1.0, sAssociateType);
else if(sElem == "btn_perc_range") ai_PercRangeIncrement(oPC, oAssociate, -1, sAssociateType, -1);
else if(sElem == "btn_buff_long") ai_DelaySpellSpeed(oPC, oAssociate, -0.1, sAssociateType);
else if(sElem == "btn_buff_short") ai_DelaySpellSpeed(oPC, oAssociate, -0.1, sAssociateType);
else if(sElem == "btn_buff_all") ai_DelaySpellSpeed(oPC, oAssociate, -0.1, sAssociateType);
}
}
if(sEvent == "mousedown")
@@ -1174,9 +1266,10 @@ void main()
{
json jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins");
jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_buffing");
jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_forcerest");
jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_henchmen");
jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_crafting");
jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_forcerest");
jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_fast_travel");
jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_henchmen");
jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_mod_set");
jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_debug");
jPlugins = ai_Plugin_Add(oPC, jPlugins, "pi_test");
@@ -1209,8 +1302,11 @@ void main()
ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins);
DelayCommand(0.0, NuiDestroy(oPC, nToken));
DelayCommand(0.1, ai_CreatePluginNUI(oPC));
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC));
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC));
}
}
if(sElem == "btn_clear_plugins")
{
@@ -1229,8 +1325,11 @@ void main()
ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins);
DelayCommand(0.0, NuiDestroy(oPC, nToken));
DelayCommand(0.1, ai_CreatePluginNUI(oPC));
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC));
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC));
}
}
else if(sElem == "btn_add_plugin")
{
@@ -1249,8 +1348,11 @@ void main()
ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins);
DelayCommand(0.0, NuiDestroy(oPC, nToken));
DelayCommand(0.1, ai_CreatePluginNUI(oPC));
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC));
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC));
}
}
else if(GetStringLeft(sElem, 11) == "btn_plugin_") ai_Plugin_Execute(oPC, sElem);
}
@@ -1265,8 +1367,11 @@ void main()
jPlugin = JsonArraySet(jPlugin, 1, JsonBool(bCheck));
jPlugins = JsonArraySet(jPlugins, nIndex, jPlugin);
ai_SetAssociateDbJson(oPC, "pc", "plugins", jPlugins);
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC));
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.0, NuiDestroy(oPC, NuiFindWindow(oPC, "pc" + AI_WIDGET_NUI)));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oPC));
}
}
}
return;
@@ -1348,11 +1453,14 @@ void main()
}
else if(sEvent == "close")
{
int nUIToken = NuiFindWindow(oPC, sAssociateType + AI_QUICK_WIDGET_NUI);
if(nUIToken)
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.0, NuiDestroy(oPC, nUIToken));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
int nUIToken = NuiFindWindow(oPC, sAssociateType + AI_QUICK_WIDGET_NUI);
if(nUIToken)
{
DelayCommand(0.0, NuiDestroy(oPC, nUIToken));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
}
}
}
return;
@@ -1435,11 +1543,14 @@ void main()
}
else if(sEvent == "close")
{
int nUIToken = NuiFindWindow(oPC, sAssociateType + AI_QUICK_WIDGET_NUI);
if(nUIToken)
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.0, NuiDestroy(oPC, nUIToken));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
int nUIToken = NuiFindWindow(oPC, sAssociateType + AI_QUICK_WIDGET_NUI);
if(nUIToken)
{
DelayCommand(0.0, NuiDestroy(oPC, nUIToken));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
}
}
}
return;
@@ -1615,6 +1726,7 @@ void main()
if(GetLocalInt(oAssociate, "AI_KNOWN_SPELL_CHANGE"))
{
RemoveHenchman(oPC, oAssociate);
ChangeToStandardFaction(oAssociate, STANDARD_FACTION_DEFENDER);
json jHenchman = ObjectToJson(oAssociate, TRUE);
json jClassList = GetLocalJson(oAssociate, AI_CLASS_LIST_JSON);
jHenchman = GffReplaceList(jHenchman, "ClassList", jClassList);
@@ -1627,8 +1739,12 @@ void main()
AssignCommand(oAssociate, SetIsDestroyable(TRUE, FALSE, FALSE));
DestroyObject(oAssociate);
oAssociate = ai_AddHenchman(oPC, jHenchman, lLocation, nFamiliar, nCompanion);
DeleteLocalJson(oAssociate, AI_CLASS_LIST_JSON);
DeleteLocalInt(oAssociate, "AI_KNOWN_SPELL_CHANGE");
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
}
}
}
return;
@@ -1698,7 +1814,11 @@ void ai_AddAssociate(object oPC, int nToken, json jAssociate, location lLocation
AddHenchman(oPC, oAssociate);
DeleteLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE");
DelayCommand(0.0, NuiDestroy(oPC, nToken));
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
string sAssociateType = ai_GetAssociateType(oPC, oAssociate);
if(!ai_GetWidgetButton(oPC, BTN_WIDGET_OFF, oAssociate, sAssociateType) || oPC == oAssociate)
{
DelayCommand(0.1, ai_CreateWidgetNUI(oPC, oAssociate));
}
if(nRange) SetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION, nRange);
if(nFamiliar) SummonFamiliar(oAssociate);
if(nCompanion) SummonAnimalCompanion(oAssociate);
@@ -1816,12 +1936,12 @@ void ai_Perc_Range(object oPC, object oAssociate, int nToken, string sAssociateT
SetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE", TRUE);
int nBtnPercRange = GetLocalInt(oAssociate, AI_ASSOCIATE_PERCEPTION + "_MENU");
string sText, sText2;
float fRange = 20.0;
float fRange = 25.0;
if(nBtnPercRange == 8)
{
sText = "short";
sText2 = " Perception Range Short [10 meters Sight / 10 meters Listen]";
fRange = 10.0;
fRange = 15.0;
}
else if(nBtnPercRange == 9)
{
@@ -1832,7 +1952,7 @@ void ai_Perc_Range(object oPC, object oAssociate, int nToken, string sAssociateT
{
sText = "long";
sText2 = " Perception Range Long [35 meters Sight / 20 meters Listen]";
fRange = 35.0;
fRange = 40.0;
}
else if(nBtnPercRange == 11)
{
@@ -1914,49 +2034,6 @@ json ai_AddRestrictedSpell(json jRules, int nSpell, int bRestrict = TRUE)
SetLocalJson(oModule, AI_RULE_RESTRICTED_SPELLS, jRSpells);
return JsonObjectSet(jRules, AI_RULE_RESTRICTED_SPELLS, jRSpells);
}
void ai_TurnOn(object oPC, object oTarget, string sAssociateType)
{
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ai_tooltip", " AI On");
ai_SendMessages("AI turned on for " + GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC);
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "xx_pc_1_hb");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_NOTICE, "xx_pc_2_percept");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "xx_pc_3_endround");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "xx_pc_4_convers");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "xx_pc_5_phyatked");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "xx_pc_6_damaged");
//SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DEATH, "");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "xx_pc_8_disturb");
//SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, "");
//SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_RESTED, "");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "xx_pc_b_castat");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "xx_pc_e_blocked");
//SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, "");
// This sets the script for the PC to run AI based on class.
ai_SetAssociateAIScript(oTarget, FALSE);
// Set so PC can hear associates talking in combat.
ai_SetListeningPatterns(oTarget);
}
void ai_TurnOff(object oPC, object oAssociate, string sAssociateType)
{
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ai_tooltip", " AI Off");
ai_SendMessages("AI Turned off for " + GetName(oAssociate) + ".", AI_COLOR_YELLOW, oPC);
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_NOTICE, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "");
//SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DEATH, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "");
//SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, "");
//SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_RESTED, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "");
//SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, "");
DeleteLocalInt(oAssociate, "AI_I_AM_BEING_HEALED");
DeleteLocalString(oAssociate, "AIScript");
ai_ClearCreatureActions();
}
object ai_AddHenchman(object oPC, json jHenchman, location lLocation, int nFamiliar, int nCompanion)
{
jHenchman = GffReplaceResRef(jHenchman, "ScriptSpawn", "");

View File

@@ -5,6 +5,7 @@
Menu event script
sEvent: close, click, mousedown, mouseup, watch (if bindwatch is set).
/*//////////////////////////////////////////////////////////////////////////////
#include "0i_menus"
#include "0i_menus_dm"
void ai_SetDMWidgetButtonToCheckbox(object oDM, int nButton, int nToken, string sElem);
void ai_SetDMWAccessButtonToCheckbox(object oDM, int nButton, int nToken, string sElem);
@@ -32,6 +33,16 @@ void main()
// " nToken: " + IntToString(nToken) + " oPC: " + GetName(oPC));
//WriteTimestampedLogEntry("0e_nui, 58, sWndId: " + sWndId + " sEvent: " + sEvent + " sElem: " + sElem +
// " nToken: " + IntToString(nToken) + " oDM: " + GetName(oDM));
if(ai_GetIsCharacter(oDM))
{
if(!NuiFindWindow(oDM, "pc" + AI_WIDGET_NUI))
{
ai_SendMessages(GetName(oDM) + " is now a Player! Loading player widget.", AI_COLOR_YELLOW, oDM);
ai_CreateWidgetNUI(oDM, oDM);
}
DelayCommand(0.0, NuiDestroy(oDM, nToken));
return;
}
//**************************************************************************
string sName = ai_RemoveIllegalCharacters(GetName(oDM));
// Watch to see if the window moves and save.
@@ -197,10 +208,10 @@ void main()
{
int nMaxHenchmen = StringToInt(JsonGetString(NuiGetBind(oDM, nToken, sElem)));
if(nMaxHenchmen < 1) nMaxHenchmen = 1;
if(nMaxHenchmen > 12)
if(nMaxHenchmen > AI_MAX_HENCHMAN)
{
nMaxHenchmen = 12;
ai_SendMessages("The maximum henchmen for this mod is 12!", AI_COLOR_RED, oDM);
nMaxHenchmen = AI_MAX_HENCHMAN;
ai_SendMessages("The maximum henchmen for this mod is " + IntToString(AI_MAX_HENCHMAN) + "!", AI_COLOR_RED, oDM);
}
SetMaxHenchmen(nMaxHenchmen);
json jRules = ai_GetCampaignDbJson("rules");
@@ -232,7 +243,7 @@ void main()
{
int nNumber = StringToInt(JsonGetString(NuiGetBind(oDM, nToken, sElem)));
if(nNumber < 0) nNumber = 0;
else if(nNumber > 100) nNumber = 100;
else if(nNumber > 500) nNumber = 500;
SetLocalInt(GetModule(), AI_INCREASE_MONSTERS_HP, nNumber);
json jRules = ai_GetCampaignDbJson("rules");
jRules = JsonObjectSet(jRules, AI_INCREASE_MONSTERS_HP, JsonInt(nNumber));
@@ -253,6 +264,11 @@ void main()
SetLocalInt(oModule, AI_RULE_BUFF_MONSTERS, bCheck);
jRules = JsonObjectSet(jRules, AI_RULE_BUFF_MONSTERS, JsonInt(bCheck));
}
else if(sElem == "chbx_full_buff_check")
{
SetLocalInt(oModule, AI_RULE_FULL_BUFF_MONSTERS, bCheck);
jRules = JsonObjectSet(jRules, AI_RULE_FULL_BUFF_MONSTERS, JsonInt(bCheck));
}
else if(sElem == "chbx_buff_summons_check")
{
SetLocalInt(oModule, AI_RULE_PRESUMMON, bCheck);

View File

@@ -15,9 +15,5 @@ void main()
object oCreature = OBJECT_SELF;
// This can be moved to the OnClientLoad script event of your module.
if(ai_GetIsCharacter(oCreature)) ai_CheckPCStart(oCreature);
// If this is a server you can add this as well.
else if(AI_SERVER && (GetIsDM(oCreature) || GetIsPlayerDM(oCreature)))
{
ai_CheckPCStart(oCreature);
}
else if(ai_GetIsDungeonMaster(oCreature)) ai_CheckDMStart(oCreature);
}

View File

@@ -10,6 +10,8 @@
action of the target.
AI_TARGET_MODE is the constant used.
AI_TARGET_ASSOCIATE is the associate that triggered the target mode.
AI_TARGET_MODE_ON defines if the player is in target mode for a henchman instead of the PC.
/*//////////////////////////////////////////////////////////////////////////////
#include "0i_player_target"
void main()
@@ -31,6 +33,7 @@ void main()
location lLocation = Location(GetArea(oPC), vTarget, GetFacing(oPC));
object oAssociate = GetLocalObject(oPC, AI_TARGET_ASSOCIATE);
string sTargetMode = GetLocalString(oPC, AI_TARGET_MODE);
DeleteLocalString(oPC, AI_TARGET_MODE);
// ********************* Exiting Target Actions ************************
// If the user manually exited targeting mode without selecting a target, return
if(!GetIsObjectValid(oTarget) && vTarget == Vector())
@@ -38,50 +41,61 @@ void main()
if(sTargetMode == "ASSOCIATE_ACTION_ALL")
{
ai_SendMessages("You have exited selecting an action for the party.", AI_COLOR_YELLOW, oPC);
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
if(GetLocalInt(oPC, sGhostModeVarname)) ai_OriginalRemoveAllActionMode(oPC);
}
else ai_RemoveAllActionMode(oPC);
ai_RemoveAllActionMode(oPC);
return;
}
else if(sTargetMode == "ASSOCIATE_ACTION")
{
ai_SendMessages("You have exited selecting an action for " + GetName(oAssociate) + ".", AI_COLOR_YELLOW, oPC);
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
// Clean up any PC AI being turned on as well as variables.
DeleteLocalObject(oPC, AI_TARGET_ASSOCIATE);
DeleteLocalInt(oPC, AI_TARGET_MODE_ON);
DeleteLocalObject(oPC, AI_TARGET_MODE_ASSOCIATE);
// Make sure the camera goes back to the player since we are leaving henchmen control.
if(GetLocalObject(oPC, "AI_CAMERA_ON_ASSOCIATE") != OBJECT_INVALID)
{
if(GetLocalInt(oPC, sGhostModeVarname))
{
ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST);
DeleteLocalInt(oAssociate, sGhostModeVarname);
}
DeleteLocalObject(oPC, "AI_CAMERA_ON_ASSOCIATE");
AttachCamera(oPC, oPC);
if(!GetLocalInt(GetModule(), AI_USING_PRC)) ai_TurnOff(oPC, oPC, "pc");
}
else
ai_SetAIMode(oAssociate, AI_MODE_COMMANDED, FALSE);
if(ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST) && !ai_GetAIMode(oPC, AI_MODE_GHOST) &&
GetLocalInt(oAssociate, sGhostModeVarname))
{
ai_SetAIMode(oAssociate, AI_MODE_COMMANDED, FALSE);
if(ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST) && !ai_GetAIMode(oPC, AI_MODE_GHOST) &&
GetLocalInt(oAssociate, sGhostModeVarname))
{
ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST);
DeleteLocalInt(oAssociate, sGhostModeVarname);
}
ExecuteScript("nw_ch_ac1", oAssociate);
ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST);
DeleteLocalInt(oAssociate, sGhostModeVarname);
}
ExecuteScript("nw_ch_ac1", oAssociate);
return;
}
else if(sTargetMode == "ASSOCIATE_GET_TRAP")
{
ai_SendMessages(GetName(oAssociate) + " has exited selecing a trap!", AI_COLOR_YELLOW, oPC);
if(GetLocalInt(oPC, AI_TARGET_MODE_ON)) ai_EnterAssociateTargetMode(oPC, GetLocalObject(oPC, AI_TARGET_MODE_ASSOCIATE));
return;
}
else if(sTargetMode == "ASSOCIATE_PLACE_TRAP")
{
ai_SendMessages(GetName(oAssociate) + " has exited placing the trap!", AI_COLOR_YELLOW, oPC);
if(GetLocalInt(oPC, AI_TARGET_MODE_ON)) ai_EnterAssociateTargetMode(oPC, GetLocalObject(oPC, AI_TARGET_MODE_ASSOCIATE));
return;
}
else if(sTargetMode == "DM_SELECT_CAMERA_VIEW")
{
AttachCamera(oPC, oPC);
ai_SendMessages(GetName(oPC) + " has defaulted camera view back to the player!", AI_COLOR_YELLOW, oPC);
return;
}
// If these actions are canceled and we are in target mode with a henchmen
// then turn target mode back on for that henchmen.
else if(sTargetMode == "ASSOCIATE_USE_ITEM" ||
sTargetMode == "ASSOCIATE_USE_FEAT" ||
sTargetMode == "ASSOCIATE_CAST_SPELL" ||
sTargetMode == "ASSOCIATE_FOLLOW_TARGET")
{
if(GetLocalInt(oPC, AI_TARGET_MODE_ON)) ai_EnterAssociateTargetMode(oPC, GetLocalObject(oPC, AI_TARGET_MODE_ASSOCIATE));
return;
}
return;
}
// ************************* Targeted Actions **************************
else
@@ -89,45 +103,60 @@ void main()
// This action makes an associates move to vTarget.
if(sTargetMode == "ASSOCIATE_ACTION_ALL")
{
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
ai_OriginalActionAllAssociates(oPC, oTarget, lLocation);
}
else ai_ActionAllAssociates(oPC, oTarget, lLocation);
ai_ActionAllAssociates(oPC, oTarget, lLocation);
SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_ACTION_ALL");
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
return;
}
else if(sTargetMode == "ASSOCIATE_ACTION")
{
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
AssignCommand(oAssociate, ai_OriginalActionAssociate(oPC, oTarget, lLocation));
}
else AssignCommand(oAssociate, ai_ActionAssociate(oPC, oTarget, lLocation));
AssignCommand(oAssociate, ai_ActionAssociate(oPC, oTarget, lLocation));
return;
}
else if(sTargetMode == "ASSOCIATE_FOLLOW_TARGET")
{
ai_SelectFollowTarget(oPC, oAssociate, oTarget);
return;
}
else if(sTargetMode == "ASSOCIATE_GET_TRAP")
{
ai_SelectTrap(oPC, oAssociate, oTarget);
return;
}
else if(sTargetMode == "ASSOCIATE_PLACE_TRAP")
{
AssignCommand(oAssociate, ai_PlaceTrap(oPC, lLocation));
return;
}
else if(sTargetMode == "ASSOCIATE_FOLLOW_TARGET") ai_SelectFollowTarget(oPC, oAssociate, oTarget);
else if(sTargetMode == "ASSOCIATE_GET_TRAP") ai_SelectTrap(oPC, oAssociate, oTarget);
else if(sTargetMode == "ASSOCIATE_PLACE_TRAP") AssignCommand(oAssociate, ai_PlaceTrap(oPC, lLocation));
else if(sTargetMode == "ASSOCIATE_USE_ITEM")
{
if(oTarget == GetArea(oPC)) oTarget = OBJECT_INVALID;
ai_UseWidgetItem(oPC, oAssociate, oTarget, lLocation);
DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate));
if(GetLocalInt(oPC, AI_TARGET_MODE_ON)) ai_EnterAssociateTargetMode(oPC, GetLocalObject(oPC, AI_TARGET_MODE_ASSOCIATE));
return;
}
else if(sTargetMode == "ASSOCIATE_USE_FEAT")
{
if(oTarget == GetArea(oPC)) oTarget = OBJECT_INVALID;
ai_UseWidgetFeat(oPC, oAssociate, oTarget, lLocation);
DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate));
if(GetLocalInt(oPC, AI_TARGET_MODE_ON)) ai_EnterAssociateTargetMode(oPC, GetLocalObject(oPC, AI_TARGET_MODE_ASSOCIATE));
return;
}
else if(sTargetMode == "ASSOCIATE_CAST_SPELL")
{
if(oTarget == GetArea(oPC)) oTarget = OBJECT_INVALID;
ai_CastWidgetSpell(oPC, oAssociate, oTarget, lLocation);
DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate));
if(GetLocalInt(oPC, AI_TARGET_MODE_ON)) ai_EnterAssociateTargetMode(oPC, GetLocalObject(oPC, AI_TARGET_MODE_ASSOCIATE));
return;
}
else if(sTargetMode == "DM_SELECT_CAMERA_VIEW")
{
AttachCamera(oPC, oTarget);
ai_SendMessages(GetName(oPC) + " has changed the camera view to " + GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC);
return;
}
else if(sTargetMode == "DM_SELECT_OPEN_INVENTORY")
{
@@ -137,18 +166,20 @@ void main()
ai_SendMessages("You have opened the inventory of "+ GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC);
}
else ai_SendMessages(GetName(oTarget) + " is not in your line of sight!", AI_COLOR_YELLOW, oPC);
return;
}
else if(GetStringLeft(sTargetMode, 15) == "DM_SELECT_GROUP")
{
ai_AddToGroup(oPC, oTarget, sTargetMode);
return;
}
else if(GetStringLeft(sTargetMode, 15) == "DM_ACTION_GROUP")
{
ai_DMAction(oPC, oTarget, lLocation, sTargetMode);
return;
}
// Get saved module player target script and execute it for pass through compatibility.
string sModuleTargetScript = GetLocalString(GetModule(), AI_MODULE_TARGET_EVENT);
ExecuteScript(sModuleTargetScript);
}
// Get saved module player target script and execute it for pass through compatibility.
ExecuteScript(GetLocalString(GetModule(), AI_MODULE_TARGET_EVENT));
}
}

View File

@@ -0,0 +1,317 @@
/*//////////////////////////////////////////////////////////////////////////////
// Script Name: 0e_prc_id_events
////////////////////////////////////////////////////////////////////////////////
Infinite Dungeons monster event handler while using the PRC.
*///////////////////////////////////////////////////////////////////////////////
#include "0i_actions"
#include "x0_i0_assoc"
// Followers special heartbeat script.
void ai_hen_id1_heart(object oCreature);
// Followers special conversation script.
void ai_hen_id1_convo(object oCreature, int nMatch);
// Followers special perception script.
void ai_hen_id1_percept(object oCreature);
// Followers special end of round script.
void ai_hen_id1_endcombat(object oCreature, int bFollower);
// Followers special castat script.
void ai_hen_id1_castat(object oCreature);
void main()
{
object oCreature = OBJECT_SELF;
int nEvent = GetCurrentlyRunningEvent();
int bFollower = GetLocalInt(oCreature, "bFollower");
switch (nEvent)
{
case EVENT_SCRIPT_CREATURE_ON_HEARTBEAT:
{
if(bFollower)
{
if(GetImmortal(oCreature)) SetImmortal(oCreature, FALSE);
ai_hen_id1_heart(oCreature);
}
else
{
ExecuteScript("nw_c2_default1", oCreature);
ExecuteScript("prc_npc_hb", oCreature);
}
break;
}
case EVENT_SCRIPT_CREATURE_ON_NOTICE:
{
if(bFollower) ai_hen_id1_percept(oCreature);
else
{
ExecuteScript("nw_c2_default2", oCreature);
ExecuteScript("prc_npc_percep", oCreature);
}
break;
}
case EVENT_SCRIPT_CREATURE_ON_DIALOGUE:
{
int nMatch = GetListenPatternNumber();
if(nMatch == -1)
{
if(ai_GetIsBusy(oCreature) || ai_Disabled(oCreature) ||
GetLocalInt(oCreature, AI_AM_I_SEARCHING)) return;
ai_ClearCreatureActions();
string sConversation = GetLocalString(oCreature, "sConversation");
if(sConversation != "") BeginConversation(sConversation);
else BeginConversation();
}
if(bFollower) ai_hen_id1_convo(oCreature, nMatch);
else
{
//ExecuteScript("nw_c2_default4", oCreature);
ExecuteScript("prc_npc_conv", oCreature);
}
break;
}
case EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED:
{
if(bFollower) ExecuteScript("nw_ch_ac5", oCreature);
else
{
ExecuteScript("nw_c2_default5", oCreature);
ExecuteScript("prc_npc_physatt", oCreature);
}
break;
}
case EVENT_SCRIPT_CREATURE_ON_DAMAGED:
{
if(bFollower) ExecuteScript("nw_ch_ac6", oCreature);
else
{
ExecuteScript("nw_c2_default6", oCreature);
ExecuteScript("prc_npc_damaged", oCreature);
}
break;
}
case EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT:
{
if(bFollower) ai_hen_id1_castat(oCreature);
else
{
ExecuteScript("nw_c2_defaultb", oCreature);
ExecuteScript("prc_npc_spellat", oCreature);
}
break;
}
case EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND:
{
if(bFollower) ai_hen_id1_endcombat(oCreature, bFollower);
else
{
ExecuteScript("nw_c2_default3", oCreature);
ExecuteScript("prc_npc_combat", oCreature);
}
break;
}
case EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR:
{
if(bFollower) ExecuteScript("nw_ch_ace", oCreature);
else
{
ExecuteScript("nw_c2_defaulte", oCreature);
ExecuteScript("prc_npc_blocked", oCreature);
}
break;
}
case EVENT_SCRIPT_CREATURE_ON_RESTED:
{
if(bFollower) ExecuteScript("nw_ch_aca", oCreature);
else ExecuteScript("prc_npc_rested", oCreature);
break;
}
case EVENT_SCRIPT_CREATURE_ON_DISTURBED:
{
if(bFollower) ExecuteScript("nw_ch_ac8", oCreature);
else
{
ExecuteScript("nw_c2_default8", oCreature);
ExecuteScript("prc_npc_disturb", oCreature);
}
break;
}
case EVENT_SCRIPT_CREATURE_ON_DEATH:
{
if(bFollower) ExecuteScript("nw_ch_ac7", oCreature);
else
{
ExecuteScript("nw_c2_default7", oCreature);
}
break;
}
}
}
void ai_hen_id1_heart(object oCreature)
{
// Sometimes they slip out of this mode!
if(GetAssociateState(NW_ASC_MODE_DYING, oCreature) &&
GetCommandable())
{
ActionPlayAnimation(ANIMATION_LOOPING_DEAD_FRONT, 1.0, 65.0);
SetCommandable(FALSE);
}
ExecuteScript("nw_ch_ac1", oCreature);
}
void ai_hen_id1_convo(object oCreature, int nMatch)
{
if(nMatch == ASSOCIATE_COMMAND_INVENTORY)
{
// * cannot modify disabled equipment
if(!GetLocalInt(OBJECT_SELF, "X2_JUST_A_DISABLEEQUIP"))
{
OpenInventory(oCreature, GetLastSpeaker());
}
// * feedback as to why
else SendMessageToPCByStrRef(GetMaster(), 100895);
return;
}
else if(nMatch == ASSOCIATE_COMMAND_LEAVEPARTY)
{
object oMaster = GetMaster();
string sTag = GetTag(GetArea(oMaster));
// * henchman cannot be kicked out in the reaper realm
// * Followers can never be kicked out
if (sTag == "GatesofCania" || GetIsFollower(oCreature)) return;
if(GetIsObjectValid(oMaster))
{
ai_ClearCreatureActions();
if(GetAssociateType(oCreature) == ASSOCIATE_TYPE_HENCHMAN)
{
string sConversation = GetLocalString(oCreature, "sConversation");
if (sConversation == "id1_plotgiver")
{
string sVariable = GetLocalString(oCreature, "sVariable");
object oDungeon = GetLocalObject(GetModule(), "oCurrentDungeon");
SetLocalInt(oDungeon, "b" + sVariable + "Gone", FALSE);
}
RemoveHenchman(oMaster);
DestroyObject(oCreature);
}
}
return;
}
ExecuteScript("nw_ch_ac4", oCreature);
}
void ai_hen_id1_percept(object oCreature)
{
// If henchman is dying and Player disappears then force a respawn of the henchman
if (GetIsHenchmanDying(oCreature))
{
// The henchman must be removed otherwise their corpse will follow the player
object oOldMaster = GetMaster();
object oPC = GetLastPerceived();
int bVanish = GetLastPerceptionVanished();
if(GetIsObjectValid(oPC) && bVanish)
{
if (oPC == oOldMaster)
{
RemoveHenchman(oPC, oCreature);
// Only in chapter 1
if(GetTag(GetModule()) == "x0_module1")
{
SetCommandable(TRUE);
DoRespawn(oPC, oCreature); // Should teleport henchman back
}
}
}
}
ExecuteScript("nw_ch_ac2", oCreature);
}
void ai_hen_id1_endcombat(object oCreature, int bFollower)
{
if (ai_GetIsInCombat(oCreature))
{
int nNum;
int nLine;
string sString;
int nCreature;
int bIntelligent;
int nRandom = d100();
// chance of a oneliner
int nOnelinerPercentage = GetLocalInt(GetModule(), "nFlagCombatOneLinerFrequencyValue");
if(nRandom <= nOnelinerPercentage)
{
string sCreature = GetLocalString(oCreature, "sVariable");
// if the current creature is hostile towards PCs
if(sCreature != "")
{
object oDungeon = GetLocalObject(GetModule(), "oCurrentDungeon");
if(GetIsReactionTypeHostile(GetFirstPC()))
{
nCreature = GetLocalInt(oDungeon, "n" + sCreature);
bIntelligent = GetLocalInt(oDungeon, "bListCreature" + IntToString(nCreature) + "Intelligent");
if(bIntelligent)
{
nNum = GetLocalInt(GetModule(), "nLinesHostileNum");
nLine = Random(nNum) + 1;
if(nLine > 0)
{
sString = GetLocalString(GetModule(), "sLinesHostile" + IntToString(nLine));
SpeakString(sString, TALKVOLUME_SHOUT);
}
}
}
else
{
nCreature = GetLocalInt(oDungeon, "n" + sCreature);
bIntelligent = GetLocalInt(oDungeon, "bListCreature" + IntToString(nCreature) + "Intelligent");
if(bIntelligent)
{
nNum = GetLocalInt(GetModule(), "nLinesAlliesNum");
nLine = Random(nNum) + 1;
if (nLine > 0)
{
sString = GetLocalString(GetModule(), "sLinesAllies" + IntToString(nLine));
SpeakString(sString, TALKVOLUME_SHOUT);
}
}
}
}
}
}
if(bFollower) ExecuteScript("nw_ch_ac3", oCreature);
else ExecuteScript("nw_c2_default3", oCreature);
}
void ai_hen_id1_castat(object oCreature)
{
if(!GetLastSpellHarmful())
{
int nSpell = GetLastSpell();
if(nSpell == SPELL_RAISE_DEAD || nSpell == SPELL_RESURRECTION)
{
object oCaster = GetLastSpellCaster();
// Restore merchant faction to neutral
SetStandardFactionReputation(STANDARD_FACTION_MERCHANT, 100, oCaster);
SetStandardFactionReputation(STANDARD_FACTION_COMMONER, 100, oCaster);
SetStandardFactionReputation(STANDARD_FACTION_DEFENDER, 100, oCaster);
ClearPersonalReputation(oCaster, oCreature);
AssignCommand(oCreature, SurrenderToEnemies());
AssignCommand(oCreature, ai_ClearCreatureActions(TRUE));
// Reset henchmen attack state - Oct 28 (BK)
ai_SetAIMode(oCreature, AI_MODE_DEFEND_MASTER, FALSE);
ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, FALSE);
ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE);
// Oct 30 - If player previously hired this hench
// then just have them rejoin automatically
if(GetPlayerHasHired(oCaster, oCreature))
{
// Feb 11, 2004 - Jon: Don't fire the HireHenchman function if the
// henchman is already oCaster's associate. Fixes a silly little problem
// that occured when you try to raise a henchman who wasn't actually dead.
if(GetMaster(oCreature)!= oCaster) HireHenchman(oCaster, oCreature, TRUE);
}
else
{
string sFile = GetDialogFileToUse(oCaster);
AssignCommand(oCaster, ActionStartConversation(oCreature, sFile));
}
}
}
ExecuteScript("nw_ch_acb", oCreature);
}

View File

@@ -152,6 +152,8 @@ void ai_AmbientAnimations();
void ai_DoAssociateCombatRound(object oCreature, object oTarget = OBJECT_INVALID)
{
object oMaster = GetMaster(oCreature);
if(GetLocalInt(oMaster, AI_TARGET_MODE_ON) && GetLocalObject(oMaster, AI_TARGET_MODE_ASSOCIATE) == oCreature) return;
if(ai_StayClose(oCreature)) return;
// Is the target our Player has locked in dead? If so then clear it.
if(GetIsDead(GetLocalObject(oCreature, AI_PC_LOCKED_TARGET))) DeleteLocalObject(oCreature, AI_PC_LOCKED_TARGET);
@@ -176,21 +178,27 @@ void ai_DoAssociateCombatRound(object oCreature, object oTarget = OBJECT_INVALID
// the polymorph AI script.
if(sAI != "ai_coward" && sAI != "ai_a_peaceful")
{
if(AI_DEBUG) ai_Debug("0i_actions", "173", "Should we use polymorph? " +
IntToString(GetAppearanceType(oCreature) != ai_GetNormalAppearance(oCreature)));
if(AI_DEBUG)
{
ai_Debug("0i_actions", "181", "Should we use polymorph? Current: " +
IntToString(GetAppearanceType(oCreature)) + " Normal: " + IntToString(ai_GetNormalAppearance(oCreature)));
if(ai_GetIsHidden(oCreature))
{
ai_Debug("0i_actions", "179", "We are hidden!" +
ai_Debug("0i_actions", "185", "We are hidden!" +
" Can they see us? " + IntToString(ai_GetNearestIndexThatSeesUs(oCreature)));
}
}
if(GetAppearanceType(oCreature) != ai_GetNormalAppearance(oCreature))
if(ai_GetIsHidden(oCreature) && !ai_GetNearestIndexThatSeesUs(oCreature)) sAI = "ai_a_invisible";
else if(GetAppearanceType(oCreature) != ai_GetNormalAppearance(oCreature))
{
sAI = "ai_a_polymorphed";
if(!GetLocalInt(oCreature, AI_POLYMORPHED))
{
SetLocalInt(oCreature, AI_POLYMORPHED, TRUE);
ai_ClearTalents(oCreature);
ai_SetCreatureSpecialAbilityTalents(oCreature, FALSE, FALSE, FALSE);
}
}
else if(ai_GetIsHidden(oCreature) && !ai_GetNearestIndexThatSeesUs(oCreature)) sAI = "ai_a_invisible";
}
if(sAI == "") sAI = "ai_a_default";
if(AI_DEBUG) ai_Debug("0i_actions", "190", "********** " + GetName (oCreature) + " **********");
@@ -211,6 +219,7 @@ void ai_DoAssociateCombatRound(object oCreature, object oTarget = OBJECT_INVALID
void ai_StartAssociateCombat(object oAssociate, object oTarget = OBJECT_INVALID)
{
if(AI_DEBUG) ai_Debug("0i_actions", "217", "---------- " + GetName(oAssociate) + " is starting combat! ----------");
//ai_SetCreatureTalentsByLevel(oAssociate, FALSE);
ai_SetCreatureTalents(oAssociate, FALSE);
ai_CheckXPPartyScale(oAssociate);
ai_DoAssociateCombatRound(oAssociate, oTarget);
@@ -226,11 +235,24 @@ void ai_DoMonsterCombatRound(object oMonster)
string sAI = GetLocalString(oMonster, AI_COMBAT_SCRIPT);
if(sAI != "ai_coward")
{
if(GetAppearanceType(oMonster) != ai_GetNormalAppearance(oMonster))
if(AI_DEBUG) ai_Debug("0i_actions", "235", "Should we use polymorph? Current: " +
IntToString(GetAppearanceType(oMonster)) + " Normal: " + IntToString(ai_GetNormalAppearance(oMonster)));
if(ai_GetIsHidden(oMonster))
{
if(AI_DEBUG) ai_Debug("0i_actions", "239", "We are hidden!" +
" Can they see us? " + IntToString(ai_GetNearestIndexThatSeesUs(oMonster)));
}
if(ai_GetIsHidden(oMonster) && !ai_GetNearestIndexThatSeesUs(oMonster)) sAI = "ai_invisible";
else if(GetAppearanceType(oMonster) != ai_GetNormalAppearance(oMonster))
{
sAI = "ai_polymorphed";
if(!GetLocalInt(oMonster, AI_POLYMORPHED))
{
SetLocalInt(oMonster, AI_POLYMORPHED, TRUE);
ai_ClearTalents(oMonster);
ai_SetCreatureSpecialAbilityTalents(oMonster, TRUE, FALSE, FALSE);
}
}
else if(ai_GetIsHidden(oMonster) && !ai_GetNearestIndexThatSeesUs(oMonster)) sAI = "ai_invisible";
}
if(sAI == "") sAI = "ai_default";
if(AI_DEBUG) ai_Debug("0i_actions", "230", "********** " + GetName (oMonster) + " **********");
@@ -277,7 +299,7 @@ int ai_StayClose(object oCreature)
if(fPerceptionDistance == 0.0)
{
fPerceptionDistance = GetLocalFloat(oMaster, AI_ASSOC_PERCEPTION_DISTANCE);
if(fPerceptionDistance == 0.0) fPerceptionDistance = 20.0;
if(fPerceptionDistance == 0.0) fPerceptionDistance = 25.0;
}
object oTarget = GetLocalObject(oCreature, AI_FOLLOW_TARGET);
if(oTarget == OBJECT_INVALID) oTarget = oMaster;
@@ -389,9 +411,20 @@ int ai_SearchForHiddenCreature(object oCreature, int bMonster, object oInvisible
}
}
float fPerceptionDistance, fDistance;
// Check to see if the creature is invisible because we cannot hurt them with our weapon.
// If so we need to stay away from them! Maybe add weapon swapping code later?
if(AI_DEBUG) ai_Debug("0i_actions", "415", GetName(oCreature) + "IsWeaponEffective? " +
IntToString(GetIsWeaponEffective(oInvisible)) + " oInvisible: " + GetName(oInvisible));
/*if(!GetIsWeaponEffective(oInvisible))
{
ai_HaveCreatureSpeak(oCreature, 20, ":21:47:7:");
fDistance = GetDistanceBetween(oCreature, oInvisible);
if(fDistance < AI_RANGE_LONG) ActionMoveAwayFromObject(oInvisible, TRUE, AI_RANGE_LONG);
return TRUE;
} */
if(bMonster)
{
GetDistanceBetween(oCreature, oInvisible);
fDistance = GetDistanceBetween(oCreature, oInvisible);
fPerceptionDistance = GetLocalFloat(GetModule(), AI_RULE_PERCEPTION_DISTANCE);
}
else
@@ -399,7 +432,7 @@ int ai_SearchForHiddenCreature(object oCreature, int bMonster, object oInvisible
// We want to use the distance between the PC and target not us.
object oMaster = GetMaster();
if(oMaster != OBJECT_INVALID) fDistance = GetDistanceBetween(oMaster, oInvisible);
else GetDistanceBetween(oCreature, oInvisible);
else fDistance = GetDistanceBetween(oCreature, oInvisible);
fPerceptionDistance = GetLocalFloat(oCreature, AI_ASSOC_PERCEPTION_DISTANCE);
if(fPerceptionDistance == 0.0) fPerceptionDistance = 20.0;
}
@@ -512,6 +545,9 @@ int ai_MoralCheck(object oCreature)
nRaceType == RACIAL_TYPE_UNDEAD ||
nRaceType == RACIAL_TYPE_CONSTRUCT ||
ai_GetIsCharacter(oCreature)) return FALSE;
int nAssociateType = GetAssociateType(oCreature);
//if(nAssociateType == ASSOCIATE_TYPE_FAMILIAR || nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION ||
// nAssociateType == ASSOCIATE_TYPE_SUMMONED) return FALSE;
// Moral DC is AI_WOUNDED_MORAL_DC - The number of allies.
// or AI_BLOODY_MORAL_DC - number of allies.
int nDC;
@@ -521,11 +557,11 @@ int ai_MoralCheck(object oCreature)
if(nHpPercent <= AI_HEALTH_WOUNDED)
{
// Debug code to look for multiple moral checks at once by one creature?
if(GetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE) == "")
{
SetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE, GetName(oCreature));
ai_Debug("0i_actions", "424", GetName(oCreature) + " starting debug mode to test Moral checks!");
}
//if(GetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE) == "")
//{
// SetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE, GetName(oCreature));
// ai_Debug("0i_actions", "424", GetName(oCreature) + " starting debug mode to test Moral checks!");
//}
if(nHpPercent <= AI_HEALTH_BLOODY) nDC = AI_BLOODY_MORAL_DC;
else nDC = AI_WOUNDED_MORAL_DC;
nDC = nDC - GetLocalInt(oCreature, AI_ALLY_NUMBERS);
@@ -681,17 +717,17 @@ void ai_DoPhysicalAttackOnBest(object oCreature, int nInMelee, int bAlwaysAtk =
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
}
else
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
if(AI_DEBUG) ai_Debug("0i_actions", "519", "Do ranged attack against nearest: " + GetName(oTarget) + "!");
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
@@ -739,17 +775,17 @@ void ai_DoPhysicalAttackOnNearest(object oCreature, int nInMelee, int bAlwaysAtk
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature);
}
else
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
if(AI_DEBUG) ai_Debug("0i_actions", "519", "Do ranged attack against nearest: " + GetName(oTarget) + "!");
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
@@ -796,17 +832,17 @@ void ai_DoPhysicalAttackOnLowestCR(object oCreature, int nInMelee, int bAlwaysAt
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
}
else
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
if(AI_DEBUG) ai_Debug("0i_actions", "559", GetName(OBJECT_SELF) + " does ranged attack on weakest: " + GetName(oTarget) + "!");
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
@@ -1112,7 +1148,7 @@ void ai_ActionTryHealing(object oCreature, object oTarget)
}
int ai_TryHealing(object oCreature, object oTarget, int bForce = FALSE)
{
if(AI_DEBUG) ai_Debug("0i_actions", "733", "Try healing: oCreature: " + GetName(oCreature) +
if(AI_DEBUG) ai_Debug("0i_actions", "1136", "Try healing: oCreature: " + GetName(oCreature) +
" oTarget: " + GetName(oTarget) + " No Party Healing: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_PARTY_HEALING_OFF)) +
" No Self Healing: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_SELF_HEALING_OFF)) +
" AI_I_AM_BEING_HEALED: " + IntToString(GetLocalInt(oTarget, "AI_I_AM_BEING_HEALED")) +
@@ -1133,52 +1169,92 @@ int ai_TryHealing(object oCreature, object oTarget, int bForce = FALSE)
oCreature != oTarget) return FALSE;
if(ai_GetAIMode(oCreature, AI_MODE_SELF_HEALING_OFF) &&
oCreature == oTarget) return FALSE;
// Undead don't heal so lets skip this for them, maybe later we can fix this.
if(GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) return FALSE;
int nHpLost = ai_GetPercHPLoss(oTarget);
// If the player is forcing a heal then we always heal.
if(bForce && nHpLost < 100) nHpLost = 0;
if(AI_DEBUG) ai_Debug("0i_actions", "743", "nHpLost: " + IntToString(nHpLost) +
if(AI_DEBUG) ai_Debug("0i_actions", "1160", "nHpLost: " + IntToString(nHpLost) +
" limit: " + IntToString(ai_GetHealersHpLimit(oTarget, FALSE)));
if(nHpLost >= ai_GetHealersHpLimit(oTarget, FALSE))
// Check to see if we need poison, disease, or ability drain removed.
int nEffectType;
effect eEffect = GetFirstEffect(oTarget);
while(GetIsEffectValid(eEffect))
{
// Check to see if we need poison, disease, or ability drain removed.
int nEffectType;
effect eEffect = GetFirstEffect(oTarget);
while(GetIsEffectValid(eEffect))
nEffectType = GetEffectType(eEffect);
if(AI_DEBUG) ai_Debug("0i_actions", "1168", "Checking to cure(31/32/39) nEffectType: " + IntToString(nEffectType));
if(nEffectType == EFFECT_TYPE_DISEASE)
{
nEffectType = GetEffectType(eEffect);
if(AI_DEBUG) ai_Debug("0i_actions", "1094", "Checking to cure(31/32/39) nEffectType: " + IntToString(nEffectType));
if(nEffectType == EFFECT_TYPE_DISEASE)
if(AI_DEBUG) ai_Debug("0i_actions", "1171", GetName(oTarget) + " is diseased!");
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_DISEASED, bForce)) return TRUE;
if(oCreature == oTarget)
{
if(AI_DEBUG) ai_Debug("0i_actions", "1097", "I am diseased!");
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_DISEASED, bForce)) return TRUE;
if(oCreature == oTarget)
{
if(!d20()) ai_HaveCreatureSpeak(oCreature, 5, ":43:4:14:15:16:");
SpeakString(AI_I_AM_DISEASED, TALKVOLUME_SILENT_TALK);
}
if(!Random(20)) ai_HaveCreatureSpeak(oCreature, 5, ":43:4:14:15:16:");
SpeakString(AI_I_AM_DISEASED, TALKVOLUME_SILENT_TALK);
}
else if(nEffectType == EFFECT_TYPE_POISON)
}
else if(nEffectType == EFFECT_TYPE_POISON)
{
if(AI_DEBUG) ai_Debug("0i_actions", "1181", GetName(oTarget) + " is poisoned!");
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_POISONED, bForce)) return TRUE;
if(oCreature == oTarget)
{
if(AI_DEBUG) ai_Debug("0i_actions", "1107", "I am poisoned!");
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_POISONED, bForce)) return TRUE;
if(oCreature == oTarget)
{
if(!d20()) ai_HaveCreatureSpeak(oCreature, 6, ":43:4:14:15:16:19:");
SpeakString(AI_I_AM_POISONED, TALKVOLUME_SILENT_TALK);
}
if(!Random(20)) ai_HaveCreatureSpeak(oCreature, 6, ":43:4:14:15:16:19:");
SpeakString(AI_I_AM_POISONED, TALKVOLUME_SILENT_TALK);
}
else if(nEffectType == EFFECT_TYPE_ABILITY_DECREASE)
}
else if(nEffectType == EFFECT_TYPE_ABILITY_DECREASE)
{
if(AI_DEBUG) ai_Debug("0i_actions", "1191", GetName(oTarget) + " is weak!");
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_WEAK, bForce)) return TRUE;
if(oCreature == oTarget)
{
if(AI_DEBUG) ai_Debug("0i_actions", "1117", "I am weak!");
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_WEAK, bForce)) return TRUE;
if(oCreature == oTarget)
{
if(!d20()) ai_HaveCreatureSpeak(oCreature, 3, ":43:4:5:");
SpeakString(AI_I_AM_WEAK, TALKVOLUME_SILENT_TALK);
}
if(!Random(20)) ai_HaveCreatureSpeak(oCreature, 3, ":43:4:5:");
SpeakString(AI_I_AM_WEAK, TALKVOLUME_SILENT_TALK);
}
eEffect = GetNextEffect(oTarget);
}
eEffect = GetNextEffect(oTarget);
}
// Everything below here is for healing.
if(nHpLost >= ai_GetHealersHpLimit(oTarget, FALSE)) return FALSE;
// Undead require inflict spells to heal!
object oMaster = ai_GetPlayerMaster(oCreature);
if(GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD)
{
// Do we have no magic on?
if(!ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC))
{
int nClass, nPosition = 1;
string sMemorized;
while(nPosition <= AI_MAX_CLASSES_PER_CHARACTER)
{
nClass = GetClassByPosition(nPosition, oCreature);
if(AI_DEBUG) ai_Debug("0i_actions", "753", "nClass: " + IntToString(nClass));
if(nClass == CLASS_TYPE_INVALID) break;
sMemorized = Get2DAString("classes", "MemorizesSpells", nClass);
// If Memorized column is "" then they are not a caster.
if(sMemorized != "")
{
if(sMemorized == "1")
{
if(ai_CastMemorizedInflict(oCreature, oTarget, oMaster, nClass))
{
SetLocalInt(oTarget, "AI_I_AM_BEING_HEALED", TRUE);
return TRUE;
}
}
else if(ai_CastKnownInflict(oCreature, oTarget, oMaster, nClass))
{
SetLocalInt(oTarget, "AI_I_AM_BEING_HEALED", TRUE);
return TRUE;
}
}
nPosition++;
}
}
// We can't heal ourselves! Can any of our allies? Lets ask.
if(oCreature == oTarget)
{
SetLocalInt(oCreature, "AI_WOUNDED_SHOUT_LIMIT", GetLocalInt(oCreature, "AI_WOUNDED_SHOUT_LIMIT") + 1);
SpeakString(AI_I_AM_WOUNDED, TALKVOLUME_SILENT_TALK);
}
return FALSE;
}
@@ -1192,7 +1268,6 @@ int ai_TryHealing(object oCreature, object oTarget, int bForce = FALSE)
return TRUE;
}
}
object oMaster = ai_GetPlayerMaster(oCreature);
// Do we have no magic on?
if(!ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC))
{

View File

@@ -52,6 +52,8 @@ void ai_OnRested(object oCreature);
// Increments/Decrements the following distance of associates.
void ai_FollowIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType);
// Increments/Decrements the delay when casting each auto buff spell.
void ai_DelaySpellSpeed(object oPC, object oAssociate, float fIncrement, string sAssociateType);
// Turns on/off Ranged combat for oAssociate.
void ai_Ranged(object oPC, object oAssociate, string sAssociateType);
// Turns on/off Ignore enemy associates for oAssociate.
@@ -115,7 +117,7 @@ void ai_Philos_SetStealth(object oMaster, object oCreature, string sAssociateTyp
// Button action for giving commands to associates.
void ai_DoCommand(object oPC, object oAssociate, int nCommand);
// Button action to have associate do an action based on the target via OnPlayer Target event.
void ai_Action(object oPC, object oAssociate);
void ai_Action(object oPC, object oAssociate, int bPCAI = FALSE);
// Toggles between normal ai script and special tactic ai scripts.
void ai_AIScript(object oPC, object oAssociate, string sAssociate, int nToken);
// Has the PC select a Trap and then place it on the ground from an associate.
@@ -130,6 +132,10 @@ void ai_ChangeCameraView(object oPC, object oAssociate);
void ai_OpenInventory(object oAssociate, object oPC);
// Executes an installed plugin.
void ai_Plugin_Execute(object oPC, string sElem, int bUser = 0);
// Turns on oAssociate AI, Setting all event scripts.
void ai_TurnOn(object oPC, object oAssociate, string sAssociateType);
// Turns off oAssociate AI, Setting all event scripts.
void ai_TurnOff(object oPC, object oAssociate, string sAssociateType);
int ai_CanIAttack(object oCreature)
{
@@ -161,7 +167,7 @@ object ai_GetNearestLockedObject(object oCreature)
void ai_FindTheEnemy(object oCreature, object oSpeaker, object oTarget, int bMonster)
{
if(GetLocalInt(oCreature, AI_AM_I_SEARCHING)) return;
if(oSpeaker == oTarget && d100() < 34)
if(oSpeaker == oTarget && d100() < 16)
{
// Let them know we heard something in the distance!.
if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK))
@@ -232,7 +238,7 @@ void ai_FindTheEnemy(object oCreature, object oSpeaker, object oTarget, int bMon
if(AI_DEBUG) ai_Debug("0i_associates", "176", "Moving and searching for " + GetName(oTarget));
SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE);
ActionMoveToLocation(GetLocation(oTarget), FALSE);
//ActionMoveToObject(oTarget, FALSE, AI_RANGE_MELEE);
//ActionMoveToObject(oTarget, FALSE, AI_RANGE_MELEE);
AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING)));
return;
}
@@ -519,6 +525,24 @@ void ai_SelectAssociateCommand(object oCreature, object oCommander, int nCommand
ai_FireHenchman (GetPCSpeaker(), oCreature);
PlayVoiceChat (VOICE_CHAT_GOODBYE, oCreature);
}
else if(AI_PATROL_AHEAD_RADIAL_OPTION)
{
if(ai_GetAIMode(oCreature, AI_MODE_SCOUT_AHEAD))
{
ai_ClearCreatureActions();
ai_HaveCreatureSpeak(oCreature, 6, ":29:35:46:10");
ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_SendMessages(GetName(oCreature) + " has stopped patrolling ahead.", AI_COLOR_YELLOW, oMaster);
}
else
{
ai_ClearCreatureActions();
ai_HaveCreatureSpeak(oCreature, 6, ":29:35:46:22:");
ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, TRUE);
ai_SendMessages(GetName(oCreature) + " is now patrolling ahead.", AI_COLOR_YELLOW, oMaster);
ai_ScoutAhead(oCreature);
}
}
}
}
}
@@ -769,7 +793,7 @@ void ai_AssociateEvaluateNewThreat(object oCreature, object oLastPerceived, stri
if(sPerception == AI_I_SEE_AN_ENEMY || GetObjectSeen(oLastPerceived, oCreature))
{
// We are not in combat and we see the enemy so alert our allies!
ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:");
ai_HaveCreatureSpeak(oCreature, 10, ":0:1:2:3:6:");
SetLocalObject (oCreature, AI_MY_TARGET, oLastPerceived);
SpeakString(sPerception, TALKVOLUME_SILENT_TALK);
ai_StartAssociateCombat(oCreature);
@@ -832,10 +856,10 @@ void ai_MonsterEvaluateNewThreat(object oCreature, object oLastPerceived, string
if(d100() < 34)
{
// We are not in combat so alert our allies!
ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:");
ai_HaveCreatureSpeak(oCreature, 10, ":0:1:2:3:6:");
}
SetLocalObject(oCreature, AI_MY_TARGET, oLastPerceived);
SpeakString(sPerception, TALKVOLUME_SILENT_TALK);
SpeakString(AI_I_SEE_AN_ENEMY, TALKVOLUME_SILENT_TALK);
ai_StartMonsterCombat(oCreature);
}
else ai_FindTheEnemy(oCreature, oLastPerceived, oLastPerceived, TRUE);
@@ -919,6 +943,23 @@ void ai_FollowIncrement(object oPC, object oAssociate, float fIncrement, string
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_follow_target_tooltip", " " + GetName(oAssociate) + " following " + sTarget + " [" + sRange + " meters]");
}
}
void ai_DelaySpellSpeed(object oPC, object oAssociate, float fIncrement, string sAssociateType)
{
float fAdjustment = GetLocalFloat(oAssociate, AI_DELAY_BUFF_CASTING) + fIncrement;
if(fAdjustment > 6.0) fAdjustment = 6.0;
else if(fAdjustment < 0.1) fAdjustment = 0.1;
SetLocalFloat(oAssociate, AI_DELAY_BUFF_CASTING, fAdjustment);
json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata");
jAIData = JsonArraySet(jAIData, 11, JsonFloat(fAdjustment));
ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData);
string sDelay = FloatToString(fAdjustment, 0, 1);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI,
"btn_buff_long_tooltip", " Buff the party with long duration spells. Cast speed [" + sDelay + "]");
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI,
"btn_buff_short_tooltip", " Buff the party with short duration spells. Cast speed [" + sDelay + "]");
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI,
"btn_buff_all_tooltip", " Buff the party with all spells. Cast speed [" + sDelay + "]");
}
void ai_Ranged(object oPC, object oAssociate, string sAssociateType)
{
//ai_ClearCreatureActions();
@@ -1903,18 +1944,20 @@ void ai_DoCommand(object oPC, object oAssociate, int nCommand)
}
}
}
void ai_Action(object oPC, object oAssociate)
void ai_Action(object oPC, object oAssociate, int bPCAI = FALSE)
{
if(oPC == oAssociate)
{
DeleteLocalObject(oPC, "NW_ASSOCIATE_COMMAND");
SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_ACTION_ALL");
ai_SendMessages("Select an action for the party.", AI_COLOR_YELLOW, oPC);
}
else
{
SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate);
SetLocalObject(oPC, AI_TARGET_MODE_ASSOCIATE, oAssociate);
SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_ACTION");
SetLocalInt(oPC, AI_TARGET_MODE_ON, TRUE);
if(!GetLocalInt(GetModule(), AI_USING_PRC) && bPCAI) ai_TurnOn(oPC, oPC, "pc");
ai_SendMessages("Select an action for " + GetName(oAssociate) + ".", AI_COLOR_YELLOW, oPC);
}
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
@@ -2139,6 +2182,7 @@ void ai_ChangeCameraView(object oPC, object oAssociate)
{
SetLocalObject(oPC, "AI_CAMERA_ON_ASSOCIATE", oAssociate);
AttachCamera(oPC, oAssociate);
if(!ai_GetIsCharacter(oAssociate)) ai_Action(oPC, oAssociate, TRUE);
}
}
void ai_SelectCameraView(object oPC)
@@ -2190,3 +2234,47 @@ void ai_Plugin_Execute(object oPC, string sElem, int bUser = 0)
ExecuteScript(sScript, oPC);
}
}
void ai_TurnOn(object oPC, object oTarget, string sAssociateType)
{
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ai_tooltip", " AI On");
ai_SendMessages("AI turned on for " + GetName(oTarget) + ".", AI_COLOR_YELLOW, oPC);
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "xx_pc_1_hb");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_NOTICE, "xx_pc_2_percept");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "xx_pc_3_endround");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "xx_pc_4_convers");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "xx_pc_5_phyatked");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "xx_pc_6_damaged");
//SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DEATH, "");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "xx_pc_8_disturb");
//SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, "");
//SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_RESTED, "");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "xx_pc_b_castat");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "xx_pc_e_blocked");
//SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, "");
// This sets the script for the PC to run AI based on class.
ai_SetAssociateAIScript(oTarget, FALSE);
// Set so PC can hear associates talking in combat.
ai_SetListeningPatterns(oTarget);
}
void ai_TurnOff(object oPC, object oAssociate, string sAssociateType)
{
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ai_tooltip", " AI Off");
ai_SendMessages("AI Turned off for " + GetName(oAssociate) + ".", AI_COLOR_YELLOW, oPC);
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_NOTICE, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DIALOGUE, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_MELEE_ATTACKED, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "");
//SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DEATH, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_DISTURBED, "");
//SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPAWN_IN, "");
//SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_RESTED, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, "");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_BLOCKED_BY_DOOR, "");
//SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_USER_DEFINED_EVENT, "");
DeleteLocalInt(oAssociate, "AI_I_AM_BEING_HEALED");
DeleteLocalString(oAssociate, "AIScript");
ai_ClearCreatureActions();
}

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
Changes to any constants will not take effect until the scripts are recompiled.
*///////////////////////////////////////////////////////////////////////////////
const string PHILOS_VERSION = "Philos' Enhancing Player System (PEPS) version:07.20.25";
const string PHILOS_VERSION = "Philos' Enhancing Player System (PEPS) version:11.16.25";
// The following constants are designed to be changed to allow the AI to work
// differently based on what a developer wants.
// If you change these constants make sure the database has been removed
@@ -18,7 +18,7 @@ const string PHILOS_VERSION = "Philos' Enhancing Player System (PEPS) version:07
// This will only work if you are using the PEPS menu system.
const int AI_DEBUG = FALSE;
// Defines if we are compiling for single player or a server. Always on for servers!
const int AI_SERVER = FALSE;
const int AI_SERVER = TRUE;
// The number of classes allowed for a creature to take in the server/module.
const int AI_MAX_CLASSES_PER_CHARACTER = 8;
// Taunts cool down time before the AI attemps another Taunt.
@@ -35,14 +35,14 @@ const int AI_MONSTER_HEAL_OUT_COMBAT_CHANCE = 70;
const int AI_HENCHMAN_WIDGET = TRUE;
// Change the Custom token number if it conflicts with your server.
const int AI_BASE_CUSTOM_TOKEN = 1000;
// Delay between creatures casting Buff spells. Must be minimum of 0.1 seconds.
const float AI_HENCHMAN_BUFF_DELAY = 0.2;
//******************* These can be changed within the game *******************
// Moral checks on or off. If wounded they will make Will saves, if they fail the flee.
const int AI_MORAL_CHECKS = FALSE;
// Allows monsters to prebuff before combat starts.
const int AI_PREBUFF = TRUE;
// Allows monsters to buff with all spells before combat starts. VERY DIFFICULT!
const int AI_FULL_BUFF = FALSE;
// Allows monsters cast summons spells when prebuffing.
const int AI_PRESUMMONS = TRUE;
// Allows monsters to use tactical AI scripts such as ambush, flanker, ranged.
@@ -111,8 +111,13 @@ const int AI_SCOUT_AHEAD_ON = TRUE;
const int AI_OPEN_INVENTORY = TRUE;
// Allows players to have associates pickup loot.
const int AI_PICKUP_LOOT = TRUE;
// Allows players to remove a henchman.
// Allows players to take any henchman that is standing around.
const int AI_ALLOW_TAKING_HENCHMAN = FALSE;
// Allows players to remove a henchman through PEPS.
const int AI_REMOVE_HENCHMAN_ON = FALSE;
// Allows players to toggle patrolling ahead via the radial menu for remove henchman.
// Used on my server as a way to toggle patrolling ahead via the radial menu.
const int AI_PATROL_AHEAD_RADIAL_OPTION = FALSE;
//***************************** Health Constants *****************************
// % of health for when a creature is considered wounded.
const int AI_HEALTH_WOUNDED = 50;
@@ -141,7 +146,9 @@ const string AI_EFFECT_ICON_NUI = "ai_effect_icon_nui";
// The following constants are core constants and changing any of these without
// understanding the whole system could cause unforseen results.
// CHANGE AT YOUR OWN RISK.
// Variable used to asave a monster object for changing.
// Variable used to check if the module is running as a server.
const string AI_IS_SERVER = "AI_IS_SERVER";
// Variable used to save a monster object for changing.
const string AI_MONSTER_OBJECT = "AI_MONSTER_OBJECT";
// Variable used to save a monsters json for changing.
const string AI_MONSTER_JSON = "AI_MONSTER_JSON";
@@ -160,7 +167,7 @@ const string AI_PLUGIN_SET = "AI_PLUGIN_SET";
// Monster modification variable to let PEPS know what mods are available.
const string AI_MONSTER_MOD_JSON = "AI_MONSTER_MOD_JSON";
// The maximum number of henchman the code works with.
const int AI_MAX_HENCHMAN = 12;
const int AI_MAX_HENCHMAN = 30;
// Delay between Henchman casting Healing spells. Must be minimum of 0.5 seconds.
const float AI_HENCHMAN_HEALING_DELAY = 6.0;
// A variable that can be set on creatures to stop mobile animations.
@@ -219,7 +226,6 @@ const string AI_I_AM_DEAD = "AI_I_AM_DEAD";
const string AI_I_AM_DISEASED = "AI_I_AM_DISEASED";
const string AI_I_AM_POISONED = "AI_I_AM_POISONED";
const string AI_I_AM_WEAK = "AI_I_AM_WEAK";
const int AI_ALLY_SEES_AN_ENEMY = 1;
const int AI_ALLY_HEARD_AN_ENEMY = 2;
const int AI_ALLY_ATKED_BY_WEAPON = 3;
const int AI_ALLY_ATKED_BY_SPELL = 4;
@@ -228,6 +234,7 @@ const int AI_ALLY_IS_DEAD = 6;
const int AI_ALLY_IS_DISEASED = 7;
const int AI_ALLY_IS_POISONED = 8;
const int AI_ALLY_IS_WEAK = 9;
const int AI_ALLY_SEES_AN_ENEMY = 10;
const string AI_MY_TARGET = "AI_MY_TARGET";
// Constant used by monsters to reduce checks while searching for unseen targets.
const string AI_AM_I_SEARCHING = "AI_AM_I_SEARCHING";
@@ -238,6 +245,8 @@ const string AI_IS_INVISIBLE = "AI_IS_INVISIBLE";
// Constants used in combat to keep track of a creatures last action.
// 0+ is the last spell cast from the line number in Spells.2da.
const string sLastActionVarname = "AI_LAST_ACTION";
// Constants used in combat to keep track of a creatures last action time.
const string sLastActionTimeVarname = "AI_LAST_ACTION_TIME";
const int AI_LAST_ACTION_CAST_SPELL = -1;
const int AI_LAST_ACTION_NONE = -2;
const int AI_LAST_ACTION_MELEE_ATK = -3;
@@ -255,6 +264,8 @@ const string AI_ATTACKED_PHYSICAL = "AI_ATTACKED_PHYSICAL";
const string AI_ATTACKED_SPELL = "AI_ATTACKED_SPELL";
// Variable name used to keep track of a creatures normal polymorph form.
const string AI_NORMAL_FORM = "AI_NORMAL_FORM";
// Variable name used to have associates defined as Polymorphed.
const string AI_POLYMORPHED = "AI_POLYMORPHED";
// Variable name used to keep track if a creature has been buffed yet.
const string AI_CASTER_BUFFS_SET = "AI_CASTER_BUFFS_SET";
// Variable name used to keep track of rounds in combat for a custom ai script.
@@ -320,6 +331,7 @@ const int AI_CONDITION_CONFUSED = 0x00020000;
const int AI_CONDITION_CURSE = 0x00040000;
const int AI_CONDITION_PARALYZE = 0x00080000;
const int AI_CONDITION_DOMINATED = 0x00100000;
const int AI_CONDITION_DEAD = 0x00200000;
// Database constants for Associate modes.
const string AI_MODE_DB_TABLE = "AI_MODE_DB_TABLE";
// Bitwise constants for Associate modes that are used with Get/SetAssociateMode().
@@ -394,30 +406,31 @@ const int AI_MAGIC_NO_SPONTANEOUS_CURE = 0x00000800; // Caster will stop using s
const string AI_NO_NUI_SAVE = "AI_NO_NUI_SAVE";
// Bitwise menu constants for Widget buttons that are used with Get/SetAssociateWidgetButtons().
const string sWidgetButtonsVarname = "ASSOCIATE_WIDGET_BUTTONS";
const int BTN_WIDGET_OFF = 0x00000001; // Removes the widget from the screen, For PC it removes all associates.
const int BTN_WIDGET_LOCK = 0x00000002; // Locks the widget to the current coordinates.
const int BTN_CMD_GUARD = 0x00000004; // Command associates to Guard Me. PC widget only.
const int BTN_CMD_FOLLOW = 0x00000008; // Command associates to Follow. PC widget only.
const int BTN_CMD_HOLD = 0x00000010; // Command associates to Stand Ground. PC widget only.
const int BTN_CMD_ATTACK = 0x00000020; // Command associates to Attack Nearest. PC widget only.
const int BTN_BUFF_REST = 0x00000040; // Buffs with long duration spells after resting. Associate widget only.
const int BTN_BUFF_SHORT = 0x00000080; // Buffs with short duration spells.
const int BTN_BUFF_LONG = 0x00000100; // Buffs with long duration spells.
const int BTN_BUFF_ALL = 0x00000200; // Buffs with all spells.
const int BTN_CMD_ACTION = 0x00000400; // Command associate to do an action.
const int BTN_CMD_GHOST_MODE = 0x00000800; // Toggle's associates ghost mode.
const int BTN_CMD_AI_SCRIPT = 0x00001000; // Toggle's special tactics ai scripts.
const int BTN_CMD_PLACE_TRAP = 0x00002000; // A trapper may place traps.
const int BTN_CMD_CAMERA = 0x00004000; // Places camera view on associate.
const int BTN_CMD_INVENTORY = 0x00008000; // Opens inventory of associate.
const int BTN_CMD_FAMILIAR = 0x00010000; // Summons familiar.
const int BTN_CMD_COMPANION = 0x00020000; // Summons Companion.
const int BTN_CMD_SEARCH = 0x00040000; // Command all associates to use search mode. PC widget only.
const int BTN_CMD_STEALTH = 0x00080000; // Command all associates to use stealth mode. PC widget only.
const int BTN_CMD_SCOUT = 0x00100000; // Command associate to scout ahead of the part.
const int BTN_CMD_SPELL_WIDGET = 0x00200000; // Allows adding or removing spells from Spell Widget.
const int BTN_CMD_JUMP_TO = 0x00400000; // Player can make associates jump to them.
const int BTN_WIDGET_VERTICAL = 0x80000000; // Widget will be displayed vertical.
const int BTN_WIDGET_OFF = 0x00000001; // Removes the widget from the screen, For PC it removes all associates.
const int BTN_WIDGET_LOCK = 0x00000002; // Locks the widget to the current coordinates.
const int BTN_CMD_GUARD = 0x00000004; // Command associates to Guard Me. PC widget only.
const int BTN_CMD_FOLLOW = 0x00000008; // Command associates to Follow. PC widget only.
const int BTN_CMD_HOLD = 0x00000010; // Command associates to Stand Ground. PC widget only.
const int BTN_CMD_ATTACK = 0x00000020; // Command associates to Attack Nearest. PC widget only.
const int BTN_BUFF_REST = 0x00000040; // Buffs with long duration spells after resting. Associate widget only.
const int BTN_BUFF_SHORT = 0x00000080; // Buffs with short duration spells.
const int BTN_BUFF_LONG = 0x00000100; // Buffs with long duration spells.
const int BTN_BUFF_ALL = 0x00000200; // Buffs with all spells.
const int BTN_CMD_ACTION = 0x00000400; // Command associate to do an action.
const int BTN_CMD_GHOST_MODE = 0x00000800; // Toggle's associates ghost mode.
const int BTN_CMD_AI_SCRIPT = 0x00001000; // Toggle's special tactics ai scripts.
const int BTN_CMD_PLACE_TRAP = 0x00002000; // A trapper may place traps.
const int BTN_CMD_CAMERA = 0x00004000; // Places camera view on associate.
const int BTN_CMD_INVENTORY = 0x00008000; // Opens inventory of associate.
const int BTN_CMD_FAMILIAR = 0x00010000; // Summons familiar.
const int BTN_CMD_COMPANION = 0x00020000; // Summons Companion.
const int BTN_CMD_SEARCH = 0x00040000; // Command all associates to use search mode. PC widget only.
const int BTN_CMD_STEALTH = 0x00080000; // Command all associates to use stealth mode. PC widget only.
const int BTN_CMD_SCOUT = 0x00100000; // Command associate to scout ahead of the part.
const int BTN_CMD_SPELL_WIDGET = 0x00200000; // Allows adding or removing spells from Spell Widget.
const int BTN_CMD_JUMP_TO = 0x00400000; // Player can make associates jump to them.
const int BTN_ASSOC_WIDGETS_OFF = 0x00800000; // Turns all associate widgets on/off.
const int BTN_WIDGET_VERTICAL = 0x80000000; // Widget will be displayed vertical.
// Bitwise menu constants for Associate AI buttons that are used with Get/SetAssociateAIButtons().
const string sAIButtonsVarname = "ASSOCIATE_AI_BUTTONS";
const int BTN_AI_FOR_PC = 0x00000001; // PC use AI. PC widget only.
@@ -521,6 +534,8 @@ const string AI_ASSOCIATE_PERCEPTION = "AI_PERCEPTION_RANGE";
const string AI_ASSOC_PERCEPTION_DISTANCE = "AI_ASSOC_PERCEPTION_DISTANCE";
// Variable that holds the open doors range of the henchman.
const string AI_OPEN_DOORS_RANGE = "AI_OPEN_DOORS_RANGE";
// Variable that holds the delay for casting buff spells.
const string AI_DELAY_BUFF_CASTING = "AI_DELAY_BUFF_CASTING";
// Variable that holds the Spell widgets json data.
const string AI_SPELLS_WIDGET = "AI_SPELLS_WIDGET";
// The number of Buff Groups
@@ -548,6 +563,8 @@ const string AI_PC_LOCKED_TARGET = "AI_PC_LOCKED_TARGET";
const string AI_TALENT_IMMUNITY = "AI_TALENT_IMMUNITY";
// Variables keeps track of the maximum level for the talent category.
const string AI_MAX_TALENT = "AI_MAX_TALENT_";
// Variables keeps track of the maximum level for the talent level.
const string AI_MAX_LEVEL = "AI_MAX_LEVEL_";
// Backward compatability constants.
const int X2_EVENT_CONCENTRATION_BROKEN = 12400;
// Variable set on the module if the module is using PRC.
@@ -568,6 +585,12 @@ const string AI_MODULE_GUI_EVENT = "AI_MODULE_GUI_EVENT";
const string AI_TARGET_MODE = "AI_TARGET_MODE";
// Variable used on the player to define which associate triggered the OnPlayer Target.
const string AI_TARGET_ASSOCIATE = "AI_TARGET_ASSOCIATE";
// Variable use on the player to define if the player is using target mode on an associate.
const string AI_TARGET_MODE_ON = "AI_TARGET_MODE_ON";
// Variable used on the player to define what associate has Target Mode set on it.
const string AI_TARGET_MODE_ASSOCIATE = "AI_TARGET_MODE_ASSOCIATE";
// Variable used on a creature to define how long ago their immunities were saved.
const string sIPTimeStampVarname = "AI_IP_TIMESTAMP";
// Bitwise constants for immune damage item properties that is used with Get/SetItemProperty().
const string sIPImmuneVarname = "AI_IP_IMMUNE";
// Bitwise constants for resisted damage item properties that is used with Get/SetItemProperty().
@@ -585,6 +608,8 @@ const string AI_RULE_DEBUG_CREATURE = "AI_RULE_DEBUG_CREATURE";
const string AI_RULE_MORAL_CHECKS = "AI_RULE_MORAL_CHECKS";
// Allows monsters to prebuff before combat starts.
const string AI_RULE_BUFF_MONSTERS = "AI_RULE_BUFF_MONSTERS";
// Allows monsters to prebuff with all defensive spells before combat starts.
const string AI_RULE_FULL_BUFF_MONSTERS = "AI_RULE_FULL_BUFF_MONSTERS";
// Allows monsters to use the ambush AI scripts.
const string AI_RULE_AMBUSH = "AI_RULE_AMBUSH";
// Enemies may summon familiars and Animal companions and will be randomized.

View File

@@ -12,7 +12,7 @@
*/////////////////////////////////////////////////////////////////////////////////////////////////////
#include "0i_constants"
#include "0i_nui"
void ai_SetupModuleGUIEvents(object oCreature)
void ai_SetupModuleGUIEvents()
{
object oModule = GetModule();
string sModuleGUIEvents = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_GUIEVENT);

View File

@@ -25,6 +25,8 @@ const string AI_DM_TABLE = "DM_TABLE";
// Sets PEPS RULES from the database to the module.
// Creates default rules if they do not exist.
void ai_SetAIRules();
// Returns TRUE if the module is being run as a server.
int ai_GetIsServer();
// Returns TRUE if oCreature is controlled by a player.
int ai_GetIsCharacter(object oCreature);
// Returns TRUE if oCreature is controlled by a dungeon master.
@@ -32,6 +34,9 @@ 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 top master of oAssociate, for example a henchmen summons a bat,
// this will return the henchman's player.
object ai_GetTopMaster(object oAssociate);
// Returns the percentage of hit points oCreature has left.
int ai_GetPercHPLoss(object oCreature);
// Returns a rolled result from sDice string.
@@ -129,6 +134,9 @@ void ai_SetAIRules()
// 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 to prebuff with all spells before combat starts.
SetLocalInt(oModule, AI_RULE_FULL_BUFF_MONSTERS, AI_FULL_BUFF);
jRules = JsonObjectSet(jRules, AI_RULE_FULL_BUFF_MONSTERS, JsonInt(AI_FULL_BUFF));
// Allows monsters cast summons spells when prebuffing.
SetLocalInt(oModule, AI_RULE_PRESUMMON, AI_PRESUMMONS);
jRules = JsonObjectSet(jRules, AI_RULE_PRESUMMON, JsonInt(AI_PRESUMMONS));
@@ -215,6 +223,9 @@ void ai_SetAIRules()
// Allows monsters to prebuff before combat starts.
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_BUFF_MONSTERS));
SetLocalInt(oModule, AI_RULE_BUFF_MONSTERS, bValue);
// Allows monsters to buff with all spells before combat starts.
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_FULL_BUFF_MONSTERS));
SetLocalInt(oModule, AI_RULE_FULL_BUFF_MONSTERS, bValue);
// Allows monsters cast summons spells when prebuffing.
bValue = JsonGetInt(JsonObjectGet(jRules, AI_RULE_PRESUMMON));
SetLocalInt(oModule, AI_RULE_PRESUMMON, bValue);
@@ -307,13 +318,17 @@ void ai_SetAIRules()
SetLocalInt(oModule, sDMAIAccessVarname, bValue);
}
}
int ai_GetIsServer()
{
return GetLocalInt(GetModule(), AI_IS_SERVER) || AI_SERVER;
}
int ai_GetIsCharacter(object oCreature)
{
return (GetIsPC(oCreature) && !GetIsDM(oCreature) && !GetIsDMPossessed(oCreature));
return (GetIsPC(oCreature) && !GetIsDM(oCreature) && !GetIsDMPossessed(oCreature) && !GetIsPlayerDM(oCreature));
}
int ai_GetIsDungeonMaster(object oCreature)
{
return (GetIsDM(oCreature) || GetIsDMPossessed(oCreature));
return (GetIsDM(oCreature) || GetIsDMPossessed(oCreature) || GetIsPlayerDM(oCreature));
}
object ai_GetPlayerMaster(object oAssociate)
{
@@ -322,6 +337,16 @@ object ai_GetPlayerMaster(object oAssociate)
if(ai_GetIsCharacter(oMaster)) return oMaster;
return OBJECT_INVALID;
}
object ai_GetTopMaster(object oAssociate)
{
object oMaster = GetMaster(oAssociate);
while(oMaster != OBJECT_INVALID)
{
if(GetMaster(oMaster) == OBJECT_INVALID) break;
oMaster = GetMaster(oMaster);
}
return oMaster;
}
int ai_GetPercHPLoss(object oCreature)
{
int nHP = GetCurrentHitPoints(oCreature);
@@ -862,12 +887,14 @@ void ai_SetupAIData(object oPlayer, object oAssociate, string sAssociateType)
// 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);
SetLocalFloat(oAssociate, AI_ASSOC_PERCEPTION_DISTANCE, 25.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.
jAIData = JsonArrayInsert(jAIData, JsonFloat(0.1)); // 11 - Delay for casting buff spells.
SetLocalFloat(oAssociate, AI_DELAY_BUFF_CASTING, 0.1);
ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData, AI_TABLE);
}
void ai_SetupLootFilters(object oPlayer, object oAssociate, string sAssociateType)
@@ -979,6 +1006,8 @@ void ai_RestoreDatabase(object oPlayer, object oAssociate, string sAssociateType
SetLocalJson(oPlayer, AI_SPELLS_WIDGET, jValue);
}
jAIData = JsonArrayInsert(jAIData, jValue);
fValue = GetLocalFloat(oAssociate, AI_DELAY_BUFF_CASTING);
jAIData = JsonArrayInsert(jAIData, JsonFloat(fValue));
ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData);
// ********** LootFilters **********
json jLootFilters = JsonArray();
@@ -1080,6 +1109,14 @@ void ai_CheckAssociateData(object oPlayer, object oAssociate, string sAssociateT
ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData);
SetLocalJson(oPlayer, AI_SPELLS_WIDGET, jSpellsWidget);
}
json jSpellDelay = JsonArrayGet(jAIData, 11);
if(JsonGetType(jSpellDelay) == JSON_TYPE_NULL)
{
jAIData = JsonArrayInsert(jAIData, JsonFloat(0.1));
ai_SetAssociateDbJson(oPlayer, sAssociateType, "aidata", jAIData);
SetLocalFloat(oAssociate, AI_DELAY_BUFF_CASTING, 0.1);
}
else SetLocalFloat(oAssociate, AI_DELAY_BUFF_CASTING, JsonGetFloat(jSpellDelay));
}
// ********** LootFilters **********
json jLootFilters = ai_GetAssociateDbJson(oPlayer, sAssociateType, "lootfilters");
@@ -1140,7 +1177,7 @@ void ai_SetupDMData(object oPlayer, string sName)
void ai_CheckDMData(object oPlayer)
{
//ai_Debug("0i_main", "898", "Checking data for DM: " + GetName(oPlayer));
string sName = ai_RemoveIllegalCharacters(GetName(oPlayer));
string sName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPlayer)));
// ********** Buttons **********
json jButtons = ai_GetCampaignDbJson("buttons", sName, AI_DM_TABLE);
// if there is no saved AImodes then set the defaults.
@@ -1241,7 +1278,7 @@ json ai_CheckOldPluginJson(object oPC)
json ai_UpdatePluginsForPC(object oPC)
{
// Check if the server is running or single player.
if(!AI_SERVER) return ai_CheckOldPluginJson(oPC);
if(!ai_GetIsServer()) return ai_CheckOldPluginJson(oPC);
int nJsonType, nCounter, nIndex, bWidget, bAllow;
string sScript, sName, sIcon;
json jServerPlugins = ai_GetCampaignDbJson("plugins");
@@ -1283,7 +1320,7 @@ json ai_UpdatePluginsForPC(object oPC)
json ai_UpdatePluginsForDM(object oPC)
{
int nJsonType, nCounter, nIndex, bWidget, bAllow;
string sName, sIcon, sDbName = ai_RemoveIllegalCharacters(GetName(oPC));
string sName, sIcon, sDbName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPC)));
json jServerPlugins = ai_GetCampaignDbJson("plugins");
ai_CheckDMDataAndInitialize(oPC);
json jDMPlugin, jDMPlugins = ai_GetCampaignDbJson("plugins", sDbName, AI_DM_TABLE);
@@ -1323,7 +1360,7 @@ void ai_StartupPlugins(object oPC)
int bUpdatePlugins;
string sScript;
json jPlugins;
if(GetIsDM(oPC)) jPlugins = ai_UpdatePluginsForDM(oPC);
if(ai_GetIsDungeonMaster(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);

File diff suppressed because it is too large Load Diff

View File

@@ -268,7 +268,7 @@ void ai_CreateDMOptionsNUI(object oPC)
int nMonsterAI = (ResManGetAliasFor("ai_default", RESTYPE_NCS) != "");
int nAssociateAI = (ResManGetAliasFor("ai_a_default", RESTYPE_NCS) != "");
string sText = " [Single player]";
if(AI_SERVER) sText = " [Server]";
if(ai_GetIsServer()) sText = " [Server]";
// ************************************************************************* Width / Height
// Row 1 ******************************************************************* 500 / 73
json jRow = JsonArrayInsert(JsonArray(), NuiSpacer());
@@ -282,6 +282,8 @@ void ai_CreateDMOptionsNUI(object oPC)
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
// Row 3 ******************************************************************* 500 / 129
jRow = CreateButton(JsonArray(), "Plugin Manager", "btn_plugin_manager", 160.0f, 20.0f, -1.0, "btn_plugin_manager_tooltip");
//jRow = JsonArrayInsert(jRow, NuiSpacer());
//jRow = CreateButtonSelect(jRow, "Effect Icons", "btn_effect_icon", 160.0f, 20.0f, "btn_effect_icon_tooltip");
jRow = JsonArrayInsert(jRow, NuiSpacer());
jRow = CreateButton(jRow, "Widget Manager", "btn_widget_manager", 160.0f, 20.0f, -1.0, "btn_widget_manager_tooltip");
// Add row to the column.
@@ -331,7 +333,8 @@ void ai_CreateDMOptionsNUI(object oPC)
jGroupRow = CreateTextEditBox(JsonArray(), "sPlaceHolder", "txt_perception_distance", 2, FALSE, 35.0f, 20.0f, "txt_perception_distance_tooltip");
jGroupRow = CreateLabel(jGroupRow, "meters is the distance a monster can respond to allies.", "lbl_perception_distance", 411.0f, 20.0f, NUI_HALIGN_LEFT, 0, 0.0, "txt_perception_distance_tooltip");
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
jGroupRow = CreateCheckBox(JsonArray(), " Monsters can prebuff before combat starts.", "chbx_buff_monsters", 450.0, 20.0);
jGroupRow = CreateCheckBox(JsonArray(), " Monsters buff before combat starts.", "chbx_buff_monsters", 275.0, 20.0, "chbx_buff_monsters_tooltip");
jGroupRow = CreateCheckBox(jGroupRow, " Use all buff spells instead!", "chbx_full_buff", 210.0, 20.0, "chbx_full_buff_tooltip");
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
jGroupRow = CreateCheckBox(JsonArray(), " Monsters can use summons before combat starts.", "chbx_buff_summons", 450.0, 20.0);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
@@ -423,6 +426,10 @@ void ai_CreateDMOptionsNUI(object oPC)
// Row 3
NuiSetBind(oPC, nToken, "btn_plugin_manager_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_plugin_manager_tooltip", JsonString(" Manages external executable scripts."));
int bEffectIcon = ai_GetMagicMode(oPC, AI_MAGIC_EFFECT_ICON_REPORT);
//NuiSetBind(oPC, nToken, "btn_effect_icon", JsonBool (bEffectIcon));
//NuiSetBind(oPC, nToken, "btn_effect_icon_event", JsonBool(TRUE));
//NuiSetBind(oPC, nToken, "btn_effect_icon_tooltip", JsonString(" When on sends effect icon reports to the chat screen."));
NuiSetBind(oPC, nToken, "btn_widget_manager_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_widget_manager_tooltip", JsonString(" Manages widgets the players have access to."));
// Row 3 Label for AI RULES
@@ -448,9 +455,15 @@ void ai_CreateDMOptionsNUI(object oPC)
NuiSetBind(oPC, nToken, "txt_ai_difficulty_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_ai_difficulty", JsonString(IntToString(GetLocalInt(oModule, AI_RULE_AI_DIFFICULTY))));
NuiSetBindWatch(oPC, nToken, "txt_ai_difficulty", TRUE);
NuiSetBind(oPC, nToken, "chbx_buff_monsters_check", JsonBool(GetLocalInt(oModule, AI_RULE_BUFF_MONSTERS)));
int bMonsterBuff = GetLocalInt(oModule, AI_RULE_BUFF_MONSTERS);
NuiSetBind(oPC, nToken, "chbx_buff_monsters_check", JsonBool(bMonsterBuff));
NuiSetBindWatch(oPC, nToken, "chbx_buff_monsters_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_buff_monsters_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "chbx_buff_monsters_tooltip", JsonString(" Monsters will cast all longer duration buff spells just before combat starts."));
NuiSetBind(oPC, nToken, "chbx_full_buff_check", JsonBool(GetLocalInt(oModule, AI_RULE_FULL_BUFF_MONSTERS)));
NuiSetBindWatch(oPC, nToken, "chbx_full_buff_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_full_buff_event", JsonBool(bMonsterBuff));
NuiSetBind(oPC, nToken, "chbx_full_buff_tooltip", JsonString(" Monsters will cast all buff spells just before combat starts! VERY DIFFICULTY!"));
NuiSetBind(oPC, nToken, "chbx_buff_summons_check", JsonBool(GetLocalInt(oModule, AI_RULE_PRESUMMON)));
NuiSetBindWatch(oPC, nToken, "chbx_buff_summons_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_buff_summons_event", JsonBool(TRUE));
@@ -876,6 +889,9 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
jRow = CreateLabel(JsonArray(), "Having a check next to a button will remove that button from the players menus.", "lbl_info2", 636.0, 15.0);
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
// Row 4 ******************************************************************* 575 / 162
jRow = CreateButtonImage(jRow, "ir_invite", "btn_toggle_assoc_widget", 35.0f, 35.0f, 0.0, "btn_toggle_assoc_widget_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_toggle_assoc_widget", 25.0, 20.0, "btn_toggle_assoc_widget_tooltip");
jRow = CreateButtonImage(JsonArray(), "ir_action", "btn_cmd_action", 35.0f, 35.0f, 0.0, "btn_cmd_action_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_cmd_action", 25.0, 20.0, "btn_cmd_action_tooltip");
@@ -903,10 +919,11 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
jRow = CreateButtonImage(jRow, "ir_scommand", "btn_cmd_ai_script", 35.0f, 35.0f, 0.0, "btn_cmd_ai_script_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_cmd_ai_script", 25.0, 20.0, "btn_cmd_ai_script_tooltip");
jRow = CreateButtonImage(jRow, "isk_settrap", "btn_cmd_place_trap", 35.0f, 35.0f, 0.0, "btn_cmd_place_trap_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_cmd_place_trap", 25.0, 20.0, "btn_cmd_place_trap_tooltip");
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
// Row 5 ******************************************************************* 575 / 205
jRow = CreateButtonImage(jRow, "isk_settrap", "btn_cmd_place_trap", 35.0f, 35.0f, 0.0, "btn_cmd_place_trap_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_cmd_place_trap", 25.0, 20.0, "btn_cmd_place_trap_tooltip");
jRow = CreateButtonImage(JsonArray(), "isk_spellcraft", "btn_quick_widget", 35.0f, 35.0f, 0.0, "btn_quick_widget_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_quick_widget", 25.0, 20.0, "btn_quick_widget_tooltip");
@@ -934,10 +951,10 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
jRow = CreateButtonImage(jRow, "ir_examine", "btn_camera", 35.0f, 35.0f, 0.0, "btn_camera_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_camera", 25.0, 20.0, "btn_camera_tooltip");
jRow = CreateButtonImage(jRow, "ir_pickup", "btn_inventory", 35.0f, 35.0f, 0.0, "btn_inventory_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_inventory", 25.0, 20.0, "btn_inventory_tooltip");
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
// Row 6 ******************************************************************* 575 / 248
jRow = CreateButtonImage(jRow, "ir_pickup", "btn_inventory", 35.0f, 35.0f, 0.0, "btn_inventory_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_inventory", 25.0, 20.0, "btn_inventory_tooltip");
jRow = CreateButtonImage(JsonArray(), "ife_familiar", "btn_familiar", 35.0f, 35.0f, 0.0, "btn_familiar_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_familiar", 25.0, 20.0, "btn_familiar_tooltip");
@@ -966,10 +983,10 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
jRow = CreateButtonImage(jRow, "ir_open", "btn_open_door", 35.0f, 35.0f, 0.0, "btn_open_door_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_open_door", 25.0, 20.0, "btn_open_door_tooltip");
jRow = CreateButtonImage(jRow, "isk_distrap", "btn_traps", 35.0f, 35.0f, 0.0, "btn_traps_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_traps", 25.0, 20.0, "btn_traps_tooltip");
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
// Row 7 ******************************************************************* 575 / 291
jRow = CreateButtonImage(jRow, "isk_distrap", "btn_traps", 35.0f, 35.0f, 0.0, "btn_traps_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_traps", 25.0, 20.0, "btn_traps_tooltip");
jRow = CreateButtonImage(JsonArray(), "isk_olock", "btn_pick_locks", 35.0f, 35.0f, 0.0, "btn_pick_locks_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_pick_locks", 25.0, 20.0, "btn_pick_locks_tooltip");
@@ -998,10 +1015,11 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
jRow = CreateButtonImage(jRow, "isk_heal", "btn_heal_out", 35.0f, 35.0f, 0.0, "btn_heal_out_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_heal_out", 25.0, 20.0, "btn_heal_out_tooltip");
jRow = CreateButtonImage(jRow, "dm_heal", "btn_heal_in", 35.0f, 35.0f, 0.0, "btn_heal_in_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_heal_in", 25.0, 20.0, "btn_heal_in_tooltip");
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
// Row 8 ******************************************************************* 575 / 334
jRow = CreateButtonImage(jRow, "dm_heal", "btn_heal_in", 35.0f, 35.0f, 0.0, "btn_heal_in_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_heal_in", 25.0, 20.0, "btn_heal_in_tooltip");
jRow = CreateButtonImage(JsonArray(), "ir_heal", "btn_heals_onoff", 35.0f, 35.0f, 0.0, "btn_heals_onoff_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_heals_onoff", 25.0, 20.0, "btn_heals_onoff_tooltip");
@@ -1023,7 +1041,6 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
jRow = CreateButtonImage(jRow, "ir_dmchat", "btn_perc_range", 35.0f, 35.0f, 0.0, "btn_perc_range_tooltip");
jRow = CreateCheckBox(jRow, "", "chbx_perc_range", 25.0, 20.0, "btn_perc_range_tooltip");
// Add row to the column.
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
float fHeight = 334.0;
// Get the window location to restore it from the database.
@@ -1049,6 +1066,7 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
// Row 2 & 3 Labels.
// Load all the buttons states.
//int bAIWidgetLock = ai_GetDMWAccessButton(BTN_WIDGET_LOCK);
int bAssocWidgetOff = ai_GetDMWAccessButton(BTN_ASSOC_WIDGETS_OFF);
int bCmdAction = ai_GetDMWAccessButton(BTN_CMD_ACTION);
int bCmdGuard = ai_GetDMWAccessButton(BTN_CMD_GUARD);
int bCmdHold = ai_GetDMWAccessButton(BTN_CMD_HOLD);
@@ -1101,6 +1119,12 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
SetLocalInt(oPC, "CHBX_SKIP", TRUE);
DelayCommand(2.0, DeleteLocalInt(oPC, "CHBX_SKIP"));
// Row 4
NuiSetBind(oPC, nToken, "chbx_toggle_assoc_widget_check", JsonBool (bCmdAction));
NuiSetBindWatch(oPC, nToken, "chbx_toggle_assoc_widget_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_toggle_assoc_widget_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_toggle_assoc_widget_event", JsonBool (TRUE));
NuiSetBind(oPC, nToken, "btn_toggle_assoc_widget_tooltip", JsonString(" Associate widgets"));
NuiSetBind(oPC, nToken, "chbx_cmd_action_check", JsonBool (bCmdAction));
NuiSetBindWatch(oPC, nToken, "chbx_cmd_action_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_cmd_action_event", JsonBool(TRUE));
@@ -1154,13 +1178,13 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
NuiSetBind(oPC, nToken, "chbx_cmd_ai_script_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_cmd_ai_script_event", JsonBool (TRUE));
NuiSetBind(oPC, nToken, "btn_cmd_ai_script_tooltip", JsonString(" Combat Tactics button"));
// Row 5
NuiSetBind(oPC, nToken, "chbx_cmd_place_trap_check", JsonBool (bCmdPlacetrap));
NuiSetBindWatch (oPC, nToken, "chbx_cmd_place_trap_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_cmd_place_trap_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_cmd_place_trap_event", JsonBool (TRUE));
NuiSetBind(oPC, nToken, "btn_cmd_place_trap_tooltip", JsonString (" Place Trap button"));
// Row 5
NuiSetBind(oPC, nToken, "chbx_quick_widget_check", JsonBool (bSpellWidget));
NuiSetBindWatch (oPC, nToken, "chbx_quick_widget_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_quick_widget_event", JsonBool(TRUE));
@@ -1214,13 +1238,13 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
NuiSetBind(oPC, nToken, "chbx_camera_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_camera_event", JsonBool (TRUE));
NuiSetBind(oPC, nToken, "btn_camera_tooltip", JsonString(" Change Camera button"));
// Row 6
NuiSetBind(oPC, nToken, "chbx_inventory_check", JsonBool (bInventory));
NuiSetBindWatch (oPC, nToken, "chbx_inventory_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_inventory_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_inventory_event", JsonBool (TRUE));
NuiSetBind(oPC, nToken, "btn_inventory_tooltip", JsonString(" Open Inventory button"));
// Row 6
NuiSetBind(oPC, nToken, "chbx_familiar_check", JsonBool(bBtnFamiliar));
NuiSetBindWatch (oPC, nToken, "chbx_familiar_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_familiar_event", JsonBool(TRUE));
@@ -1274,13 +1298,13 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
NuiSetBind(oPC, nToken, "chbx_open_door_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_open_door_event", JsonBool(TRUE));
NuiSetBind (oPC, nToken, "btn_open_door_tooltip", JsonString(" Open Door button"));
// Row 7
NuiSetBind(oPC, nToken, "chbx_traps_check", JsonBool(bTraps));
NuiSetBindWatch (oPC, nToken, "chbx_traps_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_traps_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_traps_event", JsonBool(TRUE));
NuiSetBind (oPC, nToken, "btn_traps_tooltip", JsonString(" Disable Traps button"));
// Row 7
NuiSetBind(oPC, nToken, "chbx_pick_locks_check", JsonBool(bPickLocks));
NuiSetBindWatch(oPC, nToken, "chbx_pick_locks_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_pick_locks_event", JsonBool(TRUE));
@@ -1334,13 +1358,13 @@ void ai_CreateDMWidgetManagerNUI(object oPC)
NuiSetBind(oPC, nToken, "chbx_heal_out_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_heal_out_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_heal_out_tooltip", JsonString(" Heal Out of Combat button"));
// Row 8
NuiSetBind(oPC, nToken, "chbx_heal_in_check", JsonBool(bHealIn));
NuiSetBindWatch (oPC, nToken, "chbx_heal_in_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_heal_in_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_heal_in_event", JsonBool (TRUE));
NuiSetBind(oPC, nToken, "btn_heal_in_tooltip", JsonString(" Heal In Combat button"));
// Row 8
NuiSetBind(oPC, nToken, "chbx_heals_onoff_check", JsonBool(bSelfHealOnOff));
NuiSetBindWatch (oPC, nToken, "chbx_heals_onoff_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_heals_onoff_event", JsonBool(TRUE));

View File

@@ -7,15 +7,18 @@
#include "x2_inc_switches"
#include "0i_associates"
#include "0i_menus"
#include "0i_menus_dm"
#include "0i_player_target"
#include "0i_gui_events"
// Add to nw_c2_default9 OnSpawn event script of monsters and
int ai_OnMonsterSpawn(object oCreature);
// Add to nw_ch_ac9 OnSpawn event script of henchman.
void ai_OnAssociateSpawn(object oCreature);
// Run all of the players starting scripts.
// Run all of the game setup scripts and build for PC.
// If oPC is passed as Invalid then it will get the firt PC in the game.
void ai_CheckPCStart(object oPC = OBJECT_INVALID);
// Run all of the games setup scripts and build for DM.
void ai_CheckDMStart(object oDM);
// Checks to see if we should change the monster via Json.
int ai_ChangeMonster(object oCreature, object oModule);
// Checks to see if we should change the associate via Json.
@@ -45,7 +48,7 @@ int ai_OnMonsterSpawn(object oCreature)
int nInfiniteDungeons;
int nPRC = GetLocalInt(oModule, AI_USING_PRC);
// If you are running a server this will not affect the module.
if(!AI_SERVER)
if(!ai_GetIsServer())
{
ai_CheckPCStart();
string sModuleName = GetModuleName();
@@ -107,7 +110,7 @@ void ai_OnAssociateSpawn(object oCreature)
SetLocalInt(oCreature, AI_ONSPAWN_EVENT, TRUE);
int bPRC = GetLocalInt(GetModule(), AI_USING_PRC);
// If you are running a server this will not affect the module.
if(!AI_SERVER)
if(!ai_GetIsServer())
{
if(bPRC) ai_SetPRCAssociateEventScripts(oCreature);
}
@@ -117,8 +120,17 @@ void ai_OnAssociateSpawn(object oCreature)
// We change this script so we can setup permanent summons on/off.
// If you don't use this you may remove the next three lines.
string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH);
SetLocalString(oCreature, "AI_ON_DEATH", sScript);
SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH, "0e_ch_7_ondeath");
// If our script is set in the OnDeath event then don't save as secondary.
if(sScript != "0e_ch_7_ondeath")
{
SetLocalString(oCreature, "AI_ON_DEATH", sScript);
SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_DEATH, "0e_ch_7_ondeath");
}
else if(GetLocalString(oCreature, "AI_ON_DEATH") == "0e_ch_7_ondeath")
{
// If we have somehow saved our death script then change to default.
SetLocalString(oCreature, "AI_ON_DEATH", "nw_ch_ac7");
}
}
// Initialize Associate modes for basic use.
ai_SetListeningPatterns(oCreature);
@@ -147,12 +159,28 @@ void ai_CheckPCStart(object oPC = OBJECT_INVALID)
ai_SetAIRules();
ai_CheckAssociateData(oPC, oPC, "pc");
ai_StartupPlugins(oPC);
ai_SetupPlayerTarget(oPC);
ai_SetupModuleGUIEvents(oPC);
ai_SetupPlayerTarget();
ai_SetupModuleGUIEvents();
ai_CreateWidgetNUI(oPC, oPC);
ai_SetNormalAppearance(oPC);
}
}
void ai_CheckDMStart(object oDM)
{
if(!NuiFindWindow(oDM, "dm" + AI_WIDGET_NUI))
{
object oModule = GetModule();
// Do PRC check and save variable to the module.
if(ResManGetAliasFor("prc_ai_fam_percp", RESTYPE_NCS) != "")
SetLocalInt(oModule, AI_USING_PRC, TRUE);
ai_SetAIRules();
ai_CheckDMData(oDM);
ai_StartupPlugins(oDM);
ai_SetupPlayerTarget();
ai_SetupModuleGUIEvents();
ai_CreateDMWidgetNUI(oDM);
}
}
void ai_CopyMonster(object oCreature, object oModule)
{
// After setting the monster lets see if we should copy it.
@@ -179,6 +207,7 @@ void ai_CreateMonster(json jCreature, location lLocation, object oModule)
{
//WriteTimestampedLogEntry("0i_module, 181, " + JsonDump(jCreature, 1));
object oCreature = JsonToObject(jCreature, lLocation, OBJECT_INVALID, TRUE);
if(AI_DEBUG) ai_Debug("0i_module", "210", "Creating: " + GetName(oCreature));
// Lets set the new version as spawned so we skip the initial setup again.
SetLocalInt(oCreature, AI_ONSPAWN_EVENT, TRUE);
/*if(GetLocalInt(oModule, AI_RULE_CORPSES_STAY))
@@ -188,6 +217,12 @@ void ai_CreateMonster(json jCreature, location lLocation, object oModule)
} */
if(AI_DEBUG) ai_Debug("0i_module", "187", GetName(oCreature));
ai_CopyMonster(oCreature, oModule);
// This is a hak to allow wild shaped creatures to be able to attack!
if(GetHasFeat(FEAT_WILD_SHAPE, oCreature))
{
AssignCommand(oCreature, ActionUseFeat(FEAT_WILD_SHAPE, oCreature, SUBFEAT_WILD_SHAPE_BADGER));
DelayCommand(4.0, ai_RemoveASpecificEffect(oCreature, EFFECT_TYPE_POLYMORPH));
}
return;
}
json ai_SetCompanionSummoning(object oCreature, json jCreature)
@@ -198,7 +233,7 @@ json ai_SetCompanionSummoning(object oCreature, json jCreature)
jFamiliar = JsonObjectSet(jFamiliar, "value", JsonString("Summoned Familiar"));
jCreature = JsonObjectSet(jCreature, "FamiliarName", jFamiliar);
jFamiliar = JsonObjectGet(jCreature, "FamiliarType");
jFamiliar = JsonObjectSet(jFamiliar, "value", JsonInt(Random(11)));
jFamiliar = JsonObjectSet(jFamiliar, "value", JsonInt(10)); //JsonInt(Random(11)));
return JsonObjectSet(jCreature, "FamiliarType", jFamiliar);
}
if(GetHasFeat(FEAT_ANIMAL_COMPANION , oCreature, TRUE))
@@ -217,9 +252,9 @@ int ai_ChangeMonster(object oCreature, object oModule)
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, oCreature);
// Lets not mess up the cutscenes with silly RULES.
if(GetCutsceneMode(oPC)) return FALSE;
//float fDistance = GetDistanceBetween(oCreature, oPC);
float fDistance = GetDistanceBetween(oCreature, oPC);
// Looks bad to see creatures wink in and out plus could cause module errors.
//if(fDistance != 0.0 && fDistance < AI_RANGE_PERCEPTION) return oCreature;
if(fDistance != 0.0 && fDistance < 20.0) return FALSE;
if(IsInConversation(oCreature)) return FALSE;
json jCreature = ObjectToJson(oCreature, TRUE);
// We now use plugins to mod our monsters.
@@ -238,8 +273,8 @@ int ai_ChangeMonster(object oCreature, object oModule)
jCreature = GetLocalJson(oModule, AI_MONSTER_JSON);
}
int nSummon = GetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS) &&
(GetHasFeat(FEAT_SUMMON_FAMILIAR, oCreature, TRUE)) ||
GetHasFeat(FEAT_ANIMAL_COMPANION, oCreature, TRUE);
(GetHasFeat(FEAT_SUMMON_FAMILIAR, oCreature, TRUE) ||
GetHasFeat(FEAT_ANIMAL_COMPANION, oCreature, TRUE));
int nPercDist = GetLocalInt(oModule, AI_RULE_MON_PERC_DISTANCE) != 11 &&
GetReputation(oCreature, oPC) < 11;
//WriteTimestampedLogEntry(GetName(oCreature) + ": fDistance: " + FloatToString(fDistance, 0, 2) + " nSummon: " + IntToString(nSummon) +
@@ -256,10 +291,12 @@ int ai_ChangeMonster(object oCreature, object oModule)
if(nSummon) jCreature = ai_SetCompanionSummoning(oCreature, jCreature);
SetLocalInt(oModule, AI_MONSTER_CHANGED, TRUE);
}
// Did any of the Monster mods get used? These are done in independent mod scripts.
if(GetLocalInt(oModule, AI_MONSTER_CHANGED))
{
SetIsDestroyable(TRUE, FALSE, FALSE, oCreature);
location lLocation = GetLocation(oCreature);
if(AI_DEBUG) ai_Debug("0i_module", "299", "Destroying: " + GetName(oCreature));
DestroyObject(oCreature);
AssignCommand(oModule, DelayCommand(1.0, ai_CreateMonster(jCreature, lLocation, oModule)));
DeleteLocalInt(oModule, AI_MONSTER_CHANGED);
@@ -268,11 +305,18 @@ int ai_ChangeMonster(object oCreature, object oModule)
else ai_CopyMonster(oCreature, oModule);
DeleteLocalJson(oModule, AI_MONSTER_JSON);
DeleteLocalObject(oModule, AI_MONSTER_OBJECT);
// This is a hak to allow wild shaped creatures to be able to attack!
if(GetHasFeat(FEAT_WILD_SHAPE))
{
AssignCommand(oCreature, ActionUseFeat(FEAT_WILD_SHAPE, oCreature, SUBFEAT_WILD_SHAPE_BADGER));
DelayCommand(4.0, ai_RemoveASpecificEffect(oCreature, EFFECT_TYPE_POLYMORPH));
}
return FALSE;
}
// Special event scripts for Infinite Dungeons!
void ai_SetIDMonsterEventScripts(object oCreature)
{
if(GetIsPC(oCreature)) return;
//if(AI_DEBUG) ai_Debug("0i_module", "433", "Changing " + GetName(oCreature) + "'s Infinte Dungeons event scripts.");
//********** On Heartbeat **********
string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT);
@@ -355,6 +399,7 @@ void ai_SetIDMonsterEventScripts(object oCreature)
// Special event scripts for Infinite Dungeons with PRC!
void ai_SetPRCIDMonsterEventScripts(object oCreature)
{
if(GetIsPC(oCreature)) return;
//if(AI_DEBUG) ai_Debug("0i_module", "433", "Changing " + GetName(oCreature) + "'s Infinte Dungeons event scripts for PRC.");
//********** On Heartbeat **********
string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT);
@@ -437,6 +482,7 @@ void ai_SetPRCIDMonsterEventScripts(object oCreature)
// Special event scripts for PRC associates!
void ai_SetPRCAssociateEventScripts(object oCreature)
{
if(GetIsPC(oCreature)) return;
//if(AI_DEBUG) ai_Debug("0i_module", "433", "Changing " + GetName(oCreature) + "'s Infinte Dungeons event scripts for PRC.");
//********** On Heartbeat **********
string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT);
@@ -494,6 +540,7 @@ void ai_SetPRCAssociateEventScripts(object oCreature)
}
void ai_ChangeEventScriptsForMonster(object oCreature)
{
if(GetIsPC(oCreature)) return;
//********** On Heartbeat **********
string sScript = GetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT);
if(sScript == "0e_c2_1_hb") SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "nw_c2_default1");
@@ -528,6 +575,7 @@ void ai_ChangeEventScriptsForMonster(object oCreature)
}
void ai_ChangeEventScriptsForAssociate(object oCreature)
{
if(GetIsPC(oCreature)) return;
SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT, "nw_ch_ac1");
SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_NOTICE, "nw_ch_ac2");
SetEventScript(oCreature, EVENT_SCRIPT_CREATURE_ON_END_COMBATROUND, "nw_ch_ac3");

View File

@@ -8,11 +8,9 @@
#include "0i_menus"
// Setup an AI OnPlayerTarget Event script while allowing any module onplayer
// target event script to still work.
void ai_SetupPlayerTarget(object oCreature);
void ai_SetupPlayerTarget();
// Selects a target for oAssocite to follow.
void ai_AllSelectTarget(object oPC, object oAssociate, object oTarget);
// Removes the Cutscene ghosts and variables from all associates. For original AI scripts.
void ai_OriginalRemoveAllActionMode(object oPC);
// Removes the Cutscene ghosts and Command mode from all associates.
void ai_RemoveAllActionMode(object oPC);
// Once a trap has been selected from the associates inventory move to placing the trap.
@@ -30,7 +28,14 @@ void ai_UpdateAssociateWidget(object oPC, object oAssociate);
// Sets oAssociates action mode for nFeat from the quick widget menu
int ai_SetActionMode(object oAssociate, int nFeat);
void ai_SetupPlayerTarget(object oCreature)
void ai_EnterAssociateTargetMode(object oPC, object oAssociate)
{
SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate);
SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_ACTION");
SetLocalInt(oPC, AI_TARGET_MODE_ON, TRUE);
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
}
void ai_SetupPlayerTarget()
{
object oModule = GetModule();
string sModuleTargetEvent = GetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_TARGET);
@@ -40,129 +45,7 @@ void ai_SetupPlayerTarget(object oCreature)
}
SetEventScript(oModule, EVENT_SCRIPT_MODULE_ON_PLAYER_TARGET, "0e_player_target");
}
void ai_OriginalActionAssociate(object oPC, object oTarget, location lLocation)
{
object oAssociate = OBJECT_SELF;
if(!GetLocalInt(oAssociate, sGhostModeVarname) && GetLocalInt(oPC, sGhostModeVarname))
{
effect eGhost = EffectCutsceneGhost();
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, oAssociate);
SetLocalInt(oAssociate, sGhostModeVarname, TRUE);
}
int nObjectType = GetObjectType(oTarget);
ai_ClearCreatureActions(TRUE);
if(oTarget == GetArea(oPC))
{
ActionMoveToLocation(lLocation, TRUE);
if(GetLocalObject(oPC, AI_FOLLOW_TARGET) == oAssociate)
{
float fFollowDistance = 3.0;
AssignCommand(oPC, ai_ClearCreatureActions());
AssignCommand(oPC, ActionForceFollowObject(oAssociate, fFollowDistance));
}
}
else if(nObjectType == OBJECT_TYPE_CREATURE)
{
if(oTarget != GetLocalObject(oPC, AI_TARGET_ASSOCIATE))
{
if(GetMaster(oTarget) == oPC)
{
SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_ACTION");
SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oTarget);
ai_SendMessages(GetName(oTarget) + " is now in Action Mode.", AI_COLOR_YELLOW, oPC);
}
else ActionMoveToObject(oTarget, TRUE);
}
}
else if(nObjectType == OBJECT_TYPE_DOOR)
{
if(GetIsTrapped(oTarget) && GetAssociateState(NW_ASC_DISARM_TRAPS, oAssociate))
{
if(GetTrapDetectedBy(oTarget, oPC)) SetTrapDetectedBy(oTarget, oAssociate);
if(GetTrapDetectedBy(oTarget, oAssociate))
{
bkAttemptToDisarmTrap(oTarget);
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
return;
}
}
if(GetLocked(oTarget)) bkAttemptToOpenLock(oTarget);
if(GetIsOpen(oTarget))
{
ActionCloseDoor(oTarget, TRUE);
}
else ActionOpenDoor(oTarget, TRUE);
}
else if(nObjectType == OBJECT_TYPE_ITEM)
{
ActionPickUpItem(oTarget);
}
else if(nObjectType == OBJECT_TYPE_PLACEABLE)
{
ActionMoveToObject(oTarget, TRUE);
if(GetHasInventory(oTarget))
{
if(GetIsTrapped(oTarget) && GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS, oAssociate))
{
if(GetTrapDetectedBy(oTarget, oPC)) SetTrapDetectedBy(oTarget, oAssociate);
if(GetTrapDetectedBy(oTarget, oAssociate))
{
bkAttemptToDisarmTrap(oTarget);
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
return;
}
if(GetLocked(oTarget))
{
if(GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS, oAssociate))
{
bkAttemptToOpenLock(oTarget);
}
else AssignCommand(oAssociate, ai_HaveCreatureSpeak(oAssociate, 0, "This " + GetName(oTarget) + " is locked!"));
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
return;
}
DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE);
}
else if(GetLocked(oTarget))
{
if(GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS, oAssociate))
{
bkAttemptToOpenLock(oTarget);
}
else AssignCommand(oAssociate, ai_HaveCreatureSpeak(oAssociate, 0, "This " + GetName(oTarget) + " is locked!"));
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
return;
}
DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE);
}
DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE);
}
else if(nObjectType == OBJECT_TYPE_TRIGGER)
{
if(GetIsTrapped(oTarget) && GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS, oAssociate))
{
if(GetTrapDetectedBy(oTarget, oPC)) SetTrapDetectedBy(oTarget, oAssociate);
if(GetTrapDetectedBy(oTarget, oAssociate)) bkAttemptToDisarmTrap(oTarget);
}
}
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
}
void ai_OriginalActionAllAssociates(object oPC, object oTarget, location lLocation)
{
object oAssociate;
int nIndex;
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_OriginalActionAssociate(oPC, oTarget, lLocation));
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_OriginalActionAssociate(oPC, oTarget, lLocation));
}
}
void ai_ActionAssociate(object oPC, object oTarget, location lLocation)
void ai_ActionAssociate(object oPC, object oTarget, location lLocation, int bActionAll = FALSE)
{
object oAssociate = OBJECT_SELF;
if(ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST) &&
@@ -204,12 +87,14 @@ void ai_ActionAssociate(object oPC, object oTarget, location lLocation)
{
SetLocalString(oAssociate, AI_COMBAT_SCRIPT, GetLocalString(oAssociate, AI_DEFAULT_SCRIPT));
}
if(ai_GetIsInCombat(oAssociate)) ai_DoAssociateCombatRound(oAssociate, oTarget);
else
{
ai_HaveCreatureSpeak(oAssociate, 5, ":0:1:2:3:6:");
ai_StartAssociateCombat(oAssociate, oTarget);
}
//if(ai_GetIsInCombat(oAssociate)) ai_DoAssociateCombatRound(oAssociate, oTarget);
//else
//{
// ai_HaveCreatureSpeak(oAssociate, 5, ":0:1:2:3:6:");
// ai_StartAssociateCombat(oAssociate, oTarget);
//}
if(ai_GetIsRangeWeapon(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oAssociate))) ActionAttack(oTarget, TRUE);
else ActionAttack(oTarget);
ai_SendMessages(GetName(oAssociate) + " is attacking " + GetName(oTarget), AI_COLOR_RED, oPC);
}
else
@@ -231,7 +116,7 @@ void ai_ActionAssociate(object oPC, object oTarget, location lLocation)
if(ai_ReactToTrap(oAssociate, oTarget, TRUE)) bStopAction = TRUE;
if(bStopAction)
{
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
ai_EnterAssociateTargetMode(oPC, oAssociate);
return;
}
}
@@ -256,7 +141,7 @@ void ai_ActionAssociate(object oPC, object oTarget, location lLocation)
{
if(ai_ReactToTrap(oAssociate, oTarget, TRUE))
{
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
ai_EnterAssociateTargetMode(oPC, oAssociate);
return;
}
@@ -289,7 +174,7 @@ void ai_ActionAssociate(object oPC, object oTarget, location lLocation)
if(GetTrapDetectedBy(oTarget, oAssociate)) ai_ReactToTrap(oAssociate, oTarget, TRUE);
}
}
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
if(!bActionAll) ai_EnterAssociateTargetMode(oPC, oAssociate);
}
void ai_ActionAllAssociates(object oPC, object oTarget, location lLocation)
{
@@ -298,12 +183,12 @@ void ai_ActionAllAssociates(object oPC, object oTarget, location lLocation)
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_ActionAssociate(oPC, oTarget, lLocation));
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_ActionAssociate(oPC, oTarget, lLocation, TRUE));
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_ActionAssociate(oPC, oTarget, lLocation));
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_ActionAssociate(oPC, oTarget, lLocation, TRUE));
}
}
void ai_SelectFollowTarget(object oPC, object oAssociate, object oTarget)
@@ -317,6 +202,7 @@ void ai_SelectFollowTarget(object oPC, object oAssociate, object oTarget)
{
ai_SetAIMode(oAssociate, AI_MODE_FOLLOW, FALSE);
DeleteLocalObject(oAssociate, AI_FOLLOW_TARGET);
ClearAllActions(FALSE, oAssociate);
string sTarget;
if(ai_GetIsCharacter(oAssociate))
{
@@ -340,34 +226,6 @@ void ai_SelectFollowTarget(object oPC, object oAssociate, object oTarget)
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_OriginalRemoveAllActionMode(object oPC)
{
if(!ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST)) return;
object oAssociate;
int nIndex;
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID &&
!ai_GetAIMode(oAssociate, AI_MODE_GHOST) &&
GetLocalInt(oAssociate, sGhostModeVarname))
{
ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST);
DeleteLocalInt(oAssociate, sGhostModeVarname);
}
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID &&
!ai_GetAIMode(oAssociate, AI_MODE_GHOST) &&
GetLocalInt(oAssociate, sGhostModeVarname))
{
ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST);
DeleteLocalInt(oAssociate, sGhostModeVarname);
}
}
}
void ai_RemoveAllActionMode(object oPC)
{
object oAssociate;
@@ -634,21 +492,23 @@ void ai_SelectWidgetSpellTarget(object oPC, object oAssociate, string sElem)
json jSpell = JsonArrayGet(jWidget, nIndex);
int nSpell = JsonGetInt(JsonArrayGet(jSpell, 0));
int nClass = JsonGetInt(JsonArrayGet(jSpell, 1));
SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate);
if(nClass == -1) // This is an Item.
{
object oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jSpell, 5)));
int nBaseItemType = GetBaseItemType(oItem);
int nIprpSubType = JsonGetInt(JsonArrayGet(jSpell, 4));
itemproperty ipProperty = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ipProperty))
{
if(nIprpSubType == GetItemPropertySubType(ipProperty)) break;
ipProperty = GetNextItemProperty(oItem);
}
if(Get2DAString("spells", "Range", nSpell) == "P" || // Self
nBaseItemType == BASE_ITEM_ENCHANTED_POTION ||
nBaseItemType == BASE_ITEM_POTIONS)
nBaseItemType == BASE_ITEM_POTIONS ||
nIprpSubType == IP_CONST_CASTSPELL_UNIQUE_POWER_SELF_ONLY)
{
int nIprpSubType = JsonGetInt(JsonArrayGet(jSpell, 4));
itemproperty ipProperty = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ipProperty))
{
if(nIprpSubType == GetItemPropertySubType(ipProperty)) break;
ipProperty = GetNextItemProperty(oItem);
}
if(ai_GetIsInCombat(oAssociate)) AssignCommand(oAssociate, ai_ClearCreatureActions(TRUE));
AssignCommand(oAssociate, ActionUseItemOnObject(oItem, ipProperty, oAssociate));
DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate));
@@ -693,8 +553,7 @@ void ai_SelectWidgetSpellTarget(object oPC, object oAssociate, string sElem)
EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_ATTACK, MOUSECURSOR_NOATTACK);
}
// Check feat and adjust if it is an action mode feat.
if(ai_SetActionMode(oAssociate, nFeat)) return;
AssignCommand(oAssociate, ActionUseFeat(nFeat, oAssociate, nSpell));
if(!ai_SetActionMode(oAssociate, nFeat)) AssignCommand(oAssociate, ActionUseFeat(nFeat, oAssociate, nSpell));
DelayCommand(6.0, ai_UpdateAssociateWidget(oPC, oAssociate));
return;
}
@@ -702,7 +561,6 @@ void ai_SelectWidgetSpellTarget(object oPC, object oAssociate, string sElem)
}
else SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_CAST_SPELL");
}
SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate);
int nObjectType;
string sTarget = Get2DAString("spells", "TargetType", nSpell);
int nTarget = ai_HexStringToInt(sTarget);
@@ -784,6 +642,7 @@ int ai_SetActionMode(object oAssociate, int nFeat)
else if(nFeat == FEAT_EXPERTISE) nMode = ACTION_MODE_EXPERTISE;
else if(nFeat == FEAT_IMPROVED_EXPERTISE) nMode = ACTION_MODE_IMPROVED_EXPERTISE;
else if(nFeat == FEAT_DIRTY_FIGHTING) nMode = ACTION_MODE_DIRTY_FIGHTING;
else if(nFeat == FEAT_DWARVEN_DEFENDER_DEFENSIVE_STANCE) nMode = 12; // ACTION_MODE_DEFENSIVE_STANCE
if(nMode)
{
SetActionMode(oAssociate, nMode, !GetActionMode(oAssociate, nMode));

View File

@@ -149,12 +149,12 @@ void ai_SetupAllyHealingTargets(object oCaster, object oPC);
// Clears the casters buff targets.
void ai_ClearBuffTargets(object oCaster, string sVariable);
// Cycles through a casters spells casting all buffs via actions.
void ai_ActionCastMemorizedBuff(struct stSpell stSpell);
void ai_ActionCastMemorizedBuff(struct stSpell stSpell, float fDelay, int bInstantSpell);
// Cycles through a casters spells casting all buffs via actions.
void ai_ActionCastKnownBuff(struct stSpell stSpell);
void ai_ActionCastKnownBuff(struct stSpell stSpell, float fDelay, int bInstantSpell);
// Checks oCaster for buffing spells and casts them based on nTarget;
// These are cast as actions and will happen at the speed based on
// AI_HENCHMAN_BUFF_DELAY, but are still actions.
// These are cast as actions and will happen at the speed based on the delay set
// by the player. 6.0 seconds to 0.1 second. Default 0.1 second.
// nTarget is 0-9 where 0 is all targets, 1 is oPC, 2 is the caster
// 3 Familiar, 4 is Animal Companion, 5 is Summons, 6 is Dominated, and 7+ is henchman.
// Targets must be defined in variable AI_ALLY_TARGET_* where * is 1 to #.
@@ -163,6 +163,12 @@ void ai_CastBuffs(object oCaster, int nBuffType, int nTarget, object oPC);
// Returns TRUE if oCaster cast spontaneous cure spell on oTarget.
// This uses an action and must use AssignCommand or OBJECT_SELF is the caster!
int ai_CastSpontaneousCure(object oCreature, object oTarget, object oPC);
// Returns TRUE if oCaster casts a memorized inflict spell on oTarget.
// This uses an action and must use AssignCommand or OBJECT_SELF is the caster!
int ai_CastMemorizedInflict(object oCreature, object oTarget, object oPC, int nClass);
// Returns TRUE if oCaster casts a known inflict spell on oTarget.
// This uses an action and must use AssignCommand or OBJECT_SELF is the caster!
int ai_CastKnownInflict(object oCreature, object oTarget, object oPC, int nClass);
// Returns TRUE if oCaster casts a memorized cure spell on oTarget.
// This uses an action and must use AssignCommand or OBJECT_SELF is the caster!
int ai_CastMemorizedHealing(object oCreature, object oTarget, object oPC, int nClass);
@@ -178,6 +184,8 @@ void ai_SpellConcentrationCheck(object oCaster);
int ai_CastInMelee(object oCreature, int nSpell, int nInMelee);
// Returns a float range for the caster to search for a target of an offensive spell.
float ai_GetOffensiveSpellSearchRange(object oCreature, int nSpell);
// Returns TRUE if nSpell is an inflict spell and will not over heal for nDamage.
int ai_ShouldWeCastThisInflictSpell(int nSpell, int nDamage);
// Returns TRUE if nSpell is a cure spell and will not over heal for nDamage.
int ai_ShouldWeCastThisCureSpell(int nSpell, int nDamage);
// Casts the spell on the current target for oAssociate.
@@ -394,73 +402,198 @@ int ai_GetIsSpellBookRestrictedCaster(object oAssociate)
}
return FALSE;
}
// This is used to set immunities on a creature not using the AI.
// Should only update every minute.
void ai_SetCreatureItemImmunities(object oCreature)
{
// Create an Immunity in json so we can check item immunities quickly for non-AI creatures.
SetLocalInt(oCreature, sIPTimeStampVarname, ai_GetCurrentTimeStamp());
if(AI_DEBUG) ai_Debug("0i_spells", "402", "Checking for Item immunities on " + GetName(oCreature));
int nSpellImmunity, bHasItemImmunity, nSlot;
json jImmunity = JsonArray();
DeleteLocalInt(oCreature, sIPImmuneVarname);
DeleteLocalInt(oCreature, sIPResistVarname);
DeleteLocalInt(oCreature, sIPReducedVarname);
int nIprpSubType, nSpell, nLevel, nIPType, nIndex;
itemproperty ipProp;
// Cycle through all the creatures equiped items.
object oItem = GetItemInSlot(nSlot, oCreature);
while(nSlot < 12)
{
if(oItem != OBJECT_INVALID)
{
if(AI_DEBUG) ai_Debug("0i_spells", "416", "Checking Item immunities on " + GetName(oItem));
ipProp = GetFirstItemProperty(oItem);
// Check for immunities on items.
while(GetIsItemPropertyValid(ipProp))
{
nIPType = GetItemPropertyType(ipProp);
if(AI_DEBUG) ai_Debug("0i_spells", "422", "ItempropertyType(53/20/23/22): " + IntToString(nIPType));
if(nIPType == ITEM_PROPERTY_IMMUNITY_SPECIFIC_SPELL)
{
bHasItemImmunity = TRUE;
nSpellImmunity = GetItemPropertyCostTableValue(ipProp);
nSpellImmunity = StringToInt(Get2DAString("iprp_spellcost", "SpellIndex", nSpellImmunity));
//if(AI_DEBUG) ai_Debug("0i_talents", "1950", "SpellImmunity to " + Get2DAString("spells", "Label", nSpellImmunity));
jImmunity = JsonArrayInsert(jImmunity, JsonInt(nSpellImmunity));
}
else if(nIPType == ITEM_PROPERTY_IMMUNITY_DAMAGE_TYPE)
{
int nBit, nIpSubType = GetItemPropertySubType(ipProp);
if(AI_DEBUG) ai_Debug("0i_talents", "434", "Immune DmgType: nIPSubType: " + IntToString(nIpSubType));
if(nIpSubType == 0) nBit = DAMAGE_TYPE_BLUDGEONING;
else if(nIpSubType == 1) nBit = DAMAGE_TYPE_PIERCING;
else if(nIpSubType == 2) nBit = DAMAGE_TYPE_SLASHING;
else if(nIpSubType == 5) nBit = DAMAGE_TYPE_MAGICAL;
else if(nIpSubType == 6) nBit = DAMAGE_TYPE_ACID;
else if(nIpSubType == 7) nBit = DAMAGE_TYPE_COLD;
else if(nIpSubType == 8) nBit = DAMAGE_TYPE_DIVINE;
else if(nIpSubType == 9) nBit = DAMAGE_TYPE_ELECTRICAL;
else if(nIpSubType == 10) nBit = DAMAGE_TYPE_FIRE;
else if(nIpSubType == 11) nBit = DAMAGE_TYPE_NEGATIVE;
else if(nIpSubType == 12) nBit = DAMAGE_TYPE_POSITIVE;
else if(nIpSubType == 13) nBit = DAMAGE_TYPE_SONIC;
if(nBit > 0) ai_SetItemProperty(oCreature, sIPImmuneVarname, nBit, TRUE);
}
else if(nIPType == ITEM_PROPERTY_DAMAGE_RESISTANCE)
{
int nBit, nIpSubType = GetItemPropertySubType(ipProp);
if(AI_DEBUG) ai_Debug("0i_talents", "452", "Dmg Resist: nIPSubType: " + IntToString(nIpSubType));
if(nIpSubType == 0) nBit = DAMAGE_TYPE_BLUDGEONING;
else if(nIpSubType == 1) nBit = DAMAGE_TYPE_PIERCING;
else if(nIpSubType == 2) nBit = DAMAGE_TYPE_SLASHING;
else if(nIpSubType == 5) nBit = DAMAGE_TYPE_MAGICAL;
else if(nIpSubType == 6) nBit = DAMAGE_TYPE_ACID;
else if(nIpSubType == 7) nBit = DAMAGE_TYPE_COLD;
else if(nIpSubType == 8) nBit = DAMAGE_TYPE_DIVINE;
else if(nIpSubType == 9) nBit = DAMAGE_TYPE_ELECTRICAL;
else if(nIpSubType == 10) nBit = DAMAGE_TYPE_FIRE;
else if(nIpSubType == 11) nBit = DAMAGE_TYPE_NEGATIVE;
else if(nIpSubType == 12) nBit = DAMAGE_TYPE_POSITIVE;
else if(nIpSubType == 13) nBit = DAMAGE_TYPE_SONIC;
if(nBit > 0) ai_SetItemProperty(oCreature, sIPResistVarname, nBit, TRUE);
}
else if(nIPType == ITEM_PROPERTY_DAMAGE_REDUCTION)
{
int nIpSubType = GetItemPropertySubType(ipProp);
if(AI_DEBUG) ai_Debug("0i_talents", "470", "Dmg Reduction: nIPSubType: " + IntToString(nIpSubType));
SetLocalInt(oCreature, sIPReducedVarname, nIpSubType);
}
nIndex++;
ipProp = GetNextItemProperty(oItem);
}
// If nSpellImmunity has been set then we need to save our Immunity json.
if(bHasItemImmunity) SetLocalJson(oCreature, AI_TALENT_IMMUNITY, jImmunity);
}
oItem = GetItemInSlot(++nSlot, oCreature);
// Make the final check the creatures hide.
if(nSlot == 11) oItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oCreature);
}
}
int ai_CreatureImmuneToEffect(object oCaster, object oCreature, int nSpell)
{
// This checks for creatures not using the AI system (usually players).
// Creatures using the AI system will always have a value in sIPReducedVarname!
// Updates thier immunity values every minute. Should be good as we only update
// equiped items. Spell effects are checked on the creature and are not saved.
if(AI_DEBUG)
{
if(GetLocalInt(oCreature, sIPReducedVarname) == 0) ai_Debug("0i_spells", "492",
" Immunities last saved: " + IntToString(GetLocalInt(oCreature, sIPTimeStampVarname)) +
" + 60 < " + IntToString(ai_GetCurrentTimeStamp()));
}
if(GetLocalInt(oCreature, sIPReducedVarname) == 0 &&
GetLocalInt(oCreature, sIPTimeStampVarname) + 60 < ai_GetCurrentTimeStamp()) ai_SetCreatureItemImmunities(oCreature);
string sIType = Get2DAString("ai_spells", "ImmunityType", nSpell);
// Let us check if the creature is disabled while we look for immunities.
int nDisabled = ai_Disabled(oCreature);
if(AI_DEBUG) ai_Debug("0i_spells", "499", "Checking spell immunity type(" + sIType + ").");
if(sIType != "")
{
if(AI_DEBUG) ai_Debug("0i_spells", "290", "Checking spell immunity type(" + sIType + ").");
if(sIType == "Death" && GetIsImmune(oCreature, IMMUNITY_TYPE_DEATH)) return TRUE;
else if(sIType == "Level_Drain" && GetIsImmune(oCreature, IMMUNITY_TYPE_NEGATIVE_LEVEL)) return TRUE;
else if(sIType == "Ability_Drain" && GetIsImmune(oCreature, IMMUNITY_TYPE_ABILITY_DECREASE)) return TRUE;
else if(sIType == "Poison" && GetIsImmune(oCreature, IMMUNITY_TYPE_POISON)) return TRUE;
else if(sIType == "Disease" && GetIsImmune(oCreature, IMMUNITY_TYPE_DISEASE)) return TRUE;
else if(sIType == "Curse" && GetIsImmune(oCreature, IMMUNITY_TYPE_CURSED)) return TRUE;
else if(sIType == "Mind_Affecting" && GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS)) return TRUE;
else if(sIType == "Petrification" && ai_IsImmuneToPetrification(oCaster, oCreature)) return TRUE;
else if(sIType == "Mind_Affecting" &&
(GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS) || nDisabled)) return TRUE;
else if(sIType == "Petrification" &&
(ai_IsImmuneToPetrification(oCaster, oCreature) && nDisabled)) return TRUE;
else if(sIType == "Fear" &&
(GetIsImmune(oCreature, IMMUNITY_TYPE_FEAR) ||
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE;
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS) || nDisabled)) return TRUE;
else if(sIType == "Sleep" &&
(GetIsImmune(oCreature, IMMUNITY_TYPE_SLEEP) ||
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE;
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS) || nDisabled)) return TRUE;
else if(sIType == "Paralysis" &&
(GetIsImmune(oCreature, IMMUNITY_TYPE_PARALYSIS) ||
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE;
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS) || nDisabled)) return TRUE;
else if(sIType == "Domination" &&
(GetIsImmune(oCreature, IMMUNITY_TYPE_DOMINATE) ||
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE;
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS) || nDisabled)) return TRUE;
else if(sIType == "Confusion" &&
(GetIsImmune(oCreature, IMMUNITY_TYPE_CONFUSED) ||
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE;
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS) || nDisabled)) return TRUE;
else if(sIType == "Blindness" &&
(GetIsImmune(oCreature, IMMUNITY_TYPE_BLINDNESS) ||
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE;
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS) || ai_GetHasEffectType(oCreature, EFFECT_TYPE_BLINDNESS))) return TRUE;
else if(sIType == "Dazed" &&
(GetIsImmune(oCreature, IMMUNITY_TYPE_DAZED) ||
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE;
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS) || nDisabled)) return TRUE;
else if(sIType == "Charm" &&
(GetIsImmune(oCreature, IMMUNITY_TYPE_CHARM) ||
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS))) return TRUE;
GetIsImmune(oCreature, IMMUNITY_TYPE_MIND_SPELLS) || nDisabled)) return TRUE;
// Check for damage immunities.
// Negative damage does not work on undead!
else if(sIType == "Negative" && GetRacialType(oCreature) == RACIAL_TYPE_UNDEAD)
{
if(AI_DEBUG) ai_Debug("0i_spell", "325", "Undead are immune to Negative energy!");
if(AI_DEBUG) ai_Debug("0i_spell", "538", "Undead are immune to Negative energy!");
return TRUE;
}
else if(sIType == "Poison" && ai_GetHasEffectType(oCreature, EFFECT_TYPE_POISON)) return TRUE;
else if(sIType == "Disease" && ai_GetHasEffectType(oCreature, EFFECT_TYPE_DISEASE)) return TRUE;
// Elemental damage resistances should be checked.
if(sIType == "Acid" || sIType == "Cold" || sIType == "Fire" ||
sIType == "Electricty" || sIType == "Sonic")
{
if(ai_GetHasEffectType(oCreature, EFFECT_TYPE_DAMAGE_RESISTANCE))
{
if(AI_DEBUG) ai_Debug("0i_spell", "334", GetName(oCreature) + " has damage resistance to my " + sIType + " spell!");
if(AI_DEBUG) ai_Debug("0i_spell", "547", GetName(oCreature) + " has damage resistance to my " + sIType + " spell!");
return TRUE;
}
// Check for resistances and immunities. Treat resistance as immune.
int nIPResist = GetLocalInt(oCreature, sIPResistVarname);
if(AI_DEBUG) ai_Debug("0i_spell", "372", "nIPResist:" + IntToString(nIPResist));
if(AI_DEBUG) ai_Debug("0i_spell", "552", "nIPResist:" + IntToString(nIPResist));
int nIPImmune = GetLocalInt(oCreature, sIPImmuneVarname) | nIPResist;
if(AI_DEBUG) ai_Debug("0i_spell", "374", "nIPImmune:" + IntToString(nIPImmune));
if(nIPImmune > 0)
if(AI_DEBUG) ai_Debug("0i_spell", "554", "nIPImmune:" + IntToString(nIPImmune));
int bImmune;
if(nIPImmune > 0) {
if(sIType == "Acid" && (nIPImmune & DAMAGE_TYPE_ACID)) bImmune = TRUE;
else if(sIType == "Cold" && (nIPImmune & DAMAGE_TYPE_COLD)) bImmune = TRUE;
else if(sIType == "Fire" && (nIPImmune & DAMAGE_TYPE_FIRE)) bImmune = TRUE;
else if(sIType == "Electricity" && (nIPImmune & DAMAGE_TYPE_ELECTRICAL)) bImmune = TRUE;
else if(sIType == "Sonic" && (nIPImmune & DAMAGE_TYPE_SONIC)) bImmune = TRUE;
}
if(bImmune)
{
if(AI_DEBUG) ai_Debug("0i_spell", "391", GetName(oCreature) + " is immune/resistant to my " + sIType + " spell through an item!");
if(sIType == "Acid" && (nIPImmune & DAMAGE_TYPE_ACID)) return TRUE;
else if(sIType == "Cold" && (nIPImmune & DAMAGE_TYPE_COLD)) return TRUE;
else if(sIType == "Fire" && (nIPImmune & DAMAGE_TYPE_FIRE)) return TRUE;
else if(sIType == "Electricity" && (nIPImmune & DAMAGE_TYPE_ELECTRICAL)) return TRUE;
else if(sIType == "Sonic" && (nIPImmune & DAMAGE_TYPE_SONIC)) return TRUE;
if(AI_DEBUG) ai_Debug("0i_spell", "567", GetName(oCreature) + " is immune/resistant to my " + sIType + " spell through an item!");
return TRUE;
}
}
// Lets also check undead and constructs vs mind spells.
int nRace = GetRacialType(oCreature);
int nClass = GetClassByPosition(1, oCreature);
if(nRace == RACIAL_TYPE_UNDEAD || nRace == RACIAL_TYPE_CONSTRUCT ||
nClass == CLASS_TYPE_UNDEAD || nClass == CLASS_TYPE_CONSTRUCT)
{
if(sIType == "Mind_Affecting" || sIType == "Fear" || sIType == "Sleep" ||
sIType == "Confusion" || sIType == "Blindness" || sIType == "Daze" ||
sIType == "Poison" || sIType == "Disease" || sIType == "Charm")
{
if(AI_DEBUG) ai_Debug("0i_spell", "595", GetName(oCreature) + " is immune/resistant to my " + sIType + " spell because they are Undead or a Construct!");
return TRUE;
}
}
}
@@ -479,12 +612,12 @@ int ai_CreatureImmuneToEffect(object oCaster, object oCreature, int nSpell)
{
if(nSpell == JsonGetInt(jSpell))
{
if(AI_DEBUG) ai_Debug("0i_spells", "407", GetName(oCreature) + " is immune to the spell via an Item!");
if(AI_DEBUG) ai_Debug("0i_spells", "581", GetName(oCreature) + " is immune to the spell via an Item!");
return TRUE;
}
jSpell = JsonArrayGet(jSpellImmunity, ++nIndex);
}
if(AI_DEBUG) ai_Debug("0i_spell", "347", GetName(oCreature) + " is not immune to the spell.");
if(AI_DEBUG) ai_Debug("0i_spell", "586", GetName(oCreature) + " is not immune to the spell.");
return FALSE;
}
float ai_GetSpellRange(int nSpell)
@@ -651,9 +784,9 @@ int ai_IsSilenced(object oCreature, int nSpell)
}
int ai_ArcaneSpellFailureTooHigh(object oCreature, int nClass, int nLevel, int nSlot)
{
if(AI_DEBUG) ai_Debug("0i_spells", "561", "Arcane Spells: " + Get2DAString("classes", "ASF", nClass) +
if(AI_DEBUG) ai_Debug("0i_spells", "746", "Arcane Spells: " + Get2DAString("classes", "ASF", nClass) +
" Arcane Spell Failure: " + IntToString(GetArcaneSpellFailure(oCreature)) +
" AI_ASF_WILL_USE: " + IntToString(AI_ASF_WILL_USE));
" > " + IntToString(AI_ASF_WILL_USE) + " skip.");
if(Get2DAString("classes", "ASF", nClass) == "1" &&
GetArcaneSpellFailure(oCreature) > AI_ASF_WILL_USE)
{
@@ -1181,7 +1314,7 @@ int ai_CheckAndCastSpell(object oCaster, int nSpell, int nSpellGroup, float fDel
// Search all memorized spells for the spell.
if(Get2DAString("classes", "MemorizesSpells", nClass) == "1")
{
// Check each level starting with the highest to lowest.
// Check each level starting with the lowest to the highest.
nSpellLevel = 0;
while(nSpellLevel < 10)
{
@@ -1193,6 +1326,8 @@ int ai_CheckAndCastSpell(object oCaster, int nSpell, int nSpellGroup, float fDel
if(GetMemorizedSpellReady(oCaster, nClass, nSpellLevel, nSpellSlot))
{
nMemorizedSpell = GetMemorizedSpellId(oCaster, nClass, nSpellLevel, nSpellSlot);
if(AI_DEBUG) ai_Debug("0i_spells", "1326", "nMemorizedSpell: " + IntToString(nMemorizedSpell) +
" nSpell: " + IntToString(nSpell));
if(nMemorizedSpell == nSpell)
{
ai_CastMemorizedSpell(oCaster, nClass, nSpellLevel, nSpellSlot, oTarget, FALSE, oPC);
@@ -1431,7 +1566,7 @@ void ai_CheckForPerDayItems(object oCreature, object oPC, int nBuffType)
nCntr++;
}
}
void ai_CheckForBuffSpells(struct stSpell stSpell)
void ai_CheckForBuffSpells(struct stSpell stSpell, float fDelay, int bInstantSpell)
{
ai_SetupAllyTargets(stSpell.oCaster, stSpell.oPC);
stSpell.nPosition = 1;
@@ -1452,13 +1587,13 @@ void ai_CheckForBuffSpells(struct stSpell stSpell)
if(Get2DAString("classes", "MemorizesSpells", stSpell.nClass) == "1")
{
stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell));
AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell, fDelay, bInstantSpell));
return;
}
else
{
stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell));
AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell, fDelay, bInstantSpell));
return;
}
}
@@ -1466,7 +1601,7 @@ void ai_CheckForBuffSpells(struct stSpell stSpell)
}
ai_CheckForPerDayItems(stSpell.oCaster, stSpell.oPC, stSpell.nBuffType);
}
void ai_ActionCastMemorizedSummons(struct stSpell stSpell)
void ai_ActionCastMemorizedSummons(struct stSpell stSpell, float fDelay, int bInstantSpell)
{
if(AI_DEBUG) ai_Debug("0i_spells", "1122", "Start of ActionCastMemorizedSummons!");
int nSpell;
@@ -1492,14 +1627,14 @@ void ai_ActionCastMemorizedSummons(struct stSpell stSpell)
if(Get2DAString("ai_spells", "Category", nSpell) == "S")
{
SetLocalInt(stSpell.oCaster, "AI_USED_SPELL_GROUP_-2", TRUE);
ai_CastMemorizedSpell(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot, stSpell.oCaster, TRUE, stSpell.oPC);
ai_CastMemorizedSpell(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot, stSpell.oCaster, bInstantSpell, stSpell.oPC);
stSpell.nPosition = 1;
stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster);
stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2;
stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
stSpell.nSlot = 0;
DelayCommand(2.0, ai_SetupAllyTargets(stSpell.oCaster, stSpell.oPC));
DelayCommand(2.0 + 0.5, AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell)));
DelayCommand(2.0 + 0.5, AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell, fDelay, bInstantSpell)));
return;
}
}
@@ -1529,14 +1664,14 @@ void ai_ActionCastMemorizedSummons(struct stSpell stSpell)
else
{
stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell));
AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell, fDelay, bInstantSpell));
return;
}
}
}
ai_CheckForBuffSpells(stSpell);
ai_CheckForBuffSpells(stSpell, fDelay, bInstantSpell);
}
void ai_ActionCastKnownSummons(struct stSpell stSpell)
void ai_ActionCastKnownSummons(struct stSpell stSpell, float fDelay, int bInstantSpell)
{
//ai_Debug("0i_spells", "1184", "Start of ActionCastKnownSummons!");
int nSpell;
@@ -1564,14 +1699,14 @@ void ai_ActionCastKnownSummons(struct stSpell stSpell)
{
SetLocalInt(stSpell.oCaster, "AI_USED_SPELL_GROUP_S", TRUE);
//ai_Debug("0i_spells", "1209", "nSpell: " + IntToString(nSpell));
ai_CastKnownSpell(stSpell.oCaster, stSpell.nClass, nSpell, stSpell.oCaster, TRUE, stSpell.oPC);
ai_CastKnownSpell(stSpell.oCaster, stSpell.nClass, nSpell, stSpell.oCaster, bInstantSpell, stSpell.oPC);
stSpell.nPosition = 1;
stSpell.nClass = GetClassByPosition(stSpell.nPosition, stSpell.oCaster);
stSpell.nLevel = (GetLevelByPosition(stSpell.nPosition, stSpell.oCaster) + 1) / 2;
stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
stSpell.nSlot = 0;
ai_SetupAllyTargets(stSpell.oCaster, stSpell.oPC);
DelayCommand(AI_HENCHMAN_BUFF_DELAY, AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell)));
DelayCommand(fDelay, AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell, fDelay, bInstantSpell)));
return;
}
}
@@ -1598,15 +1733,15 @@ void ai_ActionCastKnownSummons(struct stSpell stSpell)
if(Get2DAString("classes", "MemorizesSpells", stSpell.nClass) == "1")
{
stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell));
AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell, fDelay, bInstantSpell));
return;
}
else stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
}
}
ai_CheckForBuffSpells(stSpell);
ai_CheckForBuffSpells(stSpell, fDelay, bInstantSpell);
}
void ai_ActionCastMemorizedBuff(struct stSpell stSpell)
void ai_ActionCastMemorizedBuff(struct stSpell stSpell, float fDelay, int bInstantSpell)
{
int nSpell;
string sBuffGroup, sBuffTarget;
@@ -1649,9 +1784,9 @@ void ai_ActionCastMemorizedBuff(struct stSpell stSpell)
" oTarget: " + GetName(oTarget));
if(oTarget != OBJECT_INVALID)
{
ai_CastMemorizedSpell(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot, oTarget, TRUE, stSpell.oPC);
ai_CastMemorizedSpell(stSpell.oCaster, stSpell.nClass, stSpell.nLevel, stSpell.nSlot, oTarget, bInstantSpell, stSpell.oPC);
stSpell.nSlot++;
DelayCommand(AI_HENCHMAN_BUFF_DELAY, AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell)));
DelayCommand(fDelay, AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell, fDelay, bInstantSpell)));
return;
}
}
@@ -1682,14 +1817,14 @@ void ai_ActionCastMemorizedBuff(struct stSpell stSpell)
else
{
stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell));
AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell, fDelay, bInstantSpell));
return;
}
}
}
ai_CheckForPerDayItems(stSpell.oCaster, stSpell.oPC, stSpell.nBuffType);
}
void ai_ActionCastKnownBuff(struct stSpell stSpell)
void ai_ActionCastKnownBuff(struct stSpell stSpell, float fDelay, int bInstantSpell)
{
int nSpell;
string sBuffGroup, sBuffTarget;
@@ -1734,9 +1869,9 @@ void ai_ActionCastKnownBuff(struct stSpell stSpell)
// " oTarget: " + GetName(oTarget));
if(oTarget != OBJECT_INVALID)
{
ai_CastKnownSpell(stSpell.oCaster, stSpell.nClass, nSpell, oTarget, TRUE, stSpell.oPC);
ai_CastKnownSpell(stSpell.oCaster, stSpell.nClass, nSpell, oTarget, bInstantSpell, stSpell.oPC);
stSpell.nSlot++;
DelayCommand(AI_HENCHMAN_BUFF_DELAY, AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell)));
DelayCommand(fDelay, AssignCommand(stSpell.oCaster, ai_ActionCastKnownBuff(stSpell, fDelay, bInstantSpell)));
return;
}
}
@@ -1764,7 +1899,7 @@ void ai_ActionCastKnownBuff(struct stSpell stSpell)
if(Get2DAString("classes", "MemorizesSpells", stSpell.nClass) == "1")
{
stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell));
AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedBuff(stSpell, fDelay, bInstantSpell));
return;
}
else stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
@@ -1786,8 +1921,12 @@ void ai_CastBuffs(object oCaster, int nBuffType, int nTarget, object oPC)
stSpell.nBuffType = nBuffType;
stSpell.nTarget = nTarget;
stSpell.nPosition = 1;
float fDelay = GetLocalFloat(stSpell.oCaster, AI_DELAY_BUFF_CASTING);
int bInstantSpell;
if(fDelay < 4.9) bInstantSpell = TRUE;
else fDelay = 6.0;
// Look for summons spells on All, Long durations and the whole party.
if((nBuffType == 1 || nBuffType == 3) && nTarget == 0)
if((nBuffType == 1 || nBuffType == 3) && nTarget == 0 && GetAssociate(ASSOCIATE_TYPE_SUMMONED, oCaster) == OBJECT_INVALID)
{
while(stSpell.nPosition <= AI_MAX_CLASSES_PER_CHARACTER)
{
@@ -1802,13 +1941,13 @@ void ai_CastBuffs(object oCaster, int nBuffType, int nTarget, object oPC)
if(Get2DAString("classes", "MemorizesSpells", stSpell.nClass) == "1")
{
stSpell.nMaxSlots = GetMemorizedSpellCountByLevel(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedSummons(stSpell));
AssignCommand(stSpell.oCaster, ai_ActionCastMemorizedSummons(stSpell, fDelay, bInstantSpell));
return;
}
else
{
stSpell.nMaxSlots = GetKnownSpellCount(stSpell.oCaster, stSpell.nClass, stSpell.nLevel);
AssignCommand(stSpell.oCaster, ai_ActionCastKnownSummons(stSpell));
AssignCommand(stSpell.oCaster, ai_ActionCastKnownSummons(stSpell, fDelay, bInstantSpell));
return;
}
}
@@ -1817,7 +1956,7 @@ void ai_CastBuffs(object oCaster, int nBuffType, int nTarget, object oPC)
// Exit here; if we summoned a monster then it linked off of that spell
// cast to continue the action queue for all buff spell cast actions.
}
ai_CheckForBuffSpells(stSpell);
ai_CheckForBuffSpells(stSpell, fDelay, bInstantSpell);
}
int ai_CastSpontaneousCure(object oCreature, object oTarget, object oPC)
{
@@ -1883,6 +2022,98 @@ int ai_CastSpontaneousCure(object oCreature, object oTarget, object oPC)
}
return FALSE;
}
int ai_CastMemorizedInflict(object oCreature, object oTarget, object oPC, int nClass)
{
if(AI_DEBUG) ai_Debug("0i_spells", "1993", GetName(oCreature) + " is looking to cast a memorized inflict spell.");
int nDamage = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget);
int nSpell, nSlot, nMaxSlots, nLevel = 9;
int nClassSave, nSlotSave, nLevelSave = 10;
while(nLevel > -1)
{
nMaxSlots = GetMemorizedSpellCountByLevel(oCreature, nClass, nLevel);
nSlot = 0;
if(AI_DEBUG) ai_Debug("0i_spells", "2001", "nLevel: " + IntToString(nLevel) + " nMaxSlots: " + IntToString(nMaxSlots));
while(nSlot < nMaxSlots)
{
if(AI_DEBUG) ai_Debug("0i_spells", "2004", "nSlot: " + IntToString(nSlot) +
" Spell Ready: " + IntToString(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot)));
if(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot))
{
nSpell = GetMemorizedSpellId(oCreature, nClass, nLevel, nSlot);
if(ai_ShouldWeCastThisInflictSpell(nSpell, nDamage))
{
string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
if(AI_DEBUG) ai_Debug("0i_spells", "2012", GetName(oCreature) + " has cast " + sSpellName + " on " + GetName(oTarget) + ".");
ai_CastMemorizedSpell(oCreature, nClass, nLevel, nSlot, oTarget, FALSE, oPC);
return TRUE;
}
// Save the lowest level inflict spell as we might need to cast it.
else if(nLevel < nLevelSave && (nSpell > 430 && nSpell < 436))
{
nClassSave = nClass;
nLevelSave = nLevel;
nSlotSave = nSlot;
}
}
nSlot++;
}
nLevel--;
}
// Did we find a cure spell? If we did then use it.
if(nLevelSave < 10)
{
if(AI_DEBUG) ai_Debug("0i_spells", "1740", GetName(oCreature) + " has cast the lowest level cure spell on " + GetName(oTarget) + ".");
ai_CastMemorizedSpell(oCreature, nClassSave, nLevelSave, nSlotSave, oTarget, FALSE, oPC);
return TRUE;
}
return FALSE;
}
int ai_CastKnownInflict(object oCreature, object oTarget, object oPC, int nClass)
{
if(AI_DEBUG) ai_Debug("0i_spells", "2041", GetName(oCreature) + " is looking to cast a known inflict spell.");
int nDamage = GetMaxHitPoints(oTarget) - GetCurrentHitPoints(oTarget);
int nSpell, nSlot, nMaxSlots, nLevel = 9;
int nClassSave, nSpellSave, nLevelSave = 10;
while(nLevel > -1)
{
nMaxSlots = GetKnownSpellCount(oCreature, nClass, nLevel);
nSlot = 0;
if(AI_DEBUG) ai_Debug("0i_spells", "2049", "nLevel: " + IntToString(nLevel) + " nMaxSlots: " + IntToString(nMaxSlots));
while(nSlot < nMaxSlots)
{
nSpell = GetKnownSpellId(oCreature, nClass, nLevel, nSlot);
if(AI_DEBUG) ai_Debug("0i_spells", "2053", "nSlot: " + IntToString(nSlot) +
" Spell Ready: " + IntToString(GetSpellUsesLeft(oCreature, nClass, nSpell)));
if(GetSpellUsesLeft(oCreature, nClass, nSpell))
{
if(ai_ShouldWeCastThisInflictSpell(nSpell, nDamage))
{
string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
if(AI_DEBUG) ai_Debug("0i_spells", "2060", GetName(oCreature) + " has cast " + sSpellName + " on " + GetName(oTarget) + ".");
ai_CastKnownSpell(oCreature, nClass, nSpell, oTarget, FALSE, oPC);
return TRUE;
}
// Save the lowest level cure spell as we might need to cast it.
else if(nLevel < nLevelSave && (nSpell > 430 && nSpell < 436))
{
nClassSave = nClass;
nLevelSave = nLevel;
nSpellSave = nSpell;
}
}
nSlot++;
}
nLevel--;
}
return FALSE;
// Did we find a cure spell? If we did then use it.
if(nLevelSave < 10)
{
if(AI_DEBUG) ai_Debug("0i_spells", "1781", GetName(oCreature) + " has cast the lowest level cure spell on " + GetName(oTarget) + ".");
ai_CastKnownSpell(oCreature, nClassSave, nSpellSave, oTarget, FALSE, oPC);
return TRUE;
}
}
int ai_CastMemorizedHealing(object oCreature, object oTarget, object oPC, int nClass)
{
if(AI_DEBUG) ai_Debug("0i_spells", "1702", GetName(oCreature) + " is looking to cast a memorized cure spell.");
@@ -1909,7 +2140,7 @@ int ai_CastMemorizedHealing(object oCreature, object oTarget, object oPC, int nC
return TRUE;
}
// Save the lowest level cure spell as we might need to cast it.
else if(nLevel < nLevelSave && (nSpell > 26 && nSpell < 32))
else if(nLevel < nLevelSave && (nSpell > 30 && nSpell < 36))
{
nClassSave = nClass;
nLevelSave = nLevel;
@@ -1955,7 +2186,7 @@ int ai_CastKnownHealing(object oCreature, object oTarget, object oPC, int nClass
return TRUE;
}
// Save the lowest level cure spell as we might need to cast it.
else if(nLevel < nLevelSave && (nSpell > 26 && nSpell < 32))
else if(nLevel < nLevelSave && (nSpell > 30 && nSpell < 36))
{
nClassSave = nClass;
nLevelSave = nLevel;
@@ -2074,7 +2305,7 @@ float ai_GetOffensiveSpellSearchRange(object oCreature, int nSpell)
// We check this because if the enemy is moving or has not started acting
// then we don't want to move up on them as they might move towards us!
int nAction = GetCurrentAction(oNearestEnemy);
if(AI_DEBUG) ai_Debug("0i_spells", "1130", GetName(oNearestEnemy) + " current action: " + IntToString(nAction));
if(AI_DEBUG) ai_Debug("0i_spells", "2228", GetName(oNearestEnemy) + " current action: " + IntToString(nAction));
if(nAction != ACTION_MOVETOPOINT || nAction != ACTION_ITEMCASTSPELL ||
nAction != ACTION_INVALID || nAction != ACTION_USEOBJECT ||
nAction != ACTION_RANDOMWALK) fRange = fEnemyDistance + (fRange - 7.5);
@@ -2083,6 +2314,18 @@ float ai_GetOffensiveSpellSearchRange(object oCreature, int nSpell)
else if(fRange < 0.1f) return 0.1f;
return fRange;
}
int ai_ShouldWeCastThisInflictSpell(int nSpell, int nDamage)
{
if(AI_DEBUG) ai_Debug("0i_spells", "2239", "nSpell: " + IntToString(nSpell) + " nDamage: " +
IntToString(nDamage));
if(nSpell == SPELL_HEAL && nDamage > 50) return TRUE;
else if(nSpell == SPELL_INFLICT_CRITICAL_WOUNDS && nDamage > 31) return TRUE;
else if(nSpell == SPELL_INFLICT_SERIOUS_WOUNDS && nDamage > 23) return TRUE;
else if(nSpell == SPELL_INFLICT_MODERATE_WOUNDS && nDamage > 15) return TRUE;
else if(nSpell == SPELL_INFLICT_LIGHT_WOUNDS && nDamage > 6) return TRUE;
else if(nSpell == SPELL_INFLICT_MINOR_WOUNDS) return TRUE;
return FALSE;
}
int ai_ShouldWeCastThisCureSpell(int nSpell, int nDamage)
{
if(AI_DEBUG) ai_Debug("0i_spells", "1127", "nSpell: " + IntToString(nSpell) + " nDamage: " +
@@ -2112,7 +2355,7 @@ void ai_CastWidgetSpell(object oPC, object oAssociate, object oTarget, location
// " oTarget: " + GetName(oTarget) +
// " nMetaMagic: " + IntToString(nMetaMagic) +
// " nDomain: " + IntToString(nDomain));
if(GetCurrentAction(oAssociate) != ACTION_CASTSPELL) AssignCommand(oAssociate, ai_ClearCreatureActions(TRUE));
if(GetCurrentAction(oAssociate) != ACTION_CASTSPELL) AssignCommand(oAssociate, ai_ClearCreatureActions(FALSE));
if(!GetIsObjectValid(oTarget))
{
AssignCommand(oAssociate, ActionCastSpellAtLocation(nSpell, lLocation, nMetaMagic, FALSE, 0, FALSE, -1, FALSE, nDomain));
@@ -2134,7 +2377,7 @@ void ai_UseWidgetFeat(object oPC, object oAssociate, object oTarget, location lL
// We use nLevel at -1 to denote this is a feat with a subradial spell.
int nSubSpell;
if(nLevel == -1) nSubSpell = JsonGetInt(JsonArrayGet(jFeat, 0));
if(ai_GetIsInCombat(oAssociate)) AssignCommand(oAssociate, ai_ClearCreatureActions(TRUE));
if(ai_GetIsInCombat(oAssociate)) AssignCommand(oAssociate, ai_ClearCreatureActions(FALSE));
//SendMessageToPC(oPC, "0i_spells, 2104, nFeat: " + IntToString(nFeat) + " oTarget: " + GetName(oTarget));
if(!GetIsObjectValid(oTarget))
{
@@ -2155,7 +2398,7 @@ void ai_UseWidgetItem(object oPC, object oAssociate, object oTarget, location lL
int nIprpSubType = JsonGetInt(JsonArrayGet(jItem, 4));
object oItem = GetObjectByUUID(JsonGetString(JsonArrayGet(jItem, 5)));
itemproperty ipProperty;
if(ai_GetIsInCombat(oAssociate)) AssignCommand(oAssociate, ai_ClearCreatureActions(TRUE));
if(ai_GetIsInCombat(oAssociate)) AssignCommand(oAssociate, ai_ClearCreatureActions(FALSE));
if(nSpell == SPELL_HEALINGKIT)
{
ipProperty = GetFirstItemProperty(oItem);
@@ -2172,9 +2415,9 @@ void ai_UseWidgetItem(object oPC, object oAssociate, object oTarget, location lL
if(nIprpSubType == GetItemPropertySubType(ipProperty)) break;
ipProperty = GetNextItemProperty(oItem);
}
if(!GetIsObjectValid(oTarget))
if(GetIsObjectValid(oTarget))
{
AssignCommand(oAssociate, ActionUseItemAtLocation(oItem, ipProperty, lLocation));
AssignCommand(oAssociate, ActionUseItemOnObject(oItem, ipProperty, oTarget));
}
else AssignCommand(oAssociate, ActionUseItemOnObject(oItem, ipProperty, oTarget));
else AssignCommand(oAssociate, ActionUseItemAtLocation(oItem, ipProperty, lLocation));
}

View File

@@ -94,6 +94,7 @@ void ai_ClearCreatureActions(int bClearCombatState = FALSE)
void ai_SetLastAction(object oCreature, int nAction = AI_LAST_ACTION_NONE)
{
SetLocalInt(oCreature, sLastActionVarname, nAction);
SetLocalInt(oCreature, sLastActionTimeVarname, ai_GetCurrentTimeStamp());
}
int ai_CompareLastAction(object oCreature, int nAction)
{
@@ -105,6 +106,7 @@ int ai_CompareLastAction(object oCreature, int nAction)
}
void ai_SetListeningPatterns(object oCreature)
{
SetListening(oCreature, TRUE);
SetListenPattern(oCreature, AI_I_SEE_AN_ENEMY, AI_ALLY_SEES_AN_ENEMY);
SetListenPattern(oCreature, AI_I_HEARD_AN_ENEMY, AI_ALLY_HEARD_AN_ENEMY);
SetListenPattern(oCreature, AI_ATKED_BY_WEAPON, AI_ALLY_ATKED_BY_WEAPON);
@@ -114,7 +116,6 @@ void ai_SetListeningPatterns(object oCreature)
SetListenPattern(oCreature, AI_I_AM_DISEASED, AI_ALLY_IS_DISEASED);
SetListenPattern(oCreature, AI_I_AM_POISONED, AI_ALLY_IS_POISONED);
SetListenPattern(oCreature, AI_I_AM_WEAK, AI_ALLY_IS_WEAK);
SetListening(oCreature, TRUE);
}
int ai_IsNonliving(int nRacialType)
{
@@ -134,12 +135,12 @@ int ai_GetIsInCombat(object oCreature)
}
void ai_SetCombatRound(object oCreature)
{
SetLocalInt(oCreature, "AI_COMBAT_ROUND_START", SQLite_GetTimeStamp());
if(AI_DEBUG) ai_Debug("0i_states_cond", "116", " ===============> " + GetName(oCreature) + " ROUND START:" + IntToString(SQLite_GetTimeStamp()) + " <===============");
SetLocalInt(oCreature, "AI_COMBAT_ROUND_START", ai_GetCurrentTimeStamp());
if(AI_DEBUG) ai_Debug("0i_states_cond", "116", " ===============> " + GetName(oCreature) + " ROUND START:" + IntToString(ai_GetCurrentTimeStamp()) + " <===============");
}
void ai_EndCombatRound(object oCreature)
{
if(AI_DEBUG) ai_Debug("0i_states_cond", "120", " ===============> " + GetName(oCreature) + " ROUND END:" + IntToString(SQLite_GetTimeStamp()) + " <===============");
if(AI_DEBUG) ai_Debug("0i_states_cond", "120", " ===============> " + GetName(oCreature) + " ROUND END:" + IntToString(ai_GetCurrentTimeStamp()) + " <===============");
DeleteLocalInt(oCreature, "AI_COMBAT_ROUND_START");
}
int ai_IsInCombatRound(object oCreature, int nCombatRound = AI_COMBAT_ROUND_IN_SECONDS)
@@ -148,10 +149,10 @@ int ai_IsInCombatRound(object oCreature, int nCombatRound = AI_COMBAT_ROUND_IN_S
if(AI_DEBUG) ai_Debug("0i_states_cond", "148", " nCombatRoundStart: " + IntToString(nCombatRoundStart));
if(!nCombatRoundStart) return FALSE;
// New combat round calculator. If 6 seconds has passed then we are on a new round!
int nSQLTime = SQLite_GetTimeStamp();
int nCombatRoundTime = nSQLTime - nCombatRoundStart;
if(AI_DEBUG) ai_Debug("0i_states_cond", "153", " SQLite_GetTimeStamp: " + IntToString(nSQLTime) +
"(" + IntToString(nSQLTime - nCombatRoundStart) + ")");
int nTime = ai_GetCurrentTimeStamp();
int nCombatRoundTime = nTime - nCombatRoundStart;
if(AI_DEBUG) ai_Debug("0i_states_cond", "153", " nTime + (nTime - Round Start): " + IntToString(nTime) +
"(" + IntToString(nTime - nCombatRoundStart) + ")");
if(nCombatRoundTime < nCombatRound) return TRUE;
ai_EndCombatRound(oCreature);
return FALSE;
@@ -200,9 +201,11 @@ int ai_Disabled(object oCreature)
effect eEffect = GetFirstEffect(oCreature);
while(GetIsEffectValid(eEffect))
{
switch(GetEffectType(eEffect))
switch(GetEffectType(eEffect, TRUE))
{
WriteTimestampedLogEntry("Effect Type: " + IntToString(GetEffectType(eEffect, TRUE)));
case EFFECT_TYPE_DOMINATED :
case EFFECT_TYPE_CUTSCENE_DOMINATED :
{
if(!GetCommandable(oCreature)) SetCommandable(TRUE, oCreature);
return FALSE;
@@ -213,6 +216,7 @@ int ai_Disabled(object oCreature)
case EFFECT_TYPE_CONFUSED :
case EFFECT_TYPE_FRIGHTENED :
case EFFECT_TYPE_PARALYZE :
case EFFECT_TYPE_CUTSCENE_PARALYZE :
case EFFECT_TYPE_TURNED :
case EFFECT_TYPE_CHARMED :
case EFFECT_TYPE_PETRIFY :

File diff suppressed because it is too large Load Diff

View File

@@ -8,55 +8,42 @@ int GetPosixTimestamp();
string GetCurrentDateTime();
*///////////////////////////////////////////////////////////////////////////////
// RETURNS a Timestamp in seconds since 1970-01-01.
int GetCurrentTimeInSeconds();
// RETURNS a formated date, good for timestamping logs and text.
// Returns a Timestamp in seconds since 1970-01-01.
int ai_GetCurrentTimeStamp();
// Returns a formated date, good for Dating logs and text.
string GetCurrentDateTime();
// Sends a server shutdown message 1800 seconds i.e 30 minutes before.
// nDuration is in seconds. i.e. one hours is 3600 defaults to 24 hours (86400).
// Should be put into the servers OnHeartBeat.
void CheckServerShutdownMessage(int nDuration = 86400);
/// Returns the current time formatted according to the provided sqlite date time format string.
/// Format string as used by sqlites STRFTIME().
/// Returns the current time in the requested format. Empty string on error.
string SQLite_GetFormattedSystemTime(string format);
/// Returns the number of milliseconds since midnight on January 1, 1970.
int SQLite_GetTimeMilliseconds();
/// Returns the date in the format (mm/dd/yyyy).
string SQLite_GetSystemDate();
/// Returns the current time in the format (24:mm:ss).
string SQLite_GetSystemTime();
int GetCurrentTimeInSeconds()
int ai_GetCurrentTimeStamp()
{
string stmt = "SELECT strftime('%s','now');";
sqlquery sqlQuery = SqlPrepareQueryObject(GetModule(), stmt);
SqlStep(sqlQuery);
return SqlGetInt(sqlQuery, 0);
sqlquery query = SqlPrepareQueryObject(GetModule(), "SELECT STRFTIME('%s', 'now')");
SqlStep(query);
return SqlGetInt(query, 0);
}
string GetCurrentDateTime()
{
string stmt = "SELECT datetime('now', 'localtime')";
sqlquery sqlQuery = SqlPrepareQueryObject(GetModule(), stmt);
sqlquery sqlQuery = SqlPrepareQueryObject(GetModule(), "SELECT datetime('now', 'localtime')");
SqlStep(sqlQuery);
return SqlGetString(sqlQuery, 0);
}
/// @addtogroup time Time
/// @brief Provides various time related functions.
/// @brief Returns the current time formatted according to the provided sqlite date time format string.
/// @param format Format string as used by sqlites STRFTIME().
/// @return The current time in the requested format. Empty string on error.
string SQLite_GetFormattedSystemTime(string format);
/// @return Returns the number of seconds since midnight on January 1, 1970.
int SQLite_GetTimeStamp();
/// @return Returns the number of milliseconds since midnight on January 1, 1970.
int SQLite_GetTimeMilliseconds();
/// @brief A millisecond timestamp
struct SQLite_MillisecondTimeStamp
{
int seconds; ///< Seconds since epoch
int milliseconds; ///< Milliseconds
};
/// @remark For mircosecond timestamps use NWNX_Utility_GetHighResTimeStamp().
/// @return Returns the number of milliseconds since midnight on January 1, 1970.
struct SQLite_MillisecondTimeStamp SQLite_GetMillisecondTimeStamp();
/// @brief Returns the current date.
/// @return The date in the format (mm/dd/yyyy).
string SQLite_GetSystemDate();
/// @brief Returns current time.
/// @return The current time in the format (24:mm:ss).
string SQLite_GetSystemTime();
/// @}
string SQLite_GetFormattedSystemTime(string format)
{
sqlquery query = SqlPrepareQueryObject(GetModule(), "SELECT STRFTIME(@format, 'now', 'localtime')");
@@ -64,27 +51,12 @@ string SQLite_GetFormattedSystemTime(string format)
SqlStep(query); // sqlite returns NULL for invalid format in STRFTIME()
return SqlGetString(query, 0);
}
int SQLite_GetTimeStamp()
{
sqlquery query = SqlPrepareQueryObject(GetModule(), "SELECT STRFTIME('%s', 'now')");
SqlStep(query);
return SqlGetInt(query, 0);
}
int SQLite_GetTimeMillisecond()
{
sqlquery query = SqlPrepareQueryObject(GetModule(), "select cast((julianday('now') - 2440587.5) * 86400 * 1000 as integer)");
SqlStep(query);
return SqlGetInt(query, 0);
}
struct SQLite_MillisecondTimeStamp SQLite_GetMillisecondTimeStamp()
{
sqlquery query = SqlPrepareQueryObject(GetModule(), "SELECT STRFTIME('%s', 'now'), SUBSTR(STRFTIME('%f', 'now'), 4)");
SqlStep(query);
struct SQLite_MillisecondTimeStamp t;
t.seconds = SqlGetInt(query, 0);
t.milliseconds = SqlGetInt(query, 1);
return t;
}
string SQLite_GetSystemDate()
{
return SQLite_GetFormattedSystemTime("%m/%d/%Y");

View File

@@ -92,18 +92,18 @@ void main()
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
}
else
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
if(AI_DEBUG) ai_Debug("0i_actions", "519", "Do ranged attack against nearest: " + GetName(oTarget) + "!");
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
@@ -133,7 +133,7 @@ void main()
{
oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER, AI_RANGE_MELEE, AI_ENEMY, bAlwaysAtk);
// If we didn't get a target then get any target within range.
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE, AI_ENEMY, bAlwaysAtk);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE, AI_ENEMY, bAlwaysAtk);
}
// If not then lets go find someone to attack!
else
@@ -141,7 +141,7 @@ void main()
// Get the nearest enemy.
oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_CASTER, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk);
// If we didn't get a target then get any target within range.
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk);
}
}
}

View File

@@ -92,18 +92,18 @@ void main()
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_WARRIOR);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
}
else
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_WARRIOR, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
if(AI_DEBUG) ai_Debug("0i_actions", "519", "Do ranged attack against nearest: " + GetName(oTarget) + "!");
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
@@ -133,7 +133,7 @@ void main()
{
oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_WARRIOR, AI_RANGE_MELEE, AI_ENEMY, bAlwaysAtk);
// If we didn't get a target then get any target within range.
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE, AI_ENEMY, bAlwaysAtk);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE, AI_ENEMY, bAlwaysAtk);
}
// If not then lets go find someone to attack!
else
@@ -141,7 +141,7 @@ void main()
// Get the nearest enemy.
oTarget = ai_GetNearestClassTarget(oCreature, AI_CLASS_TYPE_WARRIOR, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk);
// If we didn't get a target then get any target within range.
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_PERCEPTION, AI_ENEMY, bAlwaysAtk);
}
}
}

View File

@@ -55,12 +55,12 @@ void main()
if(oTarget == OBJECT_INVALID)
{
// Lets pick off the weakest targets.
if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature);
else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
else oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -52,12 +52,12 @@ void main()
if(oTarget == OBJECT_INVALID)
{
// Lets pick off the weakest targets.
if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature);
else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
else oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -72,12 +72,12 @@ void main()
if(oTarget == OBJECT_INVALID)
{
// Lets pick off the weakest targets.
if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature);
else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
else oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -61,7 +61,7 @@ void main()
if(ai_TryImprovedExpertiseFeat(oCreature)) return;
if(ai_TryExpertiseFeat(oCreature)) return;
// Lets get the strongest melee opponent in melee with us.
oTarget = ai_GetHighestCRTarget(oCreature, AI_RANGE_MELEE);
oTarget = ai_GetHighestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = oNearestEnemy;
// Use knockdown when appropriate and the target is not immune.
if(ai_TryKnockdownFeat(oCreature, oTarget)) return;

View File

@@ -24,12 +24,38 @@ void main()
nMaxLevel = ai_GetAssociateTalentMaxLevel(oCreature, nDifficulty);
}
// Skill, Class, Offensive AOE's, and Defensive talents.
object oTarget = OBJECT_INVALID;
// Get the Spell Level we should still cast before turning into our polymorph form.
int nSpellLevel = ai_GetHasPolymorphSelfFeat(oCreature);
int nMaxTalentLevel;
if(AI_DEBUG) ai_Debug("ai_a_druid", "31", "nSpellLevel: " + IntToString(nSpellLevel));
if(nDifficulty >= AI_COMBAT_MODERATE)
{
// *************************** SPELL TALENTS ***************************
if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING))
{
if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return;
if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return;
}
// ************************** CLASS FEATURES ***************************
if(ai_TrySummonAnimalCompanionTalent(oCreature)) return;
// *************************** SPELL TALENTS ***************************
if(ai_CheckForAssociateSpellTalent(oCreature, nInMelee, nMaxLevel)) return;
//************************** DEFENSIVE TALENTS ***************************
if(!ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING))
{
if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_MASTER)) oTarget = GetMaster(oCreature);
nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_SUMMON);
if(AI_DEBUG) ai_Debug("ai_a_druid", "47", "nMaxTalentLevel 'S' " + IntToString(nMaxTalentLevel));
if(nSpellLevel < nMaxTalentLevel &&
ai_UseCreatureTalent(oCreature, AI_TALENT_SUMMON, nInMelee, nMaxLevel, oTarget)) return;
nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_PROTECTION);
if(AI_DEBUG) ai_Debug("ai_a_druid", "51", "nMaxTalentLevel 'P' " + IntToString(nMaxTalentLevel));
if(nSpellLevel < nMaxTalentLevel &&
ai_UseCreatureTalent(oCreature, AI_TALENT_PROTECTION, nInMelee, nMaxLevel, oTarget)) return;
nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_ENHANCEMENT);
if(AI_DEBUG) ai_Debug("ai_a_druid", "55", "nMaxTalentLevel 'E' " + IntToString(nMaxTalentLevel));
if(nSpellLevel < nMaxTalentLevel &&
ai_UseCreatureTalent(oCreature, AI_TALENT_ENHANCEMENT, nInMelee, nMaxLevel, oTarget)) return;
}
}
// Offensive single target talents.
if(nDifficulty >= AI_COMBAT_EFFORTLESS)
@@ -37,16 +63,24 @@ void main()
// *************************** SPELL TALENTS ***************************
if(!ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING))
{
if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return;
if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return;
if(nInMelee > 0)
{
nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_TOUCH);
if(AI_DEBUG) ai_Debug("ai_druid", "69", "nMaxTalentLevel 'T' " + IntToString(nMaxTalentLevel));
if(nSpellLevel < nMaxTalentLevel &&
ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return;
}
nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_RANGED);
if(AI_DEBUG) ai_Debug("ai_druid", "74", "nMaxTalentLevel 'R' " + IntToString(nMaxTalentLevel));
if(nSpellLevel < nMaxTalentLevel &&
ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return;
}
if(nDifficulty >= AI_COMBAT_MODERATE && ai_TryPolymorphSelfFeat(oCreature)) return;
}
if(nDifficulty >= AI_COMBAT_MODERATE && ai_TryPolymorphSelfFeat(oCreature)) return;
//************************** SKILL FEATURES **************************
if(ai_TryAnimalEmpathy(oCreature)) return;
// PHYSICAL ATTACKS - Either we don't have talents or we are saving them.
// ************************** Ranged feat attacks **************************
object oTarget;
if(!ai_GetAIMode(oCreature, AI_MODE_STOP_RANGED) && ai_CanIUseRangedWeapon(oCreature, nInMelee))
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
@@ -56,12 +90,12 @@ void main()
if(oTarget == OBJECT_INVALID)
{
// Lets pick off the weakest targets.
if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature);
else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
else oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -51,12 +51,12 @@ void main()
if(oTarget == OBJECT_INVALID)
{
// Lets pick off the weakest targets.
if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature);
else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
else oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -60,8 +60,8 @@ void main()
{
oTarget = ai_GetFlankTarget(oCreature, AI_RANGE_MELEE);
}
// Ok we are in a serious fight so lets not give attack of opportunities.
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
// Ok we are in a serious fight so lets not give attacks of opportunities.
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
// If there are no enemies being attacked then lets stay back.
if(oTarget == OBJECT_INVALID)
@@ -83,10 +83,10 @@ void main()
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return;
oTarget = ai_GetLowestCRTarget(oCreature);
oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}
@@ -98,6 +98,12 @@ void main()
return;
}
}
// Make sure we are not the only one here. Moving around looks funny when we are by ourselves.
else if(ai_GetNearestAlly(oCreature, 1, 7, 7) == OBJECT_INVALID)
{
oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
}
}
if(oTarget != OBJECT_INVALID)
{

View File

@@ -75,12 +75,12 @@ void main()
if(oTarget == OBJECT_INVALID)
{
// Lets pick off the weakest targets.
if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature);
else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
else oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -52,12 +52,12 @@ void main()
if(oTarget == OBJECT_INVALID)
{
// Lets pick off the weakest targets.
if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature);
else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
else oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -91,17 +91,17 @@ void main()
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
}
else
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
if(AI_DEBUG) ai_Debug("ai_a_no_modes", "105", GetName(OBJECT_SELF) + " does ranged attack on weakest: " + GetName(oTarget) + "!");
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;

View File

@@ -73,12 +73,12 @@ void main()
if(oTarget == OBJECT_INVALID)
{
// Paladins face off against the strongest opponents first.
if(!nInMelee) oTarget = ai_GetHighestCRTarget(oCreature);
else oTarget = ai_GetHighestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetHighestCRPhysicalTarget(oCreature);
else oTarget = ai_GetHighestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -8,16 +8,21 @@
// Programmer: Philos
//////////////////////////////////////////////////////////////////////////////////////////////////////
#include "0i_actions"
void ai_DoActions(object oCreature, int nForm)
void main()
{
object oCreature = OBJECT_SELF;
int nInMelee = ai_GetNumOfEnemiesInRange(oCreature);
object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST);
if(ai_TryHealingTalent(oCreature, nInMelee)) return;
if(ai_TryCureConditionTalent(oCreature, nInMelee)) return;
if(GetPercentageHPLoss(oCreature) <= AI_HEALTH_BLOODY)
{
//ai_Debug("ai_a_polymorphed", "24", "We are wounded and are transforming back!");
if(AI_DEBUG) ai_Debug("ai_a_polymorphed", "20", "We are wounded and are transforming back!");
ai_RemoveASpecificEffect(oCreature, EFFECT_TYPE_POLYMORPH);
DeleteLocalInt(oCreature, AI_POLYMORPHED);
// We need to create the creatures normal forms talent list.
DelayCommand(0.0, ai_ClearTalents(oCreature));
DelayCommand(0.1, ai_SetCreatureTalents(oCreature, FALSE, TRUE));
return;
}
int nDifficulty = ai_GetDifficulty(oCreature);
@@ -51,20 +56,3 @@ void ai_DoActions(object oCreature, int nForm)
if(oTarget != OBJECT_INVALID) ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
else ai_SearchForHiddenCreature(oCreature, FALSE);
}
void main()
{
object oCreature = OBJECT_SELF;
// Need to know who we are so we can use thier abilities.
int nForm = GetAppearanceType(oCreature);
// Check to see if we are back to our normal form?(-1 to get the actual form #)
if(nForm == GetLocalInt(oCreature, AI_NORMAL_FORM) - 1)
{
// If we are transformed back then go back to our primary ai.
ai_SetCreatureAIScript(oCreature);
DeleteLocalInt(oCreature, AI_NORMAL_FORM);
string sAI = GetLocalString(oCreature, AI_COMBAT_SCRIPT);
if(sAI == "ai_a_polymorphed" || sAI == "") sAI = "ai_a_default";
ExecuteScript(sAI, oCreature);
}
else ai_DoActions(oCreature, nForm);
}

View File

@@ -68,17 +68,17 @@ void main()
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget == ai_GetRangedTarget(oCreature);
if(oTarget == OBJECT_INVALID && ai_TryRangedSneakAttack(oCreature, nInMelee)) return;
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
}
else
{
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}
@@ -88,7 +88,30 @@ void main()
return;
}
}
else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return;
else
{
if(ai_InCombatEquipBestRangedWeapon(oCreature)) return;
oTarget = ai_GetEnemyAttackingMe(oCreature);
if(oTarget != OBJECT_INVALID)
{
if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return;
if(ai_TrySneakAttack(oCreature, nInMelee)) return;
if(ai_TryWhirlwindFeat(oCreature)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
return;
}
else
{
oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryMeleeTalents(oCreature, oTarget)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
return;
}
}
}
}
}
// ************************** Melee feat attacks *************************
@@ -102,7 +125,12 @@ void main()
if(ai_TrySneakAttack(oCreature, nInMelee)) return;
if(ai_TryWhirlwindFeat(oCreature)) return;
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
return;
}
else
{
oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee);
if(oTarget != OBJECT_INVALID)
{

View File

@@ -59,17 +59,17 @@ void main()
if(!nInMelee)
{
oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
}
else
{
oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -52,12 +52,12 @@ void main()
{
if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return;
// Lets pick off the weakest targets.
if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature);
else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
else oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -50,8 +50,8 @@ void main()
if(oTarget == OBJECT_INVALID)
{
// Lets pick off the weakest targets.
if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature);
else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
else oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{

View File

@@ -52,8 +52,8 @@ void main()
if(oTarget == OBJECT_INVALID)
{
// Lets pick off the weakest targets.
if(!nInMelee) oTarget = ai_GetLowestCRTarget(oCreature);
else oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
else oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{

View File

@@ -41,11 +41,11 @@ void main()
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature);
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -39,11 +39,11 @@ void main()
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature);
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -0,0 +1,38 @@
/*////////////////////////////////////////////////////////////////////////////////////////////////////
// Script Name: ai_bloodmane
//////////////////////////////////////////////////////////////////////////////////////////////////////
AI combat action scripts for Bloodmane - Orc Warlord(Barbarian - Example).
To use this AI set the variable string "AI_DEFAULT_SCRIPT" to "ai_bloodmane" on the creature.
*/////////////////////////////////////////////////////////////////////////////////////////////////////
// Programmer: Philos
//////////////////////////////////////////////////////////////////////////////////////////////////////
#include "0i_actions"
void main()
{
object oCreature = OBJECT_SELF;
//**************************************************************************
//************************ START SPECIAL AI SCRIPTS ************************
//**************************************************************************
int nRound = ai_GetCurrentRound(oCreature);
// First round cuss and animate!
if(nRound == 1)
{
// Make him taunt the player!
ActionPlayAnimation(ANIMATION_FIREFORGET_TAUNT);
PlayVoiceChat(Random(4), oCreature);
}
// Second round go into a Rage.
else if(nRound == 2)
{
// Use Rage!
if(ai_TryBarbarianRageFeat(oCreature)) return;
// If for some reason he doesn't have a rage then charge into melee!
object oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, ai_GetNumOfEnemiesInRange(oCreature));
if(oTarget != OBJECT_INVALID) ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
// Change Bloodmane's ai to Barbarian since we are done with his special ai.
SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_barbarian");
}
//**************************************************************************
//************************ END SPECIAL AI SCRIPTS **************************
//**************************************************************************
}

View File

@@ -41,8 +41,8 @@ void main()
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature);
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);

View File

@@ -0,0 +1,103 @@
/*////////////////////////////////////////////////////////////////////////////////////////////////////
// Script Name: ai_dragon_boss
//////////////////////////////////////////////////////////////////////////////////////////////////////
ai script a unique dragon that lives deep in a dark cave using it as a defense.
OBJECT_SELF is the dragon running the ai.
*/////////////////////////////////////////////////////////////////////////////////////////////////////
// Programmer: Philos
//////////////////////////////////////////////////////////////////////////////////////////////////////
#include "0i_actions"
void main()
{
object oCreature = OBJECT_SELF;
// Get the number of enemies that we are in melee combat with.
int nInMelee = ai_GetNumOfEnemiesInRange(oCreature);
//**************************************************************************
//************************ ROUND BASED AI SCRIPTS *************************
//**************************************************************************
int nRound = ai_GetCurrentRound(oCreature);
// First time fly to our enemy, the rest of combat lets not do that!
object oTarget;
if(!GetLocalInt(OBJECT_SELF, "AI_DONE_FLYING"))
{
SetLocalInt(OBJECT_SELF, "AI_DONE_FLYING", TRUE);
oTarget = ai_GetLowestCRTarget(oCreature);
// We assign the voice to the PC so they get to hear it.
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
AssignCommand(oPC, PlaySound("vs_ndredm_bat2"));
// Can we do a crush attack(HD 18+)?
if(ai_TryCrushAttack(oCreature, oTarget)) return;
ai_FlyToTarget(oCreature, oTarget);
return;
}
else if(nRound == 2)
{
oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_CLOSE);
ai_TryDragonBreathAttack(oCreature, nRound, oTarget);
return;
}
//*************************** HEALING & CURES ****************************
if(ai_TryHealingTalent(oCreature, nInMelee)) return;
if(ai_TryCureConditionTalent(oCreature, nInMelee)) return;
// Check to see if we need to retreat to get healing.
int nPercentageHP = ai_GetPercHPLoss(oCreature);
//ai_Debug("ai_dragon_boss", "43", "nPercentageHP: " + IntToString(nPercentageHP));
if(nPercentageHP < 75 && !GetLocalInt(oCreature, "AI_HOME"))
{
string sWaypoint;
// If we are below half then go to last defensive position.
if(nPercentageHP < 50)
{
SetLocalInt(oCreature, "AI_HOME", TRUE);
sWaypoint = "0_wp_dragon2";
}
// else we just go back a little bit to heal up.
else sWaypoint = "0_wp_dragon1";
if(!GetLocalInt(oCreature, sWaypoint))
{
string sVoice;
switch(d6())
{
case 1 :
case 2 : sVoice = "vs_ndredm_attk"; break;
case 3 :sVoice = "vs_ndredm_heal"; break;
case 4 :sVoice = "vs_ndredm_help"; break;
case 5 :sVoice = "vs_ndredm_no"; break;
case 6 :sVoice = "vs_ndredm_bat3"; break;
}
SetImmortal(oCreature, TRUE);
DelayCommand(6.0f, SetImmortal(oCreature, FALSE));
AssignCommand(ai_GetNearestTarget(oCreature), PlaySound(sVoice));
object oWaypoint = GetNearestObjectByTag(sWaypoint);
//ai_Debug("ai_dragon_boss", "71", "Flying to " + sWaypoint + ".");
effect eFly = EffectDisappearAppear(GetLocation(oWaypoint));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFly, oCreature, 6.0f);
SetLocalInt(oCreature, sWaypoint, TRUE);
return;
}
}
int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature);
//******************* OFFENSIVE AREA OF EFFECT TALENTS *******************
// Check the battlefield for a group of enemies to shoot a big talent at!
// We are checking here since these opportunities are rare and we need
// to take advantage of them as often as possible.
if(ai_UseCreatureTalent(oCreature, AI_TALENT_INDISCRIMINANT_AOE, nInMelee, nMaxLevel)) return;
if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return;
//************************** DEFENSIVE TALENTS ***************************
if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return;
//********************** OFFENSIVE TARGETED TALENTS **********************
// Look for a touch attack since we are in melee.
if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return;
if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return;
// ************************ MELEE ATTACKS ********************************
oTarget = ai_GetLowestCRTargetForMeleeCombat(oCreature, nInMelee);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryDragonBreathAttack(oCreature, nRound)) return;
ai_TryWingAttacks(oCreature);
// If we don't do a Tail sweep attack(HD 30+) then see if we can do a Tail slap(HD 12+)!
if(!ai_TryTailSweepAttack(oCreature)) ai_TryTailSlap(oCreature);
ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
}
else ai_SearchForHiddenCreature(oCreature, TRUE);
}

View File

@@ -24,14 +24,36 @@ void main()
if(ai_UseCreatureTalent(oCreature, AI_TALENT_DISCRIMINANT_AOE, nInMelee, nMaxLevel)) return;
//**************************** CLASS FEATURES ****************************
if(GetLocalInt(GetModule(), AI_RULE_SUMMON_COMPANIONS) && ai_TrySummonAnimalCompanionTalent(oCreature)) return;
if(ai_TryPolymorphSelfFeat(oCreature)) return;
//************************** DEFENSIVE TALENTS ***************************
int nRound = ai_GetCurrentRound(oCreature);
if(ai_TryDefensiveTalents(oCreature, nInMelee, nMaxLevel, nRound)) return;
// Get the Spell Level we should still cast before turning into our polymorph form.
int nSpellLevel = ai_GetHasPolymorphSelfFeat(oCreature);
if(AI_DEBUG) ai_Debug("ai_druid", "30", "nSpellLevel: " + IntToString(nSpellLevel));
int nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_SUMMON);
if(AI_DEBUG) ai_Debug("ai_druid", "32", "nMaxTalentLevel 'S' " + IntToString(nMaxTalentLevel));
if(nSpellLevel < nMaxTalentLevel &&
ai_UseCreatureTalent(oCreature, AI_TALENT_SUMMON, nInMelee, nMaxLevel)) return;
nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_PROTECTION);
if(AI_DEBUG) ai_Debug("ai_druid", "36", "nMaxTalentLevel 'P' " + IntToString(nMaxTalentLevel));
if(nSpellLevel < nMaxTalentLevel &&
ai_UseCreatureTalent(oCreature, AI_TALENT_PROTECTION, nInMelee, nMaxLevel)) return;
nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_ENHANCEMENT);
if(AI_DEBUG) ai_Debug("ai_druid", "40", "nMaxTalentLevel 'E' " + IntToString(nMaxTalentLevel));
if(nSpellLevel < nMaxTalentLevel &&
ai_UseCreatureTalent(oCreature, AI_TALENT_ENHANCEMENT, nInMelee, nMaxLevel)) return;
//********************** OFFENSIVE TARGETED TALENTS **********************
// Look for a touch attack since we are in melee.
if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return;
if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return;
if(nInMelee > 0)
{
nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_TOUCH);
if(AI_DEBUG) ai_Debug("ai_druid", "48", "nMaxTalentLevel 'T' " + IntToString(nMaxTalentLevel));
if(nSpellLevel < nMaxTalentLevel &&
ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return;
}
nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_RANGED);
if(AI_DEBUG) ai_Debug("ai_druid", "53", "nMaxTalentLevel 'R' " + IntToString(nMaxTalentLevel));
if(nSpellLevel < nMaxTalentLevel &&
ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return;
if(ai_TryPolymorphSelfFeat(oCreature)) return;
//**************************** SKILL FEATURES ****************************
if(ai_TryAnimalEmpathy(oCreature)) return;
// All else fails lets see if we have any good potions.
@@ -43,10 +65,11 @@ void main()
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
// Lets pick off the nearest targets.
if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature);
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -36,11 +36,11 @@ void main()
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature);
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}
@@ -54,7 +54,7 @@ void main()
}
// **************************** MELEE ATTACKS ****************************
if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return;
if(ai_TryWhirlwindFeat (oCreature)) return;
if(ai_TryWhirlwindFeat(oCreature)) return;
oTarget = ai_GetNearestTargetForMeleeCombat (oCreature, nInMelee);
if (oTarget != OBJECT_INVALID)
{

View File

@@ -53,7 +53,7 @@ void main()
oTarget = ai_GetFlankTarget(oCreature, AI_RANGE_MELEE);
}
// Ok we are in a serious fight so lets not give attack of opportunities.
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
// If there are no enemies being attacked then lets stay back.
if(oTarget == OBJECT_INVALID)
@@ -75,10 +75,10 @@ void main()
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if(ai_TryRangedSneakAttack(oCreature, nInMelee)) return;
oTarget = ai_GetNearestTarget(oCreature);
oTarget = ai_GetNearestPhysicalTarget(oCreature);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -44,8 +44,8 @@ void main()
{
if (ai_TryRangedSneakAttack (oCreature, nInMelee)) return;
string sIndex;
if (!nInMelee) oTarget = ai_GetNearestTarget(oCreature);
else oTarget = ai_GetNearestTarget (oCreature, AI_RANGE_MELEE);
if (!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget (oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat (oCreature, oTarget, nInMelee)) return;
@@ -63,19 +63,21 @@ void main()
// ************************* MELEE ATTACKS *******************************
if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return;
oTarget = ai_GetNearestTargetForMeleeCombat (oCreature, nInMelee);
if (oTarget != OBJECT_INVALID)
if(oTarget != OBJECT_INVALID)
{
// If we are using our hands then do a touch attack instead.
if (GetItemInSlot (INVENTORY_SLOT_RIGHTHAND) == OBJECT_INVALID)
if(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND) == OBJECT_INVALID)
{
if (GetItemInSlot (INVENTORY_SLOT_CWEAPON_L) != OBJECT_INVALID)
// If they don't have a claw then we need to do a special attack instead.
if(GetItemInSlot(INVENTORY_SLOT_CWEAPON_L) != OBJECT_INVALID)
{
// Randomize so they don't appear synchronized.
float fDelay = IntToFloat(Random(2) + 1);
DelayCommand(fDelay, ActionCastSpellAtObject (769/*Shadow_Attack*/, oTarget, METAMAGIC_ANY, TRUE));
ai_SetLastAction(oCreature, AI_LAST_ACTION_MELEE_ATK);
SetLocalObject (oCreature, AI_ATTACKED_PHYSICAL, oTarget);
SetLocalObject(oCreature, AI_ATTACKED_PHYSICAL, oTarget);
}
else ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
}
else ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
}

View File

@@ -47,11 +47,11 @@ void main()
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature);
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -38,8 +38,8 @@ void main()
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if (!nInMelee) oTarget = ai_GetNearestTarget (oCreature);
else oTarget = ai_GetNearestTarget (oCreature, AI_RANGE_MELEE);
if (!nInMelee) oTarget = ai_GetNearestPhysicalTarget (oCreature);
else oTarget = ai_GetNearestPhysicalTarget (oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);

View File

@@ -43,8 +43,8 @@ void main()
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
// Paladins face the biggest challenges first!
if(!nInMelee) oTarget = ai_GetHighestCRTarget(oCreature);
else oTarget = ai_GetHighestCRTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetHighestCRPhysicalTarget(oCreature);
else oTarget = ai_GetHighestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);

View File

@@ -8,16 +8,21 @@
// Programmer: Philos
//////////////////////////////////////////////////////////////////////////////////////////////////////
#include "0i_actions"
void ai_DoActions(object oCreature, int nForm)
void main()
{
object oCreature = OBJECT_SELF;
int nInMelee = ai_GetNumOfEnemiesInRange(oCreature);
object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST);
if(ai_TryHealingTalent(oCreature, nInMelee)) return;
if(ai_TryCureConditionTalent(oCreature, nInMelee)) return;
if(GetPercentageHPLoss(oCreature) <= AI_HEALTH_BLOODY)
{
if(AI_DEBUG) ai_Debug("ai_polymorphed", "19", "We are wounded and are transforming back!");
if(AI_DEBUG) ai_Debug("ai_polymorphed", "20", "We are wounded and are transforming back!");
ai_RemoveASpecificEffect(oCreature, EFFECT_TYPE_POLYMORPH);
DeleteLocalInt(oCreature, AI_POLYMORPHED);
// We need to create the creatures normal forms talent list.
DelayCommand(0.0, ai_ClearTalents(oCreature));
DelayCommand(0.1, ai_SetCreatureTalents(oCreature, TRUE, TRUE));
return;
}
int nMaxLevel = ai_GetMonsterTalentMaxLevel(oCreature);
@@ -31,25 +36,30 @@ void ai_DoActions(object oCreature, int nForm)
if(nInMelee > 0 && ai_UseCreatureTalent(oCreature, AI_TALENT_TOUCH, nInMelee, nMaxLevel)) return;
if(ai_UseCreatureTalent(oCreature, AI_TALENT_RANGED, nInMelee, nMaxLevel)) return;
// PHYSICAL ATTACKS - Either we don't have talents or we are saving them.
object oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee);
// If we don't find a target then we don't want to fight anyone!
// *************************** RANGED ATTACKS ****************************
object oTarget;
if(ai_CanIUseRangedWeapon(oCreature, nInMelee))
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if(!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}
else
{
ai_SearchForHiddenCreature(oCreature, TRUE);
return;
}
}
else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return;
}
// **************************** MELEE ATTACKS ****************************
oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee);
if(oTarget != OBJECT_INVALID) ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
else ai_SearchForHiddenCreature(oCreature, TRUE);
}
void main()
{
object oCreature = OBJECT_SELF;
// Need to know who we are so we can use thier abilities.
int nForm = GetAppearanceType(oCreature);
// Check to see if we are back to our normal form?(-1 to get the actual form #)
if(nForm == GetLocalInt(oCreature, AI_NORMAL_FORM) - 1)
{
// If we are transformed back then go back to our primary ai.
ai_SetCreatureAIScript(oCreature);
DeleteLocalInt(oCreature, AI_NORMAL_FORM);
string sAI = GetLocalString(oCreature, AI_COMBAT_SCRIPT);
if(sAI == "ai_polymorphed" || sAI == "") sAI = "ai_default";
ExecuteScript(sAI, oCreature);
}
else ai_DoActions(oCreature, nForm);
}

View File

@@ -59,16 +59,16 @@ void main()
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget == ai_GetRangedTarget(oCreature);
if(oTarget == OBJECT_INVALID && ai_TryRangedSneakAttack(oCreature, nInMelee)) return;
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature);
}
else
{
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}
@@ -78,7 +78,30 @@ void main()
return;
}
}
else if(ai_InCombatEquipBestRangedWeapon(oCreature)) return;
else
{
if(ai_InCombatEquipBestRangedWeapon(oCreature)) return;
oTarget = ai_GetEnemyAttackingMe(oCreature);
if(oTarget != OBJECT_INVALID)
{
if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return;
if(ai_TrySneakAttack(oCreature, nInMelee)) return;
if(ai_TryWhirlwindFeat(oCreature)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
return;
}
else
{
oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryMeleeTalents(oCreature, oTarget)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
return;
}
}
}
}
// ************************** Melee feat attacks *************************
object oNearestEnemy = GetLocalObject(oCreature, AI_ENEMY_NEAREST);
@@ -90,7 +113,12 @@ void main()
if(ai_InCombatEquipBestMeleeWeapon(oCreature)) return;
if(ai_TrySneakAttack(oCreature, nInMelee)) return;
if(ai_TryWhirlwindFeat(oCreature)) return;
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
ai_ActionAttack(oCreature, AI_LAST_ACTION_MELEE_ATK, oTarget);
return;
}
else
{
oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTargetForMeleeCombat(oCreature, nInMelee);
if(oTarget != OBJECT_INVALID)
{

View File

@@ -45,16 +45,16 @@ void main()
if(!nInMelee)
{
oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature);
}
else
{
oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
}
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -38,7 +38,7 @@ void main()
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if (ai_TryRangedSneakAttack (oCreature, nInMelee)) return;
oTarget = ai_GetNearestTarget (oCreature);
oTarget = ai_GetNearestPhysicalTarget (oCreature);
if(oTarget != OBJECT_INVALID)
{
if (ai_TryRapidShotFeat (oCreature, oTarget, nInMelee)) return;

View File

@@ -38,11 +38,11 @@ void main()
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
string sIndex;
if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature);
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -37,8 +37,8 @@ void main()
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature);
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);

View File

@@ -49,11 +49,11 @@ void main()
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if (!nInMelee) oTarget = ai_GetNearestTarget (oCreature);
else oTarget = ai_GetNearestTarget (oCreature, AI_RANGE_MELEE);
if (!nInMelee) oTarget = ai_GetNearestPhysicalTarget (oCreature);
else oTarget = ai_GetNearestPhysicalTarget (oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
return;
}

View File

@@ -39,8 +39,8 @@ void main()
{
if(ai_HasRangedWeaponWithAmmo(oCreature))
{
if(!nInMelee) oTarget = ai_GetNearestTarget(oCreature);
else oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
if(!nInMelee) oTarget = ai_GetNearestPhysicalTarget(oCreature);
else oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
if(oTarget != OBJECT_INVALID)
{
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);

View File

@@ -3,7 +3,7 @@
int StartingUp(object oPC);
json ai_CheckToReplaceSpell(json jSpellList, int nClass, int nLevel, int nSlot)
{
//if(d100() > 49) return jSpellList;
if(d100() > 49) return jSpellList;
string sSpellTableColumn = Get2DAString("classes", "SpellTableColumn", nClass);
int nRoll = d10() + 1 + nLevel * 10;
int nSpell = StringToInt(Get2DAString("prc_add_spells", sSpellTableColumn, nRoll));

View File

@@ -35,6 +35,7 @@ void main()
}
}
// Send the user-defined event signal if specified here so it doesn't get skipped.
//SendMessageToPC(GetFirstPC(), "HB_EVENT: " + IntToString(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT)));
if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))
{
SignalEvent(oCreature, EventUserDefined(EVENT_HEARTBEAT));
@@ -76,17 +77,9 @@ void main()
ai_ClearBuffTargets(oCreature, "AI_ALLY_TARGET_");
}
}
if(!IsInConversation (oCreature))
{
if(GetWalkCondition(NW_WALK_FLAG_CONSTANT)) WalkWayPoints();
if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS)) PlayMobileAmbientAnimations_NonAvian();
else if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN)) PlayMobileAmbientAnimations_Avian();
else if(GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS)) PlayImmobileAmbientAnimations();
else if(GetLocalInt(GetModule(), AI_RULE_WANDER) && GetStandardFactionReputation(STANDARD_FACTION_HOSTILE, oCreature) > 89)
{
ai_AmbientAnimations();
}
}
if(ai_TryHealing(oCreature, oCreature)) return;
// This is where PEPS passes control to either the Bioware Waypoint system and
// AmbientAnimation scripts. A Persistent World can write there own scripts in 0e_animations.
ExecuteScript("0e_animations", oCreature);
}

View File

@@ -22,7 +22,7 @@ void main()
" Current action: " + IntToString(GetCurrentAction(oCreature)));
if(GetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT))
{
SignalEvent(OBJECT_SELF, EventUserDefined(1003));
SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_END_COMBAT_ROUND));
}
if(ai_Disabled(oCreature)) return;
// Action modes get cleared prior to each OnCombatRoundEnd!
@@ -59,7 +59,7 @@ void main()
}
if(ai_GetIsInCombat(oCreature))
{
ai_DoAssociateCombatRound (oCreature);
ai_DoMonsterCombatRound (oCreature);
return;
}
if(ai_GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) ai_DetermineSpecialBehavior(oCreature);

View File

@@ -12,6 +12,7 @@ void ai_MonsterCommands(object oCreature, object oSpeaker, int nMatch);
void main()
{
object oCreature = OBJECT_SELF;
object oLastSpeaker = GetLastSpeaker();
ExecuteScript("prc_npc_conv", oCreature);
if(AI_DEBUG) ai_Debug("nw_c2_default4", "15", GetName(oCreature) + " listens " +
IntToString(GetListenPatternNumber()) + " to " + GetName(GetLastSpeaker()) + "." +
@@ -22,7 +23,7 @@ void main()
ai_DoMonsterCombatRound(oCreature);
return;
}
object oLastSpeaker = GetLastSpeaker();
//object oLastSpeaker = GetLastSpeaker();
int nMatch = GetListenPatternNumber();
if(nMatch != -1)
{

View File

@@ -59,6 +59,8 @@ void main()
string sAssociateType = ai_GetAssociateType(oMaster, oCreature);
ai_CheckAssociateData(oMaster, oCreature, sAssociateType);
ai_CheckPCStart(oMaster);
// When a henchman dies and is brought back the plot flag can be set to TRUE!
SetPlotFlag(oCreature, FALSE);
if(AI_HENCHMAN_WIDGET)
{
// This keeps widgets from disappearing and reappearing.

View File

@@ -37,6 +37,14 @@ void main()
case ACTION_CASTSPELL :
case ACTION_ITEMCASTSPELL :
case ACTION_COUNTERSPELL : return;
case ACTION_ATTACKOBJECT :
{
if(!ai_GetIsInCombat(oCreature))
{
ai_ClearCreatureActions();
return;
}
}
// Might be doing a special action that is not a defined action.
case ACTION_INVALID :
{

View File

@@ -27,7 +27,10 @@ void main()
int nSpell = GetLastSpell();
if(AI_DEBUG) ai_Debug("nw_ch_acb", "21", GetName(OBJECT_SELF) + " has been hit by a harmful spell(" +
Get2DAString("spells", "Label", nSpell) + ")!");
if(ai_GetInAOEReaction(oCreature, oCaster, nSpell) &&
object oMaster = GetMaster(oCreature);
if((!GetLocalInt(oMaster, AI_TARGET_MODE_ON) ||
GetLocalObject(oMaster, AI_TARGET_MODE_ASSOCIATE) != oCreature) &&
ai_GetInAOEReaction(oCreature, oCaster, nSpell) &&
ai_IsInADangerousAOE(oCreature, AI_RANGE_BATTLEFIELD, TRUE)) return;
if(ai_GetIsBusy(oCreature)) return;
if(ai_CheckForCombat(oCreature, FALSE)) return;

View File

@@ -26,73 +26,82 @@ json GetBuffDatabaseJson(object oPlayer, string sDataField, string sTag = "");
// Returns the level if this spell has a domain spell on nLevel, or 0.
int GetHasDomainSpell(object oCaster, int nClass, int nLevel, int nSpell);
// We do some crazy hack to get all the correct information when casting spells.
// GetLastSpellCastClass() will only give the class if this script is running
// on the actual caster, i.e. our PC.
// GetLastSpellLevel() will only give the level if this script is running on
// the actual caster, i.e. our PC.
// So for this to work we run this scrip in the event OnSpellCastAt of our
// target, then we ExecuteScript this script again with the Caster (oPC)
// as OBJECT_SELF for this script on its second pass. This allows us to get the
// information from the above functions! Neat!
void main()
{
object oTarget = OBJECT_SELF;
// The first pass we get oCaster via GetLastSpellCaster() fails in ExecuteScript!
// The second pass we get oCaster via the variable "AI_BUFF_CASTER".
object oCaster = GetLocalObject(oTarget, "AI_BUFF_CASTER");
if(oCaster == OBJECT_INVALID) oCaster = GetLastSpellCaster();
// We setting up the save spells button we saved the PC to itself.
// Here we get the PC to make sure the caster of this spell is our saving PC.
object oPC = GetLocalObject(oCaster, "AI_BUFF_PC");
// The first pass we get nspell via GetLastSpell() fails in ExecuteScript!
// The second pass we get nSpell via the variable "AI_BUFF_SPELL".
int nSpell = GetLocalInt(oTarget, "AI_BUFF_SPELL");
if(nSpell == 0) nSpell = GetLastSpell();
// If this is a harful spell or The caster does not equal our saving PC then
// we need to fix the targets scripts back and run the correct OnSpellCastAt script.
if(GetLastSpellHarmful() || oPC != oCaster)
object oCaster = GetLastSpellCaster();
// When setting up the save spells button we saved the PC to itself.
// Here we get the PC from either our henchmen or ourselves.
// We do this to make sure that this PC and henchmen are the ones saving spells.
object oPC = GetLocalObject(ai_GetPlayerMaster(oCaster), "AI_BUFF_PC");
// If this is a harmful spell or we couldn't find oPC then we need to fix
// the targets scripts back and run the correct OnSpellCastAt script.
if(GetLastSpellHarmful() || oPC == OBJECT_INVALID)
{
string sScript = GetLocalString(oTarget, "AI_BUFF_CAST_AT_SCRIPT");
SetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript);
DeleteLocalObject(oPC, "AI_BUFF_PC");
string sScript = GetLocalString(oPC, "AI_BUFF_CAST_AT_SCRIPT");
SetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript);
DeleteLocalString(oPC, "AI_BUFF_CAST_AT_SCRIPT");
// Cleanup your followers to allow spells to be reacted to as normal.
int nAssociateType = 2;
object oAssociate = GetAssociate(nAssociateType, oPC);
while(nAssociateType < 5)
{
if(oAssociate != OBJECT_INVALID)
{
sScript = GetLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript);
DeleteLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT");
}
oAssociate = GetAssociate(++nAssociateType, oPC);
}
int nIndex = 1;
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
while(nIndex <= AI_MAX_HENCHMAN)
{
if(oAssociate != OBJECT_INVALID)
{
sScript = GetLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT");
SetEventScript(oAssociate, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT, sScript);
DeleteLocalString(oAssociate, "AI_BUFF_CAST_AT_SCRIPT");
}
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, ++nIndex);
}
NuiSetBind(oPC, NuiFindWindow(oPC, "widgetbuffwin"), "btn_save", JsonBool(FALSE));
ai_SendMessages("Saving spells to the list has been turned off.", AI_COLOR_YELLOW, oPC);
ExecuteScript(sScript, oTarget);
return;
}
// If the oTarget != oCaster then we are casting a spell on one of our
// associates. We must make a second pass to get the correct information.
// We do this by saving the Target, Caster, and Spell so we can get them
// in the second pass as Execute Script makes them impossible to get on a
// second pass.
if(oTarget != oCaster)
{
SetLocalObject(oPC, "AI_BUFF_TARGET", oTarget);
SetLocalObject(oPC, "AI_BUFF_CASTER", oCaster);
SetLocalInt(oPC, "AI_BUFF_SPELL", nSpell);
ExecuteScript("pc_savebuffs", oPC);
return;
}
// If this is the first pass and we get here then oCaster is casting a spell
// on themselves. So oTarget will be invalid and we should use oPC.
// If this is the second pass and we get here then we have saved oTarget
// to oPC and this will get them so we can save the target to the spell!
oTarget = GetLocalObject(oPC, "AI_BUFF_TARGET");
if(oTarget == OBJECT_INVALID) oTarget = oPC;
// We need to clean up this mess!
DeleteLocalObject(oPC, "AI_BUFF_TARGET");
DeleteLocalObject(oPC, "AI_BUFF_CASTER");
DeleteLocalInt(oPC, "AI_BUFF_SPELL");
// This blocks one spell from saving multiple times due to being an AOE.
if(GetLocalInt(oPC, "AI_ONLY_ONE")) return;
SetLocalInt(oPC, "AI_ONLY_ONE", TRUE);
// We delay this for just less than half a round due to haste.
DelayCommand(2.5, DeleteLocalInt(oPC, "AI_ONLY_ONE"));
// Here is the whole problem and why we must do a second pass if the target
// is not the caster. These only work if this script is run by the caster.
int nClass = GetLastSpellCastClass();
int nLevel = GetLastSpellLevel();
// Everything below saves the spell to the database with all our now correct info.
int nDomain = GetHasDomainSpell(oPC, nClass, nLevel, nSpell);
int nMetaMagic = GetMetaMagicFeat();
// If the oTarget != oCaster then we are casting a spell on one of our
// associates. Some functions expect OBJECT_SELF to be the caster.
// We get around that by doing some ExecuteScriptChunk shenanigans.
int nClass, nLevel, nMetaMagic;
if(oTarget != oCaster)
{
// These functions need the caster to be OBJECT_SELF so lets do a HACK!
ExecuteScriptChunk("SetLocalInt(OBJECT_SELF, \"AI_BUFF_CASTCLASS\", GetLastSpellCastClass());", oCaster);
ExecuteScriptChunk("SetLocalInt(OBJECT_SELF, \"AI_BUFF_SPELLLEVEL\", GetLastSpellLevel());", oCaster);
ExecuteScriptChunk("SetLocalInt(OBJECT_SELF, \"AI_BUFF_METAMAGIC\", GetMetaMagicFeat());", oCaster);
nClass = GetLocalInt(oCaster, "AI_BUFF_CASTCLASS");
nLevel = GetLocalInt(oCaster, "AI_BUFF_SPELLLEVEL");
nMetaMagic = GetLocalInt(oCaster, "AI_METAMAGIC");
DeleteLocalInt(oCaster, "AI_BUFF_CASTCLASS");
DeleteLocalInt(oCaster, "AI_BUFF_SPELLLEVEL");
DeleteLocalInt(oCaster, "AI_BUFF_METAMAGIC");
}
else
{
nClass = GetLastSpellCastClass();
nLevel = GetLastSpellLevel();
nMetaMagic = GetMetaMagicFeat();
}
int nSpell = GetLastSpell();
int nDomain = GetHasDomainSpell(oCaster, nClass, nLevel, nSpell);
string sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
if(nDomain) sName += " [Domain]";
if(nMetaMagic > 0 && StringToInt(Get2DAString("classes", "MemorizesSpells", nClass)))
@@ -114,11 +123,13 @@ void main()
jSpell = JsonArrayInsert(jSpell, JsonInt(nLevel));
jSpell = JsonArrayInsert(jSpell, JsonInt(nMetaMagic));
jSpell = JsonArrayInsert(jSpell, JsonInt(nDomain));
string sTargetName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oTarget, TRUE)));
string sCasterName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oCaster)));
jSpell = JsonArrayInsert(jSpell, JsonString(sCasterName));
string sTargetName = ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oTarget)));
jSpell = JsonArrayInsert(jSpell, JsonString(sTargetName));
jSpell = JsonArrayInsert(jSpells, jSpell);
jSpells = JsonArrayInsert(jSpells, jSpell);
SetBuffDatabaseJson(oPC, "spells", jSpells, sList);
SendMessageToPC(oPC, sName + " has been saved for fast buffing on " + sTargetName + ".");
SendMessageToPC(oPC, sCasterName + " has cast " + sName + " to be saved for fast buffing on " + sTargetName + ".");
ExecuteScript("pi_buffing", oPC);
}
string GetBuffDatabaseString(object oPlayer, string sDataField, string sTag)

View File

@@ -45,24 +45,22 @@ void main()
// Watch to see if the window moves and save.
if(sElem == "window_geometry" && sEvent == "watch")
{
if(!GetLocalInt (oPC, AI_NO_NUI_SAVE))
if(GetLocalInt (oPC, AI_NO_NUI_SAVE)) return;
// Get the height, width, x, and y of the window.
json jGeom = NuiGetBind(oPC, nToken, "window_geometry");
// Save on the player using the sWndId.
json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata");
if(sWndId == "plbuffwin")
{
// Get the height, width, x, and y of the window.
json jGeom = NuiGetBind(oPC, nToken, "window_geometry");
// Save on the player using the sWndId.
json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata");
if(sWndId == "plbuffwin")
{
jMenuData = JsonArraySet(jMenuData, 1, JsonObjectGet(jGeom, "x"));
jMenuData = JsonArraySet(jMenuData, 2, JsonObjectGet(jGeom, "y"));
}
else if(sWndId == "widgetbuffwin")
{
jMenuData = JsonArraySet(jMenuData, 5, JsonObjectGet(jGeom, "x"));
jMenuData = JsonArraySet(jMenuData, 6, JsonObjectGet(jGeom, "y"));
}
SetBuffDatabaseJson(oPC, "spells", jMenuData, "menudata");
jMenuData = JsonArraySet(jMenuData, 1, JsonObjectGet(jGeom, "x"));
jMenuData = JsonArraySet(jMenuData, 2, JsonObjectGet(jGeom, "y"));
}
else if(sWndId == "widgetbuffwin")
{
jMenuData = JsonArraySet(jMenuData, 5, JsonObjectGet(jGeom, "x"));
jMenuData = JsonArraySet(jMenuData, 6, JsonObjectGet(jGeom, "y"));
}
SetBuffDatabaseJson(oPC, "spells", jMenuData, "menudata");
return;
}
//**************************************************************************
@@ -175,6 +173,7 @@ void main()
}
else if(sEvent == "watch")
{
if(GetLocalInt (oPC, AI_NO_NUI_SAVE)) return;
if(sElem == "buff_widget_check")
{
int bBuffWidget = JsonGetInt(NuiGetBind(oPC, nToken, "buff_widget_check"));
@@ -184,7 +183,7 @@ void main()
if(bBuffWidget) PopupWidgetBuffGUIPanel(oPC);
else NuiDestroy(oPC, NuiFindWindow(oPC, "widgetbuffwin"));
}
if(sElem == "lock_buff_widget_check")
else if(sElem == "lock_buff_widget_check")
{
int bBuffLockWidget = JsonGetInt(NuiGetBind(oPC, nToken, "lock_buff_widget_check"));
json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata");
@@ -194,11 +193,20 @@ void main()
NuiSetBind(oPC, nToken, "buff_widget_check", JsonBool(TRUE));
PopupWidgetBuffGUIPanel(oPC);
}
if(sElem == "chbx_no_monster_check_check")
else if(sElem == "chbx_no_monster_check_check")
{
int bNoCheckMonsters = JsonGetInt(NuiGetBind(oPC, nToken, sElem));
SetLocalInt(oPC, FB_NO_MONSTER_CHECK, bNoCheckMonsters);
}
else if(sElem == "txt_spell_delay")
{
string sDelay = JsonGetString(NuiGetBind(oPC, nToken, "txt_spell_delay"));
float fDelay = StringToFloat(sDelay);
if(fDelay < 0.1f) fDelay = 0.1f;
if(fDelay > 6.0f) fDelay = 6.0f;
sDelay = FloatToString(fDelay, 0, 1);
SetBuffDatabaseString(oPC, "spells", sDelay, "Delay");
}
}
}
//**************************************************************************
@@ -259,13 +267,12 @@ json GetBuffDatabaseJson (object oPlayer, string sDataField, string sTag)
if(SqlStep(sql)) return SqlGetJson(sql, 0);
else return JsonArray();
}
void CastBuffSpell (object oPC, object oTarget, int nSpell, int nClass, int nMetamagic, int nDomain, string sList, string sName)
void CastBuffSpell(object oPC, object oCaster, object oTarget, int nSpell, int nClass, int nMetamagic, int nDomain, string sList, string sName, int bInstantSpell)
{
string sTargetName;
if(oPC == oTarget) sTargetName = "myself.";
else sTargetName = GetName(oTarget);
ai_SendMessages("Quick Buffing: " + sName + " on " + sTargetName, AI_COLOR_GREEN, oPC);
AssignCommand(oPC, ActionCastSpellAtObject(nSpell, oTarget, nMetamagic, FALSE, nDomain, 0, TRUE, nClass));
string sCasterName = GetName(oCaster);
string sTargetName = GetName(oTarget);
ai_SendMessages(sCasterName + " is quick buffing " + sName + " on " + sTargetName, AI_COLOR_GREEN, oPC);
AssignCommand(oCaster, ActionCastSpellAtObject(nSpell, oTarget, nMetamagic, FALSE, nDomain, 0, bInstantSpell, nClass));
}
void CastSavedBuffSpells(object oPC)
{
@@ -314,7 +321,10 @@ void CastSavedBuffSpells(object oPC)
if(fDistance > 30.0f || fDistance == 0.0)
{
string sName;
float fDelay = 0.1f;
float fDelay;
float fDelayIncrement = StringToFloat(GetBuffDatabaseString(oPC, "spells", "Delay"));;
int bInstantSpell;
if(fDelayIncrement < 3.0f) bInstantSpell = TRUE;
int nSpell, nClass, nLevel, nMetamagic, nDomain, nSpellReady, nIndex = 0;
json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata");
string sList = JsonGetString(JsonArrayGet(jMenuData, 0));
@@ -329,58 +339,78 @@ void CastSavedBuffSpells(object oPC)
nLevel = JsonGetInt(JsonArrayGet(jSpell, 2));
nMetamagic = JsonGetInt(JsonArrayGet(jSpell, 3));
nDomain = JsonGetInt(JsonArrayGet(jSpell, 4));
// We save the target's name then look them up by it.
string sTargetName = JsonGetString(JsonArrayGet(jSpell, 5));
object oTarget;
location lLocation = GetLocation(oPC);
if(sTargetName == "" || sTargetName == ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName (oPC)))) oTarget = oPC;
else
{
oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 10.0, lLocation, TRUE);
while(oTarget != OBJECT_INVALID)
{
if(sTargetName == ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oTarget)))) break;
oTarget = GetNextObjectInShape(SHAPE_SPHERE, 10.0, lLocation, TRUE);
}
}
sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
if(oTarget == OBJECT_INVALID)
location lLocation = GetLocation(oPC);
// Saved the Caster's name so we can find them to cast the spell.
string sCasterName = JsonGetString(JsonArrayGet(jSpell, 5));
object oCaster;
if(sCasterName == "" || sCasterName == ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPC)))) oCaster = oPC;
else
{
DelayCommand(fDelay, ai_SendMessages("Cannot quick cast " + sName + " because the " + sTargetName + " is not here!", AI_COLOR_RED, oPC));
oCaster = GetFirstObjectInShape(SHAPE_SPHERE, 20.0, lLocation, TRUE);
while(oCaster != OBJECT_INVALID)
{
if(sCasterName == ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oCaster)))) break;
oCaster = GetNextObjectInShape(SHAPE_SPHERE, 20.0, lLocation, TRUE);
}
}
if(oCaster == OBJECT_INVALID)
{
DelayCommand(fDelay, ai_SendMessages("Cannot quick cast " + sName + " because the " + sCasterName + " is not here!", AI_COLOR_RED, oPC));
}
else
{
if(nMetamagic > 0)
// Saved the target's name so we can find them to cast the spell on.
string sTargetName = JsonGetString(JsonArrayGet(jSpell, 6));
object oTarget;
if(sTargetName == "" || sTargetName == ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oPC)))) oTarget = oPC;
else
{
if(nMetamagic == METAMAGIC_EMPOWER) sName += " (Empowered)";
else if(nMetamagic == METAMAGIC_EXTEND) sName += " (Extended)";
else if(nMetamagic == METAMAGIC_MAXIMIZE) sName += " (Maximized)";
else if(nMetamagic == METAMAGIC_QUICKEN) sName += " (Quickened)";
else if(nMetamagic == METAMAGIC_SILENT) sName += " (Silent)";
else if(nMetamagic == METAMAGIC_STILL) sName += " (Still)";
oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 20.0, lLocation, TRUE);
while(oTarget != OBJECT_INVALID)
{
if(sTargetName == ai_RemoveIllegalCharacters(ai_StripColorCodes(GetName(oTarget)))) break;
oTarget = GetNextObjectInShape(SHAPE_SPHERE, 20.0, lLocation, TRUE);
}
}
nSpellReady = GetSpellReady(oPC, nSpell, nClass, nLevel, nMetamagic, nDomain);
if(nSpellReady == TRUE)
if(oTarget == OBJECT_INVALID)
{
DelayCommand(fDelay, CastBuffSpell(oPC, oTarget, nSpell, nClass, nMetamagic, nDomain, sList, sName));
DelayCommand(fDelay, ai_SendMessages("Cannot quick cast " + sName + " because the " + sTargetName + " is not here!", AI_COLOR_RED, oPC));
}
else if(nSpellReady == -1)
else
{
DelayCommand(fDelay, ai_SendMessages("Cannot quick cast " + sName + " because it is not ready to cast!", AI_COLOR_RED, oPC));
if(nMetamagic > 0)
{
if(nMetamagic == METAMAGIC_EMPOWER) sName += " (Empowered)";
else if(nMetamagic == METAMAGIC_EXTEND) sName += " (Extended)";
else if(nMetamagic == METAMAGIC_MAXIMIZE) sName += " (Maximized)";
else if(nMetamagic == METAMAGIC_QUICKEN) sName += " (Quickened)";
else if(nMetamagic == METAMAGIC_SILENT) sName += " (Silent)";
else if(nMetamagic == METAMAGIC_STILL) sName += " (Still)";
}
nSpellReady = GetSpellReady(oCaster, nSpell, nClass, nLevel, nMetamagic, nDomain);
if(nSpellReady == TRUE)
{
DelayCommand(fDelay, CastBuffSpell(oPC, oCaster, oTarget, nSpell, nClass, nMetamagic, nDomain, sList, sName, bInstantSpell));
}
else if(nSpellReady == -1)
{
DelayCommand(fDelay, ai_SendMessages(sCasterName + " cannot quick cast " + sName + " because it is not ready to cast!", AI_COLOR_RED, oPC));
}
else if(nSpellReady == -2)
{
DelayCommand (fDelay, ai_SendMessages(sCasterName + " cannot quick cast " + sName + " because it is not memorized!", AI_COLOR_RED, oPC));
}
else if(nSpellReady == -3)
{
DelayCommand (fDelay, ai_SendMessages(sCasterName + " cannot quick cast " + sName + " because there are no spell slots of that level left!", AI_COLOR_RED, oPC));
}
else if(nSpellReady == -4)
{
DelayCommand (fDelay, ai_SendMessages(sCasterName + "cannot quick cast " + sName + " because that spell is not known.", AI_COLOR_RED, oPC));
}
fDelay += fDelayIncrement;
}
else if(nSpellReady == -2)
{
DelayCommand (fDelay, ai_SendMessages("Cannot quick cast " + sName + " because it is not memorized!", AI_COLOR_RED, oPC));
}
else if(nSpellReady == -3)
{
DelayCommand (fDelay, ai_SendMessages("Cannot quick cast " + sName + " because there are no spell slots of that level left!", AI_COLOR_RED, oPC));
}
else if(nSpellReady == -4)
{
DelayCommand (fDelay, ai_SendMessages("Cannot quick cast " + sName + " because that spell is not known.", AI_COLOR_RED, oPC));
}
fDelay += 0.1f;
}
}
else break;
@@ -397,6 +427,7 @@ int GetSpellReady(object oCaster, int nSpell, int nClass, int nLevel, int nMetam
if(StringToInt(Get2DAString("classes", "MemorizesSpells", nClass)))
{
int nSpellMemorized;
nMaxIndex = GetMemorizedSpellCountByLevel(oCaster, nClass, nLevel);
while(nIndex < nMaxIndex)
{
nMSpell = GetMemorizedSpellId(oCaster, nClass, nLevel, nIndex);
@@ -404,20 +435,18 @@ int GetSpellReady(object oCaster, int nSpell, int nClass, int nLevel, int nMetam
{
nMmSpell = GetMemorizedSpellMetaMagic(oCaster, nClass, nLevel, nIndex);
nDSpell = GetMemorizedSpellIsDomainSpell(oCaster, nClass, nLevel, nIndex);
//ai_Debug("pe_buffing", "308", "nMmSpell: " + IntToString(nMmSpell) +
//SendMessageToPC(oCaster, "pe_buffing, 308, nSpell: " + IntToString(nSpell) +
// " nMSpell: " + IntToString(nMSpell) +
// " nMmSpell: " + IntToString(nMmSpell) +
// " nMetamagic: " + IntToString(nMetamagic) +
// " nDomain: " + IntToString(nDomain) +
// " nDSpell: " + IntToString(nDSpell));
// Cannot save the domain status so we just use the first spell ID.
// Then return the domain statusl.
//if(nMmSpell == nMetamagic &&
// ((nDomain > 0 && nDSpell == TRUE) || nDomain == 0 && nDSpell == FALSE))
if(nMmSpell == nMetamagic)
{
nSpellMemorized = TRUE;
if(GetMemorizedSpellReady(oCaster, nClass, nLevel, nIndex))
{
if(nDSpell == nDomain) return TRUE;
if((nDomain && nDSpell) || (!nDomain && !nDSpell)) return TRUE;
}
}
}
@@ -425,18 +454,20 @@ int GetSpellReady(object oCaster, int nSpell, int nClass, int nLevel, int nMetam
{
sSubRadSpell = "SubRadSpell" + IntToString(nSubRadSpell);
if(nSpell == StringToInt(Get2DAString("spells", sSubRadSpell, nMSpell)))
nMmSpell = GetMemorizedSpellMetaMagic(oCaster, nClass, nLevel, nIndex);
nDSpell = GetMemorizedSpellIsDomainSpell(oCaster, nClass, nLevel, nIndex);
ai_Debug("pe_buffing", "421", "nMmSpell: " + IntToString(nMmSpell) +
" nMetamagic: " + IntToString(nMetamagic) +
" nDomain: " + IntToString(nDomain) +
" nDSpell: " + IntToString(nDSpell));
if(nMmSpell == nMetamagic)
{
nSpellMemorized = TRUE;
if(GetMemorizedSpellReady(oCaster, nClass, nLevel, nIndex))
nMmSpell = GetMemorizedSpellMetaMagic(oCaster, nClass, nLevel, nIndex);
nDSpell = GetMemorizedSpellIsDomainSpell(oCaster, nClass, nLevel, nIndex);
//SendMessageToPC(oCaster, "pe_buffing, 433, nMmSpell: " + IntToString(nMmSpell) +
// " nMetamagic: " + IntToString(nMetamagic) +
// " nDomain: " + IntToString(nDomain) +
// " nDSpell: " + IntToString(nDSpell));
if(nMmSpell == nMetamagic)
{
if(nDSpell == nDomain) return TRUE;
nSpellMemorized = TRUE;
if(GetMemorizedSpellReady(oCaster, nClass, nLevel, nIndex))
{
if((nDomain && nDSpell) || (!nDomain && !nDSpell)) return TRUE;
}
}
}
}
@@ -479,7 +510,6 @@ void PopupWidgetBuffGUIPanel(object oPC)
SetLocalInt(oPC, AI_NO_NUI_SAVE, TRUE);
DelayCommand(0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE));
// Row 1 (buttons)**********************************************************
json jRow = CreateButtonImage(JsonArray(), "ir_level1", "btn_one", 35.0f, 35.0f, 0.0);
jRow = CreateButtonImage(jRow, "ir_level2", "btn_two", 35.0f, 35.0f, 0.0);
jRow = CreateButtonImage(jRow, "ir_level3", "btn_three", 35.0f, 35.0f, 0.0);
@@ -519,7 +549,6 @@ void PopupWidgetBuffGUIPanel(object oPC)
if(bAIBuffWidgetLock) nToken = SetWindow (oPC, jLayout, "widgetbuffwin", "Fast Buff Widget", fX, fY, 160.0, 62.0, FALSE, FALSE, FALSE, TRUE, FALSE, "pe_buffing");
else nToken = SetWindow (oPC, jLayout, "widgetbuffwin", "Fast Buff Widget", fX, fY, 160.0, 95.0, FALSE, FALSE, FALSE, TRUE, TRUE, "pe_buffing");
// Set event watches for window inspector and save window location.
NuiSetBindWatch (oPC, nToken, "collapsed", TRUE);
NuiSetBindWatch (oPC, nToken, "window_geometry", TRUE);
// Set the buttons to show events.
//NuiSetBind (oPC, nToken, "btn_one", JsonBool (TRUE));

File diff suppressed because it is too large Load Diff

View File

@@ -57,13 +57,10 @@ void main()
}
ai_SendMessages("Your reputation with " + GetName(oTarget) + " has been set to neutral.", AI_COLOR_YELLOW, oPC);
}
else if(sTargetMode == "SET_REPUTATION")
else if(sTargetMode == "CLEAR_COMMANDABLE")
{
SetStandardFactionReputation(STANDARD_FACTION_COMMONER, 50, oTarget);
SetStandardFactionReputation(STANDARD_FACTION_DEFENDER, 50, oTarget);
SetStandardFactionReputation(STANDARD_FACTION_HOSTILE, 50, oTarget);
SetStandardFactionReputation(STANDARD_FACTION_MERCHANT, 50, oTarget);
ai_SendMessages(GetName(oTarget) + " has been set to a neutral reputation.", AI_COLOR_YELLOW, oPC);
SetCommandable(TRUE, oTarget);
ai_SendMessages(GetName(oTarget) + " has been set to be commandable.", AI_COLOR_YELLOW, oPC);
}
else if(sTargetMode == "DEBUG_INFO")
{
@@ -78,9 +75,14 @@ void main()
int nObjectType = GetObjectType(oTarget);
if(nObjectType == OBJECT_TYPE_CREATURE)
{
string sText = "Yes";
if(!GetCommandable(oTarget)) sText = "No";
ai_SendMessages("Commandable: " + sText, AI_COLOR_WHITE, oPC);
json jObject = ObjectToJson(oTarget);
string sConversation = JsonGetString(GffGetResRef(jObject, "Conversation"));
ai_SendMessages("Conversation: " + sConversation, AI_COLOR_CYAN, oPC);
int nCurrentAction = GetCurrentAction(oTarget);
ai_SendMessages("Current Action: " + IntToString(nCurrentAction), AI_COLOR_RED, oPC);
SendMessageToPC(oPC, "Creature Event Scripts:");
string sScript = GetEventScript(oTarget, EVENT_SCRIPT_CREATURE_ON_HEARTBEAT);
sScript += " [" + ResManGetAliasFor(sScript, RESTYPE_NCS) + "]";
@@ -507,14 +509,14 @@ void main()
ai_SendMessages("Select an npc to change scripts for.", AI_COLOR_YELLOW, oPC);
EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE , MOUSECURSOR_CREATE, MOUSECURSOR_NOCREATE);
}
else if(sElem == "btn_set_reputation")
else if(sElem == "btn_set_commandable")
{
// Set this variable on the player so PEPS can run the targeting script for this plugin.
SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_debug");
// Set Targeting variables.
SetLocalString(oPC, AI_TARGET_MODE, "SET_REPUTATION");
SetLocalString(oPC, AI_TARGET_MODE, "CLEAR_COMMANDABLE");
NuiDestroy(oPC, nToken);
ai_SendMessages("Select a creature to set all standard reputations to neutral.", AI_COLOR_YELLOW, oPC);
ai_SendMessages("Select a creature to set commandable.", AI_COLOR_YELLOW, oPC);
EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE);
}
else if(sElem == "btn_clear_reputation")

View File

@@ -32,6 +32,7 @@ void main()
vector vTarget = GetTargetingModeSelectedPosition();
location lLocation = Location(GetArea(oPC), vTarget, GetFacing(oPC));
object oObject = GetLocalObject(oPC, "AI_TARGET_OBJECT");
DeleteLocalString(oPC, AI_TARGET_MODE);
// If the user manually exited targeting mode without selecting a target, return
if(!GetIsObjectValid(oTarget) && vTarget == Vector())
{
@@ -327,6 +328,7 @@ void main()
if(JsonGetType(jLvlStatList) == JSON_TYPE_NULL)
{
RemoveHenchman(oPC, oHenchman);
ChangeToStandardFaction(oHenchman, STANDARD_FACTION_DEFENDER);
// Make sure to get a clean faction version of the henchman here.
jHenchman = ObjectToJson(oHenchman, TRUE);
jHenchman = CreateLevelStatList(jHenchman, oHenchman, oPC);

View File

@@ -37,6 +37,9 @@ void PopupWidgetBuffGUIPanel(object oPC);
void main()
{
object oPC = OBJECT_SELF;
// Set window to not save until it has been created.
SetLocalInt(oPC, AI_NO_NUI_SAVE, TRUE);
DelayCommand(0.5f, DeleteLocalInt(oPC, AI_NO_NUI_SAVE));
// Check to make sure the database is setup before we do anything.
CheckBuffDataAndInitialize(oPC, "menudata");
json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata");
@@ -54,22 +57,30 @@ void main()
if(StartingUp(oPC)) return;
// Row 1 (Buttons) ********************************************************* 83
json jRow = CreateButtonSelect(JsonArray(), "Save", "btn_save", 60.0f, 30.0f, "btn_save_tooltip");
CreateButton(jRow, "Clear", "btn_clear", 60.0f, 30.0f, -1.0, "btn_clear_tooltip");
CreateButton(jRow, "Buff", "btn_buff", 60.0f, 30.0f, -1.0, "btn_buff_tooltip");
CreateButtonSelect(jRow, "List 1", "btn_list1", 60.0f, 30.0f);
CreateButtonSelect(jRow, "List 2", "btn_list2", 60.0f, 30.0f);
CreateButtonSelect(jRow, "List 3", "btn_list3", 60.0f, 30.0f);
CreateButtonSelect(jRow, "List 4", "btn_list4", 60.0f, 30.0f);
jRow = CreateButton(jRow, "Clear", "btn_clear", 60.0f, 30.0f, -1.0, "btn_clear_tooltip");
jRow = CreateButton(jRow, "Buff", "btn_buff", 60.0f, 30.0f, -1.0, "btn_buff_tooltip");
jRow = CreateButtonSelect(jRow, "List 1", "btn_list1", 60.0f, 30.0f);
jRow = CreateButtonSelect(jRow, "List 2", "btn_list2", 60.0f, 30.0f);
jRow = CreateButtonSelect(jRow, "List 3", "btn_list3", 60.0f, 30.0f);
jRow = CreateButtonSelect(jRow, "List 4", "btn_list4", 60.0f, 30.0f);
jRow = CreateTextEditBox(jRow, "", "txt_spell_delay", 3, FALSE, 40.0f, 30.0f, "txt_spell_delay_tooltip");
// Add the row to the column.
json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow));
// Row 2 (Buttons) ********************************************************* 121
jRow = JsonArrayInsert(JsonArray(), NuiSpacer());
jRow = CreateCheckBox(jRow, "Buff Widget", "buff_widget", 110.0, 30.0f, "buff_widget_tooltip");
jRow = CreateCheckBox(jRow, "Lock Widget", "lock_buff_widget", 110.0, 30.0f, "lock_buff_widget_tooltip");
if(!AI_SERVER)
if(!ai_GetIsServer())
{
jRow = CreateCheckBox(jRow, "Don't Check for Monsters", "chbx_no_monster_check", 200.0, 30.0f, "chbx_no_monster_check_tooltip");
}
else
{
if(ai_GetIsDungeonMaster(oPC))
{
jRow = CreateCheckBox(jRow, "Don't Check for Monsters", "chbx_no_monster_check", 200.0, 30.0f, "chbx_no_monster_check_tooltip");
}
}
jRow = JsonArrayInsert(jRow, NuiSpacer());
// Add the row to the column.
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
@@ -96,7 +107,7 @@ void main()
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
// Get the window location to restore it from the database.
float fWidth = IntToFloat(nIndex) * 39;
if(fWidth < 470.0) fWidth = 470.0;
if(fWidth < 530.0) fWidth = 530.0;
float fX = JsonGetFloat(JsonArrayGet(jMenuData, 1));
float fY = JsonGetFloat(JsonArrayGet(jMenuData, 2));
if(fX == 0.0f && fY == 0.0f)
@@ -108,6 +119,8 @@ void main()
json jLayout = NuiCol(jCol);
int nToken = SetWindow(oPC, jLayout, "plbuffwin", "Fast Buffing Spells",
fX, fY, fWidth, 164.0, FALSE, FALSE, TRUE, FALSE, TRUE, "pe_buffing");
// Set event watches for window inspector and save window location.
NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE);
// Set the elements to show events.
int nSelected = GetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_SPELLCASTAT) == "pc_savebuffs";
NuiSetBind(oPC, nToken, "btn_save", JsonBool(nSelected));
@@ -131,11 +144,22 @@ void main()
if(sList == "list4") NuiSetBind (oPC, nToken, "btn_list4", JsonBool (TRUE));
else NuiSetBind (oPC, nToken, "btn_list4", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_list4_event", JsonBool(TRUE));
NuiSetBindWatch(oPC, nToken, "txt_spell_delay", TRUE);
string sText = " Allows you to adjust the speed that spells are cast in [0.1 seconds to 6.0 seconds]";
NuiSetBind(oPC, nToken, "txt_spell_delay_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_spell_delay_tooltip", JsonString(sText));
CheckBuffDataAndInitialize(oPC, "Delay");
sText = GetBuffDatabaseString(oPC, "spells", "Delay");
float fDelay = StringToFloat(sText);
if(fDelay < 0.1f) fDelay = 0.1f;
else if(fDelay > 6.0f) fDelay = 6.0f;
sText = FloatToString(fDelay, 0, 1);
NuiSetBind(oPC, nToken, "txt_spell_delay", JsonString(sText));
int nValue = JsonGetInt(JsonArrayGet(jMenuData, 3));
NuiSetBind(oPC, nToken, "buff_widget_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "buff_widget_check", JsonBool(nValue));
NuiSetBindWatch(oPC, nToken, "buff_widget_check", TRUE);
string sText = " Creates a set of 4 buttons on the screen for quick buffing.";
sText = " Creates a set of 4 buttons on the screen for quick buffing.";
NuiSetBind(oPC, nToken, "buff_widget_tooltip", JsonString(sText));
nValue = JsonGetInt(JsonArrayGet(jMenuData, 4));
NuiSetBind(oPC, nToken, "lock_buff_widget_event", JsonBool(TRUE));
@@ -143,7 +167,7 @@ void main()
NuiSetBindWatch(oPC, nToken, "lock_buff_widget_check", TRUE);
sText = " Locks the buffing widget in place reducing its size.";
NuiSetBind(oPC, nToken, "lock_buff_widget_tooltip", JsonString(sText));
if(!AI_SERVER)
if(!ai_GetIsServer())
{
NuiSetBind(oPC, nToken, "chbx_no_monster_check_event", JsonBool(TRUE));
nValue = GetLocalInt(oPC, FB_NO_MONSTER_CHECK);
@@ -154,7 +178,7 @@ void main()
}
// Create buttons with spells listed.
int nSpell, nClass, nLevel, nMetamagic, nDomain;
string sName, sTargetName, sResRef;
string sName, sTargetName, sCasterName, sResRef;
nCntr = 0;
nIndex = 0;
while(nCntr <= BUFF_MAX_SPELLS)
@@ -167,11 +191,13 @@ void main()
nLevel = JsonGetInt(JsonArrayGet(jSpell, 2));
nMetamagic = JsonGetInt(JsonArrayGet(jSpell, 3));
nDomain = JsonGetInt(JsonArrayGet(jSpell, 4));
sTargetName = JsonGetString(JsonArrayGet(jSpell, 5));
sCasterName = JsonGetString(JsonArrayGet(jSpell, 5));
sTargetName = JsonGetString(JsonArrayGet(jSpell, 6));
sResRef = Get2DAString("spells", "IconResRef", nSpell);
sName = " " + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
sName += " (" + GetStringByStrRef(StringToInt(Get2DAString("classes", "Short", nClass)));
sName += " / " + IntToString (nLevel);
sName = " " + sCasterName + " (";
sName += GetStringByStrRef(StringToInt(Get2DAString("classes", "Short", nClass)));
sName += " / " + IntToString (nLevel) + ") casting ";
sName += GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
if(nMetamagic > 0)
{
if(nMetamagic == METAMAGIC_EMPOWER) sName += " / Empowered";
@@ -182,7 +208,7 @@ void main()
else if(nMetamagic == METAMAGIC_STILL) sName += " / Still";
}
if(nDomain > 0) sName += " / Domain";
sName += ") " + sTargetName;
sName += " on " + sTargetName;
sIndex = IntToString(nIndex++);
NuiSetBind(oPC, nToken, "btn_spell_" + sIndex + "_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_spell_" + sIndex + "_image", JsonString(sResRef));
@@ -190,7 +216,6 @@ void main()
}
nCntr++;
}
NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE);
}
int StartingUp(object oPC)
{
@@ -295,44 +320,55 @@ void PopupWidgetBuffGUIPanel(object oPC)
SetLocalInt(oPC, AI_NO_NUI_SAVE, TRUE);
DelayCommand(0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE));
// Row 1 (buttons)**********************************************************
json jRow = JsonArray();
CreateButtonImage(jRow, "ir_level1", "btn_one", 35.0f, 35.0f, 0.0);
CreateButtonImage(jRow, "ir_level2", "btn_two", 35.0f, 35.0f, 0.0);
CreateButtonImage(jRow, "ir_level3", "btn_three", 35.0f, 35.0f, 0.0);
CreateButtonImage(jRow, "ir_level4", "btn_four", 35.0f, 35.0f, 0.0);
json jRow = CreateButtonImage(JsonArray(), "ir_level1", "btn_one", 35.0f, 35.0f, 0.0);
jRow = CreateButtonImage(jRow, "ir_level2", "btn_two", 35.0f, 35.0f, 0.0);
jRow = CreateButtonImage(jRow, "ir_level3", "btn_three", 35.0f, 35.0f, 0.0);
jRow = CreateButtonImage(jRow, "ir_level4", "btn_four", 35.0f, 35.0f, 0.0);
// Add the row to the column.
json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow));
json jWidget = GetBuffDatabaseJson(oPC, "spells", "menudata");
int bAIBuffWidgetLock = JsonGetInt(JsonArrayGet(jWidget, 4));
json jMenuData = GetBuffDatabaseJson(oPC, "spells", "menudata");
int bAIBuffWidgetLock = JsonGetInt(JsonArrayGet(jMenuData, 4));
// Get the window location to restore it from the database.
float fX = JsonGetFloat(JsonArrayGet(jWidget, 5));
float fY = JsonGetFloat(JsonArrayGet(jWidget, 6));
float fX = JsonGetFloat(JsonArrayGet(jMenuData, 5));
float fY = JsonGetFloat(JsonArrayGet(jMenuData, 6));
if(fX == 0.0f && fY == 0.0f)
{
fX = 10.0f;
fY = 10.0f;
}
float fGUI_Scale = IntToFloat(GetPlayerDeviceProperty(oPC, PLAYER_DEVICE_PROPERTY_GUI_SCALE)) / 100.0;
if(bAIBuffWidgetLock)
{
fX = fX + 4.0f;
fY = fY + 45.0f;
fX += 4.0f;
// GUI scales are a mess, I just figured them out per scale to keep the widget from moving.
if(fGUI_Scale == 1.0) fY += 37.0;
else if(fGUI_Scale == 1.1) fY += 38.0;
else if(fGUI_Scale == 1.2) fY += 40.0;
else if(fGUI_Scale == 1.3) fY += 42.0;
else if(fGUI_Scale == 1.4) fY += 43.0;
else if(fGUI_Scale == 1.5) fY += 45.0;
else if(fGUI_Scale == 1.6) fY += 47.0;
else if(fGUI_Scale == 1.7) fY += 48.0;
else if(fGUI_Scale == 1.8) fY += 50.0;
else if(fGUI_Scale == 1.9) fY += 52.0;
else if(fGUI_Scale == 2.0) fY += 54.0;
}
// Set the layout of the window.
json jLayout = NuiCol (jCol);
json jLayout = NuiCol(jCol);
int nToken;
if(bAIBuffWidgetLock) nToken = SetWindow(oPC, jLayout, "widgetbuffwin", "Fast Buff Widget", fX, fY, 160.0, 62.0, FALSE, FALSE, FALSE, TRUE, FALSE, "pe_buffing");
else nToken = SetWindow(oPC, jLayout, "widgetbuffwin", "Fast Buff Widget", fX, fY, 160.0, 95.0, FALSE, FALSE, FALSE, TRUE, TRUE, "pe_buffing");
if(bAIBuffWidgetLock) nToken = SetWindow (oPC, jLayout, "widgetbuffwin", "Fast Buff Widget", fX, fY, 160.0, 62.0, FALSE, FALSE, FALSE, TRUE, FALSE, "pe_buffing");
else nToken = SetWindow (oPC, jLayout, "widgetbuffwin", "Fast Buff Widget", fX, fY, 160.0, 95.0, FALSE, FALSE, FALSE, TRUE, TRUE, "pe_buffing");
// Set event watches for window inspector and save window location.
//NuiSetBindWatch(oPC, nToken, "collapsed", TRUE);
NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE);
NuiSetBindWatch (oPC, nToken, "collapsed", TRUE);
NuiSetBindWatch (oPC, nToken, "window_geometry", TRUE);
// Set the buttons to show events.
//NuiSetBind (oPC, nToken, "btn_one", JsonBool (TRUE));
NuiSetBind(oPC, nToken, "btn_one_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_two", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_two_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_three", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_three_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_four", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_four_event", JsonBool(TRUE));
NuiSetBind (oPC, nToken, "btn_one_event", JsonBool (TRUE));
NuiSetBind (oPC, nToken, "btn_two", JsonBool (TRUE));
NuiSetBind (oPC, nToken, "btn_two_event", JsonBool (TRUE));
NuiSetBind (oPC, nToken, "btn_three", JsonBool (TRUE));
NuiSetBind (oPC, nToken, "btn_three_event", JsonBool (TRUE));
NuiSetBind (oPC, nToken, "btn_four", JsonBool (TRUE));
NuiSetBind (oPC, nToken, "btn_four_event", JsonBool (TRUE));
}

View File

@@ -8,694 +8,20 @@
#include "0i_nui"
#include "0i_items"
#include "nw_inc_gff"
const string CRAFT_JSON = "CRAFT_JSON";
const string CRAFT_COOL_DOWN = "CRAFT_COOL_DOWN";
const string CRAFT_ITEM_SELECTION = "CRAFT_ITEM_SELECTION";
const string CRAFT_MATERIAL_SELECTION = "CRAFT_MATERIAL_SELECTION";
const string CRAFT_MODEL_SELECTION = "CRAFT_MODEL_SELECTION";
const string CRAFT_COLOR_PALLET = "CRAFT_COLOR_PALLET";
const string CRAFT_LEFT_PART_COLOR = "CRAFT_LEFT_PART_COLOR";
const string CRAFT_ALL_COLOR = "CRAFT_ALL_COLOR";
const string CRAFT_RIGHT_PART_COLOR = "CRAFT_RIGHT_PART_COLOR";
const string CRAFT_TARGET = "CRAFT_TARGET";
// Tag used in lighting effects.
const string CRAFT_HIGHLIGHT = "CRAFT_HIGHLIGHT";
const string CRAFT_ULTRALIGHT = "CRAFT_ULTRALIGHT";
json CreateItemCombo(object oPC, json jRow, string sComboBind);
json CreateModelCombo(object oPC, object oTarget, json jRow, string sComboBind);
json CreateMaterialCombo(object oPC, json jRow, string sComboBind);
// Sets the material buttons for use.
// nMaterial 0,1 Cloth 2,3 Leather 4,5 Metal -1 None.
void SetMaterialButtons(object oPC, int nToken, int nMaterial);
// Returns the correct item based on the crafting menu selected item.
object GetSelectedItem(object oTarget, int nItemSelected);
int GetArmorModelSelected(object oPC);
// Returns True if oItem, nPart has a per part color for sSide.
int GetHasPartColor(object oItem, int nPart, string sSide);
// Does startup check if the game has just been loaded.
int StartingUp(object oPC);
void main()
{
object oPC = OBJECT_SELF;
object oTarget = GetLocalObject(oPC, CRAFT_TARGET);
if(oTarget == OBJECT_INVALID) oTarget = oPC;
if(StartingUp(oPC)) return;
json jCraft = GetLocalJson(oPC, CRAFT_JSON);
if(JsonGetType(jCraft) == JSON_TYPE_NULL) jCraft = JsonObject();
// Row 1 (Object Name)****************************************************** 508 / 83
json jRow = CreateTextEditBox(JsonArray(), "plc_hold_bind", "txt_item_name", 50, FALSE, 486.0f, 30.0f); // 419
json jCol = JsonArrayInsert(JsonArray(), NuiRow(jRow));
// Row 2 (Object Name)****************************************************** 508 / 121
jRow = JsonArray();
if(!AI_SERVER) jRow = CreateButton(jRow, "Information", "btn_info", 160.0f, 30.0f, -1.0, "btn_info_tooltip");
else
{
if(GetIsDM(oTarget))
{
jRow = CreateButton(jRow, "Information", "btn_info", 160.0f, 30.0f, -1.0, "btn_info_tooltip");
}
else jRow = JsonArrayInsert(jRow, NuiSpacer());
}
jRow = CreateButton(jRow, "Wardrobe", "btn_wardrobe", 158.0f, 30.0f, -1.0, "btn_wardrobe_tooltip");
jRow = CreateButtonSelect(jRow, "Add Light", "btn_highlight", 160.0f, 30.0f, "btn_highlight_tooltip");
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
// Row 3 (Object Name)****************************************************** 508 / 159
jRow = CreateButton(JsonArray(), "Save", "btn_save", 160.0f, 30.0f, -1.0, "btn_save_tooltip");
jRow = CreateButton(jRow, "Select Target", "btn_select_target", 158.0f, 30.0f);
jRow = CreateButton(jRow, "", "btn_cancel", 160.0f, 30.0f, -1.0, "btn_cancel_tooltip");
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
// Row 4 (labels)*********************************************************** 508 / 177
jRow = CreateLabel(JsonArray(), "Model", "module_title", 143.0f, 10.0f);
jRow = CreateLabel(jRow, "Color", "color_title", 339.0f, 10.0f);
jRow = JsonArrayInsert(jCol, NuiRow(jRow));
// Row 5 (groups)
// Row 51 (title)*********************************************************** 508 / 195 / 18
json jGroupRow = CreateLabel(JsonArray(), "Item", "item__cmb_title", 128.0f, 10.0f);
json jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow));
// Row 52 (combo)*********************************************************** 508 / 233 / 56
jGroupRow = CreateItemCombo(oPC, JsonArray(), "item_combo");
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 53 (title)*********************************************************** 508 / 251 / 74
jGroupRow = CreateLabel(JsonArray(), "Model", "model_cmb_title",128.0f, 10.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 54 (combo)*********************************************************** 508 / 289 / 112
jGroupRow = CreateModelCombo(oPC, oTarget, JsonArray(), "model_combo");
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 55 (title)*********************************************************** 508 / 307 / 120
jGroupRow = CreateLabel(JsonArray(), "", "top_title",128.0f, 10.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 56 (top)************************************************************* 508 / 355 / 168
jGroupRow = CreateButtonImage(JsonArray(), "nui_shld_left", "btn_prev_t", 40.0f, 40.0f);
// Removed TextEditBox for mobile
jGroupRow = CreateTextEditBox(jGroupRow, "place_holder", "txt_model_number_t", 3, FALSE, 40.0, 40.0);
//CreateLabel(jGroupRow, "", "txt_model_number_t", 40.0, 40.0);
jGroupRow = CreateButtonImage(jGroupRow, "nui_shld_right", "btn_next_t", 40.0f, 40.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 57 (title)*********************************************************** 508 / 373 / 186
jGroupRow = CreateLabel(JsonArray(), "", "middle_title",128.0f, 10.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 58 (middle)********************************************************** 508 / 421 /234
jGroupRow = CreateButtonImage(JsonArray(), "nui_shld_left", "btn_prev_m", 40.0f, 40.0f);
// Removed TextEditBox for mobile
jGroupRow = CreateTextEditBox(jGroupRow, "place_holder", "txt_model_number_m", 3, FALSE, 40.0, 40.0);
//CreateLabel(jGroupRow, "", "txt_model_number_m", 40.0, 40.0);
jGroupRow = CreateButtonImage(jGroupRow, "nui_shld_right", "btn_next_m", 40.0f, 40.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 59 (title)*********************************************************** 508 / 439 / 252
jGroupRow = CreateLabel(JsonArray(), "", "bottom_title",128.0f, 10.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 510 (bottom)********************************************************* 508 / 487 /300
jGroupRow = CreateButtonImage(JsonArray(), "nui_shld_left", "btn_prev_b", 40.0f, 40.0f);
// Removed TextEditBox for mobile
jGroupRow = CreateTextEditBox(jGroupRow, "place_holder", "txt_model_number_b", 3, FALSE, 40.0, 40.0);
//CreateLabel(jGroupRow, "", "txt_model_number_b", 40.0, 40.0);
jGroupRow = CreateButtonImage(jGroupRow, "nui_shld_right", "btn_next_b", 40.0f, 40.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 511 (blank spacer)
jGroupRow = CreateLabel(JsonArray(), "", "blank_space",128.0f, 20.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 512 (light)********************************************************** 508 / 487 /300
jGroupRow = CreateButtonSelect(JsonArray(), "Randomize", "btn_randomize", 128.0f, 30.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
jGroupCol = JsonArrayInsert(jGroupCol, NuiSpacer());
jRow = JsonArrayInsert(JsonArray(), NuiHeight(NuiWidth(NuiGroup(NuiCol(jGroupCol)), 143.0), 442.0));
// Make the Color Group.
// Row 550 (groups)********************************************************* 508 / 361 / 184
json jImage = NuiEnabled(NuiId(NuiImage(NuiBind("color_pallet_image"), JsonInt(0), JsonInt(0), JsonInt(1)), "color_pallet"), NuiBind("color_pallet_event"));
jImage = NuiWidth(jImage, 320.0); // 256 + 64
jImage = NuiHeight(jImage, 220.0); // 176 + 44
jImage = NuiTooltip(jImage, NuiBind("color_pallet_tooltip"));
json jIndicator = JsonArrayInsert(JsonArray(), NuiDrawListRect(JsonBool(TRUE), NuiColor(255,0,0), JsonBool(FALSE), JsonFloat(2.0), NuiBind("color_pallet_pointer")));
jImage = NuiDrawList(jImage, JsonBool(FALSE), jIndicator);
jGroupRow = JsonArrayInsert(JsonArray(), jImage);
jGroupCol = JsonArrayInsert(JsonArray(), NuiRow(jGroupRow));
// Row 551 (groups)********************************************************* 508 / 379 /202
jGroupRow = CreateLabel(JsonArray(), "Part To Color", "lbl_color_parts", 320.0f, 10.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 552 (groups)********************************************************* 508 / 417 /240
jGroupRow = CreateButtonSelect(JsonArray(), "Right", "btn_right_part_color", 98.0, 30.0, "btn_right_part_color_tooltip");
jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer());
jGroupRow = CreateButtonSelect(jGroupRow, "All", "btn_all_color", 98.0, 30.0, "btn_all_color_tooltip");
jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer());
jGroupRow = CreateButtonSelect(jGroupRow, "Left", "btn_left_part_color", 98.0, 30.0, "btn_left_part_color_tooltip");
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 553 (groups)********************************************************* 508 / 435 / 258
jGroupRow = CreateLabel(JsonArray(), "Part Color To Reset", "lbl_reset_parts", 320.0f, 10.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 554 (groups)********************************************************* 508 / 473 /296
jGroupRow = CreateButton(JsonArray(), "Right", "btn_right_part_reset", 98.0, 30.0, -1.0, "btn_right_part_reset_tooltip");
jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer());
jGroupRow = CreateButton(jGroupRow, "All", "btn_all_reset", 50.0, 30.0, -1.0, "btn_all_reset_tooltip");
jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer());
jGroupRow = CreateButton(jGroupRow, "Left", "btn_left_part_reset", 98.0, 30.0, -1.0, "btn_left_part_reset_tooltip");
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 555 (groups)********************************************************* 508 / 491 / 314
jGroupRow = CreateLabel(JsonArray(), "Material to Color", "lbl_material_color", 320.0f, 10.0f);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 556 (groups)********************************************************* 508 / 529 /352
jGroupRow = CreateButtonSelect(JsonArray(), "Cloth 1", "btn_material_0", 98.0, 30.0);
jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer());
jGroupRow = CreateButtonSelect(jGroupRow, "Leather 1", "btn_material_2", 98.0, 30.0);
jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer());
jGroupRow = CreateButtonSelect(jGroupRow, "Metal 1", "btn_material_4", 98.0, 30.0);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
// Row 557 (groups)********************************************************* 508 / 567 / 390
jGroupRow = CreateButtonSelect(JsonArray(), "Cloth 2", "btn_material_1", 98.0, 30.0);
jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer());
jGroupRow = CreateButtonSelect(jGroupRow, "Leather 2", "btn_material_3", 98.0, 30.0);
jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer());
jGroupRow = CreateButtonSelect(jGroupRow, "Metal 2", "btn_material_5", 98.0, 30.0);
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
jGroupCol = JsonArrayInsert(jGroupCol, NuiSpacer());
jRow = JsonArrayInsert(jRow, NuiHeight(NuiWidth(NuiGroup(NuiCol(jGroupCol)), 339.0), 442.0)); // 275 398
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
json jLayout = NuiCol(jCol);
// Get the window location to restore it from the database.
json jGeometry = JsonObjectGet(jCraft, "CRAFT_MENU");
float fX = JsonGetFloat(JsonObjectGet(jGeometry, "x"));
float fY = JsonGetFloat(JsonObjectGet(jGeometry, "y"));
string sPCWindow;
int nToken = SetWindow(oPC, jLayout, "crafting_nui", "Crafting",
fX, fY, 508.0, 700.0, FALSE, FALSE, FALSE, FALSE, TRUE, "pe_crafting"); // 444 645
// Set all binds, events, and watches.
NuiSetBindWatch (oPC, nToken, "window_geometry", TRUE);
int nItem = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION));
object oItem = GetSelectedItem(oTarget, nItem);
// Row 1
NuiSetBind(oPC, nToken, "txt_item_name", JsonString(GetName(oItem)));
NuiSetBind(oPC, nToken, "txt_item_name_event", JsonBool(TRUE));
NuiSetBindWatch(oPC, nToken, "txt_item_name", TRUE);
// Row 2
NuiSetBind(oPC, nToken, "btn_info_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_info_tooltip", JsonString(" Look at and change item information"));
NuiSetBind(oPC, nToken, "btn_wardrobe_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_wardrobe_tooltip", JsonString(" Use your wardrobe to save/load item appearances"));
int nLight = GetLocalInt(oPC, CRAFT_HIGHLIGHT) + GetLocalInt(oPC, CRAFT_ULTRALIGHT);
NuiSetBind(oPC, nToken, "btn_highlight", JsonBool(nLight));
NuiSetBind(oPC, nToken, "btn_highlight_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_highlight_tooltip", JsonString(" Left click for White light, Right click for Ultravision"));
// Row 3
NuiSetBind(oPC, nToken, "btn_save_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_save_tooltip", JsonString(" Save current changes"));
NuiSetBind(oPC, nToken, "btn_select_target_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_cancel_label", JsonString("Exit"));
NuiSetBind(oPC, nToken, "btn_cancel_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_cancel_tooltip", JsonString(" Exit the crafting menu"));
// Row 4 Labels.
// Row 5 Groups.
// Row 51 title.
// Row 52
NuiSetBind(oPC, nToken, "item_combo_selected", JsonInt(nItem));
NuiSetBind(oPC, nToken, "item_combo_event", JsonBool(TRUE));
NuiSetBindWatch(oPC, nToken, "item_combo_selected", TRUE);
// Row 53 title.
// Row 54
int nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MODEL_SELECTION));
if(nItem == 1 || nItem == 2 || nItem == 4)
{
if(GetHiddenWhenEquipped(oItem)) nSelected = 1;
else nSelected = 0;
}
NuiSetBind(oPC, nToken, "model_combo_selected", JsonInt (nSelected));
NuiSetBind(oPC, nToken, "model_combo_event", JsonBool (TRUE));
NuiSetBindWatch(oPC, nToken, "model_combo_selected", TRUE);
// Row 55, 56, 57 titles
// Row 58 top, 59 middle, 510 bottom
string sModelTop, sModelMiddle, sModelBottom;
// Model Group
if(ai_GetIsWeapon(oItem))
{
int nModel = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_MODEL, 0);
int nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_COLOR, 0);
int nModelNumber = (nModel * 10) + nColor;
sModelTop = IntToString(nModelNumber);
nModel = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_MODEL, 1);
nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_COLOR, 1);
nModelNumber = (nModel * 10) + nColor;
sModelMiddle = IntToString(nModelNumber);
nModel = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_MODEL, 2);
nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_WEAPON_COLOR, 2);
nModelNumber = (nModel * 10) + nColor;
sModelBottom = IntToString(nModelNumber);
// Row 55
NuiSetBind(oPC, nToken, "top_title_label", JsonString("Top"));
// Row 56
//NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_model_number_t", JsonString(sModelTop));
NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(TRUE));
// Row 57
NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Middle"));
// Row 58
//NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelMiddle));
NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE));
// Row 59
NuiSetBind(oPC, nToken, "bottom_title_label", JsonString("Bottom"));
// Row 510
//NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString(sModelBottom));
NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(TRUE));
// Row 511
NuiSetBind(oPC, nToken, "btn_randomize_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_randomize_tooltip", JsonString(" Randomize the selected weapon"));
}
// Armor and clothing
else if(nItem == 0)
{
nSelected = GetArmorModelSelected(oPC);
// These models only have one side so make sure we are not linked.
if (nSelected == ITEM_APPR_ARMOR_MODEL_NECK ||
nSelected == ITEM_APPR_ARMOR_MODEL_TORSO ||
nSelected == ITEM_APPR_ARMOR_MODEL_BELT ||
nSelected == ITEM_APPR_ARMOR_MODEL_PELVIS ||
nSelected == ITEM_APPR_ARMOR_MODEL_ROBE)
{
sModelMiddle = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nSelected));
// Row 55
NuiSetBind(oPC, nToken, "top_title_label", JsonString(""));
// Row 56
//NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "txt_model_name_t", JsonString(""));
NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(FALSE));
// Row 57
NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Model"));
// Row 58
//NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelMiddle));
NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE));
// Row 59
NuiSetBind(oPC, nToken, "bottom_title_label", JsonString(""));
// Row 510
//NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString(""));
NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(FALSE));
}
else
{
sModelTop = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nSelected));
if(nSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nSelected--;
else nSelected++;
sModelBottom = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nSelected));
// Row 55
NuiSetBind(oPC, nToken, "top_title_label", JsonString("Right"));
// Row 56
//NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_model_number_t", JsonString(sModelTop));
NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(TRUE));
// Row 57
NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Right & Left"));
// Row 58
//NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelTop));
NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE));
// Row 59
NuiSetBind(oPC, nToken, "bottom_title_label", JsonString("Left"));
// Row 510
//NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString(sModelBottom));
NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(TRUE));
}
// Row 511
NuiSetBind(oPC, nToken, "btn_randomize_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_randomize_tooltip", JsonString(" Randomize the selected armor"));
}
// Shields, Cloaks, and Helmets.
else
{
sModelMiddle = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_SIMPLE_MODEL, 0));
// Row 55
NuiSetBind(oPC, nToken, "top_title_label", JsonString(""));
// Row 56
//NuiSetBind(oPC, nToken, "txt_model_number_t_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "txt_model_number_t", JsonString(""));
NuiSetBind(oPC, nToken, "btn_prev_t_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_next_t_event", JsonBool(FALSE));
// Row 57
NuiSetBind(oPC, nToken, "middle_title_label", JsonString("Model"));
// Row 58
//NuiSetBind(oPC, nToken, "txt_model_number_m_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_model_number_m", JsonString(sModelMiddle));
NuiSetBind(oPC, nToken, "btn_prev_m_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_next_m_event", JsonBool(TRUE));
// Row 59
NuiSetBind(oPC, nToken, "bottom_title_label", JsonString(""));
// Row 510
//NuiSetBind(oPC, nToken, "txt_model_number_b_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "txt_model_number_b", JsonString(""));
NuiSetBind(oPC, nToken, "btn_prev_b_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_next_b_event", JsonBool(FALSE));
// Row 511
NuiSetBind(oPC, nToken, "btn_randomize_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_randomize_tooltip", JsonString(" Randomize the selected item"));
}
// Color Group
if(ai_GetIsWeapon(oItem) || ai_GetIsShield(oItem))
{
// Need to disable the color widgets.
// Row 511
NuiSetBind(oPC, nToken, "color_pallet_image", JsonString("gui_pal_tattoo"));
NuiSetBind(oPC, nToken, "color_pallet_image_event", JsonBool(FALSE));
// Row 512 - Label Part to Color
// Row 5l3
NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(FALSE));
// Row 514 - Label Part Color to Reset
// Row 515
NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE));
// Row 516 - Label Material to Color
// Row 517
NuiSetBind(oPC, nToken, "btn_material_0", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_material_2", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_material_4", JsonBool(FALSE));
// Row 518
NuiSetBind(oPC, nToken, "btn_material_1", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_material_3", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_material_5", JsonBool(FALSE));
SetMaterialButtons(oPC, nToken, -1);
}
// Armor and clothing
else if(nItem == 0)
{
// Row 511
string sColorPallet = GetLocalString(oPC, CRAFT_COLOR_PALLET);
if(sColorPallet == "") sColorPallet = "gui_pal_tattoo";
int nMaterialSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION));
int nModelSelected = GetArmorModelSelected(oPC);
// Row 511
NuiSetBind(oPC, nToken, "color_pallet_image", JsonString(sColorPallet));
NuiSetBind(oPC, nToken, "color_pallet_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "color_pallet_tooltip", JsonString(" Select a color or use the mouse wheel"));
int nSelectedRight, nSelectedAll, nSelectedLeft;
string sColorAll = IntToString(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nMaterialSelected));
// These models only have one side so make sure we are not linked.
if (nModelSelected == ITEM_APPR_ARMOR_MODEL_NECK ||
nModelSelected == ITEM_APPR_ARMOR_MODEL_TORSO ||
nModelSelected == ITEM_APPR_ARMOR_MODEL_BELT ||
nModelSelected == ITEM_APPR_ARMOR_MODEL_PELVIS ||
nModelSelected == ITEM_APPR_ARMOR_MODEL_ROBE)
{
// Row 512 - Label Part to Color
// Row 5l3
int nPartColor = GetHasPartColor(oItem, nModelSelected, "Right");
nSelectedRight = JsonGetInt(JsonObjectGet(jCraft, CRAFT_RIGHT_PART_COLOR));
if(!nSelectedRight && nPartColor)
{
nSelectedRight = TRUE;
nSelectedLeft = FALSE;
}
nSelectedAll = !nSelectedRight;
jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonBool(nSelectedAll));
jCraft = JsonObjectSet(jCraft, CRAFT_RIGHT_PART_COLOR, JsonBool(nSelectedRight));
NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(nSelectedRight));
NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(nSelectedAll));
NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(FALSE));
// Row 514 - Label Part Color to Reset
// Row 5l5
nSelectedRight = GetHasPartColor(oItem, nModelSelected, "Right");
nSelectedAll = nSelectedRight;
NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(nSelectedRight));
NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(nSelectedAll));
NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE));
}
else
{
// Row 512 - Label Part to Color
// Row 5l3
int nPartColor = GetHasPartColor(oItem, nModelSelected, "Right");
nSelectedRight = JsonGetInt(JsonObjectGet(jCraft, CRAFT_RIGHT_PART_COLOR));
if(!nSelectedRight && nPartColor)
{
nSelectedRight = TRUE;
nSelectedLeft = FALSE;
}
else
{
nPartColor = GetHasPartColor(oItem, nModelSelected, "Left");
nSelectedLeft = JsonGetInt(JsonObjectGet(jCraft, CRAFT_LEFT_PART_COLOR));
if(!nSelectedLeft && nPartColor)
{
nSelectedLeft = TRUE;
nSelectedRight = FALSE;
}
}
nSelectedAll = !nSelectedRight && !nSelectedLeft;
jCraft = JsonObjectSet(jCraft, CRAFT_LEFT_PART_COLOR, JsonBool(nSelectedLeft));
jCraft = JsonObjectSet(jCraft, CRAFT_ALL_COLOR, JsonBool(nSelectedAll));
jCraft = JsonObjectSet(jCraft, CRAFT_RIGHT_PART_COLOR, JsonBool(nSelectedRight));
NuiSetBind(oPC, nToken, "btn_right_part_color", JsonBool(nSelectedRight));
NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(nSelectedAll));
NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(nSelectedLeft));
NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(TRUE));
// Row 514 - Label Part Color to Reset
// Row 5l5
nSelectedRight = GetHasPartColor(oItem, nModelSelected, "Right");
nSelectedLeft = GetHasPartColor(oItem, nModelSelected, "Left");
nSelectedAll = nSelectedRight || nSelectedLeft;
NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(nSelectedRight));
NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(nSelectedAll));
NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(nSelectedLeft));
}
int nColor;
if(!JsonGetInt(NuiGetBind(oPC, nToken, "btn_all_color")))
{
int nModelSelected = GetArmorModelSelected(oPC);
if(!JsonGetInt(JsonObjectGet(jCraft, CRAFT_RIGHT_PART_COLOR)))
{
// Note: Right Thigh and Left Thigh are backwards so this fixes that!
if (nModelSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nModelSelected--;
else nModelSelected++;
}
int nIndex = ITEM_APPR_ARMOR_NUM_COLORS + (nModelSelected * ITEM_APPR_ARMOR_NUM_COLORS) + nMaterialSelected;
nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nIndex);
}
else nColor = 255;
if(nColor == 255) nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nMaterialSelected);
float fPointX = IntToFloat((nColor - ((nColor / 16) * 16)) * 20);
float fPointY = IntToFloat((nColor / 16) * 20);
NuiSetBind(oPC, nToken, "color_pallet_pointer", NuiRect(fPointX, fPointY, 20.0, 20.0));
// Row 516 - Label Material to Color
// Row 517 & 518
NuiSetBind(oPC, nToken, "btn_right_part_color_tooltip", JsonString(" Select the right part to be uniquely colored"));
NuiSetBind(oPC, nToken, "btn_all_color_tooltip", JsonString(" Select all parts to be colored"));
NuiSetBind(oPC, nToken, "btn_left_part_color_tooltip", JsonString(" Select the left part to be uniquely colored"));
NuiSetBind(oPC, nToken, "btn_right_part_reset_tooltip", JsonString(" Clears the right part's unique color"));
NuiSetBind(oPC, nToken, "btn_all_reset_tooltip", JsonString(" Clears all parts unique colors"));
NuiSetBind(oPC, nToken, "btn_left_part_reset_tooltip", JsonString(" Clears the left part's unique color"));
nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION));
SetMaterialButtons(oPC, nToken, nSelected);
SetLocalJson(oPC, CRAFT_JSON, jCraft);
}
// Cloaks and Helmets.
else
{
// Row 511
string sColorPallet = GetLocalString(oPC, CRAFT_COLOR_PALLET);
if(sColorPallet == "") sColorPallet = "gui_pal_tattoo";
int nMaterialSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION));
int nModelSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MODEL_SELECTION));
int nColor = GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, nMaterialSelected);
float fPointX = IntToFloat((nColor - ((nColor / 16) * 16)) * 20);
float fPointY = IntToFloat((nColor / 16) * 20);
NuiSetBind(oPC, nToken, "color_pallet_pointer", NuiRect(fPointX, fPointY, 20.0, 20.0));
NuiSetBind(oPC, nToken, "color_pallet_image", JsonString(sColorPallet));
NuiSetBind(oPC, nToken, "color_pallet_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "color_pallet_tooltip", JsonString(" Select a color or use the mouse wheel"));
// Row 512 - Label Part to Color
// Row 5l3
NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_right_part_color_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_all_color_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_all_color", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_left_part_color_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_left_part_color", JsonBool(FALSE));
// Row 514 - Label Part Color to Reset
// Row 5l5
NuiSetBind(oPC, nToken, "btn_right_part_reset_event", JsonBool(FALSE));
//NuiSetBind(oPC, nToken, "btn_all_reset_event", JsonBool(FALSE));
NuiSetBind(oPC, nToken, "btn_left_part_reset_event", JsonBool(FALSE));
// Row 516 - Label Material to Color
// Row 517 & 518
nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MATERIAL_SELECTION));
SetMaterialButtons(oPC, nToken, nSelected);
}
// Lets make sure we clean up any cool down variables.
//DeleteLocalInt(oPC, CRAFT_COOL_DOWN);
}
json CreateItemCombo(object oPC, json jRow, string sComboBind)
{
int nCnt;
// Create the list.
json jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Armor", 0));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Cloak", 1));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Headgear", 2));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Right hand", 3));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Left hand", 4));
return CreateCombo(jRow, jCombo, sComboBind, 128.0, 40.0);
}
json CreateModelCombo(object oPC, object oTarget, json jRow, string sComboBind)
{
float fFacing = GetFacing(oTarget);
json jCombo, jCraft = GetLocalJson(oPC, CRAFT_JSON);
int nSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_ITEM_SELECTION));
// Create the list.
// Armor.
if(nSelected == 0)
{
fFacing += 180.0f;
if (fFacing > 359.0) fFacing -=359.0;
AssignCommand(oPC, SetCameraFacing(fFacing, 4.5f, 75.0, CAMERA_TRANSITION_TYPE_VERY_FAST));
jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Neck", 0));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Shoulder", 1));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Bicep", 2));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Forearm", 3));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Hand", 4));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Torso", 5));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Belt", 6));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Pelvis", 7));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Thigh", 8));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Shin", 9));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Foot", 10));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Robe", 11));
}
// Cloak.
else if(nSelected == 1)
{
if(fFacing > 359.0) fFacing -=359.0;
AssignCommand (oPC, SetCameraFacing(fFacing, 4.5f, 75.0, CAMERA_TRANSITION_TYPE_VERY_FAST));
jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Cloak", 0));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Invisible", 1));
}
// Headgear.
else if (nSelected == 2)
{
fFacing += 180.0f;
if(fFacing > 359.0) fFacing -=359.0;
AssignCommand(oPC, SetCameraFacing(fFacing, 2.5f, 75.0, CAMERA_TRANSITION_TYPE_VERY_FAST));
jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Headgear", 0));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Invisible", 1));
}
// Weapon.
else if (nSelected == 3)
{
// If they are changing a bow then face the opposite side.
object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
int nBaseItemType = GetBaseItemType(oItem);
if(nBaseItemType == BASE_ITEM_LONGBOW || nBaseItemType == BASE_ITEM_SHORTBOW) fFacing -= 90.00;
// This will make the camera face a melee weapon.
else fFacing += 90.0;
if(fFacing > 359.0) fFacing -=359.0;
AssignCommand(oPC, SetCameraFacing(fFacing, 3.5f, 75.0, CAMERA_TRANSITION_TYPE_VERY_FAST));
jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Weapon", 0));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Acidic", 1));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Frost", 2));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Electric", 3));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Unholy", 4));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Flaming", 5));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Holy", 6));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Sonic", 7));
}
// Weapon/Shield.
else if(nSelected == 4)
{
fFacing += 270.0f;
if(fFacing > 359.0) fFacing -=359.0;
AssignCommand(oPC, SetCameraFacing(fFacing, 3.5f, 75.0, CAMERA_TRANSITION_TYPE_VERY_FAST));
object oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
if(ai_GetIsShield(oItem))
{
jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Shield", 0));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Invisible", 1));
}
else
{
jCombo = JsonArrayInsert(JsonArray(), NuiComboEntry("Weapon", 0));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Acidic", 1));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Frost", 2));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Electric", 3));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Unholy", 4));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Flaming", 5));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Holy", 6));
jCombo = JsonArrayInsert(jCombo, NuiComboEntry("Sonic", 7));
}
}
return CreateCombo(jRow, jCombo, sComboBind, 128.0, 40.0);
}
void SetMaterialButtons(object oPC, int nToken, int nMaterial)
{
int nIndex, bBool, bUseable;
string sIndex;
if(nMaterial > -1) bUseable = TRUE;
for(nIndex = 0;nIndex < 6;nIndex++)
{
if(nIndex == nMaterial) bBool = TRUE;
else bBool = FALSE;
sIndex = IntToString(nIndex);
NuiSetBind(oPC, nToken, "btn_material_" + sIndex + "_event", JsonBool(bUseable));
NuiSetBind(oPC, nToken, "btn_material_" + sIndex, JsonBool(bBool));
}
}
object GetSelectedItem(object oTarget, int nItemSelected)
{
if(nItemSelected == 0) return GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget);
else if(nItemSelected == 1) return GetItemInSlot(INVENTORY_SLOT_CLOAK, oTarget);
else if(nItemSelected == 2) return GetItemInSlot(INVENTORY_SLOT_HEAD, oTarget);
else if(nItemSelected == 3) return GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
else if(nItemSelected == 4) return GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
return OBJECT_INVALID;
}
int GetArmorModelSelected(object oPC)
{
json jCraft = GetLocalJson(oPC, CRAFT_JSON);
int nModelSelected = JsonGetInt(JsonObjectGet(jCraft, CRAFT_MODEL_SELECTION));
if(nModelSelected == 0) return ITEM_APPR_ARMOR_MODEL_NECK;
if(nModelSelected == 1) return ITEM_APPR_ARMOR_MODEL_RSHOULDER;
if(nModelSelected == 2) return ITEM_APPR_ARMOR_MODEL_RBICEP;
if(nModelSelected == 3) return ITEM_APPR_ARMOR_MODEL_RFOREARM;
if(nModelSelected == 4) return ITEM_APPR_ARMOR_MODEL_RHAND;
if(nModelSelected == 5) return ITEM_APPR_ARMOR_MODEL_TORSO;
if(nModelSelected == 6) return ITEM_APPR_ARMOR_MODEL_BELT;
if(nModelSelected == 7) return ITEM_APPR_ARMOR_MODEL_PELVIS;
if(nModelSelected == 8) return ITEM_APPR_ARMOR_MODEL_RTHIGH;
if(nModelSelected == 9) return ITEM_APPR_ARMOR_MODEL_RSHIN;
if(nModelSelected == 10) return ITEM_APPR_ARMOR_MODEL_RFOOT;
return ITEM_APPR_ARMOR_MODEL_ROBE;
}
int GetHasPartColor(object oItem, int nPart, string sSide)
{
json jItem = ObjectToJson(oItem);
string sPartName = "APart_";
if(sSide == "Left")
{
// Note: Right Thigh and Left Thigh are backwards so this fixes that!
if (nPart == ITEM_APPR_ARMOR_MODEL_RTHIGH) nPart--;
else nPart++;
}
sPartName += IntToString(nPart) + "_Col_";
int nPartColor = JsonGetInt(GffGetByte(jItem, sPartName + "0"));
nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "1"));
nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "2"));
nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "3"));
nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "4"));
nPartColor += JsonGetInt(GffGetByte(jItem, sPartName + "5"));
return nPartColor;
// Set this variable on the player so PEPS can run the targeting script for this plugin.
SetLocalString(oPC, AI_PLUGIN_TARGET_SCRIPT, "pe_crafting");
// Set Targeting variables.
SetLocalString(oPC, AI_TARGET_MODE, "SELECT_TARGET");
ai_SendMessages("Select your charcter, a henchman or an item possessed by one.", AI_COLOR_YELLOW, oPC);
EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE | OBJECT_TYPE_ITEM , MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE);
}
int StartingUp(object oPC)
{

View File

@@ -16,7 +16,7 @@ void main()
//SetLocalInt (oPC, AI_NO_NUI_SAVE, TRUE);
//DelayCommand (0.5f, DeleteLocalInt (oPC, AI_NO_NUI_SAVE));
string sText = " [Single player]";
if(AI_SERVER) sText = " [Server]";
if(ai_GetIsServer()) sText = " [Server]";
// ************************************************************************* Width / Height
// Row 1 ******************************************************************* 500 / 73
json jRow = JsonArrayInsert(JsonArray(), NuiSpacer());
@@ -30,25 +30,31 @@ void main()
// Add row to the column.
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
// Row 3 ******************************************************************* 500 / 101
sText = "Monster AI (nw_c2_default1): " + ResManGetAliasFor("nw_c2_default1", RESTYPE_NCS);
jRow = CreateLabel(JsonArray(), sText, "monster_1_ai", 470.0f, 20.0f, NUI_HALIGN_CENTER);
// Add row to the column.
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
sText = ResManGetAliasFor("nw_c2_default1", RESTYPE_NCS);
if(sText != "")
{
jRow = CreateLabel(JsonArray(), "Monster AI (nw_c2_default1): " + sText, "monster_1_ai", 470.0f, 20.0f);
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
}
// Row 4 ******************************************************************* 500 / 157
sText = "Monster AI (j_ai_onheartbeat): " + ResManGetAliasFor("j_ai_onheartbeat", RESTYPE_NCS);
jRow = CreateLabel(JsonArray(), sText, "monster_2_ai", 470.0f, 20.0f, NUI_HALIGN_CENTER);
// Add row to the column.
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
sText = ResManGetAliasFor("j_ai_onheartbeat", RESTYPE_NCS);
if(sText != "")
{
jRow = CreateLabel(JsonArray(), "Monster AI (j_ai_onheartbeat): " + sText, "monster_2_ai", 470.0f, 20.0f);
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
}
// Row 5 ******************************************************************* 500 / 213
sText = "Associate AI (nw_ch_ac1): " + ResManGetAliasFor("nw_ch_ac1", RESTYPE_NCS);
jRow = CreateLabel(JsonArray(), sText, "henchman_ai", 470.0f, 20.0f, NUI_HALIGN_CENTER);
// Add row to the column.
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
sText = ResManGetAliasFor("nw_ch_ac1", RESTYPE_NCS);
if(sText != "")
{
jRow = CreateLabel(JsonArray(), "Associate AI (nw_ch_ac1): " + sText, "henchman_ai", 470.0f, 20.0f);
jCol = JsonArrayInsert(jCol, NuiRow(jRow));
}
// Row 6 ******************************************************************* 500 / 241
jRow = JsonArrayInsert(JsonArray(), NuiSpacer());
jRow = CreateButton(jRow, "Set NPC's scripts", "btn_npc_scripts", 150.0f, 20.0f, -1.0, "btn_npc_scripts_tooltip");
jRow = JsonArrayInsert(jRow, NuiSpacer());
jRow = CreateButton(jRow, "Set Reputations", "btn_set_reputation", 150.0f, 20.0f, -1.0, "btn_set_reputation_tooltip");
jRow = CreateButton(jRow, "Set Commandable", "btn_set_commandable", 150.0f, 20.0f, -1.0, "btn_set_commandable_tooltip");
jRow = JsonArrayInsert(jRow, NuiSpacer());
jRow = CreateButton(jRow, "Clear Party Rep.", "btn_clear_reputation", 150.0f, 20.0f, -1.0, "btn_clear_reputation_tooltip");
jRow = JsonArrayInsert(jRow, NuiSpacer());
@@ -146,8 +152,8 @@ void main()
// Row 6
NuiSetBind(oPC, nToken, "btn_npc_scripts_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_npc_scripts_tooltip", JsonString(" Forces NPC to use Philos AI scripts!"));
NuiSetBind(oPC, nToken, "btn_set_reputation_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_set_reputation_tooltip", JsonString(" Sets a creatures faction to neutral for all standard factions."));
NuiSetBind(oPC, nToken, "btn_set_commandable_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_set_commandable_tooltip", JsonString(" Sets a creatures to commandable."));
NuiSetBind(oPC, nToken, "btn_clear_reputation_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_clear_reputation_tooltip", JsonString(" Clears the party's reputation with creature's faction."));
// Row 7

View File

@@ -369,11 +369,12 @@ void RemoveYourHenchman(object oPC, int nToken, string sParty)
else
{
RemoveHenchman(oPC, oHenchman);
ChangeToStandardFaction(oHenchman, STANDARD_FACTION_DEFENDER);
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);
}
ai_SendMessages(GetName(oHenchman) + " has been removed from the party!", AI_COLOR_GREEN, oPC);
NuiDestroy(oPC, nToken);
ExecuteScript("pi_henchmen", oPC);
}
@@ -388,6 +389,7 @@ void RemoveWholeParty(object oPC, int nToken, string sParty)
{
ai_SendMessages(GetName(oHenchman) + " has been remove from your Party.", AI_COLOR_YELLOW, oPC);
RemoveHenchman(oPC, oHenchman);
ChangeToStandardFaction(oHenchman, STANDARD_FACTION_DEFENDER);
AssignCommand(oHenchman, SetIsDestroyable(TRUE, FALSE, FALSE));
NuiDestroy(oPC, NuiFindWindow(oPC, ai_GetAssociateType(oPC, oHenchman) + AI_WIDGET_NUI));
DestroyObject(oHenchman);
@@ -426,10 +428,20 @@ void SaveYourHenchman(object oPC, int nToken, string sParty)
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);
else
{
DestroyObject(oHenchman);
// We need to make sure the henchman is not seen as a PC or DM!
jHenchman = GffReplaceByte(jHenchman, "IsPC", 0);
jHenchman = GffReplaceByte(jHenchman, "IsDM", 0);
// Rename them with a number added to the end, helps tell the
// difference between the PC and the new henchman.
string sNameIndex, sLastName = JsonGetString(GffGetLocString(jHenchman, "LastName"));
int nNameIndex = StringToInt(GetStringRight(sLastName, 1));
if(nNameIndex > 0) GetStringLeft(sLastName, GetStringLength(sLastName) -1) + IntToString(nNameIndex++);
else sNameIndex = "_1";
jHenchman = GffReplaceLocString(jHenchman, "LastName", sLastName + "_");
}
CheckHenchmanDataAndInitialize(oPC, sSlot);
SetHenchmanDbString(oPC, "image", GetPortraitResRef(oHenchman), sSlot);
SetHenchmanDbString(oPC, "henchname", sHenchmanName, sSlot);
@@ -450,15 +462,13 @@ void SaveYourHenchman(object oPC, int nToken, string sParty)
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);
if(sName == "") ai_SendMessages(sHenchmanName + " has been saved to the party " + sParty + ".", AI_COLOR_GREEN, oPC);
else ai_SendMessages(sHenchmanName + " has replaced a copy of themselves in the party " + sParty + ".", 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);
if(nIndex == nMaxHenchman) ai_SendMessages("This party is full!", AI_COLOR_RED, oPC);
}
void SaveWholeParty(object oPC, int nToken, string sParty)
{
@@ -672,11 +682,8 @@ int GetSelectionByPackage2DA(string sClass, int nPackage)
if(Get2DAString("packages", "ClassID", nIndex) == sClass)
{
sPackageName = GetStringByStrRef(StringToInt(Get2DAString("packages", "Name", nIndex)));
if(sPackageName != "Bad Strref" && sPackageName != "")
{
if(nPackage == nIndex) return nSelection;
nSelection++;
}
if(nPackage == nIndex) return nSelection;
nSelection++;
}
nIndex++;
}
@@ -814,10 +821,25 @@ json CreateLevelStatList(json jHenchman, object oHenchman, object oPC, int nLeve
{
jLevelArray = JsonArrayInsert(jLevelArray, jLevel);
}
WriteTimestampedLogEntry("pinc_henchmen, 813, Creating LvlStatList for " + GetName(oHenchman));
//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)
int GetHasJFeat(int nFeat, json jFeatList)
{
int nIndex, nJFeat, nMaxFeats = JsonGetLength(jFeatList);
json jFeat;
//WriteTimestampedLogEntry("pinc_henchmen, 831, nFeat: " + IntToString(nFeat) + " nMaxFeats: " + IntToString(nMaxFeats) + ".");
while(nIndex < nMaxFeats)
{
jFeat = JsonArrayGet(jFeatList, nIndex);
nJFeat = JsonGetInt(GffGetWord(jFeat, "Feat"));
//WriteTimestampedLogEntry("pinc_henchmen, 831, nJFeat: " + IntToString(nJFeat) + ".");
if(nJFeat == nFeat) return TRUE;
nIndex++;
}
return FALSE;
}
int CanSelectFeat(json jCreature, object oCreature, int nFeat, json jFeats, int nPosition = 1)
{
// Check if all classes can use.
int n2DAStat = StringToInt(Get2DAString("feat", "ALLCLASSESCANUSE", nFeat));
@@ -855,28 +877,30 @@ int CanSelectFeat(json jCreature, object oCreature, int nFeat, int nPosition = 1
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 != "")
{
int nLevel = GetLevelByPosition(nPosition, oCreature);
nSpellLevel = StringToInt(Get2DAString(s2DAName, "NumSpellLevels", nLevel - 1)) - 1;
if(nSpellLevel < 0) nSpellLevel = 0;
}
if(nSpellLevel < n2DAStat) return FALSE;
n2DAStat = StringToInt(Get2DAString("feat", "PREREQFEAT1", nFeat));
if(n2DAStat > 0)
if(n2DAStat > 0 && GetHasJFeat(n2DAStat, jFeats))
{
// ************************************** 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;
if(n2DAStat > 0 && !GetHasJFeat(n2DAStat, jFeats)) 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;
if(n2DAStat > 0)
{
if(GetHasJFeat(n2DAStat, jFeats)) break;
}
else return FALSE;
++nIndex;
}
string s2DAStat = Get2DAString("feat", "REQSKILL", nFeat);
if(s2DAStat != "")
@@ -969,7 +993,7 @@ json ResetFeats(json jHenchman, object oHenchman)
int nRace = GetRacialType(oHenchman);
string sRace2DAName = Get2DAString("racialtypes", "FeatsTable", nRace);
// Give racial feats.
WriteTimestampedLogEntry("pinc_henchmen, 972, Checking for racial feats.");
WriteTimestampedLogEntry("pinc_henchmen, 996, Checking for racial feats.");
int nRaceRow, nRaceFeat;
int nRaceMaxRow = Get2DARowCount(sRace2DAName);
while(nRaceRow < nRaceMaxRow)
@@ -979,12 +1003,12 @@ json ResetFeats(json jHenchman, object oHenchman)
jFeat = GffAddWord(jFeat, "Feat", nRaceFeat);
jFeat = JsonObjectSet(jFeat, "__struct_id", JsonInt(1));
jFeatList = JsonArrayInsert(jFeatList, jFeat);
WriteTimestampedLogEntry("pinc_henchmen, 982, Adding racial feat: " +
WriteTimestampedLogEntry("pinc_henchmen, 999, Adding racial feat: " +
Get2DAString("feat", "LABEL", nRaceFeat));
nRaceRow++;
}
// Give class feats.
WriteTimestampedLogEntry("pinc_henchmen, 972, Checking for class feats.");
WriteTimestampedLogEntry("pinc_henchmen, 1004, Checking for class feats.");
int nClass = GetClassByPosition(1, oHenchman);
string sGranted, sList;
string sClsFeat2DAName = Get2DAString("classes", "FeatsTable", nClass);
@@ -1002,17 +1026,17 @@ json ResetFeats(json jHenchman, object oHenchman)
jFeat = GffAddWord(jFeat, "Feat", nClassFeat);
jFeat = JsonObjectSet(jFeat, "__struct_id", JsonInt(1));
jFeatList = JsonArrayInsert(jFeatList, jFeat);
WriteTimestampedLogEntry("pinc_henchmen, 1005, Adding class feat: " +
WriteTimestampedLogEntry("pinc_henchmen, 1022, 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));
WriteTimestampedLogEntry("pinc_henchmen, 1032, Select " + IntToString(nNumOfFeats) + " bonus feats.");
string sPackage2DAName = Get2DAString("packages", "FeatPref2DA", nClass);
int nPackageMaxRow = Get2DARowCount(sPackage2DAName);
// Give bonus feats based on the package.
@@ -1029,13 +1053,13 @@ json ResetFeats(json jHenchman, object oHenchman)
if(nClassFeat == nPackageFeat)
{
sList = Get2DAString(sClsFeat2DAName, "List", nClassRow);
if((sList == "1" || sList == "2") && CanSelectFeat(jHenchman, oHenchman, nClassFeat))
if((sList == "1" || sList == "2") && CanSelectFeat(jHenchman, oHenchman, nClassFeat, jFeatList))
{
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: " +
WriteTimestampedLogEntry("pinc_henchmen, 1055, Adding class bonus feat: " +
Get2DAString("feat", "LABEL", nPackageFeat));
nNumOfFeats--;
}
@@ -1047,44 +1071,46 @@ json ResetFeats(json jHenchman, object oHenchman)
}
}
// Give picked feats from package.
WriteTimestampedLogEntry("pinc_henchmen, 972, Checking for select feats.");
nNumOfFeats = 1;
if(GetHasFeat(FEAT_QUICK_TO_MASTER, oHenchman)) nNumOfFeats++;
WriteTimestampedLogEntry("pinc_henchmen, 1069, Select " + IntToString(nNumOfFeats) + " feats for character.");
nPackageRow = 0;
while(nPackageRow < nPackageMaxRow || nNumOfFeats > 0)
while(nPackageRow < nPackageMaxRow)
{
nClassRow = 0;
nPackageFeat = StringToInt(Get2DAString(sPackage2DAName, "FeatIndex", nPackageRow));
if(CanSelectFeat(jHenchman, oHenchman, nPackageFeat))
//WriteTimestampedLogEntry("pinc_henchmen, 1075, nPackageFeat: " + Get2DAString("feat", "LABEL", nPackageFeat) + ".");
if(CanSelectFeat(jHenchman, oHenchman, nPackageFeat, jFeatList))
{
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: " +
WriteTimestampedLogEntry("pinc_henchmen, 1082, Selecting character feat: " +
Get2DAString("feat", "LABEL", nPackageFeat));
nNumOfFeats--;
}
if(nNumOfFeats < 1) break;
nPackageRow++;
}
WriteTimestampedLogEntry("pinc_henchmen, 1071, Adding feat list.");
WriteTimestampedLogEntry("pinc_henchmen, 1089, Adding feat list.");
jHenchman = GffReplaceList(jHenchman, "FeatList", jFeatList);
return jHenchman;
}
json ResetSkills(json jHenchman, object oHenchman)
json ResetSkills(json jHenchman, object oHenchman, int nLevel)
{
// 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;
if(nIntMod > 0) nSkillPoints = nIntMod;
if(GetRacialType(oHenchman) == RACIAL_TYPE_HUMAN) nSkillPoints += 1;
nSkillPoints += StringToInt(Get2DAString("classes", "SkillPointBase", nClass));
nSkillPoints = nSkillPoints * (nLevel + 3);
int nMaxRanks = 3 + nLevel;
json jSkillList = JsonArray();
json jSkill;
// Setup the Skill List.
WriteTimestampedLogEntry("pinc_henchmen, 1087, Generating skill list.");
WriteTimestampedLogEntry("pinc_henchmen, 1112, Generating skill list.");
int nIndex, nSkillMaxRow = Get2DARowCount("skills");
for(nIndex = 0; nIndex < nSkillMaxRow; nIndex++)
{
@@ -1094,7 +1120,7 @@ json ResetSkills(json jHenchman, object oHenchman)
jSkillList = JsonArrayInsert(jSkillList, jSkill);
}
// Give skill points based on the package.
WriteTimestampedLogEntry("pinc_henchmen, 1097, Gets " + IntToString(nSkillPoints) + " skill points.");
WriteTimestampedLogEntry("pinc_henchmen, 1116, Gets " + IntToString(nSkillPoints) + " skill points.");
int nPackageSkill, nPackageRow, nCurrentRanks, bCrossClass, nClassRow, nNewRanks;
string sPackage2DAName = Get2DAString("packages", "SkillPref2DA", nClass);
int nPackageMaxRow = Get2DARowCount(sPackage2DAName);
@@ -1123,7 +1149,7 @@ json ResetSkills(json jHenchman, object oHenchman)
{
jSkill = GffReplaceByte(jSkill, "Rank", nCurrentRanks + nNewRanks);
jSkillList = JsonArraySet(jSkillList, nPackageSkill, jSkill);
WriteTimestampedLogEntry("pinc_henchmen, 1126, Adding " + IntToString(nNewRanks) +
WriteTimestampedLogEntry("pinc_henchmen, 1145, Adding " + IntToString(nNewRanks) +
" ranks to " + Get2DAString("skills", "Label", nPackageSkill) +
" CrossClass: " + IntToString(bCrossClass));
nSkillPoints -= nNewRanks;
@@ -1135,9 +1161,9 @@ json ResetSkills(json jHenchman, object oHenchman)
}
json ResetSpellsKnown(json jClass, object oHenchman)
{
WriteTimestampedLogEntry("pinc_henchmen, 1138, Checking for spells known.");
WriteTimestampedLogEntry("pinc_henchmen, 1157, Checking for spells known.");
int nClass = GetClassByPosition(1, oHenchman);
WriteTimestampedLogEntry("pinc_henchmen, 1140, SpellCaster: " + Get2DAString("classes", "SpellCaster", nClass));
WriteTimestampedLogEntry("pinc_henchmen, 1159, 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!
@@ -1179,7 +1205,7 @@ json ResetSpellsKnown(json jClass, object oHenchman)
{
nSpellsKnown = StringToInt(Get2DAString(sSpellKnown2DAName, "SpellLevel" + sSpellLevel, nLevel));
}
WriteTimestampedLogEntry("pinc_henchmen, 1165, nSpellsKnown: " + IntToString(nSpellsKnown));
WriteTimestampedLogEntry("pinc_henchmen, 1201, nSpellsKnown: " + IntToString(nSpellsKnown));
jKnownList = JsonArray();
nPackageRow = 0;
while(nPackageRow < nPackageMaxRow && nSpellsKnown > 0)
@@ -1201,7 +1227,7 @@ json ResetSpellsKnown(json jClass, object oHenchman)
if(JsonGetLength(jKnownList) == 0)
{
jClass = GffRemoveList(jClass, "KnownList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1187, Removing KnownList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1223, Removing KnownList" + sSpellLevel);
}
else if(JsonGetType(GffGetList(jClass, "KnownList" + sSpellLevel)) != JSON_TYPE_NULL)
{
@@ -1217,7 +1243,7 @@ json ResetSpellsKnown(json jClass, object oHenchman)
if(JsonGetType(jKnownList) != JSON_TYPE_NULL)
{
jClass = GffRemoveList(jClass, "KnownList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1203, Removing KnownList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1239, Removing KnownList" + sSpellLevel);
}
}
if(bMemorizesSpells)
@@ -1226,7 +1252,7 @@ json ResetSpellsKnown(json jClass, object oHenchman)
if(JsonGetType(jMemorizedList) != JSON_TYPE_NULL)
{
jClass = GffRemoveList(jClass, "MemorizedList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1210, Removing MemorizedList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1248, Removing MemorizedList" + sSpellLevel);
}
}
else
@@ -1237,7 +1263,7 @@ json ResetSpellsKnown(json jClass, object oHenchman)
jSpell = GffReplaceByte(jSpell, "NumSpellsLeft", nSpellsKnown);
jSpellsPerDayList = JsonArraySet(jSpellsPerDayList, nSpellLevel, jSpell);
jClass = GffReplaceList(jClass, "SpellsPerDayList", jSpellsPerDayList);
WriteTimestampedLogEntry("pinc_henchmen, 1223, Setting SpellsPerDay to " +
WriteTimestampedLogEntry("pinc_henchmen, 1259, Setting SpellsPerDay to " +
IntToString(nSpellsKnown));
}
nSpellLevel++;
@@ -1248,11 +1274,12 @@ object ResetCharacter(object oPC, object oHenchman)
{
SetLocalInt(oPC, "AI_IGNORE_NO_ASSOCIATE", TRUE);
RemoveHenchman(oPC, oHenchman);
ChangeToStandardFaction(oHenchman, STANDARD_FACTION_DEFENDER);
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"));
int nClass = JsonGetInt(GffGetInt(jClass, "Class"));
jClass = GffReplaceShort(jClass, "ClassLevel", 1);
// Delete extra classes.
int nClassIndex = JsonGetLength(jClassList) - 1;
@@ -1260,15 +1287,10 @@ object ResetCharacter(object oPC, object oHenchman)
{
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);
// int nPackage = GetLocalInt(oHenchman, "PACKAGE_SELECTED_1");
// if(nPackage) jHenchman = GffReplaceByte(jHenchman, "StartingPackage", nPackage);
string s2DA = Get2DAString("classes", "AttackBonusTable", nClass);
int nAtk = StringToInt(Get2DAString(s2DA, "BAB", 0));
jHenchman = GffReplaceByte(jHenchman, "BaseAttackBonus", nAtk);
@@ -1282,7 +1304,7 @@ object ResetCharacter(object oPC, object oHenchman)
json jLvlStatList = GffGetList(jHenchman, "LvlStatList");
if(JsonGetType(jLvlStatList) != JSON_TYPE_NULL)
{
WriteTimestampedLogEntry("pinc_henchmen 1275, jLvlStatList: " + JsonDump(jLvlStatList, 4));
//WriteTimestampedLogEntry("pinc_henchmen 1300, jLvlStatList: " + JsonDump(jLvlStatList, 4));
int nLevel = 1, nLevelTrack = 1;
int nAbilityStatIncrease, nAbility;
string sAbility;
@@ -1290,7 +1312,7 @@ object ResetCharacter(object oPC, object oHenchman)
json jLevel = JsonArrayGet(jLvlStatList, nLevel);
while(JsonGetType(jLevel) != JSON_TYPE_NULL)
{
WriteTimestampedLogEntry("inc_henchmen, 1297, Checking level " + IntToString(nLevelTrack));
WriteTimestampedLogEntry("inc_henchmen, 1308, 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)
@@ -1316,12 +1338,21 @@ object ResetCharacter(object oPC, object oHenchman)
jHenchman = GffRemoveList(jHenchman, "LvlStatList");
}
jHenchman = CreateLevelStatList(jHenchman, oHenchman, oPC, 1);
jHenchman = ResetSkills(jHenchman, oHenchman);
int nHitPoints = StringToInt(Get2DAString("classes", "HitDie", nClass));
int nConstitution = JsonGetInt(GffGetByte(jHenchman, "Con"));
int nRace = JsonGetInt(GffGetByte(jHenchman, "Race"));
nConstitution += StringToInt(Get2DAString("racialtypes", "ConAdjust", nRace));
if(nConstitution > 9) nHitPoints += (nConstitution - 10) / 2;
else nHitPoints += (nConstitution - 11) / 2;
jHenchman = GffReplaceShort(jHenchman, "CurrentHitPoints", nHitPoints);
jHenchman = GffReplaceShort(jHenchman, "HitPoints", nHitPoints);
jHenchman = GffReplaceShort(jHenchman, "MaxHitPoints", nHitPoints);
jHenchman = ResetSkills(jHenchman, oHenchman, 1);
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));
//WriteTimestampedLogEntry("pinc_henchmen 1348, jHenchman: " + JsonDump(jHenchman, 4));
location lLocation = GetLocation(oHenchman);
int nFamiliar, nCompanion;
object oCompanion = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oHenchman);
@@ -1342,13 +1373,13 @@ void CreateCharacterEditGUIPanel(object oPC, object oHenchman)
// 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 = CreateTextEditBox (jGroupRow, "name_placeholder", "char_name", 50, 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 = CreateTextEditBox (jGroupRow, "port_placeholder", "port_name", 16, FALSE, 140.0, 20.0, "port_tooltip");
jGroupRow = JsonArrayInsert(jGroupRow, NuiSpacer());
// Add the group row to the group column.
jGroupCol = JsonArrayInsert(jGroupCol, NuiRow(jGroupRow));
@@ -1503,11 +1534,13 @@ void CreateCharacterEditGUIPanel(object oPC, object oHenchman)
NuiSetBindWatch(oPC, nToken, "cmb_class_selected", bNoClass);
NuiSetBind(oPC, nToken, "cmb_class_event", JsonBool(bNoClass));
int nPackage = GetLocalInt(oHenchman, "PACKAGE_SELECTED_" + IntToString(nClassOption + 1));
//SendMessageToPC(oPC, "nPackage: " + IntToString(nPackage) + " nSelection: " + IntToString(GetSelectionByPackage2DA(sClass, nPackage)));
if(nPackage == 0)
{
nPackage = GetPackageBySelection2DA(sClass, 0);
SetLocalInt(oHenchman, "PACKAGE_SELECTED_" + IntToString(nClassOption + 1), nPackage);
}
//SendMessageToPC(oPC, "nPackage: " + IntToString(nPackage) + " sClass: " + sClass);
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));
@@ -1538,4 +1571,3 @@ void CreateCharacterDescriptionNUI(object oPC, string sName, string sIcon, strin
// Row 2
NuiSetBind(oPC, nToken, "btn_ok_event", JsonBool(TRUE));
}