1125 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1125 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
//::///////////////////////////////////////////////
 | 
						|
//:: x0_inc_HENAI
 | 
						|
//:: Copyright (c) 2001 Bioware Corp.
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
/*
 | 
						|
    This is a wrapper overtop of the 'generic AI'
 | 
						|
    system with custom behavior for Henchmen.
 | 
						|
 | 
						|
    BENEFIT:
 | 
						|
    - easier to isolate henchmen behavior
 | 
						|
    - easier to debug COMBAT-AI because the
 | 
						|
    advanced Henchmen behaviour won't be in those scripts
 | 
						|
 | 
						|
    CONS:
 | 
						|
    - code duplicate. The two 'combat round' functions
 | 
						|
    will share a lot of code because the old-AI still has
 | 
						|
    to allow any legacy henchmen to work.
 | 
						|
 | 
						|
 | 
						|
    NEW RADIALS/COMMANDS:
 | 
						|
  - Open Inventory    "inventory"
 | 
						|
  - Open Everything
 | 
						|
  - Remove Traps [even nonthiefs will walk to detected traps]
 | 
						|
  - NEVER FIGHT mode (or ALWAYS RETREAT) ; SetLocal; Implementation Code inside of DetermineCombatRound  DONE
 | 
						|
 | 
						|
 | 
						|
    -=-=-=-=-=-=-
 | 
						|
    MODIFICATIONS
 | 
						|
    -=-=-=-=-=-=-
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    // * BK Feb 6 2003
 | 
						|
    // * Put a check in so that when a henchmen who cannot disarm a trap
 | 
						|
    // * sees a trap they do not repeat their voiceover forever
 | 
						|
 | 
						|
 | 
						|
*/
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
//:: Created By:
 | 
						|
//:: Created On:
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
 | 
						|
// #include "nw_i0_generic"  //...and through this also x0_inc_generic
 | 
						|
 | 
						|
#include "x0_i0_henchman"
 | 
						|
 | 
						|
// ****************************
 | 
						|
// CONSTANTS
 | 
						|
// ****************************
 | 
						|
 | 
						|
// ~ Behavior Constants
 | 
						|
int BK_HEALINMELEE = 10;
 | 
						|
int BK_CURRENT_AI_MODE = 20; // Can only be in one AI mode at a time
 | 
						|
int BK_AI_MODE_FOLLOW = 9; // default mode, moving after the player
 | 
						|
int BK_AI_MODE_RUN_AWAY = 19; // something is causing AI to retreat
 | 
						|
int BK_NEVERFIGHT = 30;
 | 
						|
 | 
						|
 | 
						|
// ~ Distance Constants
 | 
						|
float BK_HEALTHRESHOLD = 5.0;
 | 
						|
float BK_FOLLOW_THRESHOLD= 15.0;
 | 
						|
 | 
						|
// difficulty difference at which familiar will flee
 | 
						|
//int BK_FAMILIAR_COWARD = 7;
 | 
						|
 | 
						|
 | 
						|
/**********************************************************************
 | 
						|
 * FUNCTION PROTOTYPES
 | 
						|
 **********************************************************************/
 | 
						|
 | 
						|
// * Sets up special additional listening patterns
 | 
						|
// * for associates.
 | 
						|
void bkSetListeningPatterns();
 | 
						|
 | 
						|
// * Henchman/associate combat round wrapper
 | 
						|
// * passing in OBJECT_INVALID is okay
 | 
						|
// * Does special stuff for henchmen and familiars, then
 | 
						|
// * falls back to default generic combat code.
 | 
						|
void HenchmenCombatRound(object oIntruder=OBJECT_INVALID);
 | 
						|
 | 
						|
// * Attempt to disarm given trap
 | 
						|
// * (called from RespondToShout and heartbeat)
 | 
						|
int bkAttemptToDisarmTrap(object oTrap, int bWasShout = FALSE);
 | 
						|
 | 
						|
// * Attempt to open a given locked object.
 | 
						|
int bkAttemptToOpenLock(object oLocked);
 | 
						|
 | 
						|
// Manually pick the nearest locked object
 | 
						|
int bkManualPickNearestLock();
 | 
						|
 | 
						|
// Handles responses to henchmen commands, including both radial
 | 
						|
// menu and voice commands.
 | 
						|
void bkRespondToHenchmenShout(object oShouter, int nShoutIndex, object oIntruder = OBJECT_INVALID, int nBanInventory=FALSE);
 | 
						|
 | 
						|
 | 
						|
 | 
						|
// * Attempt to heal self then master
 | 
						|
int bkCombatAttemptHeal();
 | 
						|
 | 
						|
// * Attempts to follow master if outside range
 | 
						|
int bkCombatFollowMaster();
 | 
						|
 | 
						|
// * set behavior used by AI
 | 
						|
void bkSetBehavior(int nBehavior, int nValue);
 | 
						|
 | 
						|
// * get behavior used by AI
 | 
						|
int bkGetBehavior(int nBehavior);
 | 
						|
 | 
						|
// ****LINEOFSIGHT*****
 | 
						|
 | 
						|
// * TRUE if the target door is in line of sight.
 | 
						|
int bkGetIsDoorInLineOfSight(object oTarget);
 | 
						|
 | 
						|
// Get the cosine of the angle between two objects.
 | 
						|
float bkGetCosAngleBetween(object Loc1, object Loc2);
 | 
						|
 | 
						|
// TRUE if target in the line of sight of the seer.
 | 
						|
int bkGetIsInLineOfSight(object oTarget, object oSeer=OBJECT_SELF);
 | 
						|
// * called from state scripts (nw_g0_charm) to signal
 | 
						|
// * to other party members to help me out
 | 
						|
void SendForHelp();
 | 
						|
 | 
						|
/**********************************************************************
 | 
						|
 * FUNCTION DEFINITIONS
 | 
						|
 **********************************************************************/
 | 
						|
void main(){}
 | 
						|
// * called from state scripts (nw_g0_charm) to signal
 | 
						|
// * to other party members to help me out
 | 
						|
void SendForHelp()
 | 
						|
{
 | 
						|
    // *
 | 
						|
    // * September 2003
 | 
						|
    // * Was this a disabling type spell
 | 
						|
    // * Signal an event so that my party members
 | 
						|
    // * can check to see if they can remove it for me
 | 
						|
    // *
 | 
						|
    int i = 0;
 | 
						|
    object oArea = GetArea(OBJECT_SELF);
 | 
						|
    object oParty = GetFirstObjectInArea(oArea);
 | 
						|
   while (GetIsObjectValid(oParty) == TRUE )
 | 
						|
   {
 | 
						|
    if(GetIsFriend(oParty,OBJECT_SELF))
 | 
						|
    {
 | 
						|
        SignalEvent(oParty, EventUserDefined(46500));
 | 
						|
        oParty = GetNextObjectInArea(oArea);
 | 
						|
    }
 | 
						|
   }
 | 
						|
 | 
						|
}
 | 
						|
// * Sets up any special listening patterns in addition to the default
 | 
						|
// * associate ones that are used
 | 
						|
void bkSetListeningPatterns()
 | 
						|
{
 | 
						|
 | 
						|
    SetListening(OBJECT_SELF, TRUE);
 | 
						|
    SetListenPattern(OBJECT_SELF, "inventory",101);
 | 
						|
    SetListenPattern(OBJECT_SELF, "pick",102);
 | 
						|
    SetListenPattern(OBJECT_SELF, "trap", 103);
 | 
						|
}
 | 
						|
 | 
						|
// Special combat round precursor for associates
 | 
						|
void HenchmenCombatRound(object oIntruder)
 | 
						|
{
 | 
						|
    // * If someone has surrendered, then don't attack them.
 | 
						|
    // * feb 25 2003
 | 
						|
    if (GetIsObjectValid(oIntruder) == TRUE)
 | 
						|
    {
 | 
						|
        if (GetIsEnemy(oIntruder) == FALSE)
 | 
						|
        {
 | 
						|
            ClearActions(999, TRUE);
 | 
						|
            ActionAttack(OBJECT_INVALID);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    //SpeakString("in combat round. Is an enemy");
 | 
						|
    // * This is the nearest enemy
 | 
						|
    object oNearestTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
 | 
						|
                                               REPUTATION_TYPE_ENEMY,
 | 
						|
                                               OBJECT_SELF, 1,
 | 
						|
                                               CREATURE_TYPE_PERCEPTION,
 | 
						|
                                               PERCEPTION_SEEN);
 | 
						|
 | 
						|
    //    SpeakString("Henchman combat dude");
 | 
						|
 | 
						|
    // ****************************************
 | 
						|
    // SETUP AND SANITY CHECKS (Quick Returns)
 | 
						|
    // ****************************************
 | 
						|
 | 
						|
    // * BK: stop fighting if something bizarre that shouldn't happen, happens
 | 
						|
    if (bkEvaluationSanityCheck(oIntruder, GetFollowDistance()) == TRUE) return;
 | 
						|
 | 
						|
    if(GetAssociateState(NW_ASC_IS_BUSY) || GetAssociateState(NW_ASC_MODE_DYING)) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    // MODIFIED FEBRUARY 13 2003
 | 
						|
    // The associate will not engage in battle if in Stand Ground mode unless
 | 
						|
    // he takes damage
 | 
						|
    if(GetAssociateState(NW_ASC_MODE_STAND_GROUND) == TRUE && GetIsObjectValid(GetLastHostileActor()) == FALSE)
 | 
						|
    {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if(BashDoorCheck(oIntruder)) {return;}
 | 
						|
 | 
						|
    // ** Store how difficult the combat is for this round
 | 
						|
    int nDiff = GetCombatDifficulty();
 | 
						|
    SetLocalInt(OBJECT_SELF, "NW_L_COMBATDIFF", nDiff);
 | 
						|
 | 
						|
    object oMaster = GetMaster();
 | 
						|
    int iHaveMaster = GetIsObjectValid(oMaster);
 | 
						|
 | 
						|
    // * Do henchmen specific things if I am a henchman otherwise run default AI
 | 
						|
    if (iHaveMaster == TRUE) {
 | 
						|
 | 
						|
        // *******************************************
 | 
						|
        // Healing
 | 
						|
        // *******************************************
 | 
						|
        // The FIRST PRIORITY: self-preservation
 | 
						|
        // The SECOND PRIORITY: heal master;
 | 
						|
        if (bkCombatAttemptHeal() == TRUE)
 | 
						|
            return;
 | 
						|
 | 
						|
        // NEXT priority: follow or return to master for up to three rounds.
 | 
						|
        if (bkCombatFollowMaster() == TRUE)
 | 
						|
            return;
 | 
						|
 | 
						|
        //5. This check is to see if the master is being attacked and in need of help
 | 
						|
        // * Guard Mode -- only attack if master attacking
 | 
						|
        // * or being attacked.
 | 
						|
        if(GetAssociateState(NW_ASC_MODE_DEFEND_MASTER))
 | 
						|
        {
 | 
						|
            oIntruder = GetLastHostileActor(GetMaster());
 | 
						|
            if(!GetIsObjectValid(oIntruder))
 | 
						|
            {
 | 
						|
                //oIntruder = GetGoingToBeAttackedBy(GetMaster());
 | 
						|
 | 
						|
                // MODIFIED Major change. Defend is now Defend only if I attack
 | 
						|
                // February 11 2003
 | 
						|
 | 
						|
 | 
						|
 | 
						|
                object oSelf = OBJECT_SELF;
 | 
						|
                oIntruder = GetAttackTarget(GetMaster());
 | 
						|
                // * February 11 2003
 | 
						|
                // * means that the player was invovled in a battle
 | 
						|
 | 
						|
                 if (GetIsObjectValid(oIntruder) || GetLocalInt(oSelf, "X0_BATTLEJOINEDMASTER") == TRUE)
 | 
						|
                {
 | 
						|
 | 
						|
                    SetLocalInt(oSelf, "X0_BATTLEJOINEDMASTER", TRUE);
 | 
						|
                    // * This is turned back to false whenever he hits the end of combat
 | 
						|
                    if (GetIsObjectValid(oIntruder) == FALSE)
 | 
						|
                    {
 | 
						|
                        oIntruder = oNearestTarget;
 | 
						|
                        if (GetIsObjectValid(oIntruder) == FALSE)
 | 
						|
                        {
 | 
						|
                            //* turn off the "I am in battle" sub-mode
 | 
						|
                            SetLocalInt(oSelf, "X0_BATTLEJOINEDMASTER", FALSE);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                // * Exit out and do nothing this combat round
 | 
						|
                else
 | 
						|
                {
 | 
						|
                  // * August 2003: If I'm getting beaten up and my master
 | 
						|
                  // * is just standing around, I should attempt, one last time
 | 
						|
                  // * to see if there is someone I should be fighting
 | 
						|
                  oIntruder = GetLastAttacker(OBJECT_SELF);
 | 
						|
 | 
						|
                  // * EXIT CONDITION = There really is not anyone
 | 
						|
                  // * near me to justify going into combat
 | 
						|
                  if (GetIsObjectValid(oIntruder) == FALSE)
 | 
						|
                        return;
 | 
						|
                }
 | 
						|
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        int iAmHenchman = FALSE;
 | 
						|
        if (GetAssociateType(OBJECT_SELF) == ASSOCIATE_TYPE_HENCHMAN)
 | 
						|
        {
 | 
						|
            iAmHenchman = TRUE;
 | 
						|
        }
 | 
						|
        if (iAmHenchman)
 | 
						|
        {
 | 
						|
            // 5% chance per round of speaking the relative challenge of the encounter.
 | 
						|
            if (d100() > 95) {
 | 
						|
                if (nDiff <= 1) VoiceLaugh(TRUE);
 | 
						|
             // MODIFIED February 7 2003. This was confusing testing
 | 
						|
             //   else if (nDiff <= 4) VoiceThreaten(TRUE);
 | 
						|
             //   else VoiceBadIdea();
 | 
						|
            }
 | 
						|
        } // is a henchman
 | 
						|
 | 
						|
        // I am a familiar FLEE if tough
 | 
						|
        /*
 | 
						|
        MODIFIED FEB10 2003. Q/A hated this.
 | 
						|
 | 
						|
        int iAmFamiliar = (GetAssociate(ASSOCIATE_TYPE_FAMILIAR,oMaster) == OBJECT_SELF);
 | 
						|
        if (iAmFamiliar) {
 | 
						|
            // Run away from tough enemies
 | 
						|
            if (nDiff >= BK_FAMILIAR_COWARD || GetPercentageHPLoss(OBJECT_SELF) < 40) {
 | 
						|
                VoiceFlee();
 | 
						|
 | 
						|
                ClearActions(CLEAR_X0_INC_HENAI_HCR);
 | 
						|
                ActionMoveAwayFromObject(oNearestTarget, TRUE, 40.0);
 | 
						|
                return;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        */
 | 
						|
     } // * is an associate
 | 
						|
 | 
						|
    // Fall through to generic combat
 | 
						|
 | 
						|
    // * only go into determinecombatround if there's a valid enemy nearby
 | 
						|
    // * feb 26 2003: To prevent henchmen from resuming combat
 | 
						|
    if (GetIsObjectValid(oIntruder) || GetIsObjectValid(oNearestTarget))
 | 
						|
    {
 | 
						|
        DetermineCombatRound(oIntruder);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Manually pick the nearest locked object
 | 
						|
int bkManualPickNearestLock()
 | 
						|
{
 | 
						|
    object oLastObject = GetLockedObject(GetMaster());
 | 
						|
 | 
						|
    MyPrintString("Attempting to unlock: " + GetTag(oLastObject));
 | 
						|
    return bkAttemptToOpenLock(oLastObject);
 | 
						|
}
 | 
						|
 | 
						|
// * attempts to disarm last trap (called from RespondToShout and heartbeat
 | 
						|
int bkAttemptToDisarmTrap(object oTrap, int bWasShout = FALSE)
 | 
						|
{
 | 
						|
    MyPrintString("Attempting to disarm: " + GetTag(oTrap));
 | 
						|
 | 
						|
    // * May 2003: Don't try to disarm a trap with no trap
 | 
						|
    if (GetIsTrapped(oTrap) == FALSE)
 | 
						|
    {
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    // * June 2003. If in 'do not disarm trap' mode, then do not disarm traps
 | 
						|
    if(!GetAssociateState(NW_ASC_DISARM_TRAPS))
 | 
						|
    {
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    int bValid = GetIsObjectValid(oTrap);
 | 
						|
    int bISawTrap = GetTrapDetectedBy(oTrap, OBJECT_SELF);
 | 
						|
    int bCloseEnough = GetDistanceToObject(oTrap) <= 15.0;
 | 
						|
    int bInLineOfSight = bkGetIsInLineOfSight(oTrap);
 | 
						|
 | 
						|
 | 
						|
    if(bValid == FALSE || bISawTrap == FALSE || bCloseEnough == FALSE || bInLineOfSight == FALSE)
 | 
						|
    {
 | 
						|
        MyPrintString("Failed basic disarm check");
 | 
						|
        if (bWasShout == TRUE)
 | 
						|
            VoiceCannotDo();
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    object oTrapSaved = GetLocalObject(OBJECT_SELF, "NW_ASSOCIATES_LAST_TRAP");
 | 
						|
    SetLocalObject(OBJECT_SELF, "NW_ASSOCIATES_LAST_TRAP", oTrap);
 | 
						|
    // We can tell we can't do it
 | 
						|
        string sID = ObjectToString(oTrap);
 | 
						|
    int nSkill = GetSkillRank(SKILL_DISABLE_TRAP);
 | 
						|
    int nTrapDC = GetTrapDisarmDC(oTrap);
 | 
						|
    if ( nSkill > 0 && (nSkill  + 20) >= nTrapDC && GetTrapDisarmable(oTrap)) {
 | 
						|
        ClearActions(CLEAR_X0_INC_HENAI_AttemptToDisarmTrap);
 | 
						|
        ActionUseSkill(SKILL_DISABLE_TRAP, oTrap);
 | 
						|
        ActionDoCommand(SetCommandable(TRUE));
 | 
						|
        ActionDoCommand(VoiceTaskComplete());
 | 
						|
        SetCommandable(FALSE);
 | 
						|
        return TRUE;
 | 
						|
    } else if (GetHasSpell(SPELL_FIND_TRAPS) && GetTrapDisarmable(oTrap) && GetLocalInt(oTrap, "NW_L_IATTEMPTEDTODISARMNOWORK") ==0)
 | 
						|
    {
 | 
						|
       // SpeakString("casting");
 | 
						|
        ClearActions(CLEAR_X0_INC_HENAI_AttemptToDisarmTrap);
 | 
						|
        ActionCastSpellAtObject(SPELL_FIND_TRAPS, oTrap);
 | 
						|
        SetLocalInt(oTrap, "NW_L_IATTEMPTEDTODISARMNOWORK", 10);
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
    // MODIFIED February 7 2003. Merged the 'attack object' inside of the bshout
 | 
						|
    // this is not really something you want the henchmen just to go and do
 | 
						|
    // spontaneously
 | 
						|
    else if (bWasShout)
 | 
						|
    {
 | 
						|
        ClearActions(CLEAR_X0_INC_HENAI_BKATTEMPTTODISARMTRAP_ThrowSelfOnTrap);
 | 
						|
 | 
						|
        //SpeakStringByStrRef(40551); // * Out of game indicator that this trap can never be disarmed by henchman.
 | 
						|
        if  (GetLocalInt(OBJECT_SELF, "X0_L_SAWTHISTRAPALREADY" + sID) != 10)
 | 
						|
        {
 | 
						|
            string sSpeak = GetStringByStrRef(40551);
 | 
						|
            SendMessageToPC(GetMaster(), sSpeak);
 | 
						|
            SetLocalInt(OBJECT_SELF, "X0_L_SAWTHISTRAPALREADY" + sID, 10);
 | 
						|
        }
 | 
						|
        if (GetObjectType(oTrap) != OBJECT_TYPE_TRIGGER)
 | 
						|
        {
 | 
						|
            // * because Henchmen are not allowed to switch weapons without the player's
 | 
						|
            // * say this needs to be removed
 | 
						|
            // it's an object we can destroy ranged
 | 
						|
            // ActionEquipMostDamagingRanged(oTrap);
 | 
						|
            ActionAttack(oTrap);
 | 
						|
            SetLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH", oTrap);
 | 
						|
            return TRUE;
 | 
						|
        }
 | 
						|
 | 
						|
        // Throw ourselves on it nobly! :-)
 | 
						|
        ActionMoveToLocation(GetLocation(oTrap));
 | 
						|
        SetFacingPoint(GetPositionFromLocation(GetLocation(oTrap)));
 | 
						|
        ActionRandomWalk();
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
    else if (nSkill > 0)
 | 
						|
    {
 | 
						|
 | 
						|
        // * BK Feb 6 2003
 | 
						|
        // * Put a check in so that when a henchmen who cannot disarm a trap
 | 
						|
        // * sees a trap they do not repeat their voiceover forever
 | 
						|
        if  (GetLocalInt(OBJECT_SELF, "X0_L_SAWTHISTRAPALREADY" + sID) != 10)
 | 
						|
        {
 | 
						|
            VoiceCannotDo();
 | 
						|
            SetLocalInt(OBJECT_SELF, "X0_L_SAWTHISTRAPALREADY" + sID, 10);
 | 
						|
           string sSpeak = GetStringByStrRef(40551);
 | 
						|
           SendMessageToPC(GetMaster(), sSpeak);
 | 
						|
        }
 | 
						|
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
//* attempts to cast knock to open the door
 | 
						|
int AttemptKnockSpell(object oLocked)
 | 
						|
{
 | 
						|
    // If that didn't work, let's try using a knock spell
 | 
						|
    if (GetHasSpell(SPELL_KNOCK)
 | 
						|
        && (GetIsDoorActionPossible(oLocked,
 | 
						|
                                    DOOR_ACTION_KNOCK)
 | 
						|
            || GetIsPlaceableObjectActionPossible(oLocked,
 | 
						|
                                                  PLACEABLE_ACTION_KNOCK)))
 | 
						|
    {
 | 
						|
        if (bkGetIsDoorInLineOfSight(oLocked) == FALSE)
 | 
						|
        {
 | 
						|
            // For whatever reason, GetObjectSeen doesn't return seen doors.
 | 
						|
            //if (GetObjectSeen(oLocked))
 | 
						|
            if (LineOfSightObject(OBJECT_SELF, oLocked) == TRUE)
 | 
						|
            {
 | 
						|
                ClearActions(CLEAR_X0_INC_HENAI_AttemptToOpenLock2);
 | 
						|
                VoiceCanDo();
 | 
						|
                ActionWait(1.0);
 | 
						|
                ActionCastSpellAtObject(SPELL_KNOCK, oLocked);
 | 
						|
                ActionWait(1.0);
 | 
						|
                return TRUE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
// * Attempt to open a given locked object.
 | 
						|
int bkAttemptToOpenLock(object oLocked)
 | 
						|
{
 | 
						|
 | 
						|
    // * September 2003
 | 
						|
    // * if door is set to not be something
 | 
						|
    // * henchmen should bash open  (like mind flayer beds)
 | 
						|
    // * then ignore it.
 | 
						|
    if (GetLocalInt(oLocked, "X2_L_BASH_FALSE") == 1)
 | 
						|
    {
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
    int bNeedKey = FALSE;
 | 
						|
    int bInLineOfSight = TRUE;
 | 
						|
 | 
						|
    if (GetLockKeyRequired(oLocked) == TRUE)
 | 
						|
    {
 | 
						|
        bNeedKey = TRUE ;
 | 
						|
    }
 | 
						|
 | 
						|
    // * October 17 2003 - BK - Decided that line of sight for doors is not relevant
 | 
						|
    // * was causing too many errors.
 | 
						|
    //if (bkGetIsInLineOfSight(oLocked) == FALSE)
 | 
						|
    //{
 | 
						|
    //    bInLineOfSight = TRUE;
 | 
						|
   // }
 | 
						|
    if ( !GetIsObjectValid(oLocked)
 | 
						|
         || bNeedKey == TRUE
 | 
						|
         || bInLineOfSight == FALSE )
 | 
						|
         //|| GetObjectSeen(oLocked) == FALSE) This check doesn't work.
 | 
						|
         {
 | 
						|
        // Can't open this, so skip the checks
 | 
						|
        MyPrintString("Failed basic check");
 | 
						|
        VoiceCannotDo();
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    // We might be able to open this
 | 
						|
 | 
						|
    int bCanDo = FALSE;
 | 
						|
 | 
						|
    // First, let's see if we notice that it's trapped
 | 
						|
    if (GetIsTrapped(oLocked) && GetTrapDetectedBy(oLocked, OBJECT_SELF))
 | 
						|
    {
 | 
						|
        // Ick! Try and disarm the trap first
 | 
						|
        MyPrintString("Trap on it to disarm");
 | 
						|
        if (! bkAttemptToDisarmTrap(oLocked))
 | 
						|
        {
 | 
						|
            // * Feb 11 2003. Attempt to cast knock because its
 | 
						|
            // * always safe to cast it, even on a trapped object
 | 
						|
            if (AttemptKnockSpell(oLocked) == TRUE)
 | 
						|
            {
 | 
						|
                return TRUE;
 | 
						|
            }
 | 
						|
            //VoicePicklock();
 | 
						|
            VoiceNo();
 | 
						|
            return FALSE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Now, let's try and pick the lock first
 | 
						|
    int nSkill = GetSkillRank(SKILL_OPEN_LOCK);
 | 
						|
    if (nSkill > 0) {
 | 
						|
        nSkill += GetAbilityModifier(ABILITY_DEXTERITY);
 | 
						|
        nSkill += 20;
 | 
						|
    }
 | 
						|
 | 
						|
    if (nSkill > GetLockUnlockDC(oLocked)
 | 
						|
        &&
 | 
						|
        (GetIsDoorActionPossible(oLocked,
 | 
						|
                                 DOOR_ACTION_UNLOCK)
 | 
						|
         || GetIsPlaceableObjectActionPossible(oLocked,
 | 
						|
                                               PLACEABLE_ACTION_UNLOCK))) {
 | 
						|
        ClearActions(CLEAR_X0_INC_HENAI_AttemptToOpenLock1);
 | 
						|
        VoiceCanDo();
 | 
						|
        ActionWait(1.0);
 | 
						|
        ActionUseSkill(SKILL_OPEN_LOCK,oLocked);
 | 
						|
        ActionWait(1.0);
 | 
						|
        bCanDo = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!bCanDo)
 | 
						|
        bCanDo = AttemptKnockSpell(oLocked);
 | 
						|
 | 
						|
 | 
						|
    if (!bCanDo
 | 
						|
        //&& GetAbilityScore(OBJECT_SELF, ABILITY_STRENGTH) >= 16 Removed since you now have control over their bashing via dialog
 | 
						|
        && !GetPlotFlag(oLocked)
 | 
						|
        && (GetIsDoorActionPossible(oLocked,
 | 
						|
                                    DOOR_ACTION_BASH)
 | 
						|
            || GetIsPlaceableObjectActionPossible(oLocked,
 | 
						|
                                                  PLACEABLE_ACTION_BASH))) {
 | 
						|
        ClearActions(CLEAR_X0_INC_HENAI_AttemptToOpenLock3);
 | 
						|
        VoiceCanDo();
 | 
						|
        ActionWait(1.0);
 | 
						|
 | 
						|
        // MODIFIED February 2003
 | 
						|
        // Since the player has direct control over weapon, automatic equipping is frustrating.
 | 
						|
        // removed.
 | 
						|
        //        ActionEquipMostDamagingMelee(oLocked);
 | 
						|
        ActionAttack(oLocked);
 | 
						|
        SetLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH", oLocked);
 | 
						|
        bCanDo = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!bCanDo && !GetPlotFlag(oLocked) && GetHasSpell(SPELL_MAGIC_MISSILE))
 | 
						|
    {
 | 
						|
        ClearActions(CLEAR_X0_INC_HENAI_AttemptToOpenLock3);
 | 
						|
        ActionCastSpellAtObject(SPELL_MAGIC_MISSILE,oLocked);
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    // If we did it, let the player know
 | 
						|
    if(!bCanDo) {
 | 
						|
        VoiceCannotDo();
 | 
						|
    } else {
 | 
						|
        ActionDoCommand(VoiceTaskComplete());
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Handles responses to henchmen commands, including both radial
 | 
						|
// menu and voice commands.
 | 
						|
void bkRespondToHenchmenShout(object oShouter, int nShoutIndex, object oIntruder = OBJECT_INVALID, int nBanInventory=FALSE)
 | 
						|
{
 | 
						|
 | 
						|
    // * if petrified, jump out
 | 
						|
    if (GetHasEffect(EFFECT_TYPE_PETRIFY, OBJECT_SELF) == TRUE)
 | 
						|
    {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    // * MODIFIED February 19 2003
 | 
						|
    // * Do not respond to shouts if in dying mode
 | 
						|
    if (GetIsHenchmanDying() == TRUE)
 | 
						|
        return;
 | 
						|
 | 
						|
    // Do not respond to shouts if you've surrendered.
 | 
						|
    int iSurrendered = GetLocalInt(OBJECT_SELF,"Generic_Surrender");
 | 
						|
    if (iSurrendered)
 | 
						|
        return;
 | 
						|
 | 
						|
    object oLastObject;
 | 
						|
    object oTrap;
 | 
						|
    object oMaster;
 | 
						|
    object oTarget;
 | 
						|
 | 
						|
    //ASSOCIATE SHOUT RESPONSES
 | 
						|
    switch(nShoutIndex)
 | 
						|
    {
 | 
						|
 | 
						|
    // * toggle search mode for henchmen
 | 
						|
    case ASSOCIATE_COMMAND_TOGGLESEARCH:
 | 
						|
    {
 | 
						|
        if (GetActionMode(OBJECT_SELF, ACTION_MODE_DETECT) == TRUE)
 | 
						|
        {
 | 
						|
            SetActionMode(OBJECT_SELF, ACTION_MODE_DETECT, FALSE);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            SetActionMode(OBJECT_SELF, ACTION_MODE_DETECT, TRUE);
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    // * toggle stealth mode for henchmen
 | 
						|
    case ASSOCIATE_COMMAND_TOGGLESTEALTH:
 | 
						|
    {
 | 
						|
        //SpeakString(" toggle stealth");
 | 
						|
        if (GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH) == TRUE)
 | 
						|
        {
 | 
						|
            SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, FALSE);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE);
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    // * June 2003: Stop spellcasting
 | 
						|
    case ASSOCIATE_COMMAND_TOGGLECASTING:
 | 
						|
    {
 | 
						|
        if (GetLocalInt(OBJECT_SELF, "X2_L_STOPCASTING") == 10)
 | 
						|
        {
 | 
						|
           // SpeakString("Was in no casting mode. Switching to cast mode");
 | 
						|
            SetLocalInt(OBJECT_SELF, "X2_L_STOPCASTING", 0);
 | 
						|
            VoiceCanDo();
 | 
						|
        }
 | 
						|
        else
 | 
						|
        if (GetLocalInt(OBJECT_SELF, "X2_L_STOPCASTING") == 0)
 | 
						|
        {
 | 
						|
         //   SpeakString("Was in casting mode. Switching to NO cast mode");
 | 
						|
            SetLocalInt(OBJECT_SELF, "X2_L_STOPCASTING", 10);
 | 
						|
            VoiceCanDo();
 | 
						|
        }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    case ASSOCIATE_COMMAND_INVENTORY:
 | 
						|
        // feb 18. You are now allowed to access inventory during combat.
 | 
						|
         if (nBanInventory == TRUE)
 | 
						|
        {
 | 
						|
            SpeakStringByStrRef(9066);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            // * cannot modify disabled equipment
 | 
						|
            if (GetLocalInt(OBJECT_SELF, "X2_JUST_A_DISABLEEQUIP") == FALSE)
 | 
						|
            {
 | 
						|
                OpenInventory(OBJECT_SELF, oShouter);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                // * feedback as to why
 | 
						|
                SendMessageToPCByStrRef(GetMaster(), 100895);
 | 
						|
            }
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_PICKLOCK:
 | 
						|
        bkManualPickNearestLock();
 | 
						|
        break;
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_DISARMTRAP: // Disarm trap
 | 
						|
        bkAttemptToDisarmTrap(GetNearestTrapToObject(GetMaster()), TRUE);
 | 
						|
        break;
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_ATTACKNEAREST:
 | 
						|
        ResetHenchmenState();
 | 
						|
        SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE);
 | 
						|
        SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE);
 | 
						|
        DetermineCombatRound();
 | 
						|
 | 
						|
        // * bonus feature. If master is attacking a door or container, issues VWE Attack Nearest
 | 
						|
        // * will make henchman join in on the fun
 | 
						|
        oTarget = GetAttackTarget(GetMaster());
 | 
						|
        if (GetIsObjectValid(oTarget) == TRUE)
 | 
						|
        {
 | 
						|
            if (GetObjectType(oTarget) == OBJECT_TYPE_PLACEABLE || GetObjectType(oTarget) == OBJECT_TYPE_DOOR)
 | 
						|
            {
 | 
						|
                ActionAttack(oTarget);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_FOLLOWMASTER:
 | 
						|
        ResetHenchmenState();
 | 
						|
        SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE);
 | 
						|
        DelayCommand(2.5, VoiceCanDo());
 | 
						|
 | 
						|
        //UseStealthMode();
 | 
						|
        //UseDetectMode();
 | 
						|
        ActionForceFollowObject(GetMaster(), GetFollowDistance());
 | 
						|
        SetAssociateState(NW_ASC_IS_BUSY);
 | 
						|
        DelayCommand(5.0, SetAssociateState(NW_ASC_IS_BUSY, FALSE));
 | 
						|
        break;
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_GUARDMASTER:
 | 
						|
    {
 | 
						|
        ResetHenchmenState();
 | 
						|
        //DelayCommand(2.5, VoiceCannotDo());
 | 
						|
 | 
						|
        //Companions will only attack the Masters Last Attacker
 | 
						|
        SetAssociateState(NW_ASC_MODE_DEFEND_MASTER);
 | 
						|
        SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE);
 | 
						|
        object oLastAttacker = GetLastHostileActor(GetMaster());
 | 
						|
        // * for some reason this is too often invalid. still the routine
 | 
						|
        // * works corrrectly
 | 
						|
        SetLocalInt(OBJECT_SELF, "X0_BATTLEJOINEDMASTER", TRUE);
 | 
						|
        HenchmenCombatRound(oLastAttacker);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    case ASSOCIATE_COMMAND_HEALMASTER:
 | 
						|
        //Ignore current healing settings and heal me now
 | 
						|
 | 
						|
        ResetHenchmenState();
 | 
						|
        //SetCommandable(TRUE);
 | 
						|
        if(TalentCureCondition())
 | 
						|
        {
 | 
						|
            DelayCommand(2.0, VoiceCanDo());
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        if(TalentHeal(TRUE, GetMaster()))
 | 
						|
        {
 | 
						|
            DelayCommand(2.0, VoiceCanDo());
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        DelayCommand(2.5, VoiceCannotDo());
 | 
						|
        break;
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_MASTERFAILEDLOCKPICK:
 | 
						|
        //Check local for re-try locked doors
 | 
						|
        if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND)
 | 
						|
           && GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS))
 | 
						|
           {
 | 
						|
            oLastObject = GetLockedObject(GetMaster());
 | 
						|
            bkAttemptToOpenLock(oLastObject);
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_STANDGROUND:
 | 
						|
        //No longer follow the master or guard him
 | 
						|
        SetAssociateState(NW_ASC_MODE_STAND_GROUND);
 | 
						|
        SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE);
 | 
						|
        DelayCommand(2.0, VoiceCanDo());
 | 
						|
        ActionAttack(OBJECT_INVALID);
 | 
						|
        ClearActions(CLEAR_X0_INC_HENAI_RespondToShout1);
 | 
						|
        break;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
        // ***********************************
 | 
						|
        // * AUTOMATIC SHOUTS - not player
 | 
						|
        // *   initiated
 | 
						|
        // ***********************************
 | 
						|
    case ASSOCIATE_COMMAND_MASTERSAWTRAP:
 | 
						|
        if(!GetIsInCombat())
 | 
						|
        {
 | 
						|
            if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND))
 | 
						|
            {
 | 
						|
                oTrap = GetLastTrapDetected(GetMaster());
 | 
						|
                bkAttemptToDisarmTrap(oTrap);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_MASTERUNDERATTACK:
 | 
						|
        // Just go to henchman combat round
 | 
						|
        //SpeakString("here 728");
 | 
						|
 | 
						|
        // * July 15, 2003: Make this only happen if not
 | 
						|
        // * in combat, otherwise the henchman will
 | 
						|
        // * ping pong between targets
 | 
						|
        if (!GetIsInCombat(OBJECT_SELF))
 | 
						|
            HenchmenCombatRound();
 | 
						|
        break;
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_MASTERATTACKEDOTHER:
 | 
						|
 | 
						|
        if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND))
 | 
						|
        {
 | 
						|
            if(!GetAssociateState(NW_ASC_MODE_DEFEND_MASTER))
 | 
						|
            {
 | 
						|
                if(!GetIsInCombat(OBJECT_SELF))
 | 
						|
                {
 | 
						|
                    //SpeakString("here 737");
 | 
						|
                    object oAttack = GetAttackTarget(GetMaster());
 | 
						|
                    // April 2003: If my master can see the enemy, then I can too.
 | 
						|
                    if(GetIsObjectValid(oAttack) && GetObjectSeen(oAttack, GetMaster()))
 | 
						|
                    {
 | 
						|
                        ClearActions(CLEAR_X0_INC_HENAI_RespondToShout2);
 | 
						|
                        HenchmenCombatRound(oAttack);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_MASTERGOINGTOBEATTACKED:
 | 
						|
        if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND))
 | 
						|
        {
 | 
						|
            if(!GetIsInCombat(OBJECT_SELF))
 | 
						|
            {   // SpeakString("here 753");
 | 
						|
                object oAttacker = GetGoingToBeAttackedBy(GetMaster());
 | 
						|
                // April 2003: If my master can see the enemy, then I can too.
 | 
						|
                // Potential Side effect : Henchmen may run
 | 
						|
                // to stupid places, trying to get an enemy
 | 
						|
                if(GetIsObjectValid(oAttacker) && GetObjectSeen(oAttacker, GetMaster()))
 | 
						|
                {
 | 
						|
                   // SpeakString("Defending Master");
 | 
						|
                    ClearActions(CLEAR_X0_INC_HENAI_RespondToShout3);
 | 
						|
                    ActionMoveToObject(oAttacker, TRUE, 7.0);
 | 
						|
                    HenchmenCombatRound(oAttacker);
 | 
						|
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
    case ASSOCIATE_COMMAND_LEAVEPARTY:
 | 
						|
        {
 | 
						|
            oMaster = GetMaster();
 | 
						|
 | 
						|
            string sTag = GetTag(GetArea(oMaster));
 | 
						|
            // * henchman cannot be kicked out in the reaper realm
 | 
						|
            // * Followers can never be kicked out
 | 
						|
            if (sTag == "GatesofCania" || GetIsFollower(OBJECT_SELF) == TRUE)
 | 
						|
                return;
 | 
						|
 | 
						|
            if(GetIsObjectValid(oMaster))
 | 
						|
            {
 | 
						|
                ClearActions(CLEAR_X0_INC_HENAI_RespondToShout4);
 | 
						|
                if(GetAssociateType(OBJECT_SELF) == ASSOCIATE_TYPE_HENCHMAN)
 | 
						|
                {
 | 
						|
                    FireHenchman(GetMaster(), OBJECT_SELF);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
//::///////////////////////////////////////////////
 | 
						|
//:: bkCombatAttemptHeal
 | 
						|
//:: Copyright (c) 2001 Bioware Corp.
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
/*
 | 
						|
    Attempt to heal self and then master
 | 
						|
*/
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
//:: Created By:
 | 
						|
//:: Created On:
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
 | 
						|
int bkCombatAttemptHeal()
 | 
						|
{
 | 
						|
    // * if master is disabled then attempt to free master
 | 
						|
    object oMaster = GetMaster();
 | 
						|
 | 
						|
 | 
						|
    // *turn into a match function...
 | 
						|
    if (MatchDoIHaveAMindAffectingSpellOnMe(oMaster)) {
 | 
						|
        int nSpellToUse = -1;
 | 
						|
 | 
						|
        if (GetHasSpell(SPELL_DISPEL_MAGIC, OBJECT_SELF) ) {
 | 
						|
            ClearActions(CLEAR_X0_INC_HENAI_CombatAttemptHeal1);
 | 
						|
            ActionCastSpellAtLocation(SPELL_DISPEL_MAGIC, GetLocation(oMaster));
 | 
						|
            return TRUE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    int iHealMelee = TRUE;
 | 
						|
    if (bkGetBehavior(BK_HEALINMELEE) == FALSE)
 | 
						|
        iHealMelee = FALSE;
 | 
						|
 | 
						|
 | 
						|
    object oNearestEnemy = GetNearestSeenEnemy();
 | 
						|
 | 
						|
    float fDistance = 0.0;
 | 
						|
    if (GetIsObjectValid(oNearestEnemy)) {
 | 
						|
        fDistance = GetDistanceToObject(oNearestEnemy);
 | 
						|
    }
 | 
						|
 | 
						|
    int iHP = GetPercentageHPLoss(OBJECT_SELF);
 | 
						|
 | 
						|
    // if less than 10% hitpoints then pretend that I am allowed
 | 
						|
    // to heal in melee. Things are getting desperate
 | 
						|
    if (iHP < 10)
 | 
						|
     iHealMelee = TRUE;
 | 
						|
 | 
						|
    int iAmFamiliar = (GetAssociate(ASSOCIATE_TYPE_FAMILIAR,oMaster) == OBJECT_SELF);
 | 
						|
 | 
						|
    // * must be out of Melee range or ALLOWED to heal in melee
 | 
						|
    if (fDistance > BK_HEALTHRESHOLD || iHealMelee) {
 | 
						|
        int iAmHenchman = GetAssociateType(OBJECT_SELF) == ASSOCIATE_TYPE_HENCHMAN;
 | 
						|
        int iAmCompanion = (GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION,oMaster) == OBJECT_SELF);
 | 
						|
        int iAmSummoned = (GetAssociate(ASSOCIATE_TYPE_SUMMONED,oMaster) == OBJECT_SELF);
 | 
						|
 | 
						|
        // Condition for immediate self-healing
 | 
						|
        // Hit-point at less than 50% and random chance
 | 
						|
        if (iHP < 50) {
 | 
						|
            // verbalize
 | 
						|
            if (iAmHenchman || iAmFamiliar) {
 | 
						|
                // * when hit points less than 10% will whine about
 | 
						|
                // * being near death
 | 
						|
                if (iHP < 10 && Random(5) == 0)
 | 
						|
                    VoiceNearDeath();
 | 
						|
            }
 | 
						|
 | 
						|
            // attempt healing
 | 
						|
            if (d100() > iHP-20) {
 | 
						|
                ClearActions(CLEAR_X0_INC_HENAI_CombatAttemptHeal2);
 | 
						|
                if (TalentHealingSelf()) return TRUE;
 | 
						|
                if (iAmHenchman || iAmFamiliar)
 | 
						|
                    if (Random(100) > 80) VoiceHealMe();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // ********************************
 | 
						|
        // Heal master if needed.
 | 
						|
        // ********************************
 | 
						|
 | 
						|
        if (GetAssociateHealMaster()) {
 | 
						|
            if (TalentHeal())
 | 
						|
                return TRUE;
 | 
						|
            else
 | 
						|
                return FALSE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // * No healing done, continue with combat round
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
//::///////////////////////////////////////////////
 | 
						|
//:: bkGetBehavior
 | 
						|
//:: Copyright (c) 2001 Bioware Corp.
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
/*
 | 
						|
    Set/get functions for CONTROL PANEL behavior
 | 
						|
*/
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
//:: Created By:
 | 
						|
//:: Created On:
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
 | 
						|
int bkGetBehavior(int nBehavior)
 | 
						|
{
 | 
						|
    return GetLocalInt(OBJECT_SELF, "NW_L_BEHAVIOR" + IntToString(nBehavior));
 | 
						|
}
 | 
						|
 | 
						|
void bkSetBehavior(int nBehavior, int nValue)
 | 
						|
{
 | 
						|
    SetLocalInt(OBJECT_SELF, "NW_L_BEHAVIOR"+IntToString(nBehavior), nValue);
 | 
						|
}
 | 
						|
 | 
						|
//::///////////////////////////////////////////////
 | 
						|
//:: bkCombatFollowMaster
 | 
						|
//:: Copyright (c) 2001 Bioware Corp.
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
/*
 | 
						|
    Forces the henchman to follow the player.
 | 
						|
    Will even do this in the middle of combat if the
 | 
						|
    distance it too great
 | 
						|
*/
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
//:: Created By:
 | 
						|
//:: Created On:
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
 | 
						|
int bkCombatFollowMaster()
 | 
						|
{
 | 
						|
    object oMaster = GetMaster();
 | 
						|
    int iAmHenchman = (GetHenchman(oMaster) == OBJECT_SELF);
 | 
						|
    int iAmFamiliar = (GetAssociate(ASSOCIATE_TYPE_FAMILIAR,oMaster) == OBJECT_SELF);
 | 
						|
 | 
						|
    if(bkGetBehavior(BK_CURRENT_AI_MODE) != BK_AI_MODE_RUN_AWAY)
 | 
						|
    {
 | 
						|
        // * double follow threshold if in combat (May 2003)
 | 
						|
        if (GetIsInCombat(OBJECT_SELF) == TRUE)
 | 
						|
        {
 | 
						|
            BK_FOLLOW_THRESHOLD = BK_FOLLOW_THRESHOLD * 2.0;
 | 
						|
        }
 | 
						|
        if(GetDistanceToObject(oMaster) > BK_FOLLOW_THRESHOLD)
 | 
						|
        {
 | 
						|
            if(GetCurrentAction(oMaster) != ACTION_FOLLOW)
 | 
						|
            {
 | 
						|
                ClearActions(CLEAR_X0_INC_HENAI_CombatFollowMaster1);
 | 
						|
                MyPrintString("*****EXIT on follow master.*******");
 | 
						|
                ActionForceFollowObject(GetMaster(), GetFollowDistance());
 | 
						|
                return TRUE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
//       4. If in 'NEVER FIGHT' mode will not fight but should TELL the player
 | 
						|
//      that they are in NEVER FIGHT mode
 | 
						|
    if (bkGetBehavior(BK_NEVERFIGHT) == TRUE)
 | 
						|
    {
 | 
						|
 | 
						|
    ClearActions(CLEAR_X0_INC_HENAI_CombatFollowMaster2);
 | 
						|
//    ActionWait(6.0);
 | 
						|
//    ActionDoCommand(DelayCommand(5.9, SetCommandable(TRUE)));
 | 
						|
//    SetCommandable(FALSE);
 | 
						|
        if (d10() > 7)
 | 
						|
        {
 | 
						|
            if (iAmHenchman || iAmFamiliar)
 | 
						|
                VoiceLookHere();
 | 
						|
        }
 | 
						|
    return TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//Pausanias: Is Object in the line of sight of the seer
 | 
						|
int bkGetIsInLineOfSight(object oTarget,object oSeer=OBJECT_SELF)
 | 
						|
{
 | 
						|
    // * if really close, line of sight
 | 
						|
    // * is irrelevant
 | 
						|
    // * if this check is removed it gets very annoying
 | 
						|
    // * because the player can block line of sight
 | 
						|
    if (GetDistanceBetween(oTarget, oSeer) < 6.0)
 | 
						|
    {
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    return LineOfSightObject(oSeer, oTarget);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
// Get the cosine of the angle between the two objects
 | 
						|
float bkGetCosAngleBetween(object Loc1, object Loc2)
 | 
						|
{
 | 
						|
    vector v1 = GetPositionFromLocation(GetLocation(Loc1));
 | 
						|
    vector v2 = GetPositionFromLocation(GetLocation(Loc2));
 | 
						|
    vector v3 = GetPositionFromLocation(GetLocation(OBJECT_SELF));
 | 
						|
 | 
						|
    v1.x -= v3.x; v1.y -= v3.y; v1.z -= v3.z;
 | 
						|
    v2.x -= v3.x; v2.y -= v3.y; v2.z -= v3.z;
 | 
						|
 | 
						|
    float dotproduct = v1.x*v2.x+v1.y*v2.y+v1.z*v2.z;
 | 
						|
 | 
						|
    return dotproduct/(VectorMagnitude(v1)*VectorMagnitude(v2));
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
//Pausanias: Is there a closed door in the line of sight.
 | 
						|
// * is door in line of sight
 | 
						|
int bkGetIsDoorInLineOfSight(object oTarget)
 | 
						|
{
 | 
						|
    float fMeDoorDist;
 | 
						|
 | 
						|
    object oView = GetFirstObjectInShape(SHAPE_SPHERE, 40.0,
 | 
						|
                                         GetLocation(OBJECT_SELF),
 | 
						|
                                         TRUE,OBJECT_TYPE_DOOR);
 | 
						|
 | 
						|
    float fMeTrapDist = GetDistanceBetween(oTarget,OBJECT_SELF);
 | 
						|
 | 
						|
    while (GetIsObjectValid(oView)) {
 | 
						|
        fMeDoorDist = GetDistanceBetween(oView,OBJECT_SELF);
 | 
						|
        //SpeakString("Trap3 : "+FloatToString(fMeTrapDist)+" "+FloatToString(fMeDoorDist));
 | 
						|
        if (fMeDoorDist < fMeTrapDist && !GetIsTrapped(oView))
 | 
						|
            if (GetIsDoorActionPossible(oView,DOOR_ACTION_OPEN) ||
 | 
						|
                GetIsDoorActionPossible(oView,DOOR_ACTION_UNLOCK)) {
 | 
						|
                float fAngle = bkGetCosAngleBetween(oView,oTarget);
 | 
						|
                //SpeakString("Angle: "+FloatToString(fAngle));
 | 
						|
                if (fAngle > 0.5) {
 | 
						|
                    // if (d10() > 7)
 | 
						|
                    // SpeakString("There's something fishy near that door...");
 | 
						|
                    return TRUE;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
        oView = GetNextObjectInShape(SHAPE_SPHERE,40.0,
 | 
						|
                                     GetLocation(OBJECT_SELF),
 | 
						|
                                     TRUE, OBJECT_TYPE_DOOR);
 | 
						|
    }
 | 
						|
 | 
						|
    //SpeakString("No matches found");
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* void main() {} /* */
 |