771 lines
22 KiB
Plaintext
771 lines
22 KiB
Plaintext
/*
|
|
|
|
Henchman Inventory And Battle AI
|
|
|
|
This file contains routines used in equipping monsters
|
|
and henchman. Contains modified EquipAppropriateWeapons
|
|
function (renamed HenchEquipAppropriateWeapons)
|
|
|
|
*/
|
|
|
|
#include "hench_i0_generic"
|
|
|
|
// void main() { }
|
|
|
|
// internal weapon state settings
|
|
const int HENCH_AI_WEAPON_INIT = 0x00000001;
|
|
const int HENCH_AI_HAS_MELEE = 0x00000002;
|
|
const int HENCH_AI_HAS_MELEE_WEAPON = 0x00000004;
|
|
const int HENCH_AI_HAS_RANGED_WEAPON = 0x00000008;
|
|
|
|
|
|
const string HENCH_AI_WEAPON = "HENCH_AI_WEAPON";
|
|
const string HENCH_AI_STORED_MELEE = "HenchStoredMeleeWeapon";
|
|
const string HENCH_AI_STORED_RANGED = "HenchStoredRangedWeapon";
|
|
const string HENCH_AI_STORED_SHIELD = "StoredShield";
|
|
const string HENCH_AI_SHIELD_STATUS = "HaveShieldStatus";
|
|
const string HENCH_AI_STORED_OFF_HAND = "StoredOffHand";
|
|
const string HENCH_AI_OFF_HAND_STATUS = "HaveOffhandStatus";
|
|
const string HENCH_AI_SWITCHED_TO_MELEE = "SwitchedToMelee";
|
|
const string HENCH_AI_COMBAT_EQUIP = "HenchCombatEquip";
|
|
|
|
|
|
// void main() { }
|
|
|
|
|
|
// cache weapon state information on self
|
|
void SetWeaponState(int nCondition, int bValid = TRUE);
|
|
|
|
// un-equip weapons from left and right hands
|
|
void UnequipWeapons();
|
|
|
|
// equip best shield available
|
|
void EquipShield(int bIndicateStatus);
|
|
|
|
// get cached weapon state information
|
|
int GetInitWeaponStatus();
|
|
|
|
// equip best melee weapon(s) against target AND check for shield
|
|
int EquipMeleeWeapons(object oTarget, int bIndicateStatus, int iCallNumber);
|
|
|
|
// equip best ranged weapon(s) against target
|
|
int EquipRangedWeapon(object oTarget, int bIndicateStatus, int iCallNumber);
|
|
|
|
// equip best weapons based on target and threshold distance
|
|
int HenchEquipAppropriateWeapons(object oTarget, float fThresholdDistance, int bIndicateSwitch, int bPolymorphed);
|
|
|
|
// continue weapon equipping that is in progress
|
|
void ActionContinueEquip(object oTarget, int bIndicateStatus, int iCallNumber);
|
|
|
|
// wrapper to equip default weapons
|
|
void HenchEquipDefaultWeapons(object oCreature = OBJECT_SELF, int bShowStatus = FALSE);
|
|
|
|
// clear all cached weapon state information
|
|
void ClearWeaponStates(object oCreature = OBJECT_SELF);
|
|
|
|
// equip weapons on self
|
|
void ActionChangeEquippedWeapons();
|
|
|
|
// equip weapons on target creature
|
|
void ChangeEquippedWeapons(object oCreature);
|
|
|
|
|
|
void SetWeaponState(int nCondition, int bValid = TRUE)
|
|
{
|
|
int nStatus = GetLocalInt(OBJECT_SELF, HENCH_AI_WEAPON);
|
|
if (bValid)
|
|
{
|
|
nStatus = nStatus | nCondition;
|
|
SetLocalInt(OBJECT_SELF, HENCH_AI_WEAPON, nStatus);
|
|
}
|
|
else
|
|
{
|
|
nStatus = nStatus & ~nCondition;
|
|
SetLocalInt(OBJECT_SELF, HENCH_AI_WEAPON, nStatus);
|
|
}
|
|
}
|
|
|
|
|
|
void UnequipWeapons()
|
|
{
|
|
object oRight = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
|
|
if (GetIsObjectValid(oRight))
|
|
{
|
|
ActionUnequipItem(oRight);
|
|
}
|
|
object oLeft = GetItemInSlot(INVENTORY_SLOT_LEFTHAND);
|
|
if (GetIsObjectValid(oLeft))
|
|
{
|
|
ActionUnequipItem(oLeft);
|
|
}
|
|
}
|
|
|
|
|
|
void EquipShield(int bIndicateStatus)
|
|
{
|
|
int iHaveShieldStatus = GetLocalInt(OBJECT_SELF, HENCH_AI_SHIELD_STATUS);
|
|
object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND);
|
|
if (iHaveShieldStatus == 2)
|
|
{
|
|
// not really a shield, get rid of
|
|
if (GetIsObjectValid(oShield))
|
|
{
|
|
ActionUnequipItem(oShield);
|
|
}
|
|
return;
|
|
}
|
|
if (iHaveShieldStatus == 1)
|
|
{
|
|
object oStoredShield = GetLocalObject(OBJECT_SELF, HENCH_AI_STORED_SHIELD);
|
|
if (oStoredShield == oShield)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (GetIsObjectValid(oStoredShield) && (GetItemPossessor(oStoredShield) == OBJECT_SELF))
|
|
{
|
|
ActionEquipItem(oStoredShield, INVENTORY_SLOT_LEFTHAND);
|
|
return;
|
|
}
|
|
}
|
|
|
|
int nMaxValue = 0;
|
|
int iCreatureSize = GetCreatureSize(OBJECT_SELF);
|
|
object oRealMaster = GetRealMaster();
|
|
int bNoPCMaster = !(GetIsObjectValid(oRealMaster) && GetIsPC(oRealMaster));
|
|
if (GetIsObjectValid(oShield))
|
|
{
|
|
int nSize = 1; // note start at one less so easy compare with creature size
|
|
switch (GetBaseItemType(oShield))
|
|
{
|
|
case BASE_ITEM_TOWERSHIELD:
|
|
nSize ++;
|
|
case BASE_ITEM_LARGESHIELD:
|
|
nSize ++;
|
|
case BASE_ITEM_SMALLSHIELD:
|
|
if (bNoPCMaster || GetIdentified(oShield))
|
|
{
|
|
int bPlotFlag = GetPlotFlag(oShield);
|
|
if (bPlotFlag)
|
|
{
|
|
SetPlotFlag(oShield, FALSE);
|
|
}
|
|
nMaxValue = GetGoldPieceValue(oShield);
|
|
if (bPlotFlag)
|
|
{
|
|
SetPlotFlag(oShield, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nMaxValue = 2;
|
|
}
|
|
break;
|
|
/* case BASE_ITEM_TORCH:
|
|
nMaxValue = 1;
|
|
break; */
|
|
default:
|
|
// not a shield - remove
|
|
ActionUnequipItem(oShield);
|
|
oShield = OBJECT_INVALID;
|
|
break;
|
|
}
|
|
}
|
|
|
|
int iNewShield = FALSE;
|
|
int tempValue;
|
|
int bHasShieldProf = GetHasFeat(FEAT_SHIELD_PROFICIENCY);
|
|
int bCantUseShield = FALSE;
|
|
// int bCanUseTorch = (iCreatureSize > 1) && GetCreatureUseItems(OBJECT_SELF);
|
|
|
|
object oItem = GetFirstItemInInventory();
|
|
while (GetIsObjectValid(oItem))
|
|
{
|
|
// skip past any items in a container
|
|
if (GetHasInventory(oItem))
|
|
{
|
|
object oContainer = oItem;
|
|
object oSubItem = GetFirstItemInInventory(oContainer);
|
|
oItem = GetNextItemInInventory();
|
|
while (GetIsObjectValid(oSubItem))
|
|
{
|
|
oItem = GetNextItemInInventory();
|
|
oSubItem = GetNextItemInInventory(oContainer);
|
|
}
|
|
continue;
|
|
}
|
|
int nSize = 1; // note start at one less so easy compare with creature size
|
|
switch (GetBaseItemType(oItem))
|
|
{
|
|
case BASE_ITEM_TOWERSHIELD:
|
|
nSize ++;
|
|
case BASE_ITEM_LARGESHIELD:
|
|
nSize ++;
|
|
case BASE_ITEM_SMALLSHIELD:
|
|
if (bHasShieldProf && (iCreatureSize >= nSize))
|
|
{
|
|
if (bNoPCMaster || GetIdentified(oItem))
|
|
{
|
|
int bPlotFlag = GetPlotFlag(oItem);
|
|
if (bPlotFlag)
|
|
{
|
|
SetPlotFlag(oItem, FALSE);
|
|
}
|
|
tempValue = GetGoldPieceValue(oItem);
|
|
if (bPlotFlag)
|
|
{
|
|
SetPlotFlag(oItem, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tempValue = 2;
|
|
}
|
|
if (tempValue > nMaxValue)
|
|
{
|
|
nMaxValue = tempValue;
|
|
oShield = oItem;
|
|
iNewShield = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bCantUseShield = TRUE;
|
|
}
|
|
break;
|
|
/* case BASE_ITEM_TORCH:
|
|
if (bCanUseTorch && (1 > nMaxValue))
|
|
{
|
|
nMaxValue = 1;
|
|
oShield = oItem;
|
|
iNewShield = TRUE;
|
|
} */
|
|
break;
|
|
default:
|
|
break;
|
|
|
|
}
|
|
oItem = GetNextItemInInventory();
|
|
}
|
|
if (nMaxValue > 0)
|
|
{
|
|
SetLocalInt(OBJECT_SELF, HENCH_AI_SHIELD_STATUS, 1);
|
|
SetLocalObject(OBJECT_SELF, HENCH_AI_STORED_SHIELD, oShield);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(OBJECT_SELF, HENCH_AI_SHIELD_STATUS, 2);
|
|
DeleteLocalObject(OBJECT_SELF, HENCH_AI_STORED_SHIELD);
|
|
}
|
|
if (iNewShield)
|
|
{
|
|
ActionEquipItem(oShield, INVENTORY_SLOT_LEFTHAND);
|
|
}
|
|
else if (bCantUseShield && bIndicateStatus)
|
|
{
|
|
SpeakString(sHenchCantUseShield);
|
|
}
|
|
}
|
|
|
|
|
|
int GetMeleeWeaponSize(object oItem)
|
|
{
|
|
if (GetWeaponRanged(oItem))
|
|
{
|
|
return 0;
|
|
}
|
|
int nBase = GetBaseItemType(oItem);
|
|
if (nBase == BASE_ITEM_TORCH)
|
|
{
|
|
return 0;
|
|
}
|
|
string sWeaponSizeStr = "HENCH_AI_WEAPON_SIZE_" + IntToString(nBase);
|
|
object oModule = GetModule();
|
|
int iWeaponSize = GetLocalInt(oModule, sWeaponSizeStr);
|
|
if (iWeaponSize == 0)
|
|
{
|
|
iWeaponSize = StringToInt(Get2DAString("baseitems", "WeaponSize", nBase));
|
|
if (iWeaponSize == 0)
|
|
{
|
|
iWeaponSize = -1;
|
|
}
|
|
SetLocalInt(oModule, sWeaponSizeStr, iWeaponSize);
|
|
}
|
|
if (iWeaponSize > 0)
|
|
{
|
|
return iWeaponSize;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int GetInitWeaponStatus()
|
|
{
|
|
int nResult = GetLocalInt(OBJECT_SELF, HENCH_AI_WEAPON);
|
|
if (nResult)
|
|
{
|
|
return nResult;
|
|
}
|
|
|
|
int bHasMeleeWeapon;
|
|
int bHasMeleeAttack;
|
|
int bHasRangedWeapon;
|
|
|
|
object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
|
|
if (GetIsObjectValid(oItem))
|
|
{
|
|
if (GetWeaponRanged(oItem))
|
|
{
|
|
bHasRangedWeapon = TRUE;
|
|
}
|
|
else if (GetMeleeWeaponSize(oItem) > 0)
|
|
{
|
|
bHasMeleeWeapon = TRUE;
|
|
}
|
|
}
|
|
|
|
oItem = GetFirstItemInInventory();
|
|
while (GetIsObjectValid(oItem) && !(bHasMeleeWeapon && bHasRangedWeapon))
|
|
{
|
|
// skip past any items in a container
|
|
if (GetHasInventory(oItem))
|
|
{
|
|
object oContainer = oItem;
|
|
object oSubItem = GetFirstItemInInventory(oContainer);
|
|
oItem = GetNextItemInInventory();
|
|
while (GetIsObjectValid(oSubItem))
|
|
{
|
|
oItem = GetNextItemInInventory();
|
|
oSubItem = GetNextItemInInventory(oContainer);
|
|
}
|
|
continue;
|
|
}
|
|
if (!bHasRangedWeapon && GetWeaponRanged(oItem))
|
|
{
|
|
bHasRangedWeapon = TRUE;
|
|
}
|
|
else if (!bHasMeleeWeapon && GetMeleeWeaponSize(oItem) > 0)
|
|
{
|
|
bHasMeleeWeapon = TRUE;
|
|
}
|
|
oItem = GetNextItemInInventory();
|
|
}
|
|
if (!bHasMeleeWeapon)
|
|
{
|
|
if (GetHasFeat(FEAT_IMPROVED_UNARMED_STRIKE))
|
|
{
|
|
bHasMeleeAttack = TRUE;
|
|
}
|
|
else if (GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_CWEAPON_R)))
|
|
{
|
|
bHasMeleeAttack = TRUE;
|
|
}
|
|
else if (GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_CWEAPON_B)))
|
|
{
|
|
bHasMeleeAttack = TRUE;
|
|
}
|
|
else if (GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_CWEAPON_L)))
|
|
{
|
|
bHasMeleeAttack = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bHasMeleeAttack = TRUE;
|
|
}
|
|
if (bHasMeleeAttack)
|
|
{
|
|
nResult = HENCH_AI_WEAPON_INIT | HENCH_AI_HAS_MELEE;
|
|
}
|
|
else
|
|
{
|
|
nResult = HENCH_AI_WEAPON_INIT;
|
|
}
|
|
if (bHasMeleeWeapon)
|
|
{
|
|
nResult = nResult | HENCH_AI_HAS_MELEE_WEAPON;
|
|
}
|
|
if (bHasRangedWeapon)
|
|
{
|
|
nResult = nResult | HENCH_AI_HAS_RANGED_WEAPON;
|
|
}
|
|
|
|
SetLocalInt(OBJECT_SELF, HENCH_AI_WEAPON, nResult);
|
|
return nResult;
|
|
}
|
|
|
|
|
|
int EquipMeleeWeapons(object oTarget, int bIndicateStatus, int iCallNumber)
|
|
{
|
|
// float time = IntToFloat(GetTimeSecond()) + IntToFloat(GetTimeMillisecond()) /1000.0;
|
|
// Jug_Debug(GetName(OBJECT_SELF) + " equip melee vs. " + GetName(oTarget) + " call number " + IntToString(iCallNumber) + " time " + FloatToString(time));
|
|
|
|
int nWeaponStatus = GetInitWeaponStatus();
|
|
if (iCallNumber == 1)
|
|
{
|
|
if (!(nWeaponStatus & HENCH_AI_HAS_MELEE_WEAPON))
|
|
{
|
|
if ((nWeaponStatus & HENCH_AI_HAS_MELEE))
|
|
{
|
|
// no weapons, has creature attacks, make sure ranged weapons removed
|
|
UnequipWeapons();
|
|
}
|
|
return TRUE;
|
|
}
|
|
ActionEquipMostDamagingMelee(oTarget);
|
|
return FALSE;
|
|
}
|
|
|
|
object oRight = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
|
|
int iCreatureSize = GetCreatureSize(OBJECT_SELF);
|
|
int iRWeaponSize = GetMeleeWeaponSize(oRight);
|
|
|
|
if (iRWeaponSize > iCreatureSize)
|
|
{
|
|
// two handed weapon - done
|
|
return TRUE;
|
|
}
|
|
// for dual weapon selection, must wait until right weapon is equipped
|
|
if (!GetIsObjectValid(oRight))
|
|
{
|
|
if (nWeaponStatus & HENCH_AI_HAS_MELEE)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetWeaponState(HENCH_AI_HAS_MELEE_WEAPON, FALSE);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
int dualWieldState = GetLocalInt(OBJECT_SELF, sHenchDualWieldState);
|
|
if (dualWieldState == 0)
|
|
{
|
|
dualWieldState = GetHasFeat(FEAT_TWO_WEAPON_FIGHTING) ? 1 : 2;
|
|
}
|
|
|
|
if (dualWieldState == 2)
|
|
{
|
|
EquipShield(bIndicateStatus);
|
|
return TRUE;
|
|
}
|
|
// already have something in left
|
|
object oOrigLeft = GetItemInSlot(INVENTORY_SLOT_LEFTHAND);
|
|
int iHaveOffHandStatus = GetLocalInt(OBJECT_SELF, HENCH_AI_OFF_HAND_STATUS);
|
|
if (iHaveOffHandStatus == 2)
|
|
{
|
|
EquipShield(bIndicateStatus);
|
|
return TRUE;
|
|
}
|
|
if (iHaveOffHandStatus == 1)
|
|
{
|
|
object oStoredOffHand = GetLocalObject(OBJECT_SELF, HENCH_AI_STORED_OFF_HAND);
|
|
if (oStoredOffHand == oOrigLeft)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (GetIsObjectValid(oStoredOffHand) && (GetItemPossessor(oStoredOffHand) == OBJECT_SELF) &&
|
|
oRight != oStoredOffHand)
|
|
{
|
|
ActionEquipItem(oStoredOffHand, INVENTORY_SLOT_LEFTHAND);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
object oLeft = OBJECT_INVALID;
|
|
int nLeftPrevEquip = GetIsObjectValid(oOrigLeft);
|
|
int nMaxValue = 0;
|
|
int iMaxWeaponSize = iCreatureSize;
|
|
if (GetLocalInt(OBJECT_SELF, sHenchLightOffHand) && (iRWeaponSize >= iCreatureSize))
|
|
{
|
|
iMaxWeaponSize--;
|
|
}
|
|
int iCurWeaponSize;
|
|
if (nLeftPrevEquip)
|
|
{
|
|
iCurWeaponSize = GetMeleeWeaponSize(oOrigLeft);
|
|
if (iCurWeaponSize != 0 && iCurWeaponSize <= iMaxWeaponSize)
|
|
{
|
|
if (GetIdentified(oOrigLeft))
|
|
{
|
|
int bPlotFlag = GetPlotFlag(oOrigLeft);
|
|
if (bPlotFlag)
|
|
{
|
|
SetPlotFlag(oOrigLeft, FALSE);
|
|
}
|
|
nMaxValue = GetGoldPieceValue(oOrigLeft);
|
|
if (bPlotFlag)
|
|
{
|
|
SetPlotFlag(oOrigLeft, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nMaxValue = 1;
|
|
}
|
|
oLeft = oOrigLeft;
|
|
}
|
|
}
|
|
// Then look for more than 1 single handed melee weapon
|
|
int iNewOffHand = FALSE;
|
|
|
|
object oItem = GetFirstItemInInventory();
|
|
while (GetIsObjectValid(oItem))
|
|
{
|
|
// skip past any items in a container
|
|
if (GetHasInventory(oItem))
|
|
{
|
|
object oContainer = oItem;
|
|
object oSubItem = GetFirstItemInInventory(oContainer);
|
|
oItem = GetNextItemInInventory();
|
|
while (GetIsObjectValid(oSubItem))
|
|
{
|
|
oItem = GetNextItemInInventory();
|
|
oSubItem = GetNextItemInInventory(oContainer);
|
|
}
|
|
continue;
|
|
}
|
|
int nItemType = GetBaseItemType(oItem);
|
|
if (nItemType != BASE_ITEM_LIGHTFLAIL && nItemType != BASE_ITEM_MORNINGSTAR &&
|
|
nItemType != BASE_ITEM_WHIP)
|
|
{
|
|
iCurWeaponSize = GetMeleeWeaponSize(oItem);
|
|
if (iCurWeaponSize != 0 && iCurWeaponSize <= iMaxWeaponSize)
|
|
{
|
|
int tempValue;
|
|
if (GetIdentified(oItem))
|
|
{
|
|
int bPlotFlag = GetPlotFlag(oItem);
|
|
if (bPlotFlag)
|
|
{
|
|
SetPlotFlag(oItem, FALSE);
|
|
}
|
|
tempValue = GetGoldPieceValue(oItem);
|
|
if (bPlotFlag)
|
|
{
|
|
SetPlotFlag(oItem, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tempValue = 1;
|
|
}
|
|
if (tempValue > nMaxValue)
|
|
{
|
|
nMaxValue = tempValue;
|
|
oLeft = oItem;
|
|
iNewOffHand = TRUE;
|
|
}
|
|
}
|
|
}
|
|
oItem = GetNextItemInInventory();
|
|
}
|
|
if (nMaxValue > 0)
|
|
{
|
|
SetLocalInt(OBJECT_SELF, HENCH_AI_OFF_HAND_STATUS, 1);
|
|
SetLocalObject(OBJECT_SELF, HENCH_AI_STORED_OFF_HAND, oLeft);
|
|
}
|
|
else
|
|
{
|
|
SetLocalInt(OBJECT_SELF, HENCH_AI_OFF_HAND_STATUS, 2);
|
|
DeleteLocalObject(OBJECT_SELF, HENCH_AI_STORED_OFF_HAND);
|
|
}
|
|
if (iNewOffHand)
|
|
{
|
|
ActionEquipItem(oLeft, INVENTORY_SLOT_LEFTHAND);
|
|
}
|
|
else if (GetIsObjectValid(oOrigLeft) && oOrigLeft == oLeft)
|
|
{
|
|
// nothing to do
|
|
}
|
|
else
|
|
{
|
|
EquipShield(bIndicateStatus);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
int EquipRangedWeapon(object oTarget, int bIndicateStatus, int iCallNumber)
|
|
{
|
|
// float time = IntToFloat(GetTimeSecond()) + IntToFloat(GetTimeMillisecond()) /1000.0;
|
|
//Jug_Debug(GetName(OBJECT_SELF) + " equip ranged vs. " + GetName(oTarget) + " call number " + IntToString(iCallNumber) + " time " + FloatToString(time));
|
|
if (iCallNumber == 1)
|
|
{
|
|
ActionEquipMostDamagingRanged(oTarget);
|
|
return FALSE;
|
|
}
|
|
|
|
object oRight = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
|
|
if (!GetWeaponRanged(oRight))
|
|
{
|
|
if (iCallNumber == 2)
|
|
{
|
|
ActionWait(0.3);
|
|
return FALSE;
|
|
}
|
|
// object oRealMaster = GetRealMaster();
|
|
// if (GetIsObjectValid(oRealMaster) && GetIsPC(oRealMaster))
|
|
// {
|
|
// SpeakString(sHenchCantUseRanged);
|
|
// }
|
|
// Jug_Debug(GetName(OBJECT_SELF) + " turning off ranged weapons");
|
|
SetWeaponState(HENCH_AI_HAS_RANGED_WEAPON, FALSE);
|
|
SetLocalInt(OBJECT_SELF, "UseRangedWeapons", FALSE);
|
|
return EquipMeleeWeapons(oTarget, bIndicateStatus, 1);
|
|
}
|
|
|
|
switch (GetBaseItemType(oRight))
|
|
{
|
|
case BASE_ITEM_DART:
|
|
case BASE_ITEM_SHURIKEN:
|
|
case BASE_ITEM_SLING:
|
|
case BASE_ITEM_THROWINGAXE:
|
|
EquipShield(bIndicateStatus);
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Equip Appropriate Weapons
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Makes the user get his best weapons. If the
|
|
user is a Henchmen then he checks the player
|
|
preference.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: April 2, 2002
|
|
//:://////////////////////////////////////////////
|
|
|
|
int HenchEquipAppropriateWeapons(object oTarget, float fThresholdDistance, int bIndicateSwitch, int bPolymorphed)
|
|
{
|
|
// Jug_Debug(GetName(OBJECT_SELF) + " trying out equip");
|
|
|
|
if (bPolymorphed)
|
|
{
|
|
return TRUE;
|
|
}
|
|
int nWeaponStatus = GetInitWeaponStatus();
|
|
int bUseRanged;
|
|
|
|
if (nWeaponStatus & HENCH_AI_HAS_RANGED_WEAPON)
|
|
{
|
|
// has ranged weapons
|
|
object oRealMaster = GetRealMaster();
|
|
if(GetIsObjectValid(oRealMaster) && GetIsPC(oRealMaster) && !GetAssociateState(NW_ASC_USE_RANGED_WEAPON))
|
|
{
|
|
bUseRanged = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (nWeaponStatus & HENCH_AI_HAS_MELEE)
|
|
{
|
|
// if has melee weapons (includes creature weapons & monk class)
|
|
// if z distance is greater than two then assume cliff
|
|
// TODO add size of creatures for distance?
|
|
bUseRanged = (GetDistanceToObject(oTarget) > fThresholdDistance) ||
|
|
(fabs(GetPosition(OBJECT_SELF).z - GetPosition(oTarget).z) > 2.0);
|
|
}
|
|
else
|
|
{
|
|
bUseRanged = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bUseRanged = FALSE;
|
|
}
|
|
if (bIndicateSwitch && GetAssociateState(NW_ASC_USE_RANGED_WEAPON))
|
|
{
|
|
if (!(nWeaponStatus & HENCH_AI_HAS_RANGED_WEAPON))
|
|
{
|
|
DeleteLocalInt(OBJECT_SELF, HENCH_AI_SWITCHED_TO_MELEE);
|
|
}
|
|
else
|
|
{
|
|
int bSwitchedToMelee = GetLocalInt(OBJECT_SELF, HENCH_AI_SWITCHED_TO_MELEE);
|
|
if (bUseRanged && bSwitchedToMelee)
|
|
{
|
|
SpeakString(sHenchSwitchToMissle);
|
|
DeleteLocalInt(OBJECT_SELF, HENCH_AI_SWITCHED_TO_MELEE);
|
|
}
|
|
else if (!bUseRanged && !bSwitchedToMelee)
|
|
{
|
|
SpeakString(sHenchSwitchToRanged);
|
|
SetLocalInt(OBJECT_SELF, HENCH_AI_SWITCHED_TO_MELEE, TRUE);
|
|
}
|
|
}
|
|
}
|
|
SetLocalInt(OBJECT_SELF, "UseRangedWeapons", bUseRanged);
|
|
if (bUseRanged)
|
|
{
|
|
object oRight = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
|
|
if (!GetWeaponRanged(oRight))
|
|
{
|
|
object oLeft = GetItemInSlot(INVENTORY_SLOT_LEFTHAND);
|
|
if (GetIsObjectValid(oLeft))
|
|
{
|
|
// get rid of weapon or shield
|
|
// shield or weapon in left hand prevents switch to ranged
|
|
ActionUnequipItem(oLeft);
|
|
ActionWait(0.3);
|
|
}
|
|
}
|
|
return EquipRangedWeapon(oTarget, bIndicateSwitch, 1);
|
|
}
|
|
else
|
|
{
|
|
return EquipMeleeWeapons(oTarget, bIndicateSwitch, 1);
|
|
}
|
|
}
|
|
|
|
|
|
void ActionContinueEquip(object oTarget, int bIndicateStatus, int iCallNumber)
|
|
{
|
|
if (GetLocalInt(OBJECT_SELF, "UseRangedWeapons"))
|
|
{
|
|
if (!EquipRangedWeapon(oTarget, bIndicateStatus, iCallNumber))
|
|
{
|
|
ActionDoCommand(ActionContinueEquip(oTarget, bIndicateStatus, iCallNumber + 1));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!EquipMeleeWeapons(oTarget, bIndicateStatus, iCallNumber))
|
|
{
|
|
ActionDoCommand(ActionContinueEquip(oTarget, bIndicateStatus, iCallNumber + 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
const string sHenchShowWeaponStatus = "HenchShowWeaponStatus";
|
|
|
|
void HenchEquipDefaultWeapons(object oCreature = OBJECT_SELF, int bShowStatus = FALSE)
|
|
{
|
|
if (bShowStatus)
|
|
{
|
|
SetLocalInt(oCreature, sHenchShowWeaponStatus, TRUE);
|
|
}
|
|
ExecuteScript("hench_o0_equip", oCreature);
|
|
}
|
|
|
|
|
|
void ClearWeaponStates(object oCreature = OBJECT_SELF)
|
|
{
|
|
DeleteLocalInt(oCreature, HENCH_AI_SWITCHED_TO_MELEE);
|
|
DeleteLocalInt(oCreature, HENCH_AI_SHIELD_STATUS);
|
|
DeleteLocalObject(oCreature, HENCH_AI_STORED_SHIELD);
|
|
DeleteLocalInt(oCreature, HENCH_AI_OFF_HAND_STATUS);
|
|
DeleteLocalObject(oCreature, HENCH_AI_STORED_OFF_HAND);
|
|
DeleteLocalInt(oCreature, HENCH_AI_WEAPON);
|
|
}
|