345 lines
11 KiB
Plaintext
345 lines
11 KiB
Plaintext
|
//::///////////////////////////////////////////////
|
||
|
//:: hench_i0_henutil (parts from the original NW_I0_HENCHMAN)
|
||
|
//:: Copyright (c) 2001 Bioware Corp.
|
||
|
//:://////////////////////////////////////////////
|
||
|
//void main() { } int GetIsHumanoid(int nRacial) { return 0; }
|
||
|
/*
|
||
|
This is the include file for the
|
||
|
henchmen who can join the player.
|
||
|
|
||
|
ASSUMPTION: All these functions
|
||
|
are meant to be ran by the henchman.
|
||
|
OBJECT_SELF is assumed to be the henchman.
|
||
|
|
||
|
RULES: Henchman are dialog controlled only!
|
||
|
No locals/globals should be set outside of the
|
||
|
henchman's own dialog file!
|
||
|
*/
|
||
|
//:://////////////////////////////////////////////
|
||
|
//:: Created By: Brent
|
||
|
//:: Created On: February 2002
|
||
|
//:://////////////////////////////////////////////
|
||
|
// * ---------
|
||
|
// * CONSTANTS
|
||
|
// * ---------
|
||
|
|
||
|
#include "hench_i0_ident"
|
||
|
#include "hench_i0_strings"
|
||
|
|
||
|
|
||
|
int GetIsHumanoid(int nRacial);
|
||
|
|
||
|
|
||
|
// Check to see if the item was successfully equipped.
|
||
|
|
||
|
void CheckIsEquipped(object oItem, int iSlot, string sDescr)
|
||
|
{
|
||
|
|
||
|
object oWorn = GetItemInSlot(iSlot);
|
||
|
|
||
|
if (oWorn != oItem) {
|
||
|
if (oWorn == OBJECT_INVALID ||
|
||
|
GetGoldPieceValue(oWorn) / GetNumStackedItems(oWorn) < GetGoldPieceValue(oItem)/GetNumStackedItems(oItem))
|
||
|
SpeakString(sHenchUnableToEquip1 + sDescr + sHenchUnableToEquip2);
|
||
|
else
|
||
|
SpeakString(sHenchUnableToEquip3 + sDescr + sHenchUnableToEquip4);
|
||
|
} else
|
||
|
SpeakString(sHenchAbleToEquip + sDescr + ".");
|
||
|
}
|
||
|
|
||
|
|
||
|
// Equip an item in iSlot, or optionally in iOtherSlot if iSlot is full.
|
||
|
void EquipIfWorthIt(object oItem, int iMaxGPIdentify, int iSlot, string sDescr,
|
||
|
int iOtherSlot=500)
|
||
|
{
|
||
|
string sName;
|
||
|
|
||
|
// These variables store the value of the most valuable
|
||
|
// object in the NPC's inventory examined thus far. They are set
|
||
|
// to -1 at the beginning of inventory control.
|
||
|
string sSlotVar = "Invent"+IntToString(iSlot);
|
||
|
string sSlotVarName = "InventName"+IntToString(iSlot);
|
||
|
string sOtherVar = "Invent"+IntToString(iOtherSlot);
|
||
|
int iStoredValue = GetLocalInt(OBJECT_SELF,sSlotVar);
|
||
|
int iOtherValue = GetLocalInt(OBJECT_SELF,sOtherVar);
|
||
|
int iNewValue = 0;
|
||
|
|
||
|
// Don't want to reveal the object's name unless it's already
|
||
|
// identified. Again, assign unidentified items a nominal value of 1.
|
||
|
if (GetIdentified(oItem)) {
|
||
|
sName = GetName(oItem);
|
||
|
iNewValue = GetGoldPieceValue(oItem) / GetNumStackedItems(oItem);
|
||
|
}
|
||
|
else {
|
||
|
sName = "unidentified "+sDescr;
|
||
|
iNewValue = 1;
|
||
|
}
|
||
|
|
||
|
// If we are already equipping something in the given slot, get its value.
|
||
|
// Unidentified items have a nominal value of 1. Note: this only works with
|
||
|
// items equipped before inventory control.
|
||
|
if (iStoredValue == -1) {
|
||
|
object oOld = GetItemInSlot(iSlot);
|
||
|
if (GetIsObjectValid(oOld) && !GetLocalInt(oOld,"DestroyItem") &&
|
||
|
oOld != GetLocalObject(OBJECT_SELF,"Decency")) {
|
||
|
HenchIdentifyItem(oOld, iMaxGPIdentify);
|
||
|
//SpeakString(GetName(oOld)+GetName(oItem)+IntToString(GetGoldPieceValue(oOld)/GetNumStackedItems(oOld))+
|
||
|
// " "+IntToString(GetGoldPieceValue(oItem)/GetNumStackedItems(oItem)));
|
||
|
if (GetIdentified(oOld)) {
|
||
|
iStoredValue = GetGoldPieceValue(oOld) / GetNumStackedItems(oOld);
|
||
|
SetLocalString(OBJECT_SELF,sSlotVarName,GetName(oOld));
|
||
|
}
|
||
|
else {
|
||
|
iStoredValue = 1;
|
||
|
SetLocalString(OBJECT_SELF,sSlotVarName,"unidentifed "+GetName(oOld));
|
||
|
}
|
||
|
SetLocalInt(OBJECT_SELF,sSlotVar,iStoredValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we already have considered an item of this type, we need to
|
||
|
// juggle the inventory.
|
||
|
if (iStoredValue >= 0) {
|
||
|
|
||
|
// If we have another slot in which we can equip this item,
|
||
|
// and if the item in the other slot is not better than the item in
|
||
|
// the current iSlot, then run the function on that other slot.
|
||
|
|
||
|
if (iNewValue > iOtherValue && iOtherSlot != 500)
|
||
|
if (iOtherValue < iStoredValue) {
|
||
|
EquipIfWorthIt(oItem, iMaxGPIdentify, iOtherSlot, sDescr);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// If the item is better than what we had before, tell the player so and
|
||
|
// store its value. Otherwise, tell the player and do nothing else.
|
||
|
|
||
|
if (iNewValue > iStoredValue)
|
||
|
SpeakString(sHenchSelectItem1 + sName + ".");
|
||
|
else if (iNewValue < iStoredValue) {
|
||
|
SpeakString(sHenchSelectItem2 + GetLocalString(OBJECT_SELF, sSlotVarName) +
|
||
|
sHenchSelectItem3 + sName+ ".");
|
||
|
return;
|
||
|
}
|
||
|
else if (iStoredValue > 0)
|
||
|
SpeakString(sHenchDecisions);
|
||
|
}
|
||
|
|
||
|
// Now attempt to equip the items, and after a suitable time, check
|
||
|
// to see if the the attempt succeeds.
|
||
|
SetLocalInt(OBJECT_SELF,sSlotVar,iNewValue);
|
||
|
|
||
|
SetLocalString(OBJECT_SELF,sSlotVarName,sName);
|
||
|
ActionDoCommand(ActionEquipItem(oItem,iSlot));
|
||
|
DelayCommand(2.,CheckIsEquipped(oItem,iSlot,sName));
|
||
|
}
|
||
|
|
||
|
|
||
|
// Try to figure out what to do with an item.
|
||
|
void EquipItems(object oSource)
|
||
|
{
|
||
|
int i;
|
||
|
object oItem;
|
||
|
|
||
|
DestroyObject(oSource,0.0);
|
||
|
|
||
|
for (i = 0; i < NUM_INVENTORY_SLOTS; ++i)
|
||
|
SetLocalInt(OBJECT_SELF,"Invent"+IntToString(i),-1);
|
||
|
|
||
|
SetLocalInt(OBJECT_SELF,"GotAWeapon",FALSE);
|
||
|
|
||
|
int iMaxGPIdentify = HenchGetMaxGPToIdentify();
|
||
|
|
||
|
oItem = GetFirstItemInInventory();
|
||
|
|
||
|
while (GetIsObjectValid(oItem)) {
|
||
|
if (!GetLocalInt(oItem,"DestroyItem")) {
|
||
|
HenchIdentifyItem(oItem, iMaxGPIdentify);
|
||
|
switch (GetBaseItemType(oItem)) {
|
||
|
|
||
|
case BASE_ITEM_ARMOR:
|
||
|
EquipIfWorthIt(oItem, iMaxGPIdentify, INVENTORY_SLOT_CHEST, sHenchEquipArmor);
|
||
|
break;
|
||
|
|
||
|
case BASE_ITEM_LARGESHIELD:
|
||
|
case BASE_ITEM_SMALLSHIELD:
|
||
|
case BASE_ITEM_TOWERSHIELD:
|
||
|
SpeakString(sHenchEquipShield);
|
||
|
break;
|
||
|
|
||
|
case BASE_ITEM_CLOAK:
|
||
|
EquipIfWorthIt(oItem, iMaxGPIdentify, INVENTORY_SLOT_CLOAK, sHenchEquipCloak);
|
||
|
break;
|
||
|
|
||
|
case BASE_ITEM_BOOTS:
|
||
|
EquipIfWorthIt(oItem, iMaxGPIdentify, INVENTORY_SLOT_BOOTS, sHenchEquipBoots);
|
||
|
break;
|
||
|
|
||
|
case BASE_ITEM_BRACER:
|
||
|
case BASE_ITEM_GLOVES:
|
||
|
EquipIfWorthIt(oItem, iMaxGPIdentify, INVENTORY_SLOT_ARMS, sHenchEquipHandwear);
|
||
|
break;
|
||
|
|
||
|
case BASE_ITEM_HELMET:
|
||
|
EquipIfWorthIt(oItem, iMaxGPIdentify, INVENTORY_SLOT_HEAD, sHenchEquipHelmet);
|
||
|
break;
|
||
|
|
||
|
case BASE_ITEM_BELT:
|
||
|
EquipIfWorthIt(oItem, iMaxGPIdentify, INVENTORY_SLOT_BELT, sHenchEquipBelt);
|
||
|
break;
|
||
|
|
||
|
case BASE_ITEM_RING:
|
||
|
EquipIfWorthIt(oItem, iMaxGPIdentify, INVENTORY_SLOT_LEFTRING, sHenchEquipRing, INVENTORY_SLOT_RIGHTRING);
|
||
|
break;
|
||
|
|
||
|
case BASE_ITEM_AMULET:
|
||
|
EquipIfWorthIt(oItem, iMaxGPIdentify, INVENTORY_SLOT_NECK, sHenchEquipAmulet);
|
||
|
break;
|
||
|
|
||
|
// These items are auto-equipped by the ActionEquipMostDamagingRanged() command
|
||
|
case BASE_ITEM_ARROW:
|
||
|
case BASE_ITEM_BULLET:
|
||
|
case BASE_ITEM_BOLT:
|
||
|
|
||
|
// THESE SHOULD BE EDITED SO THAT THE HENCHMAN DEALS WITH THEM
|
||
|
// PROPERLY. FOR NOW THEY ARE IGNORED
|
||
|
case BASE_ITEM_CREATUREITEM:
|
||
|
case BASE_ITEM_GEM:
|
||
|
case BASE_ITEM_KEY:
|
||
|
case BASE_ITEM_MAGICROD:
|
||
|
case BASE_ITEM_MAGICSTAFF:
|
||
|
case BASE_ITEM_MAGICWAND:
|
||
|
case BASE_ITEM_POTIONS:
|
||
|
case BASE_ITEM_SPELLSCROLL:
|
||
|
case BASE_ITEM_THIEVESTOOLS:
|
||
|
case BASE_ITEM_TRAPKIT:
|
||
|
case BASE_ITEM_TORCH: // done by equip shield
|
||
|
break;
|
||
|
default:
|
||
|
if (!GetLocalInt(OBJECT_SELF,"GotAWeapon"))
|
||
|
{
|
||
|
SpeakString(sHenchEquipWeapon);
|
||
|
SetLocalInt(OBJECT_SELF,"GotAWeapon",TRUE);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
oItem = GetNextItemInInventory();
|
||
|
}
|
||
|
SpeakString(sHenchEquipWait);
|
||
|
}
|
||
|
|
||
|
|
||
|
void DestroyDecency(int bIndicateNoClothes)
|
||
|
{
|
||
|
object oDecency = GetLocalObject(OBJECT_SELF,"Decency");
|
||
|
|
||
|
if (GetItemInSlot(INVENTORY_SLOT_CHEST) != oDecency)
|
||
|
{
|
||
|
DestroyObject(oDecency);
|
||
|
DeleteLocalObject(OBJECT_SELF,"Decency");
|
||
|
}
|
||
|
else if (bIndicateNoClothes && GetIsHumanoid(GetRacialType(OBJECT_SELF)))
|
||
|
{
|
||
|
SpeakString(sHenchEquipDecency);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Copy associate's inventory.
|
||
|
void CopyAssociateItems(object oPC, object oAssociate)
|
||
|
{
|
||
|
object oItem;
|
||
|
int i;
|
||
|
for(i = 0; i < NUM_INVENTORY_SLOTS; ++i)
|
||
|
{
|
||
|
oItem = GetItemInSlot(i, oAssociate);
|
||
|
if (oItem != OBJECT_INVALID)
|
||
|
{
|
||
|
switch (GetBaseItemType(oItem))
|
||
|
{
|
||
|
case BASE_ITEM_CREATUREITEM:
|
||
|
case BASE_ITEM_CBLUDGWEAPON:
|
||
|
case BASE_ITEM_CSLASHWEAPON:
|
||
|
case BASE_ITEM_CSLSHPRCWEAP:
|
||
|
case BASE_ITEM_CPIERCWEAPON:
|
||
|
break;
|
||
|
case BASE_ITEM_DAGGER:
|
||
|
// prevent pixie dagger from being given up
|
||
|
if (!GetDroppableFlag(oItem))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
CopyItem(oItem, oPC);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Now go through the backpack.
|
||
|
oItem = GetFirstItemInInventory(oAssociate);
|
||
|
while (oItem != OBJECT_INVALID)
|
||
|
{
|
||
|
CopyItem(oItem, oPC);
|
||
|
oItem = GetNextItemInInventory(oAssociate);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Copy familiar/animal companion's inventory.
|
||
|
void CopyFamiliarAnimalCompanionItems(object oPC)
|
||
|
{
|
||
|
if (!GetIsObjectValid(oPC))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
object oAssociate;
|
||
|
|
||
|
oAssociate = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC);
|
||
|
if (GetIsObjectValid(oAssociate))
|
||
|
{
|
||
|
CopyAssociateItems(oPC, oAssociate);
|
||
|
}
|
||
|
oAssociate = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC);
|
||
|
if (GetIsObjectValid(oAssociate))
|
||
|
{
|
||
|
CopyAssociateItems(oPC, oAssociate);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void DestroyAssociates(object oCreature)
|
||
|
{
|
||
|
// Checking for henchman summons/familiars/animal companions/dominated
|
||
|
// and destroying them to prevent them going hostile.
|
||
|
if (GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oCreature)))
|
||
|
{
|
||
|
effect eUnSum = EffectVisualEffect(VFX_FNF_SMOKE_PUFF);
|
||
|
location lUnSum = GetLocation(GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oCreature));
|
||
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eUnSum, lUnSum, 5.0);
|
||
|
DestroyObject(GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oCreature));
|
||
|
}
|
||
|
if (GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_SUMMONED, oCreature)))
|
||
|
{
|
||
|
effect eUnSum = EffectVisualEffect(VFX_FNF_SMOKE_PUFF);
|
||
|
location lUnSum = GetLocation(GetAssociate(ASSOCIATE_TYPE_SUMMONED, oCreature));
|
||
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eUnSum, lUnSum, 5.0);
|
||
|
DestroyObject(GetAssociate(ASSOCIATE_TYPE_SUMMONED, oCreature));
|
||
|
}
|
||
|
if (GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oCreature)))
|
||
|
{
|
||
|
effect eUnSum = EffectVisualEffect(VFX_FNF_SMOKE_PUFF);
|
||
|
location lUnSum = GetLocation(GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oCreature));
|
||
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eUnSum, lUnSum, 5.0);
|
||
|
DestroyObject(GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oCreature));
|
||
|
}
|
||
|
if (GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_DOMINATED, oCreature)))
|
||
|
{
|
||
|
effect eUnSum = EffectVisualEffect(VFX_FNF_SMOKE_PUFF);
|
||
|
location lUnSum = GetLocation(GetAssociate(ASSOCIATE_TYPE_DOMINATED, oCreature));
|
||
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eUnSum, lUnSum, 5.0);
|
||
|
DestroyObject(GetAssociate(ASSOCIATE_TYPE_DOMINATED, oCreature));
|
||
|
}
|
||
|
}
|