918 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			918 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
/*/////////////////////// [Include - Spawn In] /////////////////////////////////
 | 
						|
    Filename: J_Inc_SpawnIn
 | 
						|
///////////////////////// [Include - Spawn In] /////////////////////////////////
 | 
						|
    This contains all the functions used in the spawning process, in one easy
 | 
						|
    and very long file.
 | 
						|
 | 
						|
    It also importantly sets up spells we have, or at least talents, so we
 | 
						|
    know if we have any spells from category X.
 | 
						|
///////////////////////// [History] ////////////////////////////////////////////
 | 
						|
    1.3 - Changed, added a lot of new things (such as constants file)
 | 
						|
    1.4 - No more setting talent categories On Spawn. This is too much hassel.
 | 
						|
          See the On rest script for ideas (remove this when complete!).
 | 
						|
 | 
						|
          Perhaps set "Items" the first time we enter combat, and reset each time
 | 
						|
          combat stops. Can be more efficeint maybe.
 | 
						|
        - Skills set to "use" should have, say, 3 or more skill points to be
 | 
						|
          used automatically, especially true for hiding.
 | 
						|
///////////////////////// [Workings] ///////////////////////////////////////////
 | 
						|
    This doesn't call anything to run the rest, except AI_SetUpEndOfSpawn has
 | 
						|
    a lot of things that the generic AI requires (SetListeningPatterns and skills
 | 
						|
    and waypoints ETC)
 | 
						|
 | 
						|
    See the spawn in script for all the actual uses.
 | 
						|
///////////////////////// [Arguments] //////////////////////////////////////////
 | 
						|
    Arguments: N/A see spawn in script
 | 
						|
///////////////////////// [Include - Spawn In] ///////////////////////////////*/
 | 
						|
 | 
						|
// All constants.
 | 
						|
#include "J_INC_SETWEAPONS"
 | 
						|
#include "prc_inc_racial"
 | 
						|
// Set weapons
 | 
						|
// - Constants file is in this
 | 
						|
 | 
						|
// Special: Bioware SoU Waypoints/Animations constants
 | 
						|
// - Here so I know where they are :-P
 | 
						|
const string sAnimCondVarname = "NW_ANIM_CONDITION";
 | 
						|
// If set, the NPC is civilized
 | 
						|
const int NW_ANIM_FLAG_IS_CIVILIZED            = 0x00000400;
 | 
						|
// If set, the NPC will use voicechats
 | 
						|
const int NW_ANIM_FLAG_CHATTER                 = 0x00000004;
 | 
						|
// If set, the NPC is mobile in a close-range
 | 
						|
const int NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE   = 0x00000200;
 | 
						|
 | 
						|
/******************************************************************************/
 | 
						|
// Functions:
 | 
						|
/******************************************************************************/
 | 
						|
// This will activate one aura, very quickly.
 | 
						|
// If we have more than one...oh well.
 | 
						|
void AI_AdvancedAuras();
 | 
						|
// Activate the aura number (IE: Spell number), if it is possible.
 | 
						|
void AI_ActivateAura(int nAuraNumber);
 | 
						|
 | 
						|
// Base for moving round thier waypoints
 | 
						|
// - Uses ExectuteScript to run the waypoint walking.
 | 
						|
// * If bRun is TRUE, we run all the waypoint.
 | 
						|
// * fPause is the time delay between walking to the next waypoint (default 1.0)
 | 
						|
void SpawnWalkWayPoints(int bRun = FALSE, float fPause = 1.0);
 | 
						|
 | 
						|
// Sets up what we will listen to (everything!)
 | 
						|
void AI_SetListeningPatterns();
 | 
						|
// This will set what creature to create OnDeath.
 | 
						|
void AI_SetDeathResRef(string sResRef);
 | 
						|
// This will set the string, sNameOfValue, to sValue. Array size of 1.
 | 
						|
// - Use nPercentToSay to determine what % out of 100 it is said.
 | 
						|
void AI_SetSpawnInSpeakValue(string sNameOfValue, string sValue, int nPercentToSay = 100);
 | 
						|
// This will choose a random string, using iAmountOfValues, which is
 | 
						|
// the amount of non-empty strings given. The size of the array is therefore 1.
 | 
						|
// - Use nPercentToSay to determine what % out of 100 it is said.
 | 
						|
void AI_SetSpawnInSpeakRandomValue(string sNameOfValue, int nPercentToSay, int nAmountOfValues, string sValue1, string sValue2, string sValue3 = "", string sValue4 = "", string sValue5 = "", string sValue6 = "", string sValue7 = "", string sValue8 = "", string sValue9 = "", string sValue10 = "", string sValue11 = "", string sValue12 = "");
 | 
						|
// This will set an array of values, to sNameOfValue, for one to be chosen to
 | 
						|
// be said at the right time :-)
 | 
						|
// - sNameOfValue must be a valid name.
 | 
						|
// - Use iPercentToSay to determine what % out of 100 it is said.
 | 
						|
// NOTE: If the sNameOfValue is any combat one, we make that 1/100 to 1/1000.
 | 
						|
void AI_SetSpawnInSpeakArray(string sNameOfValue, int nPercentToSay, int nSize, string sValue1, string sValue2, string sValue3 = "", string sValue4 = "", string sValue5 = "", string sValue6 = "", string sValue7 = "", string sValue8 = "", string sValue9 = "", string sValue10 = "", string sValue11 = "", string sValue12 = "");
 | 
						|
 | 
						|
// This applies an increase, decrease or no change to the intended stat.
 | 
						|
// * Applies the effects INSTANTLY. These CANNOT be removed easily!
 | 
						|
void AI_ApplyStatChange(int nStat, int nAmount);
 | 
						|
// This will alter (magically) an ammount of random stats - nAmount
 | 
						|
// by a value within iLowest and nHighest.
 | 
						|
// * Applies the effects INSTANTLY. These CANNOT be removed easily!
 | 
						|
void AI_CreateRandomStats(int nLowest, int nHighest, int nAmount);
 | 
						|
// This will randomise other stats. Put both numbers to 0 to ignore some.
 | 
						|
// nHPMin, nHPMax                   = HP changes.
 | 
						|
// nReflexSaveMin, nReflexSaveMax   = Reflex Save changes
 | 
						|
// nWillSaveMin, nWillSaveMax       = Will Save changes
 | 
						|
// nFortSaveMin, nFortSaveMax       = Fortitude Save changes
 | 
						|
// nACMin, nACMax                   = AC change.
 | 
						|
//      Use nACType to define the AC type - default AC_DODGE_BONUS
 | 
						|
// * Applies the effects INSTANTLY. These CANNOT be removed easily!
 | 
						|
void AI_CreateRandomOther(int nHPMin, int nHPMax, int nReflexSaveMin = 0, int nReflexSaveMax = 0, int nWillSaveMin = 0, int nWillSaveMax = 0, int nFortSaveMin = 0, int nFortSaveMax = 0, int nACMin = 0, int nACMax = 0, int nACType = AC_DODGE_BONUS);
 | 
						|
 | 
						|
// Sets up thier selection of skills, to integers, if they would ever use them.
 | 
						|
// NOTE: it also triggers "hide" if they have enough skill and not stopped.
 | 
						|
// * 1.4 Changes: Some skills are turned off automatically when they have very
 | 
						|
//   low points in that skill (IE: No possibility of doing it sucessfully). Also
 | 
						|
//   edited other parts of the AI to take this into account.
 | 
						|
void AI_SetUpSkillToUse();
 | 
						|
// Sets the turning level if we have FEAT_TURN_UNDEAD.
 | 
						|
// - Called from AI_SetUpEndOfSpawn.
 | 
						|
void AI_SetTurningLevel();
 | 
						|
// This MUST be called. It fires these events:
 | 
						|
// SetUpSpells, SetUpSkillToUse, SetListeningPatterns, SetWeapons, AdvancedAuras.
 | 
						|
// These MUST be called! the AI might fail to work correctly if they don't fire!
 | 
						|
void AI_SetUpEndOfSpawn();
 | 
						|
// This will make the visual effect passed play INSTANTLY at the creatures location.
 | 
						|
// * nVFX - The visual effect constant number
 | 
						|
void AI_SpawnInInstantVisual(int nVFX);
 | 
						|
// This will make the visual effect passed play PERMAMENTLY.
 | 
						|
// * nVFX - The visual effect constant number
 | 
						|
// NOTE: They will be made to be SUPERNATUAL, so are not dispelled!
 | 
						|
void AI_SpawnInPermamentVisual(int nVFX);
 | 
						|
// This should not be used!
 | 
						|
// * called from SetUpEndOfSpawn.
 | 
						|
void AI_SetMaybeFearless();
 | 
						|
// This will set the MAXIMUM and MINIMUM targets to pass this stage (under sName)
 | 
						|
// of the targeting system. IE:
 | 
						|
// - If we set it to min of 5, max of 10, for AC, if we cancled 5 targets on having
 | 
						|
//   AC higher then wanted, we will take the highest 5 minimum.
 | 
						|
//   If there are over 10, we take a max of 10 to choose from.
 | 
						|
// * nType - must be TARGET_HIGHER or TARGET_LOWER. Defaults to the lowest, so it
 | 
						|
//           targets the lowest value for sName.
 | 
						|
void AI_SetAITargetingValues(string sName, int nType, int nMinimum, int nMaximum);
 | 
						|
 | 
						|
 | 
						|
// Levels up us.
 | 
						|
// * nLevel - Levels to this number (doesn't do anything if already GetHitDice >= nLevel).
 | 
						|
// * nClass, nClass2, nClass3 - the 3 classes to level up in. Only needs 1 minimum
 | 
						|
// Spreads equally if there is more then 1 nClass.
 | 
						|
// Sets up spells to use automatically, but DOES NOT CHANGE CHALLENGE RATING!
 | 
						|
void AI_LevelUpCreature(int nLevel, int nClass, int nClass2 = CLASS_TYPE_INVALID,  int nClass3 = CLASS_TYPE_INVALID);
 | 
						|
 | 
						|
// Used in AI_LevelUpCreature.
 | 
						|
// - Levels up OBJECT_SELF, in nClass for nLevels
 | 
						|
void AI_LevelLoop(int nClass, int nLevels);
 | 
						|
 | 
						|
// Sets up what random spells to cheat-cast at the end of all known spells.
 | 
						|
// it does NOT check for immunities, barriers, or anything else.
 | 
						|
// - You can set spells to more then one of the imputs to have a higher % to cast that one.
 | 
						|
void SetAICheatCastSpells(int nSpell1, int nSpell2, int nSpell3, int nSpell4, int nSpell5, int nSpell6);
 | 
						|
 | 
						|
// Mark that the given creature has the given condition set for anitmations
 | 
						|
// * Bioware SoU animations thing.
 | 
						|
void SetAnimationCondition(int nCondition, int bValid = TRUE, object oCreature = OBJECT_SELF);
 | 
						|
 | 
						|
// Sets we are a Beholder and use Ray attacks, and Animagic Ray.
 | 
						|
void SetBeholderAI();
 | 
						|
// Set we are a mindflayer, and uses some special AI for them.
 | 
						|
void SetMindflayerAI();
 | 
						|
 | 
						|
// This will set a spell trigger up. Under cirtain conditions, spells are released
 | 
						|
// and cast on the caster.
 | 
						|
// Once fired, a spell trigger is only reset by resting. Only 1 of each max is fired at once!
 | 
						|
// * sType - is specifically:
 | 
						|
//   SPELLTRIGGER_DAMAGED_AT_PERCENT  - When damaged, the trigger fires. Use iValue for the %. One at a time is fired.
 | 
						|
//   SPELLTRIGGER_IMMOBILE            - Fired when held/paralyzed/sleeping ETC. One at a time is fired.
 | 
						|
//   SPELLTRIGGER_NOT_GOT_FIRST_SPELL - Makes sure !GetHasSpellEffect(iSpell1) already,
 | 
						|
//                                  then fires. Checks all in this category each round (first one fires!)
 | 
						|
//   SPELLTRIGGER_START_OF_COMBAT     - Triggered always, at the start of DetermineCombatRound.
 | 
						|
// * nNumber - can be 1-9, in sequential order of when you want them to fire.
 | 
						|
// * nValue - is only required with DAMAGED_AT_PERCENT.
 | 
						|
// * nSpellX - Cannot be 0. It should only really be defensive spells.
 | 
						|
void SetSpellTrigger(string sType, int nValue, int nNumber, int nSpell1, int nSpell2 = 0, int nSpell3 = 0, int nSpell4 = 0, int nSpell5 = 0, int nSpell6 = 0, int nSpell7 = 0, int nSpell8 = 0, int nSpell9 = 0);
 | 
						|
 | 
						|
// Mark that the given creature has the given condition set
 | 
						|
void SetAnimationCondition(int nCondition, int bValid = TRUE, object oCreature = OBJECT_SELF)
 | 
						|
{
 | 
						|
    int nCurrentCond = GetLocalInt(oCreature, sAnimCondVarname);
 | 
						|
    if (bValid) {
 | 
						|
        SetLocalInt(oCreature, sAnimCondVarname, nCurrentCond | nCondition);
 | 
						|
    } else {
 | 
						|
        SetLocalInt(oCreature, sAnimCondVarname, nCurrentCond & ~nCondition);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// Sets up what random spells to cheat-cast at the end of all known spells.
 | 
						|
// it does NOT check for immunities, barriers, or anything else.
 | 
						|
// - You can set spells to more then one of the imputs to have a higher % to cast that one.
 | 
						|
void SetAICheatCastSpells(int nSpell1, int nSpell2, int nSpell3, int nSpell4, int nSpell5, int nSpell6)
 | 
						|
{
 | 
						|
    SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(1), nSpell1);
 | 
						|
    SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(2), nSpell2);
 | 
						|
    SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(3), nSpell3);
 | 
						|
    SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(4), nSpell4);
 | 
						|
    SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(5), nSpell5);
 | 
						|
    SetAIConstant(AI_CHEAT_CAST_SPELL + IntToString(6), nSpell6);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Levels up us.
 | 
						|
// * nLevel - Levels to this number (doesn't do anything if already GetHitDice >= nLevel).
 | 
						|
// * nClass, nClass2, nClass3 - the 3 classes to level up in. Only needs 1 minimum
 | 
						|
// - Spreads equally if there is more then 1 nClass.
 | 
						|
// - Sets up spells to use automatically, but DOES NOT CHANGE CHALLENGE RATING!
 | 
						|
// - Does NOT check for validness, or report any information.
 | 
						|
void AI_LevelUpCreature(int nLevel, int nClass, int nClass2 = CLASS_TYPE_INVALID,  int nClass3 = CLASS_TYPE_INVALID)
 | 
						|
{
 | 
						|
    // Divide by 1, 2 or 3 (100%, 50%, 33%)
 | 
						|
    int nDivideBy = (nClass >= 0) + (nClass2 >= 0) + (nClass3 >= 0);
 | 
						|
 | 
						|
    int nTotalPerClass = nLevel / nDivideBy;
 | 
						|
 | 
						|
    // Limit and loop - Class 1.
 | 
						|
    AI_LevelLoop(nClass, nTotalPerClass);
 | 
						|
    // 2
 | 
						|
    AI_LevelLoop(nClass2, nTotalPerClass);
 | 
						|
    // 3
 | 
						|
    AI_LevelLoop(nClass3, nTotalPerClass);
 | 
						|
}
 | 
						|
 | 
						|
// Used in AI_LevelUpCreature.
 | 
						|
// - Levels up OBJECT_SELF, in iClass for nLevels
 | 
						|
void AI_LevelLoop(int nClass, int nLevels)
 | 
						|
{
 | 
						|
    // Limit and loop
 | 
						|
    while(nLevels > FALSE)
 | 
						|
    {
 | 
						|
        LevelUpHenchman(OBJECT_SELF, nClass, TRUE);
 | 
						|
        nLevels--;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// This will set what creature to create OnDeath.
 | 
						|
void AI_SetDeathResRef(string sResRef)
 | 
						|
{
 | 
						|
    SetLocalString(OBJECT_SELF, AI_WE_WILL_CREATE_ON_DEATH, sResRef);
 | 
						|
}
 | 
						|
// This will set the string, sNameOfValue, to sValue. Array size of 1.
 | 
						|
// - Use iPercentToSay to determine what % out of 100 it is said.
 | 
						|
void AI_SetSpawnInSpeakValue(string sNameOfValue, string sValue, int iPercentToSay)
 | 
						|
{
 | 
						|
    SetLocalString(OBJECT_SELF, sNameOfValue + "1", sValue);
 | 
						|
    // The array is 1 big!
 | 
						|
    SetLocalInt(OBJECT_SELF, ARRAY_SIZE + sNameOfValue, 1);
 | 
						|
    SetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sNameOfValue, iPercentToSay);
 | 
						|
}
 | 
						|
// This will choose a random string, using iAmountOfValues, which is
 | 
						|
// the amount of non-empty strings given. The size of the array is therefore 1.
 | 
						|
// - Use iPercentToSay to determine what % out of 100 it is said.
 | 
						|
void AI_SetSpawnInSpeakRandomValue(string sNameOfValue, int nPercentToSay, int nAmountOfValues, string sValue1, string sValue2, string sValue3, string sValue4, string sValue5, string sValue6, string sValue7, string sValue8, string sValue9, string sValue10, string sValue11, string sValue12)
 | 
						|
{
 | 
						|
    // Need a value amount of values!
 | 
						|
    if(nAmountOfValues)
 | 
						|
    {
 | 
						|
        int nRandomNum = Random(nAmountOfValues) - 1; // take one, as it is 0 - X, not 1 - X
 | 
						|
        string sValueToUse;
 | 
						|
        switch(nRandomNum)
 | 
						|
        {
 | 
						|
            case 0:{sValueToUse = sValue1;}break;
 | 
						|
            case 1:{sValueToUse = sValue2;}break;
 | 
						|
            case 2:{sValueToUse = sValue3;}break;
 | 
						|
            case 3:{sValueToUse = sValue4;}break;
 | 
						|
            case 4:{sValueToUse = sValue5;}break;
 | 
						|
            case 5:{sValueToUse = sValue6;}break;
 | 
						|
            case 6:{sValueToUse = sValue7;}break;
 | 
						|
            case 7:{sValueToUse = sValue8;}break;
 | 
						|
            case 8:{sValueToUse = sValue9;}break;
 | 
						|
            case 9:{sValueToUse = sValue10;}break;
 | 
						|
            case 10:{sValueToUse = sValue11;}break;
 | 
						|
            case 11:{sValueToUse = sValue12;}break;
 | 
						|
        }
 | 
						|
        SetLocalString(OBJECT_SELF, sNameOfValue + "1", sValueToUse);
 | 
						|
        // The array is 1 big!
 | 
						|
        SetLocalInt(OBJECT_SELF, ARRAY_SIZE + sNameOfValue, 1);
 | 
						|
        SetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sNameOfValue, nPercentToSay);
 | 
						|
    }
 | 
						|
}
 | 
						|
void AI_SetSpawnInSpeakArray(string sNameOfValue, int nPercentToSay, int nSize, string sValue1, string sValue2, string sValue3 = "", string sValue4 = "", string sValue5 = "", string sValue6 = "", string sValue7 = "", string sValue8 = "", string sValue9 = "", string sValue10 = "", string sValue11 = "", string sValue12 = "")
 | 
						|
{
 | 
						|
    if(nSize >= 1)
 | 
						|
    {
 | 
						|
        SetLocalString(OBJECT_SELF, sNameOfValue + "1", sValue1);
 | 
						|
        if(nSize >= 2)
 | 
						|
        {
 | 
						|
            SetLocalString(OBJECT_SELF, sNameOfValue + "2", sValue2);
 | 
						|
            if(nSize >= 3)
 | 
						|
            {
 | 
						|
                SetLocalString(OBJECT_SELF, sNameOfValue + "3", sValue3);
 | 
						|
                if(nSize >= 4)
 | 
						|
                {
 | 
						|
                    SetLocalString(OBJECT_SELF, sNameOfValue + "4", sValue4);
 | 
						|
                    if(nSize >= 5)
 | 
						|
                    {
 | 
						|
                        SetLocalString(OBJECT_SELF, sNameOfValue + "5", sValue5);
 | 
						|
                        if(nSize >= 6)
 | 
						|
                        {
 | 
						|
                            SetLocalString(OBJECT_SELF, sNameOfValue + "6", sValue6);
 | 
						|
                            if(nSize >= 7)
 | 
						|
                            {
 | 
						|
                                SetLocalString(OBJECT_SELF, sNameOfValue + "7", sValue7);
 | 
						|
                                if(nSize >= 8)
 | 
						|
                                {
 | 
						|
                                    SetLocalString(OBJECT_SELF, sNameOfValue + "8", sValue8);
 | 
						|
                                    if(nSize >= 9)
 | 
						|
                                    {
 | 
						|
                                        SetLocalString(OBJECT_SELF, sNameOfValue + "9", sValue9);
 | 
						|
                                        if(nSize >= 10)
 | 
						|
                                        {
 | 
						|
                                            SetLocalString(OBJECT_SELF, sNameOfValue + "10", sValue10);
 | 
						|
                                            if(nSize >= 11)
 | 
						|
                                            {
 | 
						|
                                                SetLocalString(OBJECT_SELF, sNameOfValue + "11", sValue11);
 | 
						|
                                                if(nSize >= 12)
 | 
						|
                                                {
 | 
						|
                                                    SetLocalString(OBJECT_SELF, sNameOfValue + "12", sValue12);
 | 
						|
    // Hehe, this looks not stright if you stare at it! :-P
 | 
						|
    }   }   }   }   }   }   }   }   }   }   }   }
 | 
						|
    // The array is so big...
 | 
						|
    SetLocalInt(OBJECT_SELF, ARRAY_SIZE + sNameOfValue, nSize);
 | 
						|
    SetLocalInt(OBJECT_SELF, ARRAY_PERCENT + sNameOfValue, nPercentToSay);
 | 
						|
}
 | 
						|
// This applies an increase, decrease or no change to the intended stat.
 | 
						|
// * Applies the effects INSTANTLY. These CANNOT be removed easily!
 | 
						|
void AI_ApplyStatChange(int nStat, int nAmount)
 | 
						|
{
 | 
						|
    if(nAmount != 0)
 | 
						|
    {
 | 
						|
        effect eChange;
 | 
						|
        if(nAmount < 0)
 | 
						|
        {
 | 
						|
            nAmount = abs(nAmount);
 | 
						|
            eChange = SupernaturalEffect(EffectAbilityDecrease(nStat, nAmount));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            eChange = SupernaturalEffect(EffectAbilityIncrease(nStat, nAmount));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
// This will, eventually, choose X number of stats, and change them within the
 | 
						|
// range given.
 | 
						|
void AI_CreateRandomStats(int nLowest, int nHighest, int nAmount)
 | 
						|
{
 | 
						|
    if(nAmount > 0 && nHighest != 0 && nLowest != 0 && nHighest >= nLowest)
 | 
						|
    {
 | 
						|
        int nRange = nHighest - nLowest;
 | 
						|
        int nNumSlots = nAmount;
 | 
						|
        if(nNumSlots > 6) nNumSlots = 6;
 | 
						|
        int nNumLeft = 6;
 | 
						|
        // Walk through each stat and figure out what it's chance of being
 | 
						|
        // modified is.  As an example, suppose we wanted to have 4 randomized
 | 
						|
        // abilities.  We'd look at the first ability and it would have a 4 in 6
 | 
						|
        // chance of being picked.  Let's suppose it was, the next ability would
 | 
						|
        // have a 3 in 5 chance of being picked.  If this next ability wasn't
 | 
						|
        // picked to be changed, the 3rd ability woud have a 3 in 4 chance of
 | 
						|
        // being picked and so on.
 | 
						|
        int nCnt;
 | 
						|
        int nChange;
 | 
						|
        for(nCnt = 0; (nNumSlots > 0 && nCnt < 6); nCnt++)
 | 
						|
        {
 | 
						|
           if((nNumSlots == nNumLeft) || (Random(nNumLeft) < nNumSlots))
 | 
						|
           {
 | 
						|
              nChange = Random(nRange) + nLowest;
 | 
						|
              AI_ApplyStatChange(nCnt, nChange);
 | 
						|
              nNumSlots--;
 | 
						|
           }
 | 
						|
           nNumLeft--;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// This will randomise other stats. Put both numbers to 0 to ignore some.
 | 
						|
// nHPMin, nHPMax                   = HP changes.
 | 
						|
// nReflexSaveMin, nReflexSaveMax   = Reflex Save changes
 | 
						|
// nWillSaveMin, nWillSaveMax       = Will Save changes
 | 
						|
// nFortSaveMin, nFortSaveMax       = Fortitude Save changes
 | 
						|
// nACMin, nACMax                   = AC change.
 | 
						|
//      Use nACType to define the AC type - default AC_DODGE_BONUS
 | 
						|
// * Applies the effects INSTANTLY. These CANNOT be removed easily!
 | 
						|
void AI_CreateRandomOther(int nHPMin, int nHPMax, int nReflexSaveMin = 0, int nReflexSaveMax = 0, int nWillSaveMin = 0, int nWillSaveMax = 0, int nFortSaveMin = 0, int nFortSaveMax = 0, int nACMin = 0, int nACMax = 0, int nACType = AC_DODGE_BONUS)
 | 
						|
{
 | 
						|
    int nRange, nChange, nNewChange;
 | 
						|
    effect eChange;
 | 
						|
    if(!(nHPMin == 0 && nHPMax == 0) && nHPMax >= nHPMin)
 | 
						|
    {
 | 
						|
        nRange = nHPMax - nHPMin;
 | 
						|
        nChange = Random(nRange) + nHPMin;
 | 
						|
        if(nChange > 0)
 | 
						|
        {
 | 
						|
            eChange = SupernaturalEffect(EffectTemporaryHitpoints(nChange));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
        // * Must have 1HP remaining at least.
 | 
						|
        else if(nChange < 0 && GetMaxHitPoints() > nChange)
 | 
						|
        {
 | 
						|
            eChange = EffectDamage(nChange, DAMAGE_TYPE_DIVINE, DAMAGE_POWER_PLUS_TWENTY);
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if(!(nReflexSaveMin == 0 && nReflexSaveMax == 0) && nReflexSaveMax >= nReflexSaveMin)
 | 
						|
    {
 | 
						|
        nRange = nReflexSaveMax - nReflexSaveMin;
 | 
						|
        nChange = Random(nRange) + nReflexSaveMin;
 | 
						|
        if(nChange > 0)
 | 
						|
        {
 | 
						|
            eChange = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_REFLEX, nChange));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
        // Cannot apply 0 change, but can make our saves negative
 | 
						|
        else if(nChange < 0)
 | 
						|
        {
 | 
						|
            nNewChange = abs(nChange);
 | 
						|
            eChange = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_REFLEX, nNewChange));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if(!(nWillSaveMin == 0 && nWillSaveMax == 0) && nWillSaveMax >= nWillSaveMin)
 | 
						|
    {
 | 
						|
        nRange = nWillSaveMax - nWillSaveMin;
 | 
						|
        nChange = Random(nRange) + nWillSaveMin;
 | 
						|
        if(nChange > 0)
 | 
						|
        {
 | 
						|
            eChange = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_WILL, nChange));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
        // Cannot apply 0 change, but can make our saves negative
 | 
						|
        else if(nChange < 0)
 | 
						|
        {
 | 
						|
            nNewChange = abs(nChange);
 | 
						|
            eChange = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_WILL, nNewChange));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if(!(nFortSaveMin == 0 && nFortSaveMax == 0) && nFortSaveMax >= nFortSaveMin)
 | 
						|
    {
 | 
						|
        nRange = nFortSaveMax - nFortSaveMin;
 | 
						|
        nChange = Random(nRange) + nFortSaveMin;
 | 
						|
        if(nChange > 0)
 | 
						|
        {
 | 
						|
            eChange = SupernaturalEffect(EffectSavingThrowIncrease(SAVING_THROW_FORT, nChange));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
        // Cannot apply 0 change, but can make our saves negative
 | 
						|
        else if(nChange < 0)
 | 
						|
        {
 | 
						|
            nNewChange = abs(nChange);
 | 
						|
            eChange = SupernaturalEffect(EffectSavingThrowDecrease(SAVING_THROW_FORT, nNewChange));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if(!(nACMin == 0 && nACMax == 0) && nACMax >= nACMin)
 | 
						|
    {
 | 
						|
        nRange = nACMax - nACMin;
 | 
						|
        nChange = Random(nRange) + nACMin;
 | 
						|
        if(nChange > 0)
 | 
						|
        {
 | 
						|
            eChange = SupernaturalEffect(EffectACIncrease(nChange, nACType));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
        else if(nChange < 0)
 | 
						|
        {
 | 
						|
            nNewChange = abs(nChange);
 | 
						|
            eChange = SupernaturalEffect(EffectACDecrease(nNewChange, nACType));
 | 
						|
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eChange, OBJECT_SELF);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*::///////////////////////////////////////////////
 | 
						|
//:: SetListeningPatterns
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
    Changed a lot. added in "**" (all) listening, for hearing enemies.
 | 
						|
//::////////////////////////////////////////////*/
 | 
						|
 | 
						|
void AI_SetListeningPatterns()
 | 
						|
{
 | 
						|
    // Lag check
 | 
						|
    if(GetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_LISTENING, AI_OTHER_MASTER)) return;
 | 
						|
    SetListening(OBJECT_SELF, TRUE);
 | 
						|
 | 
						|
    // Anyone that can hear it, and is not fighting, comes and helps
 | 
						|
    SetListenPattern(OBJECT_SELF, AI_SHOUT_I_WAS_ATTACKED, AI_SHOUT_I_WAS_ATTACKED_CONSTANT);
 | 
						|
 | 
						|
    //Set a custom listening pattern for the creature so that placables with
 | 
						|
    //"NW_BLOCKER" + Blocker NPC Tag will correctly call to their blockers.
 | 
						|
    string sBlocker = "NW_BLOCKER_BLK_" + GetTag(OBJECT_SELF);
 | 
						|
    SetListenPattern(OBJECT_SELF, sBlocker, AI_SHOUT_BLOCKER_CONSTANT);
 | 
						|
 | 
						|
    // Determines combat round, if not fighting
 | 
						|
    SetListenPattern(OBJECT_SELF, AI_SHOUT_CALL_TO_ARMS, AI_SHOUT_CALL_TO_ARMS_CONSTANT);
 | 
						|
 | 
						|
    // These call to allies, to move them to a battle.
 | 
						|
    SetListenPattern(OBJECT_SELF, AI_SHOUT_HELP_MY_FRIEND, AI_SHOUT_HELP_MY_FRIEND_CONSTANT);
 | 
						|
    SetListenPattern(OBJECT_SELF, AI_SHOUT_LEADER_FLEE_NOW, AI_SHOUT_LEADER_FLEE_NOW_CONSTANT);
 | 
						|
    SetListenPattern(OBJECT_SELF, AI_SHOUT_LEADER_ATTACK_TARGET, AI_SHOUT_LEADER_ATTACK_TARGET_CONSTANT);
 | 
						|
 | 
						|
    // 1.3 - Need a killed one.
 | 
						|
    SetListenPattern(OBJECT_SELF, AI_SHOUT_I_WAS_KILLED, AI_SHOUT_I_WAS_KILLED_CONSTANT);
 | 
						|
 | 
						|
    // 1.3 - PLaceables/doors which shout this get responded to!
 | 
						|
    SetListenPattern(OBJECT_SELF, AI_SHOUT_I_WAS_OPENED, AI_SHOUT_I_WAS_OPENED_CONSTANT);
 | 
						|
 | 
						|
    // This will make the listener hear anything, used to react to enemy talking.
 | 
						|
    SetListenPattern(OBJECT_SELF, "**", AI_SHOUT_ANYTHING_SAID_CONSTANT);
 | 
						|
}
 | 
						|
 | 
						|
// Base for moving round thier waypoints
 | 
						|
// - Uses ExectuteScript to run the waypoint walking.
 | 
						|
// * If bRun is TRUE, we run all the waypoint.
 | 
						|
// * fPause is the time delay between walking to the next waypoint (default 1.0)
 | 
						|
void SpawnWalkWayPoints(int bRun = FALSE, float fPause = 1.0)
 | 
						|
{
 | 
						|
    SetLocalInt(OBJECT_SELF, WAYPOINT_RUN, bRun);
 | 
						|
    SetLocalFloat(OBJECT_SELF, WAYPOINT_PAUSE, fPause);
 | 
						|
    ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF);
 | 
						|
}
 | 
						|
 | 
						|
// This MUST be called. It fires these events:
 | 
						|
// SetUpSpells, SetUpSkillToUse, SetListeningPatterns, SetWeapons, AdvancedAuras.
 | 
						|
// These MUST be called! the AI might fail to work correctly if they don't fire!
 | 
						|
void AI_SetUpEndOfSpawn()
 | 
						|
{
 | 
						|
    if(GetSpawnInCondition(AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION, AI_OTHER_MASTER))
 | 
						|
    {
 | 
						|
        // This will store thier starting location, and then move back there after combat
 | 
						|
        // Will turn off if there are waypoints. It is set in SetUpEndOfSpawn.
 | 
						|
        SetAILocation(AI_RETURN_TO_POINT, GetLocation(OBJECT_SELF));
 | 
						|
    }
 | 
						|
 | 
						|
    // Set up if we are immune to cirtain levels of spells naturally for better
 | 
						|
    // AI spellcasters.
 | 
						|
    object oHide = GetItemInSlot(INVENTORY_SLOT_CARMOUR, OBJECT_SELF);
 | 
						|
    // Get if immune is on
 | 
						|
    if(GetItemHasItemProperty(oHide, ITEM_PROPERTY_IMMUNITY_SPELLS_BY_LEVEL))
 | 
						|
    {
 | 
						|
        itemproperty eCheck = GetFirstItemProperty(oHide);
 | 
						|
        int nAmount;
 | 
						|
        // Check for item properties until we find the level.
 | 
						|
        while(GetIsItemPropertyValid(eCheck) && nAmount == FALSE)
 | 
						|
        {
 | 
						|
            // Check subtype.
 | 
						|
            if(GetItemPropertyType(eCheck) == ITEM_PROPERTY_IMMUNITY_SPELLS_BY_LEVEL)
 | 
						|
            {
 | 
						|
                // Get the amount
 | 
						|
                nAmount = GetItemPropertyCostTableValue(eCheck);
 | 
						|
            }
 | 
						|
            eCheck = GetNextItemProperty(oHide);
 | 
						|
        }
 | 
						|
        // Set it
 | 
						|
        if(nAmount)
 | 
						|
        {
 | 
						|
            SetLocalInt(OBJECT_SELF, AI_SPELL_IMMUNE_LEVEL, nAmount);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // All things only used by my personal AI.
 | 
						|
    // * If we are not using a custom AI file, we do these things.
 | 
						|
    if(GetCustomAIFileName() == "")
 | 
						|
    {
 | 
						|
        // If we are a commoner of any sort, and under 10 hit dice, we are
 | 
						|
        // panicy - IE: We set to -1 morale, which triggers the "commoner" fleeing
 | 
						|
        if(GetLevelByClass(CLASS_TYPE_COMMONER) && GetHitDice(OBJECT_SELF) < 10)
 | 
						|
        {
 | 
						|
            SetAIInteger(AI_MORALE, -1);
 | 
						|
        }
 | 
						|
        // If we are not set already to fearless, we might be set to fearless
 | 
						|
        if(!GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER))
 | 
						|
        {
 | 
						|
            AI_SetMaybeFearless();
 | 
						|
        }
 | 
						|
        // Set if we are a beholder or mindflayer
 | 
						|
        switch(GetAppearanceType(OBJECT_SELF))
 | 
						|
        {
 | 
						|
            // Sets we are a Beholder and use Ray attacks, and Animagic Ray.
 | 
						|
            case APPEARANCE_TYPE_BEHOLDER: // beholder, 401
 | 
						|
            case APPEARANCE_TYPE_BEHOLDER_EYEBALL: // beholder, 402
 | 
						|
            case APPEARANCE_TYPE_BEHOLDER_MAGE: // beholder, 403
 | 
						|
            case APPEARANCE_TYPE_BEHOLDER_MOTHER: // Hive mother, 472
 | 
						|
            {
 | 
						|
                // 1 = beholder
 | 
						|
                SetAIInteger(AI_SPECIAL_AI, AI_SPECIAL_AI_BEHOLDER);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
            // Set we are a mindflayer, and uses some special AI for them, IE:
 | 
						|
            // brain sucking.
 | 
						|
            case APPEARANCE_TYPE_MINDFLAYER: // Mindflayer, 413
 | 
						|
            case APPEARANCE_TYPE_MINDFLAYER_2: // Mindflayer2, 414
 | 
						|
            case APPEARANCE_TYPE_MINDFLAYER_ALHOON: // Mindflayer_Alhoon, 415
 | 
						|
            {
 | 
						|
                // 2 = mindflayer
 | 
						|
                SetAIInteger(AI_SPECIAL_AI, AI_SPECIAL_AI_MINDFLAYER);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        // This will turn OFF skills we cannot use, so will never attempt them
 | 
						|
        // at low skill levels anywhere in the AI.
 | 
						|
        AI_SetUpSkillToUse();
 | 
						|
 | 
						|
        // Sets the turning level if we have FEAT_TURN_UNDEAD.
 | 
						|
        AI_SetTurningLevel();
 | 
						|
 | 
						|
        // This sets what weapons the creature will use. They will use the best, according to a "value"
 | 
						|
        // Giving a creature the feat Two-weapon-fighting makes them deul wield if appropriate weapons.
 | 
						|
        SetWeapons();
 | 
						|
    }
 | 
						|
 | 
						|
    // We don't set up corpses if set not to...else set to resurrect
 | 
						|
    if(!GetSpawnInCondition(AI_FLAG_OTHER_TURN_OFF_CORPSES, AI_OTHER_MASTER))
 | 
						|
    {
 | 
						|
        // Note: Here, if we can, we set Bioware's lootable on.
 | 
						|
        if(GetSpawnInCondition(AI_FLAG_OTHER_USE_BIOWARE_LOOTING, AI_OTHER_MASTER))
 | 
						|
        {
 | 
						|
            // Set to lootable
 | 
						|
            SetLootable(OBJECT_SELF, TRUE);
 | 
						|
        }
 | 
						|
        // Just handling corpse raising/resurrection/removal
 | 
						|
        // - Undestroyable, Raiseable and Selectable
 | 
						|
        SetIsDestroyable(FALSE, TRUE, TRUE);
 | 
						|
    }
 | 
						|
 | 
						|
    // Goes through and sets up which shouts the NPC will listen to.
 | 
						|
    // - Custom AI uses this also, or should take advantage of it
 | 
						|
    AI_SetListeningPatterns();
 | 
						|
 | 
						|
    // This activates the creatures aura's.
 | 
						|
    if(GetCommandable()) AI_AdvancedAuras();
 | 
						|
}
 | 
						|
 | 
						|
// Sets the turning level if we have FEAT_TURN_UNDEAD.
 | 
						|
void AI_SetTurningLevel()
 | 
						|
{
 | 
						|
    // Most taken directly from NW_S2_TURNDEAD which is used with FEAT_TURN_UNDEAD
 | 
						|
    if(GetHasFeat(FEAT_TURN_UNDEAD))
 | 
						|
    {
 | 
						|
        // By default, it is clerical levels which provide turn undead power.
 | 
						|
        // We can turn HD up to nTurnLevel (HD = GetHitDice + GetTurnREsistsnceHD of undead)
 | 
						|
        int nTurnLevel = GetLevelByClass(CLASS_TYPE_CLERIC);
 | 
						|
        // Paladins turn at -2 the level of clerics
 | 
						|
        if(GetLevelByClass(CLASS_TYPE_PALADIN) - 2 > nTurnLevel)
 | 
						|
        {
 | 
						|
            nTurnLevel = GetLevelByClass(CLASS_TYPE_PALADIN) - 2;
 | 
						|
        }
 | 
						|
        // Blackguard gets to turn at HITDICE -2 level, not character level,
 | 
						|
        // as it says in NW_S2_TURNDEAD.
 | 
						|
        if(GetLevelByClass(CLASS_TYPE_BLACKGUARD) > 0 &&
 | 
						|
          (GetHitDice(OBJECT_SELF) - 2 > nTurnLevel))
 | 
						|
        {
 | 
						|
            nTurnLevel = GetHitDice(OBJECT_SELF) - 2;
 | 
						|
        }
 | 
						|
        // BTW, the number of undead turned is at least nTurnLevel, so we
 | 
						|
        // can always turn one :-D
 | 
						|
        SetAIInteger(AI_TURNING_LEVEL, nTurnLevel);
 | 
						|
        // Note: Turn undead could be used for FEAT_DIVINE_MIGHT and
 | 
						|
        // FEAT_DIVINE_SHIELD
 | 
						|
    }
 | 
						|
}
 | 
						|
// This should not be used!
 | 
						|
// * called from SetUpEndOfSpawn.
 | 
						|
void AI_SetMaybeFearless()
 | 
						|
{
 | 
						|
    // Cirtain races are immune to fear
 | 
						|
    switch(MyPRCGetRacialType(OBJECT_SELF))
 | 
						|
    {
 | 
						|
        case RACIAL_TYPE_CONSTRUCT:
 | 
						|
        case RACIAL_TYPE_DRAGON:
 | 
						|
        case RACIAL_TYPE_UNDEAD:
 | 
						|
        case RACIAL_TYPE_OUTSIDER:
 | 
						|
        {
 | 
						|
            SetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    // If we are immune to fear anyway, we don't care
 | 
						|
    if(GetHasFeat(FEAT_AURA_OF_COURAGE) ||
 | 
						|
       GetHasFeat(FEAT_RESIST_NATURES_LURE) ||
 | 
						|
       GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_FEAR))
 | 
						|
    {
 | 
						|
        SetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// Activate all auras.
 | 
						|
void AI_ActivateAura(int nAuraNumber)
 | 
						|
{
 | 
						|
    // Just ActionCast - cheat cast, as then we can use it unlmimted times, as books say.
 | 
						|
    if(GetHasSpell(nAuraNumber))
 | 
						|
    {
 | 
						|
        ActionCastSpellAtObject(nAuraNumber, OBJECT_SELF, METAMAGIC_NONE, TRUE, 20, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
 | 
						|
    }
 | 
						|
}
 | 
						|
// This will activate one aura, very quickly.
 | 
						|
// If we have more than one...oh well.
 | 
						|
void AI_AdvancedAuras()
 | 
						|
{
 | 
						|
    // Do aura's
 | 
						|
 | 
						|
    // NOTE:
 | 
						|
    // - All cheat cast. As DMG, they should be always on OR free action to reapply.
 | 
						|
    ClearAllActions();
 | 
						|
    AI_ActivateAura(SPELLABILITY_DRAGON_FEAR);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_UNEARTHLY_VISAGE);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_BLINDING);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_OF_COURAGE);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_PROTECTION);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_STUN);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_FIRE);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_COLD);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_ELECTRICITY);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_UNNATURAL);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_FEAR);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_UNNATURAL);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_MENACE);
 | 
						|
    AI_ActivateAura(SPELLABILITY_TYRANT_FOG_MIST);
 | 
						|
    AI_ActivateAura(AI_SPELLABILITY_AURA_OF_HELLFIRE);
 | 
						|
    AI_ActivateAura(SPELLABILITY_AURA_HORRIFICAPPEARANCE);
 | 
						|
}
 | 
						|
 | 
						|
// Sets up thier selection of skills, to integers, if they would ever use them.
 | 
						|
// NOTE: it also triggers "hide" if they have enough skill and not stopped.
 | 
						|
void AI_SetUpSkillToUse()
 | 
						|
{
 | 
						|
    // Get our hitdice
 | 
						|
    int nHitDice = GetHitDice(OBJECT_SELF);
 | 
						|
    int nRank;
 | 
						|
    // Hiding. We turn off if we have no skill or under 1 skill in it
 | 
						|
    // * Note: For the AI to decide "oh, we should hide", it requires a minimum
 | 
						|
    //   of 7 points in hide, and Rank - 4 must be >= our HD too. Can be forced.
 | 
						|
    if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_HIDING, AI_OTHER_COMBAT_MASTER))
 | 
						|
    {
 | 
						|
        if(!GetHasSkill(SKILL_HIDE) ||
 | 
						|
            GetSkillRank(SKILL_HIDE) < 1)
 | 
						|
        {
 | 
						|
            SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_HIDING, AI_OTHER_COMBAT_MASTER);
 | 
						|
            DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    // Pickpocketing...we only turn it OFF here if low skill
 | 
						|
    // (or none) Needs 1/2 HD or 10 minimum - 10 is probably needed for the DC35
 | 
						|
    // check for this skill at all.
 | 
						|
    if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PICKPOCKETING, AI_OTHER_COMBAT_MASTER))
 | 
						|
    {
 | 
						|
        nRank = GetSkillRank(SKILL_PICK_POCKET);
 | 
						|
        if(!GetHasSkill(SKILL_PICK_POCKET) ||
 | 
						|
            nRank < nHitDice/2 || nRank < 10)
 | 
						|
        {
 | 
						|
            SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PICKPOCKETING, AI_OTHER_COMBAT_MASTER);
 | 
						|
            DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_PICKPOCKETING, AI_OTHER_COMBAT_MASTER);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    // Taunting. Again, only off if low skill. Needs half of HD, or 3 minimum
 | 
						|
    if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_TAUNTING, AI_OTHER_COMBAT_MASTER))
 | 
						|
    {
 | 
						|
        nRank = GetSkillRank(SKILL_TAUNT);
 | 
						|
        if(!GetHasSkill(SKILL_TAUNT) ||
 | 
						|
            nRank < nHitDice/2 || nRank < 3)
 | 
						|
        {
 | 
						|
            SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_TAUNTING, AI_OTHER_COMBAT_MASTER);
 | 
						|
            DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_TAUNTING, AI_OTHER_COMBAT_MASTER);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    // Empathy. Again, only off if low skill. Needs any, checked futher in game.
 | 
						|
    if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_EMPATHY, AI_OTHER_COMBAT_MASTER))
 | 
						|
    {
 | 
						|
        if(!GetHasSkill(SKILL_ANIMAL_EMPATHY))
 | 
						|
        {
 | 
						|
            SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_EMPATHY, AI_OTHER_COMBAT_MASTER);
 | 
						|
            DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_EMPATHY, AI_OTHER_COMBAT_MASTER);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    // Unlocking doors. Again, only off if low skill. Needs any, checked futher in game.
 | 
						|
    if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER))
 | 
						|
    {
 | 
						|
        if(!GetHasSkill(SKILL_OPEN_LOCK))
 | 
						|
        {
 | 
						|
            SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER);
 | 
						|
            DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    // Healing kits.
 | 
						|
    if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_USING_HEALING_KITS, AI_OTHER_COMBAT_MASTER))
 | 
						|
    {
 | 
						|
        if(!GetHasSkill(SKILL_HEAL))
 | 
						|
        {
 | 
						|
            SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_USING_HEALING_KITS, AI_OTHER_COMBAT_MASTER);
 | 
						|
            DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_USING_HEALING_KITS, AI_OTHER_COMBAT_MASTER);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    // Parrying
 | 
						|
    // Only on if we have some skill in it :-)
 | 
						|
    if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PARRYING, AI_OTHER_COMBAT_MASTER))
 | 
						|
    {
 | 
						|
        if(!GetHasSkill(SKILL_PARRY))
 | 
						|
        {
 | 
						|
            SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PARRYING, AI_OTHER_COMBAT_MASTER);
 | 
						|
            DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_PARRYING, AI_OTHER_COMBAT_MASTER);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// This will make the visual effect passed play INSTANTLY at the creatures location.
 | 
						|
// * nVFX - The visual effect constant number
 | 
						|
void AI_SpawnInInstantVisual(int nVFX)
 | 
						|
{
 | 
						|
    // Beta 3 change: Made to at location.
 | 
						|
    ApplyEffectAtLocation(DURATION_TYPE_INSTANT,
 | 
						|
                          EffectVisualEffect(nVFX),
 | 
						|
                          GetLocation(OBJECT_SELF));
 | 
						|
}
 | 
						|
// This will make the visual effect passed play PERMAMENTLY.
 | 
						|
// * nVFX - The visual effect constant number
 | 
						|
// NOTE: They will be made to be SUPERNATUAL, so are not dispelled!
 | 
						|
void AI_SpawnInPermamentVisual(int nVFX)
 | 
						|
{
 | 
						|
    ApplyEffectToObject(DURATION_TYPE_INSTANT,
 | 
						|
                        SupernaturalEffect(EffectVisualEffect(nVFX)),
 | 
						|
                        OBJECT_SELF);
 | 
						|
}
 | 
						|
// This will set the MAXIMUM and MINIMUM targets to pass this stage (under sName)
 | 
						|
// of the targeting system. IE:
 | 
						|
// - If we set it to min of 5, max of 10, for AC, if we cancled 5 targets on having
 | 
						|
//   AC higher then wanted, we will take the highest 5 minimum.
 | 
						|
//   If there are over 10, we take a max of 10 to choose from.
 | 
						|
// * nType - must be TARGET_HIGHER or TARGET_LOWER. Defaults to the lowest, so it
 | 
						|
//           targets the lowest value for sName.
 | 
						|
void AI_SetAITargetingValues(string sName, int nType, int nMinimum, int nMaximum)
 | 
						|
{
 | 
						|
    // Error checking
 | 
						|
    if((nType == TARGET_HIGHER || nType == TARGET_LOWER) &&
 | 
						|
        nMinimum >= 1 && nMaximum >= 1 && nMaximum >= nMinimum)
 | 
						|
    {
 | 
						|
        // Set the type to sName.
 | 
						|
        // - It is TARGET_HIGHER (1) or TARGET_LOWER (0).
 | 
						|
        SetAIInteger(sName, nType);
 | 
						|
 | 
						|
        // Minimum amount of targets for this?
 | 
						|
        SetAIInteger(sName + MINIMUM, nMinimum);
 | 
						|
 | 
						|
        // Maximum targets for this?
 | 
						|
        SetAIInteger(sName + MAXIMUM, nMaximum);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// This will set a spell trigger up. Under cirtain conditions, spells are released
 | 
						|
// and cast on the caster.
 | 
						|
// Once fired, a spell trigger is only reset by resting. Only 1 of each max is fired at once!
 | 
						|
// * sType - is specifically:
 | 
						|
//   SPELLTRIGGER_DAMAGED_AT_PERCENT  - When damaged, the trigger fires. Use iValue for the %. One at a time is fired.
 | 
						|
//   SPELLTRIGGER_IMMOBILE            - Fired when held/paralyzed/sleeping ETC. One at a time is fired.
 | 
						|
//   SPELLTRIGGER_NOT_GOT_FIRST_SPELL - Makes sure !GetHasSpellEffect(iSpell1) already,
 | 
						|
//                                  then fires. Checks all in this category each round (first one fires!)
 | 
						|
//   SPELLTRIGGER_START_OF_COMBAT     - Triggered always, at the start of DetermineCombatRound.
 | 
						|
// * nNumber - can be 1-9, in sequential order of when you want them to fire.
 | 
						|
// * nValue - is only required with DAMAGED_AT_PERCENT.
 | 
						|
// * nSpellX - Cannot be 0. It should only really be defensive spells.
 | 
						|
void SetSpellTrigger(string sType, int nValue, int nNumber, int nSpell1, int nSpell2 = 0, int nSpell3 = 0, int nSpell4 = 0, int nSpell5 = 0, int nSpell6 = 0, int nSpell7 = 0, int nSpell8 = 0, int nSpell9 = 0)
 | 
						|
{
 | 
						|
    // Either get our spell trigger (creature) or create one
 | 
						|
    object oTrigger = GetAIObject(AI_SPELL_TRIGGER_CREATURE);
 | 
						|
    // Is it valid?
 | 
						|
    if(!GetIsObjectValid(oTrigger))
 | 
						|
    {
 | 
						|
        // Create it
 | 
						|
        oTrigger = CreateObject(OBJECT_TYPE_CREATURE, "jass_spelltrig", GetLocation(OBJECT_SELF));
 | 
						|
        // Set local on them for the target
 | 
						|
        AddHenchman(OBJECT_SELF, oTrigger);
 | 
						|
        // Local for us to get our spell trigger (should be our henchmen)
 | 
						|
        SetAIObject(AI_SPELL_TRIGGER_CREATURE, oTrigger);
 | 
						|
    }
 | 
						|
    int nSize = 1;
 | 
						|
    string sTotalID = sType + IntToString(nNumber);
 | 
						|
 | 
						|
    SetLocalInt(oTrigger, sTotalID + "1", nSpell1);
 | 
						|
    if(nSpell2 != FALSE)
 | 
						|
    {   nSize = 2;
 | 
						|
        SetLocalInt(oTrigger, sTotalID + "2", nSpell2);    }
 | 
						|
    if(nSpell3 != FALSE)
 | 
						|
    {   nSize = 3;
 | 
						|
        SetLocalInt(oTrigger, sTotalID + "3", nSpell3);    }
 | 
						|
    if(nSpell4 != FALSE)
 | 
						|
    {   nSize = 4;
 | 
						|
        SetLocalInt(oTrigger, sTotalID + "4", nSpell4);    }
 | 
						|
    if(nSpell5 != FALSE)
 | 
						|
    {   nSize = 5;
 | 
						|
        SetLocalInt(oTrigger, sTotalID + "5", nSpell5);    }
 | 
						|
    if(nSpell6 != FALSE)
 | 
						|
    {   nSize = 6;
 | 
						|
        SetLocalInt(oTrigger, sTotalID + "6", nSpell6);    }
 | 
						|
    if(nSpell7 != FALSE)
 | 
						|
    {   nSize = 7;
 | 
						|
        SetLocalInt(oTrigger, sTotalID + "7", nSpell7);    }
 | 
						|
    if(nSpell8 != FALSE)
 | 
						|
    {   nSize = 8;
 | 
						|
        SetLocalInt(oTrigger, sTotalID + "8", nSpell8);    }
 | 
						|
    if(nSpell9 != FALSE)
 | 
						|
    {   nSize = 9;
 | 
						|
        SetLocalInt(oTrigger, sTotalID + "9", nSpell9);    }
 | 
						|
 | 
						|
    // Set final sizes ETC.
 | 
						|
    SetLocalInt(oTrigger, MAXINT_ + sTotalID, nSize);
 | 
						|
    SetLocalInt(oTrigger, sTotalID + USED, FALSE);
 | 
						|
 | 
						|
    // Check value
 | 
						|
    if(nValue > GetLocalInt(oTrigger, VALUE + sType))
 | 
						|
    {
 | 
						|
        SetLocalInt(oTrigger, VALUE + sType, nValue);
 | 
						|
    }
 | 
						|
 | 
						|
    // Set how many spell triggers we have too
 | 
						|
    if(nNumber > GetLocalInt(oTrigger, MAXIMUM + sType))
 | 
						|
    {
 | 
						|
        SetLocalInt(oTrigger, MAXIMUM + sType, nNumber);
 | 
						|
    }
 | 
						|
}
 | 
						|
// Debug: To compile this script, uncomment all of the below.
 | 
						|
/* - Add two "/"'s at the start of this line
 | 
						|
void main()
 | 
						|
{
 | 
						|
    return;
 | 
						|
}
 | 
						|
//*/
 |