Added PEPS AI. Updated module name. Set all henchmen to have a random race &/or class based name using a custom version of Markshire's Nomeclature scripts, as well as appearance. Set Constructs, Undead, Outsiders & Elementals to not require food or drink. Full compile.
424 lines
20 KiB
Plaintext
424 lines
20 KiB
Plaintext
/*////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Script Name: 0i_states_cond
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
Include scripts that handle states and conditions for combat.
|
|
*/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#include "0i_main"
|
|
#include "0i_messages"
|
|
#include "0i_time"
|
|
//#include "X0_I0_COMBAT"
|
|
// Wrapper for ClearAllActions - we have added extra vars to be cleared as well.
|
|
// Note this references OBJECT_SELF!
|
|
void ai_ClearCreatureActions(int bClearCombatState = FALSE);
|
|
// Used in combat to keep track of the creatures last rounds action.
|
|
// One use is to make sure we don't use the same spell on the next round.
|
|
// 0+ is the spell that was cast, other actions use AI_LAST_ACTION_* constants.
|
|
void ai_SetLastAction(object oCreature, int nAction = AI_LAST_ACTION_NONE);
|
|
// Returns TRUE if oCreatures last rounds action is equal to nAction.
|
|
// 0+ is the spell that was cast, other actions use AI_LAST_ACTION_* constants.
|
|
int ai_CompareLastAction(object oCreature, int nAction);
|
|
// Sets the correct listen checks on oCreature.
|
|
void ai_SetListeningPatterns(object oCreature);
|
|
// Returns TRUE if oCreature is an elemental, undead, or golem i.e. non-living.
|
|
int ai_IsNonliving(int nRacialType);
|
|
// Returns TRUE if oCreature is in combat.
|
|
int ai_GetIsInCombat(object oCreature);
|
|
// Sets the time that this oCreature's current combat round started.
|
|
// Using action based combat rounds has an unfortunate side effect:
|
|
// Once you attack in melee you will continue to attack in melee do to hardcoded
|
|
// logic. This will "PUSH" your end of round back until it decides to stop attacking!
|
|
// We avoid this by setting the time and if we check for combat and 6 seconds has
|
|
// passed then we assume the current round is over, ClearAllActions, and start the next round.
|
|
void ai_SetCombatRound(object oCreature);
|
|
// Clears the current combat round timer by deleting the value.
|
|
void ai_EndCombatRound(object oCreature);
|
|
// Returns TRUE if AI_COMBAT_ROUND_IN_SECONDS has not passed since ai_SetCombatRound.
|
|
// If it returns FALSE then it will clear the current combat round timer.
|
|
int ai_IsInCombatRound(object oCreature, int nCombatRound = AI_COMBAT_ROUND_IN_SECONDS);
|
|
// Returns TRUE if oCreature is busy.
|
|
// This checks various actions to see if oCreature is busy;
|
|
// in combat, busy mode, Actions: attacking, casting spell, counterspelling,
|
|
// disabling trap, item casting spell, opening lock, resting, setting trap.
|
|
int ai_GetIsBusy(object oCreature);
|
|
// Returns a value based on the disabling effect.
|
|
// Dead = 1, Bleeding = 2, Dying = 2, Stunned = 29, Confused = 24, Paralyzed = 27
|
|
// Frightened 25, Turned = 35, Petrified = 79, Charmed = 23, Disappearappear = 75,
|
|
// Time Stop = 66, Dazed = 28, Sleep = 30.
|
|
// Returns FALSE if not Disabled.
|
|
int ai_Disabled(object oCreature);
|
|
// Set one of the AI_MODE_* bitwise constants on oAssociate to bOn.
|
|
void ai_SetAIMode(object oAssociate, int nBit, int bOn = TRUE);
|
|
// Return if nMode is set on oAssociate. Uses the AI_MODE_* bitwise constants.
|
|
int ai_GetAIMode(object oAssociate, int nBit);
|
|
// Set one of the AI_MAGIC_* bitwise constants on oAssociate to bOn.
|
|
void ai_SetMagicMode(object oAssociate, int nBit, int bOn = TRUE);
|
|
// Return if nMode is set on oAssociate. Uses the AI_MAGIC_* bitwise constants.
|
|
int ai_GetMagicMode(object oAssociate, int nBit);
|
|
// This is based off of the PC's settings for an associate and other creatures use a default.
|
|
// Set one of the AI_LOOT_* bitwise constants on oAssociate to bOn.
|
|
void ai_SetLootFilter(object oAssociate, int nBit, int bOn = TRUE);
|
|
// Return if nMode is set on oAssociate. Uses the AI_LOOT_* bitwise constants.
|
|
int ai_GetLootFilter(object oAssociate, int nBit);
|
|
// Set one of the AI_IP_* bitwise constants on oCreature to bOn.
|
|
void ai_SetItemProperty(object oCreature, string sVarname, int nBit, int bOn = TRUE);
|
|
// Return if nMode is set on oCreature. Uses the AI_IP_* bitwise constants.
|
|
int ai_GetItemProperty(object oCreature, string sVarname, int nBit);
|
|
// Returns the number of hitpoints a creature must have to not be healed.
|
|
// This is based off of the PC's settings for an associate and other creatures use a default.
|
|
int ai_GetHealersHpLimit(object oCreature, int bInCombat = TRUE);
|
|
// Returns TRUE if nCondition is within nCurrentConditions.
|
|
// nCurrentConditions is setup in ai_GetNegativeConditions.
|
|
int ai_GetHasNegativeCondition(int nCondition, int nCurrentConditions);
|
|
// Returns an integer with bitwise flags set that represent the current negative
|
|
// conditions on oCreature. ai_GetHasNegativeCondition uses this function.
|
|
int ai_GetNegativeConditions(object oCreature);
|
|
// Returns TRUE if oObject is in the line of sight of oCreature.
|
|
// If the creature is close LineOfSight doesn't work well.
|
|
int ai_GetIsInLineOfSight(object oCreature, object oObject);
|
|
// Add the specified condition flag to the behavior state of the caller
|
|
void ai_SetBehaviorState(int nCondition, int bValid = TRUE);
|
|
// Returns TRUE if the specified behavior flag is set on the caller
|
|
int ai_GetBehaviorState(int nCondition);
|
|
// Highlights the current mode for the widget passed.
|
|
void ai_HighlightWidgetMode(object oPC, object oAssociate, int nToken);
|
|
// Checks to see if the party scale is correctly adjusted.
|
|
void ai_CheckXPPartyScale(object oCreature);
|
|
|
|
void ai_ClearCreatureActions(int bClearCombatState = FALSE)
|
|
{
|
|
if(AI_DEBUG) ai_Debug("0i_states_cond", "89", GetName(OBJECT_SELF) + " is clearing actions (" +
|
|
IntToString(bClearCombatState) + ")!");
|
|
DeleteLocalInt(OBJECT_SELF, AI_CURRENT_ACTION_MODE);
|
|
ClearAllActions(bClearCombatState);
|
|
}
|
|
void ai_SetLastAction(object oCreature, int nAction = AI_LAST_ACTION_NONE)
|
|
{
|
|
SetLocalInt(oCreature, sLastActionVarname, nAction);
|
|
}
|
|
int ai_CompareLastAction(object oCreature, int nAction)
|
|
{
|
|
// Are we checking to see if we cast a spell?
|
|
if(nAction == AI_LAST_ACTION_CAST_SPELL &&
|
|
GetLocalInt(oCreature, sLastActionVarname) > -1) return TRUE;
|
|
// Check other last actions.
|
|
return (nAction == GetLocalInt(oCreature, sLastActionVarname));
|
|
}
|
|
void ai_SetListeningPatterns(object oCreature)
|
|
{
|
|
SetListenPattern(oCreature, AI_I_SEE_AN_ENEMY, AI_ALLY_SEES_AN_ENEMY);
|
|
SetListenPattern(oCreature, AI_I_HEARD_AN_ENEMY, AI_ALLY_HEARD_AN_ENEMY);
|
|
SetListenPattern(oCreature, AI_ATKED_BY_WEAPON, AI_ALLY_ATKED_BY_WEAPON);
|
|
SetListenPattern(oCreature, AI_ATKED_BY_SPELL, AI_ALLY_ATKED_BY_SPELL);
|
|
SetListenPattern(oCreature, AI_I_AM_WOUNDED, AI_ALLY_IS_WOUNDED);
|
|
SetListenPattern(oCreature, AI_I_AM_DEAD, AI_ALLY_IS_DEAD);
|
|
SetListenPattern(oCreature, AI_I_AM_DISEASED, AI_ALLY_IS_DISEASED);
|
|
SetListenPattern(oCreature, AI_I_AM_POISONED, AI_ALLY_IS_POISONED);
|
|
SetListenPattern(oCreature, AI_I_AM_WEAK, AI_ALLY_IS_WEAK);
|
|
SetListening(oCreature, TRUE);
|
|
}
|
|
int ai_IsNonliving(int nRacialType)
|
|
{
|
|
switch(nRacialType)
|
|
{
|
|
case RACIAL_TYPE_CONSTRUCT:
|
|
case RACIAL_TYPE_ELEMENTAL:
|
|
case RACIAL_TYPE_UNDEAD: return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
int ai_GetIsInCombat(object oCreature)
|
|
{
|
|
if(AI_DEBUG) ai_Debug("0i_states_cond", "110", GetName(oCreature) + " is in Combat: Enemy Numbers = " + IntToString(GetLocalInt(oCreature, AI_ENEMY_NUMBERS)));
|
|
|
|
return GetLocalInt(oCreature, AI_ENEMY_NUMBERS);
|
|
}
|
|
void ai_SetCombatRound(object oCreature)
|
|
{
|
|
SetLocalInt(oCreature, "AI_COMBAT_ROUND_START", SQLite_GetTimeStamp());
|
|
if(AI_DEBUG) ai_Debug("0i_states_cond", "116", " ===============> " + GetName(oCreature) + " ROUND START:" + IntToString(SQLite_GetTimeStamp()) + " <===============");
|
|
}
|
|
void ai_EndCombatRound(object oCreature)
|
|
{
|
|
if(AI_DEBUG) ai_Debug("0i_states_cond", "120", " ===============> " + GetName(oCreature) + " ROUND END:" + IntToString(SQLite_GetTimeStamp()) + " <===============");
|
|
DeleteLocalInt(oCreature, "AI_COMBAT_ROUND_START");
|
|
}
|
|
int ai_IsInCombatRound(object oCreature, int nCombatRound = AI_COMBAT_ROUND_IN_SECONDS)
|
|
{
|
|
int nCombatRoundStart = GetLocalInt(oCreature, "AI_COMBAT_ROUND_START");
|
|
if(AI_DEBUG) ai_Debug("0i_states_cond", "148", " nCombatRoundStart: " + IntToString(nCombatRoundStart));
|
|
if(!nCombatRoundStart) return FALSE;
|
|
// New combat round calculator. If 6 seconds has passed then we are on a new round!
|
|
int nSQLTime = SQLite_GetTimeStamp();
|
|
int nCombatRoundTime = nSQLTime - nCombatRoundStart;
|
|
if(AI_DEBUG) ai_Debug("0i_states_cond", "153", " SQLite_GetTimeStamp: " + IntToString(nSQLTime) +
|
|
"(" + IntToString(nSQLTime - nCombatRoundStart) + ")");
|
|
if(nCombatRoundTime < nCombatRound) return TRUE;
|
|
ai_EndCombatRound(oCreature);
|
|
return FALSE;
|
|
}
|
|
// Testing to see if we can fix some delaying in combat.
|
|
int ai_GetIsBusy(object oCreature)
|
|
{
|
|
int nAction = GetCurrentAction(oCreature);
|
|
if(AI_DEBUG) ai_Debug("0i_states_cond", "140", GetName(oCreature) + " Get is Busy, action: " +
|
|
IntToString(nAction));
|
|
switch(nAction)
|
|
{
|
|
case ACTION_CASTSPELL :
|
|
case ACTION_ITEMCASTSPELL :
|
|
case ACTION_OPENLOCK :
|
|
case ACTION_REST :
|
|
case ACTION_DISABLETRAP :
|
|
case ACTION_ATTACKOBJECT :
|
|
case ACTION_COUNTERSPELL :
|
|
case ACTION_SETTRAP : return TRUE;
|
|
case ACTION_WAIT :
|
|
case ACTION_INVALID :
|
|
{
|
|
int nCombatWait = GetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS);
|
|
if(AI_DEBUG) ai_Debug("0i_states_cond", "153", "nCombatWait: " + IntToString(nCombatWait) +
|
|
" AI_AM_I_SEARCHING: " + IntToString(GetLocalInt(oCreature, AI_AM_I_SEARCHING)));
|
|
if(nCombatWait)
|
|
{
|
|
if(ai_IsInCombatRound(oCreature, nCombatWait)) return TRUE;
|
|
DeleteLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS);
|
|
}
|
|
else if(GetLocalInt(oCreature, AI_AM_I_SEARCHING)) DeleteLocalInt(oCreature, AI_AM_I_SEARCHING);
|
|
return FALSE;
|
|
}
|
|
case ACTION_MOVETOPOINT :
|
|
{
|
|
return ai_GetIsInCombat(oCreature);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
int ai_Disabled(object oCreature)
|
|
{
|
|
if(GetIsDead(oCreature)) return 1;
|
|
// Check for effects.
|
|
effect eEffect = GetFirstEffect(oCreature);
|
|
while(GetIsEffectValid(eEffect))
|
|
{
|
|
switch(GetEffectType(eEffect))
|
|
{
|
|
case EFFECT_TYPE_DOMINATED :
|
|
{
|
|
if(!GetCommandable(oCreature)) SetCommandable(TRUE, oCreature);
|
|
return FALSE;
|
|
}
|
|
case EFFECT_TYPE_STUNNED :
|
|
case EFFECT_TYPE_DAZED :
|
|
case EFFECT_TYPE_SLEEP :
|
|
case EFFECT_TYPE_CONFUSED :
|
|
case EFFECT_TYPE_FRIGHTENED :
|
|
case EFFECT_TYPE_PARALYZE :
|
|
case EFFECT_TYPE_TURNED :
|
|
case EFFECT_TYPE_CHARMED :
|
|
case EFFECT_TYPE_PETRIFY :
|
|
case EFFECT_TYPE_TIMESTOP :
|
|
{
|
|
if(AI_DEBUG) ai_Debug("0i_stats_cond", "195", GetName(oCreature) + " is disabled(" +
|
|
IntToString(GetEffectType(eEffect)) + ")");
|
|
return GetEffectType(eEffect);
|
|
}
|
|
}
|
|
eEffect = GetNextEffect(oCreature);
|
|
}
|
|
// Not Commandable is basically disabled as far as the AI is concerned.
|
|
if(!GetCommandable(oCreature))
|
|
{
|
|
if(AI_DEBUG) ai_Debug("0i_stats_cond", "213", GetName(oCreature) + " is disabled(Not Commandable)!");
|
|
return EFFECT_TYPE_PARALYZE;
|
|
}
|
|
if(AI_DEBUG) ai_Debug("0i_states_cond", "202", GetName(oCreature) + " is not disabled.");
|
|
return FALSE;
|
|
}
|
|
void ai_SetAIMode(object oAssociate, int nBit, int bOn = TRUE)
|
|
{
|
|
int nAIModes = GetLocalInt(oAssociate, sAIModeVarname);
|
|
if(bOn) nAIModes = nAIModes | nBit;
|
|
else nAIModes = nAIModes & ~nBit;
|
|
SetLocalInt(oAssociate, sAIModeVarname, nAIModes);
|
|
// Set widget to show the mode they are in.
|
|
|
|
}
|
|
int ai_GetAIMode(object oAssociate, int nBit)
|
|
{
|
|
if(GetLocalInt(oAssociate, sAIModeVarname) & nBit) return TRUE;
|
|
return FALSE;
|
|
}
|
|
void ai_SetMagicMode(object oAssociate, int nBit, int bOn = TRUE)
|
|
{
|
|
int nMagicModes = GetLocalInt(oAssociate, sMagicModeVarname);
|
|
if(bOn) nMagicModes = nMagicModes | nBit;
|
|
else nMagicModes = nMagicModes & ~nBit;
|
|
SetLocalInt(oAssociate, sMagicModeVarname, nMagicModes);
|
|
}
|
|
int ai_GetMagicMode(object oAssociate, int nBit)
|
|
{
|
|
if(GetLocalInt(oAssociate, sMagicModeVarname) & nBit) return TRUE;
|
|
return FALSE;
|
|
}
|
|
void ai_SetLootFilter(object oAssociate, int nLootBit, int bOn = TRUE)
|
|
{
|
|
int nLootFilter = GetLocalInt(oAssociate, sLootFilterVarname);
|
|
if(bOn) nLootFilter = nLootFilter | nLootBit;
|
|
else nLootFilter = nLootFilter & ~nLootBit;
|
|
SetLocalInt(oAssociate, sLootFilterVarname, nLootFilter);
|
|
}
|
|
int ai_GetLootFilter(object oAssociate, int nBit)
|
|
{
|
|
if(GetLocalInt(oAssociate, sLootFilterVarname) & nBit) return TRUE;
|
|
return FALSE;
|
|
}
|
|
void ai_SetItemProperty(object oCreature, string sVarname, int nBit, int bOn = TRUE)
|
|
{
|
|
int nItemProperties = GetLocalInt(oCreature, sVarname);
|
|
if(bOn) nItemProperties = nItemProperties | nBit;
|
|
else nItemProperties = nItemProperties & ~nBit;
|
|
SetLocalInt(oCreature, sVarname, nItemProperties);
|
|
}
|
|
int ai_GetItemProperty(object oCreature, string sVarname, int nBit)
|
|
{
|
|
if(GetLocalInt(oCreature, sVarname) & nBit) return TRUE;
|
|
return FALSE;
|
|
}
|
|
int ai_GetHealersHpLimit(object oCreature, int bInCombat = TRUE)
|
|
{
|
|
if(bInCombat) return GetLocalInt(oCreature, AI_HEAL_IN_COMBAT_LIMIT);
|
|
else return GetLocalInt(oCreature, AI_HEAL_OUT_OF_COMBAT_LIMIT);
|
|
}
|
|
int ai_GetHasNegativeCondition(int nCondition, int nCurrentConditions)
|
|
{
|
|
return (nCurrentConditions & nCondition);
|
|
}
|
|
int ai_GetNegativeConditions(object oCreature)
|
|
{
|
|
int nCondition, nEffectType;
|
|
effect eEffect = GetFirstEffect(oCreature);
|
|
while(GetIsEffectValid (eEffect))
|
|
{
|
|
// Rage and maybe other abilities might come from the oCreature!
|
|
if(GetEffectCreator(eEffect) != oCreature)
|
|
{
|
|
nEffectType = GetEffectType(eEffect);
|
|
switch(nEffectType)
|
|
{
|
|
case EFFECT_TYPE_DISEASE: nCondition = nCondition | AI_CONDITION_DISEASE; break;
|
|
case EFFECT_TYPE_POISON: nCondition = nCondition | AI_CONDITION_POISON; break;
|
|
case EFFECT_TYPE_CURSE: nCondition = nCondition | AI_CONDITION_CURSE; break;
|
|
case EFFECT_TYPE_BLINDNESS:
|
|
case EFFECT_TYPE_DEAF: nCondition = nCondition | AI_CONDITION_BLINDDEAF; break;
|
|
case EFFECT_TYPE_ABILITY_DECREASE: nCondition = nCondition | AI_CONDITION_ABILITY_DRAIN; break;
|
|
case EFFECT_TYPE_NEGATIVELEVEL: nCondition = nCondition | AI_CONDITION_LEVEL_DRAIN; break;
|
|
case EFFECT_TYPE_AC_DECREASE: nCondition = nCondition | AI_CONDITION_AC_DECREASE; break;
|
|
case EFFECT_TYPE_ATTACK_DECREASE: nCondition = nCondition | AI_CONDITION_ATK_DECREASE; break;
|
|
case EFFECT_TYPE_CHARMED: nCondition = nCondition | AI_CONDITION_CHARMED; break;
|
|
case EFFECT_TYPE_CONFUSED: nCondition = nCondition | AI_CONDITION_CONFUSED; break;
|
|
case EFFECT_TYPE_DAZED: nCondition = nCondition | AI_CONDITION_DAZED; break;
|
|
case EFFECT_TYPE_DAMAGE_DECREASE: nCondition = nCondition | AI_CONDITION_DMG_DECREASE; break;
|
|
case EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE: nCondition = nCondition | AI_CONDITION_DMG_I_DECREASE; break;
|
|
case EFFECT_TYPE_DOMINATED: nCondition = nCondition | AI_CONDITION_DOMINATED; break;
|
|
case EFFECT_TYPE_FRIGHTENED: nCondition = nCondition | AI_CONDITION_FRIGHTENED; break;
|
|
case EFFECT_TYPE_PARALYZE: nCondition = nCondition | AI_CONDITION_PARALYZE; break;
|
|
case EFFECT_TYPE_SAVING_THROW_DECREASE: nCondition = nCondition | AI_CONDITION_SAVE_DECREASE; break;
|
|
case EFFECT_TYPE_SKILL_DECREASE: nCondition = nCondition | AI_CONDITION_SKILL_DECREASE; break;
|
|
case EFFECT_TYPE_SLOW: nCondition = nCondition | AI_CONDITION_SLOW; break;
|
|
case EFFECT_TYPE_SPELL_RESISTANCE_DECREASE: nCondition = nCondition | AI_CONDITION_SR_DECREASE; break;
|
|
case EFFECT_TYPE_STUNNED: nCondition = nCondition | AI_CONDITION_STUNNED; break;
|
|
}
|
|
}
|
|
eEffect = GetNextEffect(oCreature);
|
|
}
|
|
return nCondition;
|
|
}
|
|
int ai_GetIsInLineOfSight(object oCreature, object oObject)
|
|
{
|
|
// Creatures can block the line of sight so when close we shouldn't check.
|
|
if(GetDistanceBetween(oObject, oCreature) <= AI_RANGE_MELEE) return TRUE;
|
|
return LineOfSightObject(oCreature, oObject);
|
|
}
|
|
void ai_SetBehaviorState(int nCondition, int bValid = TRUE)
|
|
{
|
|
int nPlot = GetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER");
|
|
if(bValid)
|
|
{
|
|
nPlot = nPlot | nCondition;
|
|
SetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER", nPlot);
|
|
}
|
|
else
|
|
{
|
|
nPlot = nPlot & ~nCondition;
|
|
SetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER", nPlot);
|
|
}
|
|
}
|
|
int ai_GetBehaviorState(int nCondition)
|
|
{
|
|
int nPlot = GetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER");
|
|
if(nPlot & nCondition) return TRUE;
|
|
return FALSE;
|
|
}
|
|
void ai_HighlightWidgetMode(object oPC, object oAssociate, int nToken)
|
|
{
|
|
if(oPC == oAssociate) return;
|
|
int bBool;
|
|
bBool = ai_GetAIMode(oAssociate,AI_MODE_DEFEND_MASTER);
|
|
NuiSetBind(oPC, nToken, "btn_cmd_guard_encouraged", JsonBool(bBool));
|
|
bBool = ai_GetAIMode(oAssociate,AI_MODE_STAND_GROUND);
|
|
NuiSetBind(oPC, nToken, "btn_cmd_hold_encouraged", JsonBool(bBool));
|
|
bBool = ai_GetAIMode(oAssociate,AI_MODE_FOLLOW);
|
|
NuiSetBind(oPC, nToken, "btn_cmd_follow_encouraged", JsonBool(bBool));
|
|
if(!ai_GetAIMode(oAssociate, AI_MODE_DEFEND_MASTER) &&
|
|
!ai_GetAIMode(oAssociate, AI_MODE_STAND_GROUND) &&
|
|
!ai_GetAIMode(oAssociate, AI_MODE_FOLLOW)) bBool = TRUE;
|
|
else bBool = FALSE;
|
|
NuiSetBind(oPC, nToken, "btn_cmd_attack_encouraged", JsonBool(bBool));
|
|
}
|
|
void ai_CheckXPPartyScale(object oCreature)
|
|
{
|
|
object oModule = GetModule();
|
|
if(!GetLocalInt(oModule, AI_RULE_PARTY_SCALE)) return;
|
|
object oMaster;
|
|
if(!ai_GetIsCharacter(oCreature))
|
|
{
|
|
oMaster = GetMaster(oCreature);
|
|
while(oMaster != OBJECT_INVALID)
|
|
{
|
|
if(ai_GetIsCharacter(oMaster)) break;
|
|
oMaster = GetMaster(oMaster);
|
|
}
|
|
if(oMaster == OBJECT_INVALID) return;
|
|
}
|
|
else oMaster = oCreature;
|
|
float fDefaultXPScale = IntToFloat(GetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP));
|
|
float fPartySize = 4.0;
|
|
int nAssociateType, nHenchman, nHenchAssociate;
|
|
object oHenchman;
|
|
for(nAssociateType = 1; nAssociateType <= 5; nAssociateType++)
|
|
{
|
|
if(nAssociateType == ASSOCIATE_TYPE_HENCHMAN)
|
|
{
|
|
for(nHenchman = 1; nHenchman <= AI_MAX_HENCHMAN; nHenchman++)
|
|
{
|
|
oHenchman = GetAssociate(nAssociateType, oMaster, nHenchman);
|
|
if(oHenchman != OBJECT_INVALID)
|
|
{
|
|
fPartySize += 1.0;
|
|
for(nHenchAssociate = 2; nHenchAssociate <= 5; nHenchAssociate++)
|
|
{
|
|
if(GetAssociate(nHenchAssociate, oHenchman, 1) != OBJECT_INVALID) fPartySize += 1.0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(GetAssociate(nAssociateType, oMaster, 1) != OBJECT_INVALID) fPartySize += 1.0;
|
|
}
|
|
int nXPScale = FloatToInt(fPartySize / 4.0 * fDefaultXPScale);
|
|
//SendMessageToPC(oMaster, GetName(oMaster) + " nXPScale = (3 + fPartySize / 4.0 * fDefaultXPScale)" +
|
|
// IntToString(nXPScale) + " = (" + FloatToString(fPartySize, 0, 1) + " / 4.0 * " +
|
|
// FloatToString(fDefaultXPScale, 0, 1) + ")");
|
|
SetModuleXPScale(nXPScale);
|
|
}
|
|
|