2025/12/16 Update

Updated PEPS
Hooked up new GUI module event.
Updated classes.2da
Updated baseitems.2da
Updated nim tools.
Full compile.
This commit is contained in:
Jaysyn904
2025-12-16 21:30:44 -05:00
parent 97b1aa3cf2
commit 9c4c3ae83b
1065 changed files with 37628 additions and 36380 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

@@ -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

@@ -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

@@ -236,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);
@@ -274,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));
}
@@ -310,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")
{
@@ -652,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
{
@@ -659,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;
@@ -955,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
{
@@ -971,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")
@@ -1248,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");

View File

@@ -208,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");
@@ -243,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));
@@ -264,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

@@ -14,13 +14,6 @@
AI_TARGET_MODE_ON defines if the player is in target mode for a henchman instead of the PC.
/*//////////////////////////////////////////////////////////////////////////////
#include "0i_player_target"
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 main()
{
object oPC = GetLastPlayerToSelectTarget();
@@ -40,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())
@@ -47,11 +41,8 @@ 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")
{
@@ -67,41 +58,33 @@ void main()
AttachCamera(oPC, oPC);
if(!GetLocalInt(GetModule(), AI_USING_PRC)) ai_TurnOff(oPC, oPC, "pc");
}
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
ai_SetAIMode(oAssociate, AI_MODE_COMMANDED, FALSE);
if(ai_GetAIMode(oPC, AI_MODE_ACTION_GHOST) && !ai_GetAIMode(oPC, AI_MODE_GHOST) &&
GetLocalInt(oAssociate, sGhostModeVarname))
{
if(GetLocalInt(oPC, sGhostModeVarname))
{
ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST);
DeleteLocalInt(oAssociate, sGhostModeVarname);
}
}
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_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.
@@ -111,8 +94,8 @@ void main()
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
@@ -120,29 +103,38 @@ 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")
{
@@ -150,6 +142,7 @@ void main()
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")
{
@@ -157,11 +150,13 @@ void main()
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")
{
@@ -171,17 +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.
ExecuteScript(GetLocalString(GetModule(), AI_MODULE_TARGET_EVENT));
}
// Get saved module player target script and execute it for pass through compatibility.
ExecuteScript(GetLocalString(GetModule(), AI_MODULE_TARGET_EVENT));
}
}

View File

@@ -196,7 +196,7 @@ void ai_DoAssociateCombatRound(object oCreature, object oTarget = OBJECT_INVALID
{
SetLocalInt(oCreature, AI_POLYMORPHED, TRUE);
ai_ClearTalents(oCreature);
ai_SetCreatureSpecialAbilityTalents(oCreature, FALSE, TRUE);
ai_SetCreatureSpecialAbilityTalents(oCreature, FALSE, FALSE, FALSE);
}
}
}
@@ -219,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);
@@ -249,7 +250,7 @@ void ai_DoMonsterCombatRound(object oMonster)
{
SetLocalInt(oMonster, AI_POLYMORPHED, TRUE);
ai_ClearTalents(oMonster);
ai_SetCreatureSpecialAbilityTalents(oMonster, TRUE, TRUE);
ai_SetCreatureSpecialAbilityTalents(oMonster, TRUE, FALSE, FALSE);
}
}
}
@@ -410,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
@@ -420,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;
}
@@ -533,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;

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.
@@ -523,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);
}
}
}
}
}
@@ -773,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);
@@ -836,7 +856,7 @@ 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(AI_I_SEE_AN_ENEMY, TALKVOLUME_SILENT_TALK);
@@ -923,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();

View File

@@ -574,7 +574,7 @@ int ai_GetRacialTypeCount(object oCreature, int nRacial_Type, float fDistance =
object ai_GetLowestCRAttackerOnMaster(object oCreature)
{
object oTarget = OBJECT_INVALID, oMaster = GetMaster(oCreature);
if(AI_DEBUG) ai_Debug("0i_combat", "419", "Checking for weakest attacker on " + GetName(oMaster));
if(AI_DEBUG) ai_Debug("0i_combat", "577", "Checking for weakest attacker on " + GetName(oMaster));
int nEnemyCombatRating, nWeakestCombatRating, nCntr = 1;
float fNearest = AI_RANGE_MELEE + 1.0f;
// Get the weakest opponent in melee with our master.
@@ -583,7 +583,7 @@ object ai_GetLowestCRAttackerOnMaster(object oCreature)
while (oEnemy != OBJECT_INVALID && fDistance <= AI_RANGE_MELEE)
{
nEnemyCombatRating = ai_GetMyCombatRating(oEnemy);
if(AI_DEBUG) ai_Debug("0i_combat", "428", GetName(oEnemy) + " nECR: " + IntToString(nEnemyCombatRating));
if(AI_DEBUG) ai_Debug("0i_combat", "586", GetName(oEnemy) + " nECR: " + IntToString(nEnemyCombatRating));
if (nEnemyCombatRating < nWeakestCombatRating ||
nEnemyCombatRating == nWeakestCombatRating && fDistance < fNearest)
{
@@ -594,7 +594,13 @@ object ai_GetLowestCRAttackerOnMaster(object oCreature)
oEnemy = ai_GetNearestEnemy(oMaster, ++nCntr, 7, 7);
}
// No targets in melee with our master, lets see if there is a ranged attacker.
if (oTarget == OBJECT_INVALID) oTarget = GetLastHostileActor(oMaster);
if (oTarget == OBJECT_INVALID)
{
oTarget = GetLastHostileActor(oMaster);
// Sometimes things happen and our own associates may hurt the player too!
if(ai_GetTopMaster(oTarget) == oMaster) oTarget = OBJECT_INVALID;
}
if(AI_DEBUG) ai_Debug("0i_combat", "598", "Attacking master: " + GetName(oTarget));
return oTarget;
}
@@ -1091,7 +1097,101 @@ struct stTarget ai_CheckForLowestValueAllTarget(object oCreature, struct stTarge
}
return sTarget;
}
struct stTarget ai_CheckForNearestPhysicalTarget(object oCreature, struct stTarget sTarget, int nIndex, string sIndex)
{
if(AI_DEBUG) ai_Debug("0i_combat", "969", "Getting nearest physical index: " + sIndex +
" fRange: " + FloatToString(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex), 0, 2) +
" fNearestRange: " + FloatToString(sTarget.fNearestRange, 0, 2) +
" fNearestSecondaryRange: " + FloatToString(sTarget.fNearestSecondaryRange, 0, 2) +
" Weapon Effective: " + IntToString(GetIsWeaponEffective(sTarget.oTarget)));
// Lets put any disabled targets and associates if set in a secondary group.
if(GetLocalInt(oCreature, sTarget.sTargetType + "_DISABLED" + sIndex) ||
!GetIsWeaponEffective(sTarget.oTarget) ||
(ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && GetAssociateType(sTarget.oTarget)))
{
if(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestSecondaryRange)
{
sTarget.fNearestSecondaryRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex);
sTarget.nSecondaryIndex = nIndex;
}
}
else if(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestRange)
{
sTarget.fNearestRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex);
sTarget.nIndex = nIndex;
}
return sTarget;
}
struct stTarget ai_CheckForLowestValuePhysicalTarget(object oCreature, struct stTarget sTarget, int nIndex, string sIndex)
{
if(AI_DEBUG) ai_Debug("0i_combat", "1126", "Getting lowest value physcial index: " + sIndex +
" fRange: " + FloatToString(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex), 0, 2) +
" fNearestRange: " + FloatToString(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex), 0, 2) +
" fNearestSecondaryRange: " + FloatToString(sTarget.fNearestSecondaryRange, 0, 2) +
" sTarget.nValue: " + IntToString(sTarget.nValue) +
" sTarget.nBestValue: " + IntToString(sTarget.nBestValue) +
" sTarget.nBestSecondaryValue: " + IntToString(sTarget.nBestSecondaryValue) +
" Weapon Effective: " + IntToString(GetIsWeaponEffective(sTarget.oTarget)));
// Lets put any disabled targets and associates if set in a secondary group.
if(GetLocalInt(oCreature, sTarget.sTargetType + "_DISABLED" + sIndex) ||
!GetIsWeaponEffective(sTarget.oTarget) ||
(ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && GetAssociateType(sTarget.oTarget)))
{
if(sTarget.nValue < sTarget.nBestSecondaryValue ||
(sTarget.nValue == sTarget.nBestSecondaryValue &&
GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestSecondaryRange))
{
sTarget.fNearestSecondaryRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex);
sTarget.nBestSecondaryValue = sTarget.nValue;
sTarget.nSecondaryIndex = nIndex;
}
}
// Has less value or equal value and is closer.
else if(sTarget.nValue < sTarget.nBestValue ||
(sTarget.nBestValue == sTarget.nValue &&
GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestRange))
{
sTarget.fNearestRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex);
sTarget.nBestValue = sTarget.nValue;
sTarget.nIndex = nIndex;
}
return sTarget;
}
struct stTarget ai_CheckForHighestValuePhysicalTarget(object oCreature, struct stTarget sTarget, int nIndex, string sIndex)
{
if(AI_DEBUG) ai_Debug("0i_combat", "1025", "Getting highest value physical index: " + sIndex +
" fRange: " + FloatToString(GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex), 0, 2) +
" fNearestRange: " + FloatToString(sTarget.fNearestRange, 0, 2) +
" fNearestSecondaryRange: " + FloatToString(sTarget.fNearestSecondaryRange, 0, 2) +
" sTarget.nValue: " + IntToString(sTarget.nValue) +
" sTarget.nBestValue: " + IntToString(sTarget.nBestValue) +
" sTarget.nBestSecondaryValue: " + IntToString(sTarget.nBestSecondaryValue) +
" Weapon Effective: " + IntToString(GetIsWeaponEffective(sTarget.oTarget)));
// Lets put any disabled targets and associates if set in a secondary group.
if(GetLocalInt(oCreature, sTarget.sTargetType + "_DISABLED" + sIndex) ||
!GetIsWeaponEffective(sTarget.oTarget) ||
(ai_GetAIMode(oCreature, AI_MODE_IGNORE_ASSOCIATES) && GetAssociateType(sTarget.oTarget)))
{
if(sTarget.nValue > sTarget.nBestSecondaryValue ||
(sTarget.nValue == sTarget.nBestSecondaryValue &&
GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestSecondaryRange))
{
sTarget.fNearestSecondaryRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex);
sTarget.nBestSecondaryValue = sTarget.nValue;
sTarget.nSecondaryIndex = nIndex;
}
}
// Has less value or equal value and is closer.
else if(sTarget.nValue > sTarget.nBestValue ||
(sTarget.nBestValue == sTarget.nValue &&
GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex) < sTarget.fNearestRange))
{
sTarget.fNearestRange = GetLocalFloat(oCreature, sTarget.sTargetType + "_RANGE" + sIndex);
sTarget.nBestValue = sTarget.nValue;
sTarget.nIndex = nIndex;
}
return sTarget;
}
//******************************************************************************
//************ GET INDEX/TARGETs USING COMBAT STATE FUNCTIONS ******************
//******************************************************************************
@@ -1361,21 +1461,19 @@ int ai_GetNearestPhysicalIndex(object oCreature, float fMaxRange = AI_RANGE_PERC
sTarget.oTarget = GetLocalObject(oCreature, sTargetType + sCounter);
while(sTarget.oTarget != OBJECT_INVALID)
{
if(AI_DEBUG) ai_Debug("0i_combat", "1459", "Getting the nearest physical index: " +
if(AI_DEBUG) ai_Debug("0i_combat", "1464", "Getting the nearest physical index: " +
sCounter + " " + GetName(sTarget.oTarget) +
" Seen: " + IntToString(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter)) +
" GetIsDead: " + IntToString(GetIsDead(sTarget.oTarget)));
if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) &&
!GetIsDead(sTarget.oTarget))
{
if(AI_DEBUG) ai_Debug("0i_combat", "1466", "bAlwaysAtk: " + IntToString(bAlwaysAtk) +
" Weapon Effective: " + IntToString(GetIsWeaponEffective(sTarget.oTarget)));
if(AI_DEBUG) ai_Debug("0i_combat", "1471", "bAlwaysAtk: " + IntToString(bAlwaysAtk));
if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) &&
GetIsWeaponEffective(sTarget.oTarget) &&
ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) &&
ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget))
{
sTarget = ai_CheckForNearestTarget(oCreature, sTarget, nCounter, sCounter);
sTarget = ai_CheckForNearestPhysicalTarget(oCreature, sTarget, nCounter, sCounter);
}
}
sCounter = IntToString(++nCounter);
@@ -1383,7 +1481,7 @@ int ai_GetNearestPhysicalIndex(object oCreature, float fMaxRange = AI_RANGE_PERC
}
// If we do not have a normal target then use our best secondary target.
if(sTarget.nIndex == 0 && sTarget.nSecondaryIndex != 0) sTarget.nIndex = sTarget.nSecondaryIndex;
if(AI_DEBUG) ai_Debug("0i_combat", "1479", "Found nearest [" + sTargetType + "] Physical Index: " + IntToString(sTarget.nIndex));
if(AI_DEBUG) ai_Debug("0i_combat", "1484", "Found nearest [" + sTargetType + "] Physical Index: " + IntToString(sTarget.nIndex));
return sTarget.nIndex;
}
object ai_GetNearestPhysicalTarget(object oCreature, float fMaxRange = AI_RANGE_PERCEPTION, string sTargetType = AI_ENEMY, int bAlwaysAtk = TRUE)
@@ -1412,15 +1510,13 @@ int ai_GetLowestCRPhysicalIndex(object oCreature, float fMaxRange = AI_RANGE_PER
if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) &&
!GetIsDead(sTarget.oTarget))
{
if(AI_DEBUG) ai_Debug("0i_combat", "1508", "bAlwaysAtk: " + IntToString(bAlwaysAtk) +
" Weapon Effective: " + IntToString(GetIsWeaponEffective(sTarget.oTarget)));
if(AI_DEBUG) ai_Debug("0i_combat", "1508", "bAlwaysAtk: " + IntToString(bAlwaysAtk));
if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) &&
GetIsWeaponEffective(sTarget.oTarget) &&
ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) &&
ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget))
{
sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_COMBAT" + sCounter);
sTarget = ai_CheckForLowestValueTarget(oCreature, sTarget, nCounter, sCounter);
sTarget = ai_CheckForLowestValuePhysicalTarget(oCreature, sTarget, nCounter, sCounter);
}
}
sCounter = IntToString(++nCounter);
@@ -1457,15 +1553,13 @@ int ai_GetHighestCRPhysicalIndex(object oCreature, float fMaxRange = AI_RANGE_PE
if(GetLocalInt(oCreature, sTargetType + "_PERCEIVED" + sCounter) &&
!GetIsDead(sTarget.oTarget))
{
if(AI_DEBUG) ai_Debug("0i_combat", "1551", "bAlwaysAtk: " + IntToString(bAlwaysAtk) +
" Weapon Effective: " + IntToString(GetIsWeaponEffective(sTarget.oTarget)));
if(AI_DEBUG) ai_Debug("0i_combat", "1551", "bAlwaysAtk: " + IntToString(bAlwaysAtk));
if((bAlwaysAtk || !ai_IsStrongerThanMe(oCreature, nCounter)) &&
GetIsWeaponEffective(sTarget.oTarget) &&
ai_TargetIsInRangeofCreature(oCreature, sTargetType, sCounter, fMaxRange) &&
ai_TargetIsInRangeofMaster(oCreature, sTarget.oTarget))
{
sTarget.nValue = GetLocalInt(oCreature, sTargetType + "_COMBAT" + sCounter);
sTarget = ai_CheckForHighestValueTarget(oCreature, sTarget, nCounter, sCounter);
sTarget = ai_CheckForHighestValuePhysicalTarget(oCreature, sTarget, nCounter, sCounter);
}
}
sCounter = IntToString(++nCounter);
@@ -3505,7 +3599,7 @@ int ai_IsInADangerousAOE(object oCreature, float fMaxRange = AI_RANGE_BATTLEFIEL
ActionMoveToLocation(lLocation, TRUE);
return TRUE;
}
else if(bDangerous) return TRUE;
else return bDangerous;
return FALSE;
}
int ai_GetIsHidden(object oHidden)
@@ -3808,7 +3902,44 @@ int ai_CheckRangedCombatPosition(object oCreature, object oTarget, int nAction)
float fDistance = GetDistanceBetween(oCreature, oNearestEnemy);
if(AI_DEBUG) ai_Debug("0i_combat", "3337", "oNearestEnemy: " + GetName(oNearestEnemy) +
" fDistance: " + FloatToString(fDistance, 0, 2));
// If we have sneak attack then we want to be within 30'.
// If we have Point blank shot then we want to be within 15' [4 meters].
if(GetHasFeat(FEAT_POINT_BLANK_SHOT, oCreature))
{
if(fDistance > AI_RANGE_MELEE)
{
// 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. Just attack! Only sneak attack if they are busy.
int nAction = GetCurrentAction(oNearestEnemy);
if(AI_DEBUG) ai_Debug("0i_combat", "3353", GetName(oNearestEnemy) + " current action: " + IntToString(nAction));
if(nAction == ACTION_MOVETOPOINT ||
nAction == ACTION_INVALID ||
nAction == ACTION_RANDOMWALK) return FALSE;
// If they are attacking make sure it is in melee?
// If not then don't move since they might be moving toward us.
if(nAction == ACTION_ATTACKOBJECT)
{
if(!ai_GetNumOfEnemiesInRange(oNearestEnemy)) return FALSE;
}
if(AI_DEBUG) ai_Debug("0i_combat", "3355", GetName(oCreature) + " is moving closer [4.0] to " +
GetName(oNearestEnemy) + " to use Point blank shot with a ranged weapon.");
ai_SetLastAction(oCreature, AI_LAST_ACTION_MOVE);
ActionMoveToObject(oNearestEnemy, TRUE, AI_RANGE_CLOSE);
ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature));
return TRUE;
}
}
else if(fDistance < AI_RANGE_LONG)
{
// Lets move back a little, too far and we miss attacks!
if(AI_DEBUG) ai_Debug("0i_combat", "3374", GetName(oCreature) + " is moving away from " +
GetName(oNearestEnemy) + "[2.0] to use a ranged weapon.");
ai_SetLastAction(oCreature, AI_LAST_ACTION_MOVE);
ActionMoveAwayFromObject(oNearestEnemy, TRUE, 2.0);
ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature));
return TRUE;
}
// If we have sneak attack then we want to be within 30' [9 meters].
if(GetHasFeat(FEAT_SNEAK_ATTACK, oCreature))
{
if(fDistance > AI_RANGE_CLOSE)
@@ -3873,7 +4004,7 @@ int ai_CheckRangedCombatPosition(object oCreature, object oTarget, int nAction)
ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature));
return TRUE;
}
}
}
return FALSE;
}
int ai_CheckMeleeCombatPosition(object oCreature, object oTarget, int nAction, int nBaseItemType = 0)

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:08.31.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
@@ -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;
@@ -162,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.
@@ -240,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;
@@ -527,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
@@ -554,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.
@@ -597,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

@@ -34,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.
@@ -131,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));
@@ -217,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);
@@ -328,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);
@@ -874,6 +893,8 @@ void ai_SetupAIData(object oPlayer, object oAssociate, string sAssociateType)
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)
@@ -985,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();
@@ -1086,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");

View File

@@ -410,7 +410,8 @@ void ai_CreateAIMainNUI(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, " Will use all buff spells!", "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));
@@ -454,7 +455,7 @@ void ai_CreateAIMainNUI(object oPC)
if(GetStringRight(sName, 1) == "s") sName = sName + "'";
else sName = sName + "'s";
int nToken = SetWindow(oPC, jLayout, AI_MAIN_NUI, sName + " PEPS Main Menu",
fX, fY, 534.0f, fHeight, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui");
fX, fY, 554.0f, fHeight, FALSE, FALSE, TRUE, FALSE, TRUE, "0e_nui");
// Save the associate to the nui for use in 0e_nui
json jData = JsonArray();
jData = JsonArrayInsert(jData, JsonString(ObjectToString(oPC)));
@@ -537,9 +538,15 @@ void ai_CreateAIMainNUI(object oPC)
NuiSetBind(oPC, nToken, "txt_ai_difficulty", JsonString(IntToString(GetLocalInt(oModule, AI_RULE_AI_DIFFICULTY))));
NuiSetBindWatch(oPC, nToken, "txt_ai_difficulty", TRUE);
NuiSetBind(oPC, nToken, "txt_ai_difficulty_event", JsonBool(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));
@@ -595,6 +602,7 @@ void ai_CreateAIMainNUI(object oPC)
NuiSetBind(oPC, nToken, "txt_inc_enc_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "txt_inc_hp", JsonString(IntToString(GetLocalInt(oModule, AI_INCREASE_MONSTERS_HP))));
NuiSetBindWatch(oPC, nToken, "txt_inc_hp", TRUE);
NuiSetBind(oPC, nToken, "txt_inc_hp_tooltip", JsonString(" Will increase ALL monsters hitpoints by the%. Upto 500% or 6 times the normal health!"));
NuiSetBind(oPC, nToken, "txt_inc_hp_event", JsonBool(TRUE));
}
if(nMonsterAI || nAssociateAI)
@@ -1272,21 +1280,24 @@ void ai_CreateAssociateCommandNUI(object oPC, object oAssociate)
NuiSetBindWatch (oPC, nToken, "chbx_buff_short_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_buff_short_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_buff_short_event", JsonBool (TRUE));
float fDelay = GetLocalFloat(oAssociate, AI_DELAY_BUFF_CASTING);
if(fDelay < 0.1) fDelay = 0.1;
string sDelay = FloatToString(fDelay, 0, 1);
NuiSetBind (oPC, nToken, "btn_buff_short_tooltip", JsonString (
" Buff the party with short duration spells"));
" Buff the party with short duration spells. Cast speed [" + sDelay + "]"));
NuiSetBind(oPC, nToken, "chbx_buff_long_check", JsonBool (bBuffLong));
NuiSetBindWatch (oPC, nToken, "chbx_buff_long_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_buff_long_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_buff_long_event", JsonBool (TRUE));
NuiSetBind(oPC, nToken, "btn_buff_long_tooltip", JsonString (
" Buff the party with long duration spells"));
" Buff the party with long duration spells. Cast speed [" + sDelay + "]"));
// Row 11
NuiSetBind(oPC, nToken, "chbx_buff_all_check", JsonBool (bBuffAll));
NuiSetBindWatch (oPC, nToken, "chbx_buff_all_check", TRUE);
NuiSetBind(oPC, nToken, "chbx_buff_all_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_buff_all_event", JsonBool (TRUE));
NuiSetBind(oPC, nToken, "btn_buff_all_tooltip", JsonString (
" Buff the party with all our defensive spells"));
" Buff the party with all spells. Cast speed [" + sDelay + "]"));
if(!bIsPC && ResManGetAliasFor("prc_ai_fam_percp", RESTYPE_NCS) == "")
{
NuiSetBind(oPC, nToken, "chbx_buff_rest_check", JsonBool (bBuffRest));
@@ -1466,7 +1477,7 @@ void ai_CreateAssociateAINUI(object oPC, object oAssociate)
fHeight += 28.0;
}
// Row 3 ******************************************************************* 500 / 101
bRight = !ai_GetDMAIAccessButton(BTN_AI_FOR_PC);
bRight = TRUE;//!ai_GetDMAIAccessButton(BTN_AI_FOR_PC);
bLeft = !ai_GetDMAIAccessButton(BTN_AI_REDUCE_SPEECH);
if(bRight || bLeft)
{
@@ -1828,7 +1839,7 @@ void ai_CreateAssociateAINUI(object oPC, object oAssociate)
NuiSetBind(oPC, nToken, "btn_loot_filter", JsonInt(TRUE));
// Row 3
// Only activate ai on/off if this is for the pc.
if(bIsPC && ResManGetAliasFor("prc_ai_fam_percp", RESTYPE_NCS) == "")
if(bIsPC && TRUE)//ResManGetAliasFor("prc_ai_fam_percp", RESTYPE_NCS) == "")
{
NuiSetBind(oPC, nToken, "chbx_ai_check", JsonBool(bAI));
NuiSetBindWatch (oPC, nToken, "chbx_ai_check", TRUE);
@@ -2060,7 +2071,14 @@ void ai_SetWidgetBinds(object oPC, object oAssociate, string sAssociateType, int
// Set event watches for save window location.
NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE);
// Set the buttons to show events.
NuiSetBind(oPC, nToken, "btn_open_main_image", JsonString(GetPortraitResRef(oAssociate) + "s"));
string sPortrait = GetPortraitResRef(oAssociate);
string sSize;
if(ResManGetAliasFor(sPortrait + "s", RESTYPE_TGA) != "") sSize = "s";
else if(ResManGetAliasFor(sPortrait + "m", RESTYPE_TGA) != "") sSize = "m";
else if(ResManGetAliasFor(sPortrait + "l", RESTYPE_TGA)!= "") sSize = "l";
else if(ResManGetAliasFor(sPortrait + "h", RESTYPE_TGA)!= "") sSize = "h";
else sSize = "m";
NuiSetBind(oPC, nToken, "btn_open_main_image", JsonString(sPortrait + sSize));
NuiSetBind(oPC, nToken, "btn_open_main_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_open_main_tooltip", JsonString(" " + sName + " widget menu"));
if(ai_GetWidgetButton(oPC, BTN_ASSOC_WIDGETS_OFF, oAssociate, sAssociateType))
@@ -2215,17 +2233,29 @@ void ai_SetWidgetBinds(object oPC, object oAssociate, string sAssociateType, int
if(ai_GetWidgetButton(oPC, BTN_BUFF_SHORT, oAssociate, sAssociateType))
{
NuiSetBind(oPC, nToken, "btn_buff_short_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_buff_short_tooltip", JsonString(" Buff the party with short duration spells"));
float fDelay = GetLocalFloat(oAssociate, AI_DELAY_BUFF_CASTING);
if(fDelay < 0.1) fDelay = 0.1;
string sDelay = FloatToString(fDelay, 0, 1);
NuiSetBind (oPC, nToken, "btn_buff_short_tooltip", JsonString(
" Buff the party with short duration spells. Cast speed [" + sDelay + "]"));
}
if(ai_GetWidgetButton(oPC, BTN_BUFF_LONG, oAssociate, sAssociateType))
{
NuiSetBind(oPC, nToken, "btn_buff_long_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_buff_long_tooltip", JsonString(" Buff the party with long duration spells"));
float fDelay = GetLocalFloat(oAssociate, AI_DELAY_BUFF_CASTING);
if(fDelay < 0.1) fDelay = 0.1;
string sDelay = FloatToString(fDelay, 0, 1);
NuiSetBind (oPC, nToken, "btn_buff_long_tooltip", JsonString(
" Buff the party with long duration spells. Cast speed [" + sDelay + "]"));
}
if(ai_GetWidgetButton(oPC, BTN_BUFF_ALL, oAssociate, sAssociateType))
{
NuiSetBind(oPC, nToken, "btn_buff_all_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_buff_all_tooltip", JsonString(" Buff the party with all our defensive spells"));
float fDelay = GetLocalFloat(oAssociate, AI_DELAY_BUFF_CASTING);
if(fDelay < 0.1) fDelay = 0.1;
string sDelay = FloatToString(fDelay, 0, 1);
NuiSetBind (oPC, nToken, "btn_buff_all_tooltip", JsonString(
" Buff the party with all spells. Cast speed [" + sDelay + "]"));
}
if(ai_GetWidgetButton(oPC, BTN_CMD_JUMP_TO, oAssociate, sAssociateType))
{
@@ -2488,7 +2518,7 @@ void ai_SetWidgetBinds(object oPC, object oAssociate, string sAssociateType, int
object oItem;
if(JsonGetType(jWidget) != JSON_TYPE_NULL)
{
int nLevel, nSpell, nIndex, nClass, nMetaMagic, nDomain, nSubSpell, nFeat, nSAIndex;
int nLevel, nSpell, nIndex, nClass, nMetaMagic, nDomain, nSubSpell, nFeat, nSAIndex, nUses;
string sSpellIcon, sMetaMagicText, sSubSpell, sClass, sIndex;
while(nIndex < 10)
{
@@ -2533,9 +2563,10 @@ void ai_SetWidgetBinds(object oPC, object oAssociate, string sAssociateType, int
if(nUses)
{
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE));
if(nUses == 999) sText = "Unlimited";
if(nUses == 999) sText = "";
else sText = IntToString(nUses);
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sBaseName + " / " + sText + ")"));
NuiSetBind(oPC, nToken, "uses_" + sIndex + "_text", JsonString(sText));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sBaseName + ")"));
}
else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE));
}
@@ -2558,8 +2589,10 @@ void ai_SetWidgetBinds(object oPC, object oAssociate, string sAssociateType, int
}
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon));
if(GetHasFeat(nFeat, oAssociate))
nUses = GetHasFeat(nFeat, oAssociate);
if(nUses > 0)
{
NuiSetBind(oPC, nToken, "uses_" + sIndex + "_text", JsonString(IntToString(nUses)));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName));
}
else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE));
@@ -2577,18 +2610,27 @@ void ai_SetWidgetBinds(object oPC, object oAssociate, string sAssociateType, int
sMetaMagicText = ai_GetSpellIconAttributes(oAssociate, nMetaMagic, nDomain);
NuiSetBind(oPC, nToken, "metamagic_" + sIndex + "_text", JsonString(sMetaMagicText));
nSAIndex = JsonGetInt(JsonArrayGet(jSpell, 6));
if(nClass == 255 && GetSpellAbilityReady(oAssociate, nSAIndex))
if(nClass == 255)
{
sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (Special Ability / " + IntToString(nLevel) + ")"));
if(GetSpellAbilityReady(oAssociate, nSAIndex))
{
sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (Special Ability / " + IntToString(nLevel) + ")"));
}
else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE));
}
else if(GetSpellUsesLeft(oAssociate, nClass, nSpell, nMetaMagic, nDomain))
else
{
sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass)));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevel) + ")"));
nUses = GetSpellUsesLeft(oAssociate, nClass, nSpell, nMetaMagic, nDomain);
if(nUses > 0)
{
NuiSetBind(oPC, nToken, "uses_" + sIndex + "_text", JsonString(IntToString(nUses)));
sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass)));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevel) + ")"));
}
else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE));
}
else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE));
}
}
}
@@ -2641,9 +2683,10 @@ void ai_SetWidgetBinds(object oPC, object oAssociate, string sAssociateType, int
if(nUses)
{
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE));
if(nUses == 999) sText = "Unlimited";
if(nUses == 999) sText = "";
else sText = IntToString(nUses);
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sBaseName + " / " + sText + ")"));
NuiSetBind(oPC, nToken, "uses_" + sIndex + "_text", JsonString(sText));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sBaseName + ")"));
}
else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE));
}
@@ -2665,8 +2708,10 @@ void ai_SetWidgetBinds(object oPC, object oAssociate, string sAssociateType, int
}
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(TRUE));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_image", JsonString(sSpellIcon));
if(GetHasFeat(nFeat, oAssociate))
nUses = GetHasFeat(nFeat, oAssociate);
if(nUses > 0)
{
NuiSetBind(oPC, nToken, "uses_" + sIndex + "_text", JsonString(IntToString(nUses)));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName));
}
else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE));
@@ -2695,14 +2740,20 @@ void ai_SetWidgetBinds(object oPC, object oAssociate, string sAssociateType, int
sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (Special Ability / " + IntToString(nLevel) + ")"));
}
else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE));
}
else if(GetSpellUsesLeft(oAssociate, nClass, nSpell, nMetaMagic, nDomain))
else
{
sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass)));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevel) + ")"));
nUses = GetSpellUsesLeft(oAssociate, nClass, nSpell, nMetaMagic, nDomain);
if(nUses > 0)
{
NuiSetBind(oPC, nToken, "uses_" + sIndex + "_text", JsonString(IntToString(nUses)));
sName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
sClass = GetStringByStrRef(StringToInt(Get2DAString("classes", "Name", nClass)));
NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_tooltip", JsonString(" " + sName + " (" + sClass + " / " + IntToString(nLevel) + ")"));
}
else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE));
}
else NuiSetBind(oPC, nToken, "btn_widget_" + sIndex + "_event", JsonBool(FALSE));
}
}
else break;
@@ -2729,7 +2780,19 @@ void ai_CreateWidgetNUI(object oPC, object oAssociate)
jButton = NuiHeight(jButton, 35.0);
jButton = NuiMargin(jButton, 0.0);
jButton = NuiTooltip(jButton, NuiBind ("btn_open_main_tooltip"));
jButton = NuiImageRegion(jButton, NuiRect(0.0, 0.0, 32.0, 35.0));
string sPortrait = GetPortraitResRef(oAssociate);
if(ResManGetAliasFor(sPortrait + "s", RESTYPE_TGA) != "")
jButton = NuiImageRegion(jButton, NuiRect(0.0, 0.0, 32.0, 50.0));
else if(ResManGetAliasFor(sPortrait + "m", RESTYPE_TGA) != "")
jButton = NuiImageRegion(jButton, NuiRect(0.0, 0.0, 64.0, 100.0));
else if(ResManGetAliasFor(sPortrait + "l", RESTYPE_TGA)!= "")
jButton = NuiImageRegion(jButton, NuiRect(0.0, 0.0, 128.0, 200.0));
else if(ResManGetAliasFor(sPortrait + "h", RESTYPE_TGA)!= "")
jButton = NuiImageRegion(jButton, NuiRect(0.0, 0.0, 256.0, 400.0));
else jButton = NuiImageRegion(jButton, NuiRect(0.0, 0.0, 64.0, 100.0));
jButton = NuiAspect(jButton, 1.0);
//jButton = NuiImageRegion(jButton, NuiRect(0.0, 0.0, 32.0, 35.0));
//jButton = NuiImage(jButton, JsonInt(NUI_ASPECT_FIT100), JsonInt(NUI_HALIGN_CENTER), JsonInt(NUI_VALIGN_TOP));
json jRow = JsonArrayInsert(JsonArray(), jButton);
if(ai_GetWidgetButton(oPC, BTN_ASSOC_WIDGETS_OFF, oAssociate, sAssociateType))
{
@@ -3020,7 +3083,7 @@ void ai_CreateWidgetNUI(object oPC, object oAssociate)
fQuickWidgetColumns += 1.0;
int bAdd;
float fSpellButtons;
json jButton, jRectangle, jMetaMagic, jDrawList;
json jButton, jRectangle, jMetaMagic, jDrawList, jUses;
// Add row to the column.
if(bVertical) jCol = JsonArrayInsert(jCol, NuiCol(jRow));
else jCol = JsonArrayInsert(jCol, NuiRow(jRow));
@@ -3053,10 +3116,16 @@ void ai_CreateWidgetNUI(object oPC, object oAssociate)
jButton = NuiWidth(NuiHeight(jButton, 35.0), 35.0);
jButton = NuiMargin(jButton, 0.0);
jButton = NuiTooltip(jButton, NuiBind("btn_widget_" + sIndex + "_tooltip"));
jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0);
// Metamagic text.
jRectangle = NuiRect(4.0, 24.0, 10.0, 31.0);
jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_" + sIndex + "_text"));
jDrawList = JsonArrayInsert(JsonArray(), jMetaMagic);
jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList);
// Spell uses text.
jRectangle = NuiRect(24.0, 2.0, 31.0, 8.0);
jUses = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 255), jRectangle, NuiBind("uses_" + sIndex + "_text"));
jDrawList = JsonArrayInsert(JsonArray(), jUses);
jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList);
jRow = JsonArrayInsert(jRow, jButton);
fSpellButtons += 1.0;
}
@@ -3099,10 +3168,16 @@ void ai_CreateWidgetNUI(object oPC, object oAssociate)
jButton = NuiWidth(NuiHeight(jButton, 35.0), 35.0);
jButton = NuiMargin(jButton, 0.0);
jButton = NuiTooltip(jButton, NuiBind("btn_widget_" + sIndex + "_tooltip"));
jRectangle = NuiRect(4.0, 4.0, 10.0, 10.0);
// Metamagic text.
jRectangle = NuiRect(4.0, 24.0, 10.0, 31.0);
jMetaMagic = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 0), jRectangle, NuiBind("metamagic_" + sIndex + "_text"));
jDrawList = JsonArrayInsert(JsonArray(), jMetaMagic);
jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList);
// Spell uses text.
jRectangle = NuiRect(24.0, 2.0, 31.0, 8.0);
jUses = NuiDrawListText(JsonBool(TRUE), NuiColor(255, 255, 255), jRectangle, NuiBind("uses_" + sIndex + "_text"));
jDrawList = JsonArrayInsert(JsonArray(), jUses);
jButton = NuiDrawList(jButton, JsonBool(TRUE), jDrawList);
jRow = JsonArrayInsert(jRow, jButton);
fSpellButtons += 1.0;
}
@@ -3713,7 +3788,7 @@ json ai_CheckItemAbilities(json jQuickListArray, object oCreature, object oItem,
if(nCharges) nUses = nCharges;
else nUses = nPerDay;
}
sSpellIcon = Get2DAString("spells", "iConResRef", nSpell);
sSpellIcon = Get2DAString("spells", "IconResRef", nSpell);
}
jSpell_Icon = JsonArrayInsert(jSpell_Icon, JsonString(sSpellIcon));
jSpell_Text = JsonArrayInsert(jSpell_Text, JsonString(sSpellName));

View File

@@ -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));

View File

@@ -207,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))
@@ -295,6 +296,7 @@ int ai_ChangeMonster(object oCreature, object oModule)
{
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);

View File

@@ -11,8 +11,6 @@
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,6 +28,13 @@ 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_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();
@@ -40,129 +45,7 @@ void ai_SetupPlayerTarget()
}
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) &&
@@ -233,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;
}
}
@@ -258,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;
}
@@ -291,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)
{
@@ -300,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)
@@ -343,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;
@@ -642,17 +497,18 @@ void ai_SelectWidgetSpellTarget(object oPC, object oAssociate, string sElem)
{
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));

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 #.
@@ -1314,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)
{
@@ -1326,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);
@@ -1564,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;
@@ -1585,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;
}
}
@@ -1599,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;
@@ -1625,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;
}
}
@@ -1662,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;
@@ -1697,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;
}
}
@@ -1731,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;
@@ -1782,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;
}
}
@@ -1815,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;
@@ -1867,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;
}
}
@@ -1897,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);
@@ -1919,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)
{
@@ -1935,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;
}
}
@@ -1950,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)
{
@@ -2349,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));
@@ -2371,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))
{
@@ -2392,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);
@@ -2409,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)
{

View File

@@ -219,13 +219,13 @@ int ai_GetHasTalent(object oCreature, int nTalent);
// Type 4)item 0-type, 1-spell, 2-item object, 3-level, 4-slot.
// jJsonLevel is the level to place the talent in the json array
// maybe different then the talents actual level which is passed in nLevel.
void ai_SaveTalent(object oCreature, int nClass, int nJsonLevel, int nLevel, int nSlot, int nSpell, int nType, int bBuff, int bDisablePreBuffs, object oItem = OBJECT_INVALID);
void ai_SaveTalent(object oCreature, int nClass, int nJsonLevel, int nLevel, int nSlot, int nSpell, int nType, int bBuff, int bPreBuff, int bFullBuff, object oItem = OBJECT_INVALID);
// Removes a talent nSlotIndex from jLevel in jCategory.
void ai_RemoveTalent(object oCreature, json jCategory, json jLevel, string sCategory, int nLevel, int nSlotIndex);
// Saves a creatures talents to variables upon them for combat use.
// bMonster will check to see if they should be buffed when we set the talents.
// bDisablePrebuffs - Tells the talent system
void ai_SetCreatureTalents(object oCreature, int bMonster, int bDisablePreBuffs = FALSE);
// bForceTalentSetup - Tells the talent system to force a talent setup but no Buffing.
void ai_SetCreatureTalents(object oCreature, int bMonster, int bForceTalentSetup = FALSE);
// Return TRUE if oCreature spontaneously casts a cure spell from a talent in sCategory.
int ai_UseSpontaneousCureTalentFromCategory(object oCreature, string sCategory, int nInMelee, int nDamage, object oTarget = OBJECT_INVALID);
// Returns TRUE if oCreature uses jTalent on oTarget.
@@ -488,12 +488,13 @@ int ai_CheckTalentsVsConditions(object oCreature, int nConditions, int nInMelee,
{
nTalentUsed = ai_UseCreatureSpellTalent(oCreature, jLevel, jTalent, AI_TALENT_CURE, nInMelee, oTarget);
// -1 means it was a memorized spell and we need to remove it.
if(nTalentUsed == -1)
{
ai_RemoveTalent(oCreature, jCategory, jLevel, AI_TALENT_CURE, nLevel, nSlotIndex);
return TRUE;
}
else if(nTalentUsed) return TRUE;
//if(nTalentUsed == -1)
//{
// ai_RemoveTalent(oCreature, jCategory, jLevel, AI_TALENT_CURE, nLevel, nSlotIndex);
// return TRUE;
//}
//else
if(nTalentUsed) return TRUE;
}
}
else if(nType == AI_TALENT_TYPE_SP_ABILITY)
@@ -2044,10 +2045,8 @@ int ai_GetHasTalent(object oCreature, int nTalent)
object ai_CheckTalentForBuffing(object oCreature, string sCategory, int nSpell)
{
// Should we buff this monster caster? Added legacy code just in case.
if((sCategory == "P" || sCategory == "E" ||
(sCategory == "S" && GetLocalInt(GetModule(), AI_RULE_PRESUMMON))) &&
(GetLocalInt(GetModule(), AI_RULE_BUFF_MONSTERS) ||
GetLocalInt(oCreature, "NW_GENERIC_MASTER") & 0x04000000)) return ai_GetBuffTarget(oCreature, nSpell);
if(sCategory == "P" || sCategory == "E" ||
(sCategory == "S" && GetLocalInt(GetModule(), AI_RULE_PRESUMMON))) return ai_GetBuffTarget(oCreature, nSpell);
return OBJECT_INVALID;
}
int ai_UseBuffTalent(object oCreature, int nClass, int nLevel, int nSlot, int nSpell, int nType, object oTarget, object oItem)
@@ -2127,7 +2126,7 @@ int ai_SpellRestricted(int nSpell)
}
return FALSE;
}
void ai_SaveTalent(object oCreature, int nClass, int nJsonLevel, int nLevel, int nSlot, int nSpell, int nType, int bMonster, int bDisablePreBuffs, object oItem = OBJECT_INVALID)
void ai_SaveTalent(object oCreature, int nClass, int nJsonLevel, int nLevel, int nSlot, int nSpell, int nType, int bMonster, int bPreBuff, int bFullBuff, object oItem = OBJECT_INVALID)
{
// Players/Admins can restrict some spells.
if(ai_SpellRestricted(nSpell)) return;
@@ -2136,10 +2135,10 @@ void ai_SaveTalent(object oCreature, int nClass, int nJsonLevel, int nLevel, int
// If it is a blank talent or it is an Area of Effect talent we skip.
if(sCategory == "" || sCategory == "A") return;
// Check to see if we should be prebuffing.
if(bMonster && !bDisablePreBuffs)
if(bMonster && bPreBuff)
{
int nSpellBuffDuration = StringToInt(Get2DAString("ai_spells", "Buff_Duration", nSpell));
if(nSpellBuffDuration == 3)
if(nSpellBuffDuration == 3 || (nSpellBuffDuration == 2 && bFullBuff))
{
object oTarget = ai_CheckTalentForBuffing(oCreature, sCategory, nSpell);
if(oTarget != OBJECT_INVALID)
@@ -2213,7 +2212,81 @@ void ai_RemoveTalentLevel(object oCreature, json jCategory, json jLevel, string
if(AI_DEBUG) ai_Debug("0i_talents", "1861", "jCategory: " + JsonDump(jCategory, 2));
SetLocalJson(oCreature, sCategory, jCategory);
}
void ai_SetCreatureSpellTalents(object oCreature, int bMonster, int bDisablePreBuffs)
/*******************************************************************************
New Set Talents by Level then category.
*******************************************************************************/
/*void ai_SaveTalentByLevel(object oCreature, int nClass, int nJsonLevel, int nLevel, int nSlot, int nSpell, int nType, int bMonster, int bPreBuff, int bFullBuff, object oItem = OBJECT_INVALID)
{
// Players/Admins can restrict some spells.
if(ai_SpellRestricted(nSpell)) return;
// Get the talent category, we organize all talents by categories.
string sCategory = Get2DAString("ai_spells", "Category", nSpell);
// If it is a blank talent or it is an Area of Effect talent we skip.
if(sCategory == "" || sCategory == "A") return;
// Check to see if we should be prebuffing.
if(bMonster && bPreBuff)
{
int nSpellBuffDuration = StringToInt(Get2DAString("ai_spells", "Buff_Duration", nSpell));
if(nSpellBuffDuration == 3 || (nSpellBuffDuration == 2 && bFullBuff))
{
object oTarget = ai_CheckTalentForBuffing(oCreature, sCategory, nSpell);
if(oTarget != OBJECT_INVALID)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1794", GetName(oCreature) + " is prebuffing with spell " + IntToString(nSpell));
if(ai_UseBuffTalent(oCreature, nClass, nLevel, nSlot, nSpell, nType, oTarget, oItem)) return;
}
}
}
string sLevel = IntToString(nLevel);
// Get the Level saved to Json.
json jLevel = GetLocalJson(oCreature, "SPELL_LEVEL_" + sLevel);
// If jLevel is not created we set it up.
if(JsonGetType(jLevel) == JSON_TYPE_NULL) jLevel = JsonArray();
json jTalent = JsonArray();
if(nType == AI_TALENT_TYPE_SPELL || nType == AI_TALENT_TYPE_SP_ABILITY)
{
jTalent = JsonArrayInsert(jTalent, JsonInt(nType), 0);
jTalent = JsonArrayInsert(jTalent, JsonInt(nSpell));
jTalent = JsonArrayInsert(jTalent, JsonInt(nClass));
jTalent = JsonArrayInsert(jTalent, JsonInt(nLevel));
jTalent = JsonArrayInsert(jTalent, JsonInt(nSlot));
jTalent = JsonArrayInsert(jTalent, JsonString(sCategory));
}
else if(nType == AI_TALENT_TYPE_ITEM)
{
jTalent = JsonArrayInsert(jTalent, JsonInt(nType), 0);
jTalent = JsonArrayInsert(jTalent, JsonInt(nSpell));
jTalent = JsonArrayInsert(jTalent, JsonString(ObjectToString(oItem)));
jTalent = JsonArrayInsert(jTalent, JsonInt(nLevel));
jTalent = JsonArrayInsert(jTalent, JsonInt(nSlot));
jTalent = JsonArrayInsert(jTalent, JsonString(sCategory));
}
jLevel = JsonArrayInsert(jLevel, jTalent);
SetLocalJson(oCreature, "SPELL_LEVEL_" + sLevel, jLevel);
if(AI_DEBUG) ai_Debug("0i_talents", "2265", sLevel + ": " + JsonDump(jLevel, 1));
// Set AI_MAX_TALENT if this talent is higher than the maximum.
if(nJsonLevel > GetLocalInt(oCreature, AI_MAX_LEVEL + sLevel))
{
SetLocalInt(oCreature, AI_MAX_LEVEL + sLevel, nJsonLevel);
}
if(AI_DEBUG) ai_Debug("0i_talents", "2271", "AI_MAX_LEVEL: " +
IntToString(GetLocalInt(oCreature, AI_MAX_LEVEL + sLevel)) +
" nJsonLevel: " + IntToString(nJsonLevel));
}
// For removing used up spell slots.
void ai_RemoveTalentByLevel(object oCreature, json jLevel, int nLevel, int nSlotIndex)
{
if(AI_DEBUG) ai_Debug("0i_talents", "2278", "removing Talent from slot: " + IntToString(nSlotIndex));
jLevel = JsonArrayDel(jLevel, nSlotIndex);
if(AI_DEBUG) ai_Debug("0i_talents", "2280", "jLevel: " + JsonDump(jLevel, 2));
SetLocalJson(oCreature, "SPELL_LEVEL_" + IntToString(nLevel), jLevel);
}
// For removing Sorcerer/Bard spell levels once used up.
void ai_RemoveTalentLevelByLevel(object oCreature, int nLevel)
{
DeleteLocalJson(oCreature, "SPELL_LEVEL_" + IntToString(nLevel));
}
void ai_SetCreatureSpellTalentsByLevel(object oCreature, int bMonster, int bPreBuff, int bFullBuff)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1417", GetName(oCreature) + ": Setting Spell Talents for combat [Buff: " +
IntToString(bMonster) + "].");
@@ -2265,8 +2338,8 @@ void ai_SetCreatureSpellTalents(object oCreature, int bMonster, int bDisablePreB
nAdjLevel = nLevel + nMetaMagic;
if(nAdjLevel > 9) nAdjLevel = 9;
}
else nAdjLevel = nLevel; */
ai_SaveTalent(oCreature, nClass, nLevel, nLevel, nSlot, nSpell, AI_TALENT_TYPE_SPELL, bMonster, bDisablePreBuffs);
else nAdjLevel = nLevel;
ai_SaveTalentByLevel(oCreature, nClass, nLevel, nLevel, nSlot, nSpell, AI_TALENT_TYPE_SPELL, bMonster, bPreBuff, bFullBuff);
}
nSlot++;
}
@@ -2295,7 +2368,7 @@ void ai_SetCreatureSpellTalents(object oCreature, int bMonster, int bDisablePreB
IntToString(GetSpellUsesLeft(oCreature, nClass, nSpell)));
if(GetSpellUsesLeft(oCreature, nClass, nSpell) > 0)
{
ai_SaveTalent(oCreature, nClass, nLevel, nLevel, nSlot, nSpell, AI_TALENT_TYPE_SPELL, bMonster, bDisablePreBuffs);
ai_SaveTalentByLevel(oCreature, nClass, nLevel, nLevel, nSlot, nSpell, AI_TALENT_TYPE_SPELL, bMonster, bPreBuff, bFullBuff);
}
nSlot++;
}
@@ -2307,7 +2380,7 @@ void ai_SetCreatureSpellTalents(object oCreature, int bMonster, int bDisablePreB
nClass = GetClassByPosition(nClassPosition, oCreature);
}
}
void ai_SetCreatureSpecialAbilityTalents(object oCreature, int bMonster, int bDisablePreBuffs)
void ai_SetCreatureSpecialAbilityTalentsByLevel(object oCreature, int bMonster, int bPreBuff, int bFullBuff)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1488", GetName(oCreature) + ": Setting Special Ability Talents for combat.");
// Cycle through all the creatures special abilities.
@@ -2322,13 +2395,13 @@ void ai_SetCreatureSpecialAbilityTalents(object oCreature, int bMonster, int bDi
if(GetSpellAbilityReady(oCreature, nSpell))
{
nLevel = StringToInt(Get2DAString("spells", "Innate", nSpell));
ai_SaveTalent(oCreature, 255, nLevel, nLevel, nIndex, nSpell, AI_TALENT_TYPE_SP_ABILITY, bMonster, bDisablePreBuffs);
ai_SaveTalentByLevel(oCreature, 255, nLevel, nLevel, nIndex, nSpell, AI_TALENT_TYPE_SP_ABILITY, bMonster, bPreBuff, bFullBuff);
}
nIndex++;
}
}
}
void ai_CheckItemProperties(object oCreature, object oItem, int bMonster, int bDisablePreBuffs, int bEquiped = FALSE)
void ai_CheckItemPropertiesByLevel(object oCreature, object oItem, int bMonster, int bPreBuff, int bFullBuff, int bEquiped = FALSE)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1509", "Checking Item properties on " + GetName(oItem));
// We have established that we can use the item if it is equiped.
@@ -2374,7 +2447,7 @@ void ai_CheckItemProperties(object oCreature, object oItem, int bMonster, int bD
nIprpSubType = GetItemPropertySubType(ipProp);
nSpell = StringToInt(Get2DAString("iprp_spells", "SpellIndex", nIprpSubType));
nLevel = StringToInt(Get2DAString("iprp_spells", "InnateLvl", nIprpSubType));
ai_SaveTalent(oCreature, 255, nLevel, nLevel, nIndex, nSpell, AI_TALENT_TYPE_ITEM, bMonster, bDisablePreBuffs, oItem);
ai_SaveTalentByLevel(oCreature, 255, nLevel, nLevel, nIndex, nSpell, AI_TALENT_TYPE_ITEM, bMonster, bPreBuff, bFullBuff, oItem);
}
}
else if(nIPType == ITEM_PROPERTY_HEALERS_KIT)
@@ -2385,7 +2458,7 @@ void ai_CheckItemProperties(object oCreature, object oItem, int bMonster, int bD
// Must also have ranks in healing kits.
if(GetSkillRank(SKILL_HEAL, oCreature) > 0)
{
ai_SaveTalent(oCreature, 255, 7, 0, nIndex, nSpell, AI_TALENT_TYPE_ITEM, bMonster, bDisablePreBuffs, oItem);
ai_SaveTalent(oCreature, 255, 7, 0, nIndex, nSpell, AI_TALENT_TYPE_ITEM, bMonster, bPreBuff, bFullBuff, oItem);
}
}
if(bEquiped)
@@ -2449,7 +2522,7 @@ void ai_CheckItemProperties(object oCreature, object oItem, int bMonster, int bD
// If any Immunity has been set then we need to save our Immunity json.
if(bHasItemImmunity) SetLocalJson(oCreature, AI_TALENT_IMMUNITY, jImmunity);
}
void ai_SetCreatureItemTalents(object oCreature, int bMonster, int bDisablePreBuffs)
void ai_SetCreatureItemTalentsByLevel(object oCreature, int bMonster, int bPreBuff, int bFullBuff)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1561", GetName(oCreature) + ": Setting Item Talents for combat.");
int bEquiped;
@@ -2465,7 +2538,7 @@ void ai_SetCreatureItemTalents(object oCreature, int bMonster, int bDisablePreBu
// Does the item need to be equiped to use its powers?
sSlots = Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem));
if(AI_DEBUG) ai_Debug("0i_talents", "1572", GetName(oItem) + " requires " + Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)) + " slots.");
if(sSlots == "0x00000") ai_CheckItemProperties(oCreature, oItem, bMonster, bDisablePreBuffs);
if(sSlots == "0x00000") ai_CheckItemPropertiesByLevel(oCreature, oItem, bMonster, bPreBuff, bFullBuff);
}
oItem = GetNextItemInInventory(oCreature);
}
@@ -2474,29 +2547,331 @@ void ai_SetCreatureItemTalents(object oCreature, int bMonster, int bDisablePreBu
oItem = GetItemInSlot(nSlot, oCreature);
while(nSlot < 11)
{
if(oItem != OBJECT_INVALID) ai_CheckItemProperties(oCreature, oItem, bMonster, TRUE);
if(oItem != OBJECT_INVALID) ai_CheckItemPropertiesByLevel(oCreature, oItem, bMonster, bPreBuff, bFullBuff, TRUE);
oItem = GetItemInSlot(++nSlot, oCreature);
}
oItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oCreature);
if(oItem != OBJECT_INVALID) ai_CheckItemProperties(oCreature, oItem, bMonster, TRUE);
if(oItem != OBJECT_INVALID) ai_CheckItemPropertiesByLevel(oCreature, oItem, bMonster, bPreBuff, bFullBuff, TRUE);
}
void ai_SetCreatureTalents(object oCreature, int bMonster, int bDisablePreBuffs = FALSE)
void ai_SetCreatureTalentsByLevel(object oCreature, int bMonster, int bForceTalentSetup = FALSE)
{
//json jCreature = ObjectToJson(oCreature);
//if(AI_DEBUG) ai_Debug("0i_talents", "2072", GetName(oCreature) + " jCreature: " + JsonDump(jCreature, 4));
if(GetLocalInt(oCreature, AI_TALENTS_SET) && !bDisablePreBuffs) return;
if(GetLocalInt(oCreature, AI_TALENTS_SET) && !bForceTalentSetup) return;
SetLocalInt(oCreature, AI_TALENTS_SET, TRUE);
object oModule = GetModule();
int bPreBuff = GetLocalInt(GetModule(), AI_RULE_BUFF_MONSTERS) || (GetLocalInt(oCreature, "NW_GENERIC_MASTER") & 0x04000000);
int bFullBuff = GetLocalInt(GetModule(), AI_RULE_FULL_BUFF_MONSTERS);
if(bForceTalentSetup) bPreBuff = FALSE;
ai_Counter_Start();
ai_SetCreatureSpellTalents(oCreature, bMonster, bDisablePreBuffs);
ai_SetCreatureSpellTalentsByLevel(oCreature, bMonster, bPreBuff, bFullBuff);
ai_Counter_End(GetName(oCreature) + ": Spell Talents");
ai_SetCreatureSpecialAbilityTalents(oCreature, bMonster, bDisablePreBuffs);
ai_SetCreatureSpecialAbilityTalentsByLevel(oCreature, bMonster, bPreBuff, bFullBuff);
ai_Counter_End(GetName(oCreature) + ": Special Ability Talents");
DeleteLocalJson(oCreature, AI_TALENT_IMMUNITY);
ai_SetCreatureItemTalents(oCreature, bMonster, bDisablePreBuffs);
ai_SetCreatureItemTalentsByLevel(oCreature, bMonster, bPreBuff, bFullBuff);
ai_Counter_End(GetName(oCreature) + ": Item Talents");
if(GetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS) &&
GetLocalInt(oModule, AI_RULE_PRESUMMON) && bMonster && !bDisablePreBuffs)
GetLocalInt(oModule, AI_RULE_PRESUMMON) && bMonster && bPreBuff)
{
ai_TrySummonFamiliarTalent(oCreature);
ai_TrySummonAnimalCompanionTalent(oCreature);
}
// AI_CAT_CURE is setup differently we save the level as the highest.
//if(JsonGetType(GetLocalJson(oCreature, AI_TALENT_CURE)) != JSON_TYPE_NULL) SetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_CURE, 9);
// With spontaneous cure spells we need to clear this as the number of spells don't count.
//if(GetLevelByClass(CLASS_TYPE_CLERIC, oCreature)) SetLocalInt(oCreature, AI_MAX_TALENT + AI_TALENT_HEALING, 0);
} */
/*******************************************************************************
Old Set talents by category then level.
*******************************************************************************/
void ai_SetCreatureSpellTalents(object oCreature, int bMonster, int bPreBuff, int bFullBuff)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1417", GetName(oCreature) + ": Setting Spell Talents for combat [Buff: " +
IntToString(bMonster) + "].");
// Cycle through all classes and spells.
int nClassPosition = 1, nMaxSlot, nLevel, nSlot, nSpell, nIndex, nMetaMagic;
int nClass = GetClassByPosition(nClassPosition, oCreature);
while(nClassPosition <= AI_MAX_CLASSES_PER_CHARACTER && nClass != CLASS_TYPE_INVALID)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1824", "nClass: " + IntToString(nClass) +
" nClassPosition: " + IntToString(nClassPosition) +
" SpellCaster: " + Get2DAString("classes", "SpellCaster", nClass) +
" Memorized: " + Get2DAString("classes", "MemorizesSpells", nClass));
if(Get2DAString("classes", "SpellCaster", nClass) == "1")
{
// Search all memorized spells for the spell.
if(Get2DAString("classes", "MemorizesSpells", nClass) == "1")
{
// Check each level organizing from highest to lowest.
nLevel = (GetLevelByPosition(nClassPosition, oCreature) + 1) / 2;
if(nLevel > 9) nLevel = 9;
while(nLevel > -1)
{
// Check each slot within each level.
nMaxSlot = GetMemorizedSpellCountByLevel(oCreature, nClass, nLevel);
if(AI_DEBUG) ai_Debug("0i_talents", "1434", "nClass: " + IntToString(nClass) +
" nLevel: " + IntToString(nLevel) + " nMaxSlot: " +
IntToString(nMaxSlot));
nSlot = 0;
while(nSlot < nMaxSlot)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1440", "nSlot: " + IntToString(nSlot) + " nSpell: " +
IntToString(GetMemorizedSpellId(oCreature, nClass, nLevel, nSlot)) + " spell memorized: " +
IntToString(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot)));
if(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot) == 1)
{
nSpell = GetMemorizedSpellId(oCreature, nClass, nLevel, nSlot);
/* Spells are already at the higher level when saved as a talent.
// Move a spell up to a different JsonLevel as higher Jsonlevel
// spells usually get cast first.
nMetaMagic = GetMemorizedSpellMetaMagic(oCreature, nClass, nLevel, nSlot);
if(nMetaMagic > 0)
{
if(nMetaMagic == METAMAGIC_STILL) nMetaMagic = 1;
else if(nMetaMagic == METAMAGIC_EXTEND) nMetaMagic = 1;
else if(nMetaMagic == METAMAGIC_SILENT) nMetaMagic = 1;
else if(nMetaMagic == METAMAGIC_EMPOWER) nMetaMagic = 2;
else if(nMetaMagic == METAMAGIC_MAXIMIZE) nMetaMagic = 3;
else if(nMetaMagic == METAMAGIC_QUICKEN) nMetaMagic = 4;
nAdjLevel = nLevel + nMetaMagic;
if(nAdjLevel > 9) nAdjLevel = 9;
}
else nAdjLevel = nLevel; */
ai_SaveTalent(oCreature, nClass, nLevel, nLevel, nSlot, nSpell, AI_TALENT_TYPE_SPELL, bMonster, bPreBuff, bFullBuff);
}
nSlot++;
}
nLevel--;
}
}
// Check non-memorized known lists for the spell.
else
{
// Check each level starting with the highest to lowest.
nLevel = (GetLevelByPosition(nClassPosition, oCreature) + 1) / 2;
if(nLevel > 9) nLevel = 9;
while(nLevel > -1)
{
// Check each slot within each level.
nMaxSlot = GetKnownSpellCount(oCreature, nClass, nLevel);
if(AI_DEBUG) ai_Debug("0i_talents", "1462", "nClass: " + IntToString(nClass) +
" nLevel: " + IntToString(nLevel) + " nMaxSlot: " +
IntToString(nMaxSlot));
nSlot = 0;
while(nSlot < nMaxSlot)
{
nSpell = GetKnownSpellId(oCreature, nClass, nLevel, nSlot);
if(AI_DEBUG) ai_Debug("0i_talents", "1469", "nSlot: " + IntToString(nSlot) +
" nSpell: " + IntToString(nSpell) + " nUsesLeft: " +
IntToString(GetSpellUsesLeft(oCreature, nClass, nSpell)));
if(GetSpellUsesLeft(oCreature, nClass, nSpell) > 0)
{
ai_SaveTalent(oCreature, nClass, nLevel, nLevel, nSlot, nSpell, AI_TALENT_TYPE_SPELL, bMonster, bPreBuff, bFullBuff);
}
nSlot++;
}
nLevel--;
}
}
}
nClassPosition++;
nClass = GetClassByPosition(nClassPosition, oCreature);
}
}
void ai_SetCreatureSpecialAbilityTalents(object oCreature, int bMonster, int bPreBuff, int bFullBuff)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1488", GetName(oCreature) + ": Setting Special Ability Talents for combat.");
// Cycle through all the creatures special abilities.
int nMaxSpecialAbilities = GetSpellAbilityCount(oCreature);
if(AI_DEBUG) ai_Debug("0i_talents", "1491", IntToString(nMaxSpecialAbilities) + " Spell abilities.");
if(nMaxSpecialAbilities)
{
int nIndex, nSpell, nLevel;
while(nIndex < nMaxSpecialAbilities)
{
nSpell = GetSpellAbilitySpell(oCreature, nIndex);
if(GetSpellAbilityReady(oCreature, nSpell))
{
nLevel = StringToInt(Get2DAString("spells", "Innate", nSpell));
ai_SaveTalent(oCreature, 255, nLevel, nLevel, nIndex, nSpell, AI_TALENT_TYPE_SP_ABILITY, bMonster, bPreBuff, bFullBuff);
}
nIndex++;
}
}
}
void ai_CheckItemProperties(object oCreature, object oItem, int bMonster, int bPreBuff, int bFullBuff, int bEquiped = FALSE)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1509", "Checking Item properties on " + GetName(oItem));
// We have established that we can use the item if it is equiped.
if(!bEquiped && !ai_CheckIfCanUseItem(oCreature, oItem)) return;
// Get or create an Immunity in json so we can check item immunities quickly.
int nSpellImmunity, bHasItemImmunity, nPerDay, nCharges, nUses, bSaveTalent;
json jImmunity = GetLocalJson(oCreature, AI_TALENT_IMMUNITY);
if(JsonGetType(jImmunity) == JSON_TYPE_NULL) jImmunity = JsonArray();
int nIprpSubType, nSpell, nLevel, nIPType, nIndex;
itemproperty ipProp = GetFirstItemProperty(oItem);
// Lets skip this if there are no properties.
if(!GetIsItemPropertyValid(ipProp)) return;
// Check for cast spell property and add them to the talent list.
while(GetIsItemPropertyValid(ipProp))
{
nIPType = GetItemPropertyType(ipProp);
if(AI_DEBUG) ai_Debug("0i_talents", "1895", "ItempropertyType(15/80/53): " + IntToString(nIPType));
if(nIPType == ITEM_PROPERTY_CAST_SPELL)
{
bSaveTalent = TRUE;
// Get how they use the item (charges or uses per day).
nUses = GetItemPropertyCostTableValue(ipProp);
if(nUses > 1 && nUses < 7)
{
nCharges = GetItemCharges(oItem);
if(AI_DEBUG) ai_Debug("0i_talents", "1530", "Charges per use: " + IntToString(nUses) +
" Item charges: " + IntToString(nCharges));
if((nUses == IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE && nCharges < 1) ||
(nUses == IP_CONST_CASTSPELL_NUMUSES_2_CHARGES_PER_USE && nCharges < 2) ||
(nUses == IP_CONST_CASTSPELL_NUMUSES_3_CHARGES_PER_USE && nCharges < 3) ||
(nUses == IP_CONST_CASTSPELL_NUMUSES_4_CHARGES_PER_USE && nCharges < 4) ||
(nUses == IP_CONST_CASTSPELL_NUMUSES_5_CHARGES_PER_USE && nCharges < 5)) bSaveTalent = FALSE;
}
else if(nUses > 7 && nUses < 13)
{
nPerDay = GetItemPropertyUsesPerDayRemaining(oItem, ipProp);
if(AI_DEBUG) ai_Debug("0i_talents", "1676", "Item uses: " + IntToString(nPerDay));
if(nPerDay == 0) bSaveTalent = FALSE;
}
if(bSaveTalent)
{
// SubType is the ip spell index for iprp_spells.2da
nIprpSubType = GetItemPropertySubType(ipProp);
nSpell = StringToInt(Get2DAString("iprp_spells", "SpellIndex", nIprpSubType));
nLevel = StringToInt(Get2DAString("iprp_spells", "InnateLvl", nIprpSubType));
ai_SaveTalent(oCreature, 255, nLevel, nLevel, nIndex, nSpell, AI_TALENT_TYPE_ITEM, bMonster, bPreBuff, bFullBuff, oItem);
}
}
else if(nIPType == ITEM_PROPERTY_HEALERS_KIT)
{
// Lets set Healing kits as Cure Light Wounds since they heal 1d20 in combat.
nSpell = SPELL_CURE_MINOR_WOUNDS;
// Save the healer kit as level 9 so we can use them first.
// Must also have ranks in healing kits.
if(GetSkillRank(SKILL_HEAL, oCreature) > 0)
{
ai_SaveTalent(oCreature, 255, 7, 0, nIndex, nSpell, AI_TALENT_TYPE_ITEM, bMonster, bPreBuff, bFullBuff, oItem);
}
}
if(bEquiped)
{
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_HASTE)
{
SetLocalInt(oCreature, sIPHasHasteVarname, TRUE);
}
else if(nIPType == ITEM_PROPERTY_IMMUNITY_DAMAGE_TYPE)
{
int nBit, nIpSubType = GetItemPropertySubType(ipProp);
if(AI_DEBUG) ai_Debug("0i_talents", "1957", "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(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);
SetLocalInt(oCreature, sIPReducedVarname, nIpSubType);
}
}
nIndex++;
ipProp = GetNextItemProperty(oItem);
}
// If any Immunity has been set then we need to save our Immunity json.
if(bHasItemImmunity) SetLocalJson(oCreature, AI_TALENT_IMMUNITY, jImmunity);
}
void ai_SetCreatureItemTalents(object oCreature, int bMonster, int bPreBuff, int bFullBuff)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1561", GetName(oCreature) + ": Setting Item Talents for combat.");
int bEquiped;
// Set the Immunities to -1 so we know they were set incase there are no immunities.
SetLocalInt(oCreature, sIPReducedVarname, -1);
string sSlots;
// Cycle through all the creatures inventory items.
object oItem = GetFirstItemInInventory(oCreature);
while(oItem != OBJECT_INVALID)
{
if(GetIdentified(oItem))
{
// Does the item need to be equiped to use its powers?
sSlots = Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem));
if(AI_DEBUG) ai_Debug("0i_talents", "1572", GetName(oItem) + " requires " + Get2DAString("baseitems", "EquipableSlots", GetBaseItemType(oItem)) + " slots.");
if(sSlots == "0x00000") ai_CheckItemProperties(oCreature, oItem, bMonster, bPreBuff, bFullBuff);
}
oItem = GetNextItemInInventory(oCreature);
}
int nSlot;
// Cycle through all the creatures equiped items.
oItem = GetItemInSlot(nSlot, oCreature);
while(nSlot < 11)
{
if(oItem != OBJECT_INVALID) ai_CheckItemProperties(oCreature, oItem, bMonster, bPreBuff, bFullBuff, TRUE);
oItem = GetItemInSlot(++nSlot, oCreature);
}
oItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oCreature);
if(oItem != OBJECT_INVALID) ai_CheckItemProperties(oCreature, oItem, bMonster, bPreBuff, bFullBuff, TRUE);
}
void ai_SetCreatureTalents(object oCreature, int bMonster, int bForceTalentSetup = FALSE)
{
//json jCreature = ObjectToJson(oCreature);
//if(AI_DEBUG) ai_Debug("0i_talents", "2072", GetName(oCreature) + " jCreature: " + JsonDump(jCreature, 4));
if(GetLocalInt(oCreature, AI_TALENTS_SET) && !bForceTalentSetup) return;
SetLocalInt(oCreature, AI_TALENTS_SET, TRUE);
object oModule = GetModule();
int bPreBuff = GetLocalInt(GetModule(), AI_RULE_BUFF_MONSTERS) || (GetLocalInt(oCreature, "NW_GENERIC_MASTER") & 0x04000000);
int bFullBuff = GetLocalInt(GetModule(), AI_RULE_FULL_BUFF_MONSTERS);
if(bForceTalentSetup) bPreBuff = FALSE;
ai_Counter_Start();
ai_SetCreatureSpellTalents(oCreature, bMonster, bPreBuff, bFullBuff);
ai_Counter_End(GetName(oCreature) + ": Spell Talents");
ai_SetCreatureSpecialAbilityTalents(oCreature, bMonster, bPreBuff, bFullBuff);
ai_Counter_End(GetName(oCreature) + ": Special Ability Talents");
DeleteLocalJson(oCreature, AI_TALENT_IMMUNITY);
ai_SetCreatureItemTalents(oCreature, bMonster, bPreBuff, bFullBuff);
ai_Counter_End(GetName(oCreature) + ": Item Talents");
if(GetLocalInt(oModule, AI_RULE_SUMMON_COMPANIONS) &&
GetLocalInt(oModule, AI_RULE_PRESUMMON) && bMonster && bPreBuff)
{
ai_TrySummonFamiliarTalent(oCreature);
ai_TrySummonAnimalCompanionTalent(oCreature);
@@ -2622,20 +2997,6 @@ int ai_UseCreatureSpellTalent(object oCreature, json jLevel, json jTalent, strin
}
}
if(ai_ArcaneSpellFailureTooHigh(oCreature, nClass, nLevel, nSlot)) return FALSE;
if(Get2DAString("classes", "MemorizesSpells", nClass) == "1")
{
// Shouldn't need this anymore, we need to do a debug looking at this.
if(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlot) < 1) return FALSE;
if(ai_CheckSpecialTalentsandUse(oCreature, jTalent, sCategory, nInMelee, oTarget))
{
if(ai_CompareLastAction(oCreature, AI_LAST_ACTION_CAST_SPELL)) return -1;
return TRUE;
}
return FALSE;
}
if(AI_DEBUG) ai_Debug("0i_talents", "1629", "Known caster Level: " + IntToString(nLevel) +
" Uses : " + IntToString(GetSpellUsesLeft(oCreature, nClass, JsonGetInt(JsonArrayGet(jTalent, 1)))));
if(!GetSpellUsesLeft(oCreature, nClass, JsonGetInt(JsonArrayGet(jTalent, 1)))) return -2;
return ai_CheckSpecialTalentsandUse(oCreature, jTalent, sCategory, nInMelee, oTarget);
}
int ai_UseCreatureItemTalent(object oCreature, json jLevel, json jTalent, string sCategory, int nInMelee, object oTarget = OBJECT_INVALID)
@@ -2691,6 +3052,178 @@ void ai_UpdateMaxTalentLevel(object oCreature, json jCategory, string sCategory,
SetLocalInt(oCreature, AI_MAX_TALENT + sCategory, nLevel);
}
}
/*******************************************************************************
New talent system that checks by level then category.
*******************************************************************************/
/*int ai_UseCreatureTalentByLevel(object oCreature, int nInMelee, int nLevel = 10, object oTarget = OBJECT_INVALID)
{
string sLevel = IntToString(nLevel);
// Get the Max Talent Level to see if we even need to pull this talent.
int nMaxTalentLevel = GetLocalInt(oCreature, AI_MAX_LEVEL + sLevel);
if(AI_DEBUG) ai_Debug("0i_talents", "2394", AI_MAX_LEVEL + sLevel + ": " +
IntToString(nMaxTalentLevel) +
" nLevel: " + IntToString(nLevel));
if(nMaxTalentLevel == -1) return FALSE;
// If there are no talents at higher levels then start at the lowest talent level.
if(nMaxTalentLevel < nLevel) nLevel = nMaxTalentLevel;
if(nLevel < 0 || nLevel > 10) nLevel = 9;
json jTalent;
int bHasTalent, nClass, nSlot, nType, nSlotIndex, nMaxSlotIndex, nTalentUsed, nSpell;
int bUseMagic = !ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC);
int bUseMagicItems = !ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC_ITEMS);
if(AI_DEBUG) ai_Debug("0i_talents", "2413", "bUseMagic: " + IntToString(bUseMagic) +
" bUseMagicItems: " + IntToString(bUseMagicItems));
// Loop through nLevels starting at the highest then going to the lowest.
// (i.e. the highest or best is our assumption).
// Get the saved level from oCreature.
json jLevel = GetLocalJson(oCreature, "SPELL_LEVEL_" + IntToString(nLevel));
if(AI_DEBUG) ai_Debug("0i_talents", "3091", "jLevel: " + IntToString(nLevel) + " " + JsonDump(jLevel, 2));
if(JsonGetType(jCategory) == JSON_TYPE_NULL)
{
SetLocalInt(oCreature, AI_MAX_LEVEL + sCategory, -1);
return FALSE;
}
while(nLevel > -1)
{
// Get the array of nLevel cycling down to 0.
jLevel = JsonArrayGet(jCategory, nLevel);
nMaxSlotIndex = JsonGetLength(jLevel);
if(AI_DEBUG) ai_Debug("0i_talents", "2422", "Level: " + IntToString(nLevel) +
" nMaxSlotIndex: " + IntToString(nMaxSlotIndex));
if(nMaxSlotIndex > 0)
{
bHasTalent = TRUE;
// Get the talent within nLevel cycling from the first to the last.
nSlotIndex = 0;
while (nSlotIndex < nMaxSlotIndex)
{
jTalent= JsonArrayGet(jLevel, nSlotIndex);
if(AI_DEBUG) ai_Debug("0i_talents", "2432", "nSlotIndex: " + IntToString(nSlotIndex) +
" jTalent Type: " + IntToString(JsonGetInt(JsonArrayGet(jTalent, 0))));
nType = JsonGetInt(JsonArrayGet(jTalent, 0));
if(bUseMagic)
{
if(nType == AI_TALENT_TYPE_SPELL)
{
nTalentUsed = ai_UseCreatureSpellTalent(oCreature, jLevel, jTalent, sCategory, nInMelee, oTarget);
// -1 means it was a memorized spell and we need to remove it.
if(nTalentUsed == -1)
{
ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex);
if(nMaxSlotIndex == 1) ai_UpdateMaxTalentLevel(oCreature, jCategory, sCategory, nMaxTalentLevel, nLevel);
return TRUE;
}
// There are no more spell slots left for non-memorizing caster so remove the level.
else if(nTalentUsed == -2)
{
ai_RemoveTalentLevel(oCreature, jCategory, jLevel, sCategory, nLevel);
if(nMaxSlotIndex == 1) ai_UpdateMaxTalentLevel(oCreature, jCategory, sCategory, nMaxTalentLevel, nLevel);
}
else if(nTalentUsed) return TRUE;
}
else if(nType == AI_TALENT_TYPE_SP_ABILITY)
{
// Special ability spells do not need to concentrate?!
if(ai_CheckSpecialTalentsandUse(oCreature, jTalent, sCategory, nInMelee, oTarget))
{
// When the ability is used that slot is now not readied.
// Multiple uses of the same spell are stored in different slots.
ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex);
if(nMaxSlotIndex == 1) ai_UpdateMaxTalentLevel(oCreature, jCategory, sCategory, nMaxTalentLevel, nLevel);
return TRUE;
}
}
}
if(bUseMagicItems && nType == AI_TALENT_TYPE_ITEM)
{
// Items do not need to concentrate.
if(ai_UseCreatureItemTalent(oCreature, jLevel, jTalent, sCategory, nInMelee, oTarget))
{
if(AI_DEBUG) ai_Debug("0i_talents", "2473", "Checking if Item is used up: " +
IntToString(JsonGetInt(JsonArrayGet(jTalent, 4))));
if(JsonGetInt(JsonArrayGet(jTalent, 4)) == -1)
{
ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex);
if(nMaxSlotIndex == 1) ai_UpdateMaxTalentLevel(oCreature, jCategory, sCategory, nMaxTalentLevel, nLevel);
}
return TRUE;
}
}
//else if(nType == AI_TALENT_TYPE_FEAT) {}
nSlotIndex++;
}
}
else if(!bHasTalent) SetLocalInt(oCreature, AI_MAX_LEVEL + sCategory, nLevel - 1);
nLevel--;
}
return FALSE;
}
int ai_UseTalentByLevel(object oCreature, int nTalent, object oTarget)
{
if(AI_DEBUG) ai_Debug("0i_talents", "1912", GetName(oCreature) + " is trying to use " + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nTalent))) +
" on " + GetName(oTarget));
// Get the saved category from oCreature.
string sCategory = Get2DAString("ai_spells", "Category", nTalent);
json jCategory = GetLocalJson(oCreature, sCategory);
if(AI_DEBUG) ai_Debug("0i_talents", "1917", "jCategory: " + sCategory + " " + JsonDump(jCategory, 2));
if(JsonGetType(jCategory) == JSON_TYPE_NULL) return FALSE;
json jLevel, jTalent;
int nLevel, nClass, nSlot, nType, nSlotIndex, nMaxSlotIndex, nTalentUsed, nSpell;
// Loop through nLevels down to nMinNoTalentLevel looking for the first talent
// (i.e. the highest or best?).
while(nLevel <= 9)
{
// Get the array of nLevel.
jLevel = JsonArrayGet(jCategory, nLevel);
nMaxSlotIndex = JsonGetLength(jLevel);
if(AI_DEBUG) ai_Debug("0i_talents", "1925", "nLevel: " + IntToString(nLevel) +
" nMaxSlotIndex: " + IntToString(nMaxSlotIndex));
if(nMaxSlotIndex > 0)
{
// Get the talent within nLevel cycling from the first to the last.
nSlotIndex = 0;
while (nSlotIndex < nMaxSlotIndex)
{
jTalent= JsonArrayGet(jLevel, nSlotIndex);
if(AI_DEBUG) ai_Debug("0i_talents", "1936", "nSlotIndex: " + IntToString(nSlotIndex) +
" jTalent Type: " + IntToString(JsonGetInt(JsonArrayGet(jTalent, 0))));
nSpell = JsonGetInt(JsonArrayGet(jTalent, 1));
if(nSpell == nTalent)
{
nType = JsonGetInt(JsonArrayGet(jTalent, 0));
if(nType == AI_TALENT_TYPE_SPELL || nType == AI_TALENT_TYPE_SP_ABILITY)
{
if(ai_UseTalentOnObject(oCreature, jTalent, oTarget, 0))
{
ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex);
return TRUE;
}
}
else if(nType == AI_TALENT_TYPE_ITEM)
{
// Items do not need to concentrate.
if(ai_UseCreatureItemTalent(oCreature, jLevel, jTalent, sCategory, 0, oTarget))
{
if(AI_DEBUG) ai_Debug("0i_talents", "1955", "Checking if Item is used up: " +
IntToString(JsonGetInt(JsonArrayGet(jTalent, 4))));
if(JsonGetInt(JsonArrayGet(jTalent, 4)) == -1)
{
ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex);
}
return TRUE;
}
}
}
nSlotIndex++;
}
}
nLevel++;
}
return FALSE;
} */
/*******************************************************************************
Old talent system that checks by category then level.
*******************************************************************************/
int ai_UseCreatureTalent(object oCreature, string sCategory, int nInMelee, int nLevel = 10, object oTarget = OBJECT_INVALID)
{
// Get the Max Talent Level to see if we even need to pull this talent.
@@ -2740,21 +3273,28 @@ int ai_UseCreatureTalent(object oCreature, string sCategory, int nInMelee, int n
{
if(nType == AI_TALENT_TYPE_SPELL)
{
nTalentUsed = ai_UseCreatureSpellTalent(oCreature, jLevel, jTalent, sCategory, nInMelee, oTarget);
// -1 means it was a memorized spell and we need to remove it.
if(nTalentUsed == -1)
// Check to make sure they still have this spell.
nClass = JsonGetInt(JsonArrayGet(jTalent, 2));
if(AI_DEBUG) ai_Debug("0i_talents", "3290", GetName(oCreature) + " Memorizes Spells? " +
Get2DAString("classes", "MemorizesSpells", nClass));
if(Get2DAString("classes", "MemorizesSpells", nClass) == "1")
{
ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex);
if(nMaxSlotIndex == 1) ai_UpdateMaxTalentLevel(oCreature, jCategory, sCategory, nMaxTalentLevel, nLevel);
return TRUE;
if(AI_DEBUG) ai_Debug("0i_talents", "3294", " Spell Memorized? " +
IntToString(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlotIndex)));
if(GetMemorizedSpellReady(oCreature, nClass, nLevel, nSlotIndex) < 1)
{
ai_RemoveTalent(oCreature, jCategory, jLevel, sCategory, nLevel, nSlotIndex);
if(nMaxSlotIndex == 1) ai_UpdateMaxTalentLevel(oCreature, jCategory, sCategory, nMaxTalentLevel, nLevel);
}
else if(ai_UseCreatureSpellTalent(oCreature, jLevel, jTalent, sCategory, nInMelee, oTarget)) return TRUE;
}
// There are no more spell slots left for non-memorizing caster so remove the level.
else if(nTalentUsed == -2)
else if(!GetSpellUsesLeft(oCreature, nClass, JsonGetInt(JsonArrayGet(jTalent, 1))))
{
ai_RemoveTalentLevel(oCreature, jCategory, jLevel, sCategory, nLevel);
if(nMaxSlotIndex == 1) ai_UpdateMaxTalentLevel(oCreature, jCategory, sCategory, nMaxTalentLevel, nLevel);
nTalentUsed = FALSE;
}
else if(nTalentUsed) return TRUE;
else if(ai_UseCreatureSpellTalent(oCreature, jLevel, jTalent, sCategory, nInMelee, oTarget)) return TRUE;
}
else if(nType == AI_TALENT_TYPE_SP_ABILITY)
{
@@ -2769,7 +3309,7 @@ int ai_UseCreatureTalent(object oCreature, string sCategory, int nInMelee, int n
}
}
}
if(bUseMagicItems && nType == AI_TALENT_TYPE_ITEM)
else if(bUseMagicItems && nType == AI_TALENT_TYPE_ITEM)
{
// Items do not need to concentrate.
if(ai_UseCreatureItemTalent(oCreature, jLevel, jTalent, sCategory, nInMelee, oTarget))
@@ -2856,6 +3396,19 @@ int ai_UseTalent(object oCreature, int nTalent, object oTarget)
}
return FALSE;
}
// Lets do a check right before we cast the spell to see if the target is still good.
void ai_CheckSpellTarget(object oCreature, object oTarget)
{
if(GetIsDead(oTarget))
{
//SendMessageToPC(GetFirstPC(), "0i_talents, 2864, " + GetName(oCreature) +
//" is stopping our spell casting because " + GetName(oTarget) + " is dead!");
//WriteTimestampedLogEntry("0i_talents, 2864, " + GetName(oCreature) +
//" is stopping our spell casting because " + GetName(oTarget) + " is dead!");
ai_ClearCreatureActions();
ExecuteScript("0e_do_combat_rnd", oCreature);
}
}
int ai_UseTalentOnObject(object oCreature, json jTalent, object oTarget, int nInMelee, int bCheckPosition = TRUE)
{
int nClass, nLevel, nSlot, nMetaMagic, nDomain;
@@ -2955,7 +3508,14 @@ int ai_UseTalentOnObject(object oCreature, json jTalent, object oTarget, int nIn
" nDomain: " + IntToString(nDomain) + " nClass: " + IntToString(nClass));
ai_SetLastAction(oCreature, nSpell);
ActionCastSpellAtObject(nSpell, oTarget, nMetaMagic, FALSE, nDomain, 0, FALSE, nClass, FALSE);
// This was added to do a second check right before they cast to make sure
// the target was not killed between us deciding to cast and then casting!
DelayCommand(2.5, ai_CheckSpellTarget(oCreature, oTarget));
ActionDoCommand(ExecuteScript("0e_do_combat_rnd", oCreature));
// Temp Debug!!!!!
//string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
//SendMessageToPC(GetFirstPC(), "0i_talents, 1859 " + GetName(oCreature) + " is casting " + sSpellName + " on " + GetName(oTarget));
// Temp Debug!!!!!
if(AI_DEBUG)
{
string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell)));
@@ -3062,7 +3622,23 @@ int ai_UseTalentAtLocation(object oCreature, json jTalent, object oTarget, int n
int ai_CheckSpecialTalentsandUse(object oCreature, json jTalent, string sCategory, int nInMelee, object oTarget)
{
int nSpell = JsonGetInt(JsonArrayGet(jTalent, 1));
if(AI_DEBUG) ai_Debug("0i_talents", "1949", "nSpell: " + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))) +
// This checks to see if they tried to cast this spell last round and if we
// are trying to cast it again before at least 3 seconds is up then the spell
// is being canceled... remove this spell and look for another!
if(ai_CompareLastAction(oCreature, nSpell) &&
ai_GetCurrentTimeStamp() - GetLocalInt(oCreature, sLastActionTimeVarname) < 2)
{
if(AI_DEBUG)
{
int nLastTime = GetLocalInt(oCreature, sLastActionTimeVarname);
int nCurrentTime = ai_GetCurrentTimeStamp();
ai_Debug("0i_talents", "3634", "Same spell cast within less than 2 seconds!" +
" nSpell: " + IntToString(nSpell) + " nLastActionTime: " + IntToString(nLastTime) +
" nCurrentTime: " + IntToString(nCurrentTime) + " Difference: " + IntToString(nCurrentTime - nLastTime));
}
return FALSE;
}
if(AI_DEBUG) ai_Debug("0i_talents", "3637", "nSpell: " + GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpell))) +
" sCategory: " + sCategory);
if(sCategory == AI_TALENT_DISCRIMINANT_AOE)
{

View File

@@ -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

@@ -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

@@ -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

@@ -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!

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

@@ -26,77 +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)
{
// if it is an area of effect spell then we skip it on all but the caster.
if(Get2DAString("spells", "TargetShape", nSpell) == "")
{
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)))
@@ -118,11 +123,13 @@ void main()
jSpell = JsonArrayInsert(jSpell, JsonInt(nLevel));
jSpell = JsonArrayInsert(jSpell, JsonInt(nMetaMagic));
jSpell = JsonArrayInsert(jSpell, JsonInt(nDomain));
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));
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, 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);
}
}
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;
@@ -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));

View File

@@ -8,6 +8,11 @@
#include "nw_inc_gff"
#include "0i_main"
#include "0i_items"
// Banned list of BaseItemTypes use rows from baseitemtype.2da.
// Place each one between a : . Example ":21:28:" will not change belts and clubs.
// Best used for visual effect items like helms.
const string CRAFT_BANNED_BASEITEMTYPES = ":23:";
//const string CRAFT_BANNED_BASEITEMTYPES = "::";
// Maximum model number for all items except weapons.
const int CRAFT_MAX_MODEL_NUMBER = 999;
@@ -100,6 +105,8 @@ void CraftItemInfoEvents(object oPC, int nToken);
json CreateItemCombo(object oPC, json jRow, string sComboBind);
json CreateModelCombo(object oPC, object oTarget, json jRow, string sComboBind);
void CreateCreatureCraftingGUIPanel(object oPC, object oTarget);
// See above for constant that can have base item types added to the list.
int IfOnBannedBaseItemTypeList(object oPC, object oItem);
int GetColorIDChange(object oItem, int nType, int nIndex, int nChange)
{
@@ -131,7 +138,7 @@ void main()
int nObjectType = GetObjectType(oTarget);
if(nObjectType == OBJECT_TYPE_CREATURE)
{
if(ai_GetIsCharacter(oTarget) || GetMaster(oTarget) == oPC ||
if(oPC == oTarget || GetMaster(oTarget) == oPC ||
ai_GetIsDungeonMaster(oPC))
{
SetLocalObject(oPC, CRAFT_TARGET, oTarget);
@@ -1238,6 +1245,8 @@ object ChangeItemsAppearance(object oPC, object oTarget, int nToken, object oIte
// " nModelSelected: " + IntToString(nModelSelected));
}
// Change the model.
//WriteTimestampedLogEntry("pe_crafting, 1241, " + GetName(oItem) + " nModelSelected: " +
// IntToString(nModelSelected) + " nModelNumber: " + IntToString(nModelNumber));
oNewItem = CopyItemAndModify (oItem, ITEM_APPR_TYPE_ARMOR_MODEL, nModelSelected, nModelNumber, TRUE);
DestroyObject (oItem);
AssignCommand (oTarget, ActionEquipItem (oNewItem, INVENTORY_SLOT_CHEST));
@@ -1270,6 +1279,8 @@ object ChangeItemsAppearance(object oPC, object oTarget, int nToken, object oIte
// Note: Right Thigh and Left Thigh are backwards so this fixes that!
if (nModelSelected == ITEM_APPR_ARMOR_MODEL_RTHIGH) nModelSelected--;
else nModelSelected++;
//WriteTimestampedLogEntry("pe_crafting, 1275, " + GetName(oItem) + " nModelSelected: " +
// IntToString(nModelSelected) + " nModelNumber: " + IntToString(nModelNumber));
oItem = CopyItemAndModify(oNewItem, ITEM_APPR_TYPE_ARMOR_MODEL, nModelSelected, nModelNumber, TRUE);
DestroyObject(oNewItem);
AssignCommand(oTarget, ActionEquipItem(oItem, INVENTORY_SLOT_CHEST));
@@ -1586,6 +1597,7 @@ void SaveCraftedItem(object oPC, object oTarget, int nToken)
}
int CanCraftItem(object oPC, object oItem, int nToken, int bPasteCheck = FALSE)
{
if(IfOnBannedBaseItemTypeList(oPC, oItem)) return FALSE;
// Plot items cannot be changed.
if(GetPlotFlag(oItem))
{
@@ -2466,16 +2478,16 @@ void CreateCreatureCraftingGUIPanel(object oPC, object oTarget)
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 = CreateButtonSelect(JsonArray(), "Leather 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 = CreateButtonSelect(jGroupRow, "Cloth 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 = CreateButtonSelect(JsonArray(), "Leather 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 = CreateButtonSelect(jGroupRow, "Cloth 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));
@@ -2855,4 +2867,18 @@ void CreateCreatureCraftingGUIPanel(object oPC, object oTarget)
// Lets make sure we clean up any cool down variables.
//DeleteLocalInt(oPC, CRAFT_COOL_DOWN);
}
int IfOnBannedBaseItemTypeList(object oPC, object oItem)
{
int nIndex, nBaseItemType = GetBaseItemType(oItem);
int nBannedBaseItemType = StringToInt(ai_GetStringArray(CRAFT_BANNED_BASEITEMTYPES, nIndex));
while(nBannedBaseItemType)
{
if(nBaseItemType == nBannedBaseItemType)
{
ai_SendMessages(GetName(oItem) + " cannot have it's appearance changed!", AI_COLOR_RED, oPC);
return TRUE;
}
nBannedBaseItemType = StringToInt(ai_GetStringArray(CRAFT_BANNED_BASEITEMTYPES, ++nIndex));
}
return FALSE;
}

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,6 +75,9 @@ 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);
@@ -509,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

@@ -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");
@@ -60,6 +63,7 @@ void main()
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
@@ -103,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)
@@ -115,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));
@@ -138,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));
@@ -161,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)
@@ -174,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";
@@ -189,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));
@@ -197,7 +216,6 @@ void main()
}
nCntr++;
}
NuiSetBindWatch(oPC, nToken, "window_geometry", TRUE);
}
int StartingUp(object oPC)
{

View File

@@ -54,7 +54,7 @@ void main()
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());
@@ -152,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

@@ -419,11 +419,7 @@ void SaveYourHenchman(object oPC, int nToken, string sParty)
if(sName == sHenchmanName || sName == "")
{
sSlot = sParty + sIndex;
if(!bPC)
{
RemoveHenchman(oPC, oHenchman);
ChangeToStandardFaction(oHenchman, STANDARD_FACTION_DEFENDER);
}
if(!bPC) RemoveHenchman(oPC, oHenchman);
// Special check for Infinite Dungeon plot givers to be changed into henchman.
if(GetStringLeft(GetLocalString(oHenchman, "sConversation"), 8) == "id1_plot")
{
@@ -438,6 +434,13 @@ void SaveYourHenchman(object oPC, int nToken, string sParty)
// 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);
@@ -459,8 +462,8 @@ 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++;
@@ -679,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++;
}
@@ -821,7 +821,7 @@ 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 GetHasJFeat(int nFeat, json jFeatList)
@@ -1003,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, 1006, Adding racial feat: " +
WriteTimestampedLogEntry("pinc_henchmen, 999, Adding racial feat: " +
Get2DAString("feat", "LABEL", nRaceFeat));
nRaceRow++;
}
// Give class feats.
WriteTimestampedLogEntry("pinc_henchmen, 1011, 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);
@@ -1026,7 +1026,7 @@ 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, 1029, Adding class feat: " +
WriteTimestampedLogEntry("pinc_henchmen, 1022, Adding class feat: " +
Get2DAString("feat", "LABEL", nClassFeat));
}
}
@@ -1036,7 +1036,7 @@ json ResetFeats(json jHenchman, object oHenchman)
int nPackageFeat, nPackageRow;
string sBonusFeat2DAName = Get2DAString("classes", "BonusFeatsTable", nClass);
int nNumOfFeats = StringToInt(Get2DAString(sBonusFeat2DAName, "Bonus", nLevel));
WriteTimestampedLogEntry("pinc_henchmen, 1039, Select " + IntToString(nNumOfFeats) + " bonus feats.");
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.
@@ -1059,7 +1059,7 @@ 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, 1062, Adding class bonus feat: " +
WriteTimestampedLogEntry("pinc_henchmen, 1055, Adding class bonus feat: " +
Get2DAString("feat", "LABEL", nPackageFeat));
nNumOfFeats--;
}
@@ -1073,27 +1073,27 @@ json ResetFeats(json jHenchman, object oHenchman)
// Give picked feats from package.
nNumOfFeats = 1;
if(GetHasFeat(FEAT_QUICK_TO_MASTER, oHenchman)) nNumOfFeats++;
WriteTimestampedLogEntry("pinc_henchmen, 1076, Select " + IntToString(nNumOfFeats) + " feats for character.");
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));
//WriteTimestampedLogEntry("pinc_henchmen, 1082, nPackageFeat: " + Get2DAString("feat", "LABEL", 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, 1089, Selecting character feat: " +
WriteTimestampedLogEntry("pinc_henchmen, 1082, Selecting character feat: " +
Get2DAString("feat", "LABEL", nPackageFeat));
nNumOfFeats--;
}
if(nNumOfFeats < 1) break;
nPackageRow++;
}
WriteTimestampedLogEntry("pinc_henchmen, 1096, Adding feat list.");
WriteTimestampedLogEntry("pinc_henchmen, 1089, Adding feat list.");
jHenchman = GffReplaceList(jHenchman, "FeatList", jFeatList);
return jHenchman;
}
@@ -1120,7 +1120,7 @@ json ResetSkills(json jHenchman, object oHenchman, int nLevel)
jSkillList = JsonArrayInsert(jSkillList, jSkill);
}
// Give skill points based on the package.
WriteTimestampedLogEntry("pinc_henchmen, 1122, 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);
@@ -1149,7 +1149,7 @@ json ResetSkills(json jHenchman, object oHenchman, int nLevel)
{
jSkill = GffReplaceByte(jSkill, "Rank", nCurrentRanks + nNewRanks);
jSkillList = JsonArraySet(jSkillList, nPackageSkill, jSkill);
WriteTimestampedLogEntry("pinc_henchmen, 1151, Adding " + IntToString(nNewRanks) +
WriteTimestampedLogEntry("pinc_henchmen, 1145, Adding " + IntToString(nNewRanks) +
" ranks to " + Get2DAString("skills", "Label", nPackageSkill) +
" CrossClass: " + IntToString(bCrossClass));
nSkillPoints -= nNewRanks;
@@ -1161,9 +1161,9 @@ json ResetSkills(json jHenchman, object oHenchman, int nLevel)
}
json ResetSpellsKnown(json jClass, object oHenchman)
{
WriteTimestampedLogEntry("pinc_henchmen, 1163, Checking for spells known.");
WriteTimestampedLogEntry("pinc_henchmen, 1157, Checking for spells known.");
int nClass = GetClassByPosition(1, oHenchman);
WriteTimestampedLogEntry("pinc_henchmen, 1165, 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!
@@ -1183,7 +1183,7 @@ json ResetSpellsKnown(json jClass, object oHenchman)
while(nSpellLevel < 10)
{
sSpellLevel = IntToString(nSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1185, Checking Spell Level: " + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1143, Checking Spell Level: " + sSpellLevel);
// Recreate the 0th and 1st level based on the package.
if(nSpellLevel < 2 && bSpellBookRestricted)
{
@@ -1205,7 +1205,7 @@ json ResetSpellsKnown(json jClass, object oHenchman)
{
nSpellsKnown = StringToInt(Get2DAString(sSpellKnown2DAName, "SpellLevel" + sSpellLevel, nLevel));
}
WriteTimestampedLogEntry("pinc_henchmen, 1207, nSpellsKnown: " + IntToString(nSpellsKnown));
WriteTimestampedLogEntry("pinc_henchmen, 1201, nSpellsKnown: " + IntToString(nSpellsKnown));
jKnownList = JsonArray();
nPackageRow = 0;
while(nPackageRow < nPackageMaxRow && nSpellsKnown > 0)
@@ -1227,7 +1227,7 @@ json ResetSpellsKnown(json jClass, object oHenchman)
if(JsonGetLength(jKnownList) == 0)
{
jClass = GffRemoveList(jClass, "KnownList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1229, Removing KnownList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1223, Removing KnownList" + sSpellLevel);
}
else if(JsonGetType(GffGetList(jClass, "KnownList" + sSpellLevel)) != JSON_TYPE_NULL)
{
@@ -1243,7 +1243,7 @@ json ResetSpellsKnown(json jClass, object oHenchman)
if(JsonGetType(jKnownList) != JSON_TYPE_NULL)
{
jClass = GffRemoveList(jClass, "KnownList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1245, Removing KnownList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1239, Removing KnownList" + sSpellLevel);
}
}
if(bMemorizesSpells)
@@ -1252,7 +1252,7 @@ json ResetSpellsKnown(json jClass, object oHenchman)
if(JsonGetType(jMemorizedList) != JSON_TYPE_NULL)
{
jClass = GffRemoveList(jClass, "MemorizedList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1254, Removing MemorizedList" + sSpellLevel);
WriteTimestampedLogEntry("pinc_henchmen, 1248, Removing MemorizedList" + sSpellLevel);
}
}
else
@@ -1263,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, 1265, Setting SpellsPerDay to " +
WriteTimestampedLogEntry("pinc_henchmen, 1259, Setting SpellsPerDay to " +
IntToString(nSpellsKnown));
}
nSpellLevel++;
@@ -1289,8 +1289,8 @@ object ResetCharacter(object oPC, object oHenchman)
}
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);
// 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);
@@ -1304,7 +1304,7 @@ object ResetCharacter(object oPC, object oHenchman)
json jLvlStatList = GffGetList(jHenchman, "LvlStatList");
if(JsonGetType(jLvlStatList) != JSON_TYPE_NULL)
{
//WriteTimestampedLogEntry("pinc_henchmen 1289, jLvlStatList: " + JsonDump(jLvlStatList, 4));
//WriteTimestampedLogEntry("pinc_henchmen 1300, jLvlStatList: " + JsonDump(jLvlStatList, 4));
int nLevel = 1, nLevelTrack = 1;
int nAbilityStatIncrease, nAbility;
string sAbility;
@@ -1312,7 +1312,7 @@ object ResetCharacter(object oPC, object oHenchman)
json jLevel = JsonArrayGet(jLvlStatList, nLevel);
while(JsonGetType(jLevel) != JSON_TYPE_NULL)
{
WriteTimestampedLogEntry("inc_henchmen, 1314, 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)
@@ -1326,7 +1326,7 @@ object ResetCharacter(object oPC, object oHenchman)
if(nAbilityStatIncrease == ABILITY_CHARISMA) sAbility = "Cha";
nAbility = JsonGetInt(GffGetByte(jHenchman, sAbility)) - 1;
jHenchman = GffReplaceByte(jHenchman, sAbility, nAbility);
WriteTimestampedLogEntry("pinc_henchmen, 1328, Removing " + sAbility + " level bonus ability score point.");
WriteTimestampedLogEntry("pinc_henchmen, 1314, Removing " + sAbility + " level bonus ability score point.");
}
jLvlStatList = JsonArrayDel(jLvlStatList, nLevel);
// Note: nLevel is not incremented since we are removing the previous level.
@@ -1352,7 +1352,7 @@ object ResetCharacter(object oPC, object oHenchman)
jClass = ResetSpellsKnown(jClass, oHenchman);
jClassList = JsonArraySet(jClassList, 0, jClass);
jHenchman = GffReplaceList(jHenchman, "ClassList", jClassList);
//WriteTimestampedLogEntry("pinc_henchmen 1331, 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);
@@ -1571,4 +1571,3 @@ void CreateCharacterDescriptionNUI(object oPC, string sName, string sIcon, strin
// Row 2
NuiSetBind(oPC, nToken, "btn_ok_event", JsonBool(TRUE));
}