Updated Jasperre's AI
Updated Jasperre's AI to 1.4, fixed a few other coding bugs & fully compiled module.
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
#include "drownud"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oCurrentObject = GetFirstObjectInArea();
|
||||
|
@@ -23,7 +23,7 @@ effects come in.
|
||||
void main()
|
||||
{
|
||||
//Edit Settings here ///////////////////////////////////////////////////////
|
||||
float z = 14; //How High the fireworks go before exploding
|
||||
float z = 14.0; //How High the fireworks go before exploding
|
||||
//DO NOT EDIT BELOW THIS LINE //////////////////////////////////////////////
|
||||
object oArea = GetArea(OBJECT_SELF);
|
||||
object oTarget = GetObjectByTag("FireworksSource");
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [Destroy Ourself] ************************************
|
||||
/*/////////////////////// [Destroy Ourself] ////////////////////////////////////
|
||||
Filename: J_AI_DestroySelf
|
||||
************************* [Destroy Ourself] ************************************
|
||||
///////////////////////// [Destroy Ourself] ////////////////////////////////////
|
||||
This is executed OnDeath to clean up the corpse. It helps - clears all
|
||||
non-droppable stuff.
|
||||
|
||||
@@ -10,22 +10,23 @@
|
||||
|
||||
Oh, if this is executed any other time when they are dead, they are
|
||||
destroyed instantly.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added to replace a include function for death.
|
||||
- No locals are destroyed. The game should do that anyway. Items are, though.
|
||||
************************* [Workings] *******************************************
|
||||
1.4 -
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
this, if ever fired, will destroy the creature. It is not deleayed - there
|
||||
is a special function in the death script to check the whole "Did I get
|
||||
raised?" stuff.
|
||||
|
||||
I suppose you can edit this to put a corpse in :-D
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A - none needed.
|
||||
************************* [Destroy Ourself] ***********************************/
|
||||
///////////////////////// [Destroy Ourself] //////////////////////////////////*/
|
||||
|
||||
|
||||
// Exectued from death, to speed things up.
|
||||
#include "j_inc_constants"
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
// This will delete all un-droppable items, before they fade out.
|
||||
void DeleteAllThings();
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [Execute Combat Action] ******************************
|
||||
/*/////////////////////// [Execute Combat Action] //////////////////////////////
|
||||
Filename: J_AI_DeterCombat
|
||||
************************* [Execute Combat Action] ******************************
|
||||
///////////////////////// [Execute Combat Action] //////////////////////////////
|
||||
Fired from other scripts, this runs an actual actions.
|
||||
|
||||
It also contains the Pre-combat and Post-combat action events. In essense
|
||||
@@ -10,10 +10,12 @@
|
||||
Therefore, they only fire if the default AI is being used :-)
|
||||
|
||||
Do NOT mess with this file, please. :-D
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - AI Include only fired from here. This script is executed from others,
|
||||
as the default in place of custom AI scripts.
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Mainly See the generic AI include file for changes. This is just
|
||||
what calls DetermineCombatRound() and associated things.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This is simple:
|
||||
|
||||
- We execute it if there is no other AI files.
|
||||
@@ -25,11 +27,11 @@
|
||||
It cleans things up, and is the only script in the whole set that has
|
||||
j_inc_generic_ai in, reducing file size, and compile times. AI is more
|
||||
manageable too!
|
||||
************************* [Arguments] ******************************************
|
||||
Arguments: See J_Inc_Generic_AI
|
||||
************************* [Execute Combat Action] *****************************/
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: See J_INC_GENERIC_AI
|
||||
///////////////////////// [Execute Combat Action] ////////////////////////////*/
|
||||
|
||||
#include "j_inc_generic_ai"
|
||||
#include "J_INC_GENERIC_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -41,8 +43,12 @@ void main()
|
||||
// Check: Are we imputting a target? We imputt it even if invalid
|
||||
object oTarget = GetLocalObject(OBJECT_SELF, AI_TEMP_SET_TARGET);
|
||||
|
||||
// Speak combat round speakstring
|
||||
SpeakArrayString(AI_TALK_ON_COMBAT_ROUND, TRUE);
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
// Speak combat round speakstring
|
||||
SpeakArrayString(AI_TALK_ON_COMBAT_ROUND, TRUE);
|
||||
}
|
||||
|
||||
// Call combat round using include
|
||||
AI_DetermineCombatRound(oTarget);
|
||||
|
@@ -1,27 +1,26 @@
|
||||
/************************ [On Heartbeat - Animations] **************************
|
||||
/*/////////////////////// [On Heartbeat - Animations] //////////////////////////
|
||||
Filename: J_AI_Heart_aimat
|
||||
************************* [On Heartbeat - Animations] **************************
|
||||
///////////////////////// [On Heartbeat - Animations] //////////////////////////
|
||||
To keep the heartbeat small, I've divided all the bits that MIGHT fire
|
||||
into other scripts. This makes it smaller, and faster.
|
||||
|
||||
I've also shortened the perception script too - and along with the heartbeat
|
||||
is the largest, Out-Of-Combat script. It isn't divided up by execute scripts,
|
||||
but should be leaner.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added to speed up heartbeat and keep filesize down on un-used parts.
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Changed to nw_i0_generic, as to include all animations, whatever NwN version.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This is executed as file HEARTBEAT_ANIMATIONS_FILE, from the heartbeat
|
||||
script (Default1, or onheartbeat). It can run by itself, using the SoU
|
||||
animations - better then me changing and making my own, as they are vastly
|
||||
improved from NwN!
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A
|
||||
///////////////////////// [On Heartbeat - Animations] ////////////////////////*/
|
||||
|
||||
It is Not called if AI_VALID_ANIMATIONS AI Integer is not set.
|
||||
************************* [Arguments] ******************************************
|
||||
Arguments:
|
||||
************************* [On Heartbeat - Animations] *************************/
|
||||
|
||||
// SoU Animations file.
|
||||
#include "x0_i0_anims"
|
||||
// Generic Include File. This contains animations whatever NwN version it is.
|
||||
#include "NW_I0_GENERIC"
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -37,8 +36,4 @@ void main()
|
||||
{
|
||||
PlayImmobileAmbientAnimations();
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteLocalInt(OBJECT_SELF, "AI_INTEGER" + "AI_VALID_ANIMATIONS");
|
||||
}
|
||||
}
|
||||
|
@@ -1,46 +1,57 @@
|
||||
/************************ [On Heartbeat - Buff] ********************************
|
||||
/*/////////////////////// [On Heartbeat - Buff] ////////////////////////////////
|
||||
Filename: j_ai_heart_buff
|
||||
************************* [On Heartbeat - Buff] ********************************
|
||||
///////////////////////// [On Heartbeat - Buff] ////////////////////////////////
|
||||
This is ExecuteScript'ed from the heartbeat file, if they want to buff
|
||||
themselves with spells to be prepared for any battle coming up.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Will Add all the appropriate Hordes spells, notably the missing epic ones.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This contains Advance Buffing - IE quick protection spells.
|
||||
I've done what ones I think are useful - IE most protection ones & summons!
|
||||
This doesn't include any which are very short duration:
|
||||
|
||||
This doesn't include any which are (potentionally) very short duration (IE:
|
||||
1 round/level, or a set value):
|
||||
|
||||
Elemntal shield/Wounding whispers (though you can add all of these!)
|
||||
Aid, bless, aura of vitality, aura of glory, blood frenzy, prayer,
|
||||
divine* Range (Power, Might, Shield, Favor), Expeditious retreat,
|
||||
holy/unholy aura (or protection from /magic circle against),
|
||||
natures balance, one with the land, shield of faith, virtue, war cry.
|
||||
************************* [Arguments] ******************************************
|
||||
natures balance, one with the land, shield of faith, virtue, war cry, dirge,
|
||||
death armor, mestals acid sheath.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A
|
||||
************************* [On Heartbeat - Buff] *******************************/
|
||||
///////////////////////// [On Heartbeat - Buff] //////////////////////////////*/
|
||||
|
||||
// Constants for some unconstantanated spells
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
// Wrapper, to stop repeating the same lines! :-)
|
||||
int BuffCastSpell(int iSpell);
|
||||
int BuffCastSpell(int nSpell);
|
||||
|
||||
void main()
|
||||
{
|
||||
// For summons counter.
|
||||
int nCnt, iBreak;
|
||||
int nCnt, bBreak;
|
||||
// FAST BUFF SELF
|
||||
// Stop what we are doing first, to perform the actions.
|
||||
ClearAllActions();
|
||||
|
||||
//Combat Protections
|
||||
// Always cast "Epic Warding" and "Epic Mage Armor".
|
||||
BuffCastSpell(FEAT_EPIC_SPELL_EPIC_WARDING);
|
||||
BuffCastSpell(FEAT_EPIC_SPELL_MAGE_ARMOUR);
|
||||
|
||||
// Combat Protections
|
||||
if(!BuffCastSpell(SPELL_PREMONITION))
|
||||
if(!BuffCastSpell(SPELL_GREATER_STONESKIN))
|
||||
BuffCastSpell(SPELL_STONESKIN);
|
||||
|
||||
//Visage Protections
|
||||
// Visage Protections
|
||||
if(!BuffCastSpell(SPELL_SHADOW_SHIELD))
|
||||
if(!BuffCastSpell(SPELL_ETHEREAL_VISAGE))
|
||||
BuffCastSpell(SPELL_GHOSTLY_VISAGE);
|
||||
|
||||
//Mantle Protections
|
||||
// Mantle Protections
|
||||
if(!BuffCastSpell(SPELL_GREATER_SPELL_MANTLE))
|
||||
if(!BuffCastSpell(SPELL_SPELL_MANTLE))
|
||||
BuffCastSpell(SPELL_LESSER_SPELL_MANTLE);
|
||||
@@ -49,13 +60,13 @@ void main()
|
||||
if(BuffCastSpell(SPELL_TRUE_SEEING))
|
||||
BuffCastSpell(SPELL_SEE_INVISIBILITY);
|
||||
|
||||
//Elemental Protections. 4 lots. From 40/- to 10/-
|
||||
// Elemental Protections. 4 lots. From 40/- to 10/-
|
||||
if(!BuffCastSpell(SPELL_ENERGY_BUFFER))
|
||||
if(!BuffCastSpell(SPELL_PROTECTION_FROM_ELEMENTS))
|
||||
if(!BuffCastSpell(SPELL_RESIST_ELEMENTS))
|
||||
BuffCastSpell(SPELL_ENDURE_ELEMENTS);
|
||||
|
||||
//Mental Protections
|
||||
// Mental Protections
|
||||
if(!BuffCastSpell(SPELL_MIND_BLANK))
|
||||
if(!BuffCastSpell(SPELL_LESSER_MIND_BLANK))
|
||||
BuffCastSpell(SPELL_CLARITY);
|
||||
@@ -64,7 +75,7 @@ void main()
|
||||
if(!BuffCastSpell(SPELL_GLOBE_OF_INVULNERABILITY))
|
||||
BuffCastSpell(SPELL_MINOR_GLOBE_OF_INVULNERABILITY);
|
||||
|
||||
//Invisibility
|
||||
// Invisibility
|
||||
// Note: Improved has 50% consealment, etherealness has just invisiblity.
|
||||
if(!BuffCastSpell(SPELL_IMPROVED_INVISIBILITY))
|
||||
BuffCastSpell(SPELL_DISPLACEMENT);//50% consealment
|
||||
@@ -82,21 +93,22 @@ void main()
|
||||
BuffCastSpell(SPELL_EAGLE_SPLEDOR);
|
||||
if(!BuffCastSpell(SPELL_GREATER_FOXS_CUNNING))
|
||||
BuffCastSpell(SPELL_FOXS_CUNNING);
|
||||
if(!BuffCastSpell(SPELL_GREATER_OWLS_WISDOM))
|
||||
BuffCastSpell(SPELL_OWLS_WISDOM);
|
||||
if(!BuffCastSpell(SPELL_GREATER_ENDURANCE))
|
||||
BuffCastSpell(SPELL_ENDURANCE);
|
||||
if(!BuffCastSpell(AI_SPELL_OWLS_INSIGHT))
|
||||
if(!BuffCastSpell(SPELL_GREATER_OWLS_WISDOM))
|
||||
BuffCastSpell(SPELL_OWLS_WISDOM);
|
||||
|
||||
// Mage armor or shield. Don't stack them.
|
||||
if(!BuffCastSpell(SPELL_SHIELD))
|
||||
BuffCastSpell(SPELL_MAGE_ARMOR);
|
||||
// Entropic Shield (20% consealment, 1 turn/level)
|
||||
BuffCastSpell(SPELL_ENTROPIC_SHIELD);
|
||||
|
||||
// Protection from negative energy
|
||||
if(!BuffCastSpell(SPELL_UNDEATHS_ETERNAL_FOE))
|
||||
BuffCastSpell(SPELL_DEATH_WARD);
|
||||
//Misc Protections which have no more powerful.
|
||||
// Low durations (Rounds per caster level)
|
||||
// if(!BuffCastSpell(SPELL_ELEMENTAL_SHIELD))
|
||||
// BuffCastSpell(SPELL_WOUNDING_WHISPERS);
|
||||
BuffCastSpell(SPELL_BARKSKIN);
|
||||
BuffCastSpell(SPELL_ENTROPIC_SHIELD);
|
||||
BuffCastSpell(SPELL_PROTECTION_FROM_SPELLS);
|
||||
@@ -105,6 +117,12 @@ void main()
|
||||
BuffCastSpell(SPELL_REGENERATE);
|
||||
BuffCastSpell(SPELL_SPELL_RESISTANCE);
|
||||
BuffCastSpell(SPELL_FREEDOM_OF_MOVEMENT);
|
||||
BuffCastSpell(SPELL_FREEDOM_OF_MOVEMENT);
|
||||
|
||||
// Low durations (Rounds per caster level)
|
||||
// if(!BuffCastSpell(SPELL_ELEMENTAL_SHIELD))
|
||||
// BuffCastSpell(SPELL_WOUNDING_WHISPERS);
|
||||
// BuffCastSpell(SPELL_DEATH_ARMOR);
|
||||
|
||||
|
||||
//Summon Ally.
|
||||
@@ -125,13 +143,13 @@ void main()
|
||||
{
|
||||
// 8, 7, 6, 5.
|
||||
for(nCnt = SPELL_SUMMON_CREATURE_VIII;
|
||||
(nCnt >= SPELL_SUMMON_CREATURE_V && iBreak != TRUE);
|
||||
(nCnt >= SPELL_SUMMON_CREATURE_V && bBreak != TRUE);
|
||||
nCnt--)
|
||||
{
|
||||
if(BuffCastSpell(nCnt)) iBreak = TRUE;
|
||||
if(BuffCastSpell(nCnt)) bBreak = TRUE;
|
||||
}
|
||||
// Then undead
|
||||
if(iBreak != TRUE)
|
||||
if(bBreak != TRUE)
|
||||
{
|
||||
if(!BuffCastSpell(SPELL_CREATE_GREATER_UNDEAD))
|
||||
{
|
||||
@@ -141,7 +159,7 @@ void main()
|
||||
{
|
||||
// Lastly, the 4-1 ones.
|
||||
for(nCnt = SPELL_SUMMON_CREATURE_IV;
|
||||
(nCnt >= SPELL_SUMMON_CREATURE_I);
|
||||
nCnt >= SPELL_SUMMON_CREATURE_I;
|
||||
nCnt--)
|
||||
{
|
||||
if(BuffCastSpell(nCnt)) break;
|
||||
@@ -159,11 +177,11 @@ void main()
|
||||
}
|
||||
|
||||
// Wrapper, to stop repeating the same lines! :-)
|
||||
int BuffCastSpell(int iSpell)
|
||||
int BuffCastSpell(int nSpell)
|
||||
{
|
||||
if(GetHasSpell(iSpell))
|
||||
if(GetHasSpell(nSpell))
|
||||
{
|
||||
ActionCastSpellAtObject(iSpell, OBJECT_SELF, METAMAGIC_ANY, FALSE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
ActionCastSpellAtObject(nSpell, OBJECT_SELF, METAMAGIC_ANY, FALSE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
@@ -1,35 +1,36 @@
|
||||
/************************ [On Heartbeat - Move Nearer PC] **********************
|
||||
Filename: j_ai_heart_serch
|
||||
************************* [On Heartbeat - Move Nearer PC] **********************
|
||||
/*/////////////////////// [On Heartbeat - Move Nearer PC] //////////////////////
|
||||
Filename: J_AI_Heart_Serch
|
||||
///////////////////////// [On Heartbeat - Move Nearer PC] //////////////////////
|
||||
This is fired to perform moving nearer the PC, or searching towards them.
|
||||
|
||||
Yes, like the Henchmen and Battle AI code. I am sure they won't mind - if
|
||||
they do, I will remove it :-)
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Reformatted as with the rest of the AI
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This makes the NPC move nearer to a PC. Fires if the spawn condition
|
||||
is on and the timer is not, and only 1/4 heartbeats to lessen the effect.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A
|
||||
************************* [On Heartbeat - Move Nearer PC] *********************/
|
||||
///////////////////////// [On Heartbeat - Move Nearer PC] ////////////////////*/
|
||||
|
||||
#include "j_inc_constants"
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
|
||||
if(GetIsObjectValid(oPC) && GetIsEnemy(oPC) &&
|
||||
GetDistanceToObject(oPC) <
|
||||
IntToFloat(GetBoundriedAIInteger(AI_SEARCH_IF_ENEMIES_NEAR_RANGE, i25, i50, i5)))
|
||||
IntToFloat(GetBoundriedAIInteger(AI_SEARCH_IF_ENEMIES_NEAR_RANGE, 25, 50, 5)))
|
||||
{
|
||||
vector vPC = GetPosition(oPC);
|
||||
// Whats the distance we use to move a bit nearer?
|
||||
int iRandom = i10 + Random(i10);
|
||||
int nRandom = 10 + Random(10);
|
||||
// Randomise a point nearby.
|
||||
vPC.x += IntToFloat(iRandom - (Random(i2 * iRandom + i1)));
|
||||
vPC.y += IntToFloat(iRandom - (Random(i2 * iRandom + i1)));
|
||||
vPC.z += IntToFloat(iRandom - (Random(i2 * iRandom + i1)));
|
||||
vPC.x += IntToFloat(nRandom - (Random(2 * nRandom + 1)));
|
||||
vPC.y += IntToFloat(nRandom - (Random(2 * nRandom + 1)));
|
||||
vPC.z += IntToFloat(nRandom - (Random(2 * nRandom + 1)));
|
||||
// Define the location
|
||||
location lNew = Location(GetArea(oPC), vPC, IntToFloat(Random(359)));
|
||||
SetLocalTimer(AI_TIMER_SEARCHING, GetDistanceToObject(oPC));
|
||||
|
332
_module/nss/j_ai_onblocked.nss
Normal file
332
_module/nss/j_ai_onblocked.nss
Normal file
@@ -0,0 +1,332 @@
|
||||
/*/////////////////////// [On Blocked] /////////////////////////////////////////
|
||||
Filename: J_AI_OnBlocked or nw_c2_defaulte
|
||||
///////////////////////// [On Blocked] /////////////////////////////////////////
|
||||
Added in user defined constant - won't open any doors.
|
||||
0 = Default (even if not set) opens as appropriate
|
||||
1 = Always bashes the door.
|
||||
2 = Never open any doors
|
||||
3 = Never opens plot doors
|
||||
|
||||
They will: (int is intellgience needed)
|
||||
1. Open if not trapped (7 int)
|
||||
2. Unlock if possible, and rank is high enough, and it needs no key and is not trapped (7 int)
|
||||
3. Untrap the door, if possible, if trapped (7 int)
|
||||
4. Else, if has high enough stats, try Knock. (10 int)
|
||||
6. Else Equip appropriate weapons and bash (5 int)
|
||||
|
||||
Note: This also fires for blocking via. creatures. It is optimised, and
|
||||
works by re-targeting and doing a few small things to do with blocking.
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.0 - Opens with Knock. Unlocks door. Ignores trapped doors.
|
||||
1.3 - Debug messages.
|
||||
- New events, even if the change of using them is small!
|
||||
- No ClearAllactions so any previous movings will carry on once the door is gone.
|
||||
- Removed debug messages
|
||||
- Added Creature reaction code
|
||||
1.4 - Need to add a "hands" check (done on spawn, to set a setting to not
|
||||
open doors at all, IE: We do NOT have hands, do not open doors), so
|
||||
its a little more realistic "out of the box"
|
||||
- Fixed an instance of GetObjectSeen being repeated.
|
||||
- Fixed the variable AI_DOOR_INTELLIGENCE not being got via GetAIInteger().
|
||||
- Removed unneeded else statement.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Uses simple code to deal with a door in the best way possible.
|
||||
|
||||
Uses DoDoorAction, which is added to the top of an action queue and doesn't,
|
||||
therefore, delete any ActionAttack's and so on below it. (Or I hope it
|
||||
is like this)
|
||||
|
||||
Creatures are reacted by with ClearAllActions usually.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetBlockingDoor, GetIsDoorActionPossible, GetLocked, GetLockKeyRequired
|
||||
GetLockKeyTag, GetLockUnlockDC, GetPlotFlag, DoDoorAction
|
||||
///////////////////////// [On Blocked] ///////////////////////////////////////*/
|
||||
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
// Fires the end-blocked event.
|
||||
void FireBlockedEvent();
|
||||
// Range attack oTarget.
|
||||
int RangedAttack(object oTarget = OBJECT_INVALID);
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-on blocked-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_ON_BLOCKED_PRE_EVENT, EVENT_ON_BLOCKED_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
// This CAN return a blocking creature.
|
||||
object oBlocker = GetBlockingDoor();
|
||||
int nBlockerType = GetObjectType(oBlocker);
|
||||
|
||||
if(!GetIsObjectValid(oBlocker)) return;
|
||||
|
||||
// Anyone blocked by an enemy will re-target them (and attack them), blocked
|
||||
// by someone they cannot get they will cast seeing spells and react, and if
|
||||
// blocked by a friend, they may run back and use a ranged weapon if they
|
||||
// have one.
|
||||
if(nBlockerType == OBJECT_TYPE_CREATURE)
|
||||
{
|
||||
// Are we doing something that should not be overriden? (even fleeing,
|
||||
// if stuck, we can't do anything else then move again on heartbeat!)
|
||||
if(GetIsPerformingSpecialAction()) return;
|
||||
|
||||
// Blocked timer, we normally do an action. A small timer stops a lot
|
||||
// of lag.
|
||||
if(GetLocalTimer(AI_TIMER_BLOCKED)) return;
|
||||
|
||||
// Set the timer for 1 second
|
||||
SetLocalTimer(AI_TIMER_BLOCKED, 1.0);
|
||||
|
||||
// Is it an enemy?
|
||||
if(GetIsEnemy(oBlocker))
|
||||
{
|
||||
// Check if seen or heard
|
||||
if(GetObjectSeen(oBlocker) || GetObjectHeard(oBlocker))
|
||||
{
|
||||
// Enemy :-) We can re-target (as know of thier presence), using
|
||||
// them as a target.
|
||||
// - This overrides even casting a spell - basically, as we should
|
||||
// be moving, this will re-cast it at someone or something in range
|
||||
SetAIObject(AI_ATTACK_SPECIFIC_OBJECT, oBlocker);
|
||||
|
||||
// Check if we can do combat - if we cannot, we can re-do combat
|
||||
// next time
|
||||
if(!GetIsBusyWithAction())
|
||||
{
|
||||
// Attacks if we are not attacking
|
||||
ClearAllActions();
|
||||
DetermineCombatRound(oBlocker);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invisible? Not there? Some odd error? We set that we know of
|
||||
// someone invisible, and will attack if not in combat.
|
||||
if(GetHasEffect(EFFECT_TYPE_INVISIBILITY, oBlocker) ||
|
||||
GetStealthMode(oBlocker) == STEALTH_MODE_ACTIVATED)
|
||||
{
|
||||
SetAIObject(AI_LAST_TO_GO_INVISIBLE, oBlocker);
|
||||
}
|
||||
// Shout to allies
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
// Check if we can do combat
|
||||
if(!GetIsBusyWithAction())
|
||||
{
|
||||
// Attacks if we are not attacking
|
||||
ClearAllActions();
|
||||
DetermineCombatRound();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Else is non-enemy, a friend or neutral
|
||||
else
|
||||
{
|
||||
// As we are blocked by them, we re-do combat - we have a choice of
|
||||
// either using a Bow to attack our target (if that was what
|
||||
// we were doing) and move back a little, or re-initiate combat
|
||||
|
||||
// Were we attacking in combat?
|
||||
object oPrevious = GetAttackTarget();
|
||||
|
||||
// Check action
|
||||
if(GetCurrentAction() == ACTION_ATTACKOBJECT)
|
||||
{
|
||||
// This gets set to FALSE if we can cutthrough attack,
|
||||
// or whatever.
|
||||
|
||||
int bPreviousAttackFailed = FALSE;
|
||||
// Check if we can see our previous target
|
||||
if(GetObjectSeen(oPrevious) ||
|
||||
(GetObjectHeard(oPrevious) && LineOfSightObject(OBJECT_SELF, oPrevious)))
|
||||
{
|
||||
// We can! see if we can re-attack with ranged weapon, else
|
||||
// doesn't matter we can see them
|
||||
bPreviousAttackFailed = RangedAttack(oPrevious);
|
||||
}
|
||||
|
||||
// If we havn't added an action yet...
|
||||
if(bPreviousAttackFailed == FALSE)
|
||||
{
|
||||
// We have not stopped the script - so determine combat
|
||||
// round against nearest seen or heard enemy!
|
||||
if(!RangedAttack())
|
||||
{
|
||||
// Else normal round to try and get a new target
|
||||
ClearAllActions();
|
||||
DetermineCombatRound();
|
||||
}
|
||||
}
|
||||
// Action attack, normally means melee attack. If we can, we
|
||||
// attack our previous target if seen, ELSE we will re-initate
|
||||
// combat.
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
|
||||
// Fire the On blocked event as normal
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
else // if(nAction == ACTION_CASTSPELL and others)
|
||||
{
|
||||
// Reinitate combat, but don't attack oPrevious
|
||||
ClearAllActions();
|
||||
DetermineCombatRound();
|
||||
|
||||
// Action attack, normally means melee attack. If we can, we
|
||||
// attack our previous target if seen, ELSE we will re-initate
|
||||
// combat.
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
|
||||
// Fire the On blocked event as normal
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Placeable - Currently not returned, however, added just in case!
|
||||
else if(nBlockerType == OBJECT_TYPE_PLACEABLE)
|
||||
{
|
||||
// Check for plot, and therefore attack it to bring it down.
|
||||
// - Remember, ActionAttack will re-initiate when combat round fires
|
||||
// again in 3 or 6 seconds (or less, if we just were moving)
|
||||
if(!GetPlotFlag(oBlocker) &&
|
||||
GetIsPlaceableObjectActionPossible(oBlocker, PLACEABLE_ACTION_BASH))
|
||||
{
|
||||
// Do placeable action
|
||||
DoPlaceableObjectAction(oBlocker, PLACEABLE_ACTION_BASH);
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Door behaviour
|
||||
else if(nBlockerType == OBJECT_TYPE_DOOR)
|
||||
{
|
||||
int nDoorIntelligence = GetAIInteger(AI_DOOR_INTELLIGENCE);
|
||||
int nInt = GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE);
|
||||
if(nDoorIntelligence == 1)// 1 = Always bashes the doors, plot, locked or anything.
|
||||
{
|
||||
DoDoorAction(oBlocker, DOOR_ACTION_BASH);
|
||||
// We re-initiate combat.
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
else if(nDoorIntelligence == 2)// 2 = Never open anything, bashing or not.
|
||||
{
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
else if(nDoorIntelligence == 3)// 3 = Never tries anything against plot doors.
|
||||
{
|
||||
if(GetPlotFlag(oBlocker))
|
||||
{
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(nInt >= 5)
|
||||
{
|
||||
// Need some intelligence :-)
|
||||
if(nInt >= 7)
|
||||
{
|
||||
// Right, first, we may...shock...open it!!!
|
||||
// Checks Key, lock, trap and if the action is possible.
|
||||
if(GetIsDoorActionPossible(oBlocker, DOOR_ACTION_OPEN) &&
|
||||
!GetLocked(oBlocker) &&
|
||||
!GetIsTrapped(oBlocker) &&
|
||||
(!GetLockKeyRequired(oBlocker) ||
|
||||
(GetLockKeyRequired(oBlocker) && GetItemPossessor(GetObjectByTag(GetLockKeyTag(oBlocker))) == OBJECT_SELF)))
|
||||
{
|
||||
DoDoorAction(oBlocker, DOOR_ACTION_OPEN);
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
// Unlock it with the skill, if it is not trapped and we can :-P
|
||||
// We take 20 off the door DC, thats our minimum roll, after all.
|
||||
if(GetLocked(oBlocker) &&
|
||||
!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER) &&
|
||||
!GetLockKeyRequired(oBlocker) && GetHasSkill(SKILL_OPEN_LOCK) &&
|
||||
GetIsDoorActionPossible(oBlocker, DOOR_ACTION_UNLOCK) && !GetIsTrapped(oBlocker) &&
|
||||
(GetSkillRank(SKILL_OPEN_LOCK) >= (GetLockLockDC(oBlocker) - 20)))
|
||||
{
|
||||
DoDoorAction(oBlocker, DOOR_ACTION_UNLOCK);
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
// Specilist thing - knock
|
||||
if(nInt >= 10)
|
||||
{
|
||||
if((GetIsDoorActionPossible(oBlocker, DOOR_ACTION_KNOCK)) &&
|
||||
GetLockUnlockDC(oBlocker) <= 25 &&
|
||||
!GetLockKeyRequired(oBlocker) && GetHasSpell(SPELL_KNOCK))
|
||||
{
|
||||
DoDoorAction(oBlocker, DOOR_ACTION_KNOCK);
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If Our Int is over 5, we will bash after everything else.
|
||||
if(GetIsDoorActionPossible(oBlocker, DOOR_ACTION_BASH) && !GetPlotFlag(oBlocker))
|
||||
{
|
||||
if(GetAttackTarget() != oBlocker)
|
||||
{
|
||||
DoDoorAction(oBlocker, DOOR_ACTION_BASH);
|
||||
}
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fire Blocked event
|
||||
FireBlockedEvent();
|
||||
}
|
||||
// Fires the end-blocked event.
|
||||
void FireBlockedEvent()
|
||||
{
|
||||
// Fire End-blocked-UDE
|
||||
FireUserEvent(AI_FLAG_UDE_ON_BLOCKED_EVENT, EVENT_ON_BLOCKED_EVENT);
|
||||
}
|
||||
// Range attack oTarget.
|
||||
int RangedAttack(object oTarget)
|
||||
{
|
||||
// If we are primarily melee, don't use this
|
||||
if(!GetSpawnInCondition(AI_FLAG_COMBAT_BETTER_AT_HAND_TO_HAND, AI_COMBAT_MASTER)) return FALSE;
|
||||
|
||||
object oRangedTarget = oTarget;
|
||||
if(!GetIsObjectValid(oRangedTarget))
|
||||
{
|
||||
oRangedTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
if(!GetIsObjectValid(oTarget))
|
||||
{
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
// heard must be in LOS to attack, as we are probably stuck
|
||||
if(!GetIsObjectValid(oTarget) && LineOfSightObject(OBJECT_SELF, oRangedTarget))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ranged weapon attack against oTarget
|
||||
// doesn't matter we can see them
|
||||
object oRanged = GetAIObject(AI_WEAPON_RANGED);
|
||||
int nAmmo = GetAIInteger(AI_WEAPON_RANGED_AMMOSLOT);
|
||||
|
||||
// Check ammo and validness
|
||||
if(GetIsObjectValid(oRanged) && (nAmmo == INVENTORY_SLOT_RIGHTHAND ||
|
||||
GetIsObjectValid(GetItemInSlot(nAmmo))))
|
||||
{
|
||||
// Attack with it
|
||||
ClearAllActions();
|
||||
ActionEquipItem(oRanged, INVENTORY_SLOT_RIGHTHAND);
|
||||
ActionAttack(oRangedTarget);
|
||||
// Stop
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
37
_module/nss/j_ai_oncombatrou.nss
Normal file
37
_module/nss/j_ai_oncombatrou.nss
Normal file
@@ -0,0 +1,37 @@
|
||||
/*/////////////////////// [On Combat Round End] ////////////////////////////////
|
||||
Filename: nw_c2_default3 or J_AI_OnCombatrou
|
||||
///////////////////////// [On Combat Round End] ////////////////////////////////
|
||||
This is run every 3 or 6 seconds, if the creature is in combat. It is
|
||||
executed only in combat automatically.
|
||||
|
||||
It runs what the AI should do, bascially.
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Executes same script as the other parts of the AI to cuase a new action
|
||||
1.4 -
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Calls the combat AI file using the J_INC_OTHER_AI include function,
|
||||
DetermineCombatRound.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetAttackTarget, GetLastHostileActor, GetAttemptedAttackTarget,
|
||||
GetAttemptedSpellTarget (Or these are useful at least!)
|
||||
///////////////////////// [On Combat Round End] //////////////////////////////*/
|
||||
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-combat-round-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_END_COMBAT_ROUND_PRE_EVENT, EVENT_END_COMBAT_ROUND_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
// It is our normal call (every 3 or 6 seconds, when we can change actions)
|
||||
// so no need to delete, and we fire the UDE's.
|
||||
|
||||
// Determine combat round against an invalid target (as default)
|
||||
DetermineCombatRound();
|
||||
|
||||
// Fire End of end combat round event
|
||||
FireUserEvent(AI_FLAG_UDE_END_COMBAT_ROUND_EVENT, EVENT_END_COMBAT_ROUND_EVENT);
|
||||
}
|
160
_module/nss/j_ai_onconversat.nss
Normal file
160
_module/nss/j_ai_onconversat.nss
Normal file
@@ -0,0 +1,160 @@
|
||||
/*/////////////////////// [On Conversation] ////////////////////////////////////
|
||||
Filename: J_AI_OnConversat or nw_c2_default4
|
||||
///////////////////////// [On Conversation] ////////////////////////////////////
|
||||
OnConversation/ Listen to shouts.
|
||||
Documented, and checked. -Working-
|
||||
|
||||
Added spawn in condition - Never clear actions when talking.
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added in conversation thing - IE we can set speakstrings, no need for conversation file.
|
||||
- Sorted more shouts out.
|
||||
- Should work right, and not cause too many actions (as we ignore
|
||||
shouts for normally 12 or so seconds before letting them affect us again).
|
||||
1.4 - Deafness incorpreated.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Uses RespondToShout to react to allies' shouts, and just attacks any enemy
|
||||
who speaks, or at least moves to them. (OK, dumb if they are invisible, but
|
||||
oh well, they shouldn't talk so loud!)
|
||||
|
||||
Remember, whispers are never heard if too far away, speakstrings don't go
|
||||
through walls, and shouts are always heard (so we don't go off to anyone
|
||||
not in our area, remember)
|
||||
|
||||
Deafness causes us to never hear battle, so unless we see the target speaking
|
||||
we do not react. Doesn't apply to normal conversations - although if we cannot
|
||||
talk (also restricted by deafness) then so be it.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetListenPatternNumber, GetLastSpeaker, TestStringAgainstPattern,
|
||||
GetMatchedSubstring
|
||||
///////////////////////// [On Conversation] //////////////////////////////////*/
|
||||
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-conversation-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_ON_DIALOGUE_PRE_EVENT, EVENT_ON_DIALOGUE_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
// Declarations
|
||||
int nMatch = GetListenPatternNumber();
|
||||
object oShouter = GetLastSpeaker();
|
||||
string sSpoken = GetMatchedSubstring(0);
|
||||
|
||||
// We can ignore everything under special cases - EG no valid shouter,
|
||||
// we are fleeing, its us, or we are not in the same area.
|
||||
// - We break out of the script if this happens.
|
||||
if(!GetIsObjectValid(oShouter) || /* Must be a valid speaker! */
|
||||
oShouter == OBJECT_SELF || /* Not us! */
|
||||
GetIsPerformingSpecialAction() || /* Not fleeing */
|
||||
GetIgnore(oShouter) || /* Not ignoring the shouter */
|
||||
GetArea(oShouter) != GetArea(OBJECT_SELF))/* Same area (Stops loud yellow shouts getting NPCs) */
|
||||
{
|
||||
// Fire End of Dialogue event
|
||||
FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_EVENT, EVENT_ON_DIALOGUE_EVENT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Conversation if not a shout.
|
||||
if(nMatch == -1)
|
||||
{
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
// Make sure it is a PC and we are not fighting.
|
||||
if(!GetIsFighting() && (GetIsPC(oShouter) || GetIsDMPossessed(oShouter)))
|
||||
{
|
||||
// If we have something random (or not) to say instead of
|
||||
// the conversation, we will say that.
|
||||
if(GetLocalInt(OBJECT_SELF, ARRAY_SIZE + AI_TALK_ON_CONVERSATION))
|
||||
{
|
||||
ClearAllActions();// Stop
|
||||
SetFacingPoint(GetPosition(oShouter));// Face
|
||||
SpeakArrayString(AI_TALK_ON_CONVERSATION);// Speak string
|
||||
PlayAnimation(ANIMATION_LOOPING_TALK_NORMAL, 1.0, 3.0);// "Talk", then resume potitions.
|
||||
ActionDoCommand(ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF));
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are set to NOT clear all actions, we won't.
|
||||
if(!GetSpawnInCondition(AI_FLAG_OTHER_NO_CLEAR_ACTIONS_BEFORE_CONVERSATION, AI_OTHER_MASTER))
|
||||
{
|
||||
ClearAllActions();
|
||||
}
|
||||
BeginConversation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If it is a valid shout...and a valid shouter.
|
||||
// - Not a DM. Not ignoring shouting. Not a Debug String.
|
||||
else if(!GetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID) &&// Not listening (IE heard already)
|
||||
!GetIsDM(oShouter) && FindSubString(sSpoken, "[Debug]") == -1 &&
|
||||
// 1.4 - Deafness (or they are seen) check, for fun.
|
||||
(!GetHasEffect(EFFECT_TYPE_DEAF) || GetObjectSeen(oShouter)))
|
||||
{
|
||||
if(GetIsFriend(oShouter) || GetFactionEqual(oShouter))
|
||||
{
|
||||
// If they are a friend, not a PC, and a valid number, react.
|
||||
// In the actual RespondToShout call, we do check to see if we bother.
|
||||
// - Is PC - or is...master?
|
||||
// - Shouts which are not negative, and not AI_ANYTHING_SAID_CONSTANT.
|
||||
if(nMatch >= 0 && nMatch != AI_SHOUT_ANYTHING_SAID_CONSTANT &&
|
||||
!GetIsPC(oShouter) && !GetIsPC(GetMaster(oShouter)))
|
||||
{
|
||||
// Respond to the shout
|
||||
RespondToShout(oShouter, nMatch);
|
||||
}
|
||||
// Else either is PC or is shout 0 (everything!)
|
||||
// - not if we are in combat, or they are not.
|
||||
else if(!CannotPerformCombatRound() &&
|
||||
GetIsInCombat(oShouter) &&
|
||||
GetObjectType(oShouter) == OBJECT_TYPE_CREATURE)
|
||||
{
|
||||
// 57: "[Shout] Friend (may be PC) in combat. Attacking! [Friend] " + GetName(oShouter)
|
||||
DebugActionSpeakByInt(57, oShouter);
|
||||
|
||||
// Respond to oShouter
|
||||
IWasAttackedResponse(oShouter);
|
||||
}
|
||||
}
|
||||
else if(GetIsEnemy(oShouter) && GetObjectType(oShouter) == OBJECT_TYPE_CREATURE)
|
||||
{
|
||||
// If we hear anything said by an enemy, and are not fighting, attack them!
|
||||
if(!CannotPerformCombatRound())
|
||||
// the negatives are associate shouts, Normally (!)
|
||||
// 0+ are my shouts. 0 is anything
|
||||
{
|
||||
// We make sure it isn't an emote (set by default)
|
||||
if(nMatch == AI_SHOUT_ANYTHING_SAID_CONSTANT &&
|
||||
GetSpawnInCondition(AI_FLAG_OTHER_DONT_RESPOND_TO_EMOTES, AI_OTHER_MASTER))
|
||||
{
|
||||
// Jump out if its an emote - "*Nods*"
|
||||
if(GetStringLeft(sSpoken, 1) == EMOTE_STAR &&
|
||||
GetStringRight(sSpoken, 1) == EMOTE_STAR)
|
||||
{
|
||||
// Fire End of Dialogue event
|
||||
FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_EVENT, EVENT_ON_DIALOGUE_EVENT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 58: "[Shout] Responding to shout [Enemy] " + GetName(oShouter) + " Who has spoken!"
|
||||
DebugActionSpeakByInt(58, oShouter);
|
||||
|
||||
// Short non-respond
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0);
|
||||
|
||||
// Attack the enemy!
|
||||
ClearAllActions();
|
||||
DetermineCombatRound(oShouter);
|
||||
|
||||
// Shout to allies to attack the shouter
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fire End of Dialogue event
|
||||
FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_EVENT, EVENT_ON_DIALOGUE_EVENT);
|
||||
}
|
241
_module/nss/j_ai_ondamaged.nss
Normal file
241
_module/nss/j_ai_ondamaged.nss
Normal file
@@ -0,0 +1,241 @@
|
||||
/*/////////////////////// [On Damaged] /////////////////////////////////////////
|
||||
Filename: nw_c2_default6 or J_AI_OnDamaged
|
||||
///////////////////////// [On Damaged] /////////////////////////////////////////
|
||||
We attack any damager if same area (and not already fighting
|
||||
then search for enemies (defaults to searching if there are no enemies left).
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - If we have a damager, not equal faction, and not a DM...
|
||||
- We set Max Elemental damage.
|
||||
- Sets the highest damager and amount (if the new damager is seen/heard)
|
||||
- Polymorph improved a little
|
||||
- Hide check
|
||||
- Morale penalty (if set)
|
||||
1.4 - Elemental damage fixed with bugfixed introduced in later patches.
|
||||
- Moved things around, more documentation, a little more ordered.
|
||||
- Added the missing silent shout strings to get allies to attack.
|
||||
- Damaged taunting will not happen if we are dead.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Now with fixes, we can correctly set physical damage done (and elemental
|
||||
damage).
|
||||
|
||||
Otherwise, this acts like a hositile spell, or a normal attack or pickpocket
|
||||
attempt would - and attack the damn person who dares damage us!
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetTotalDamageDealt, GetLastDamager, GetCurrentHitPoints (and max),
|
||||
GetDamageDealtByType (must be done seperatly for each, doesn't count melee damage)
|
||||
///////////////////////// [On Damaged] ///////////////////////////////////////*/
|
||||
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-damaged-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_DAMAGED_PRE_EVENT, EVENT_DAMAGED_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
// Define Objects/Integers.
|
||||
int nDamage = GetTotalDamageDealt();
|
||||
object oDamager = GetLastDamager();
|
||||
// Check to see if we will polymorph.
|
||||
int nPolymorph = GetAIConstant(AI_POLYMORPH_INTO);
|
||||
|
||||
// Total up the physical damage
|
||||
|
||||
// Polymorph check.
|
||||
if(nPolymorph >= 0)
|
||||
{
|
||||
// We won't polymorph if already so
|
||||
if(!GetHasEffect(EFFECT_TYPE_POLYMORPH))
|
||||
{
|
||||
// Polymorph into the requested shape. Cannot be dispelled.
|
||||
effect eShape = SupernaturalEffect(EffectPolymorph(nPolymorph));
|
||||
effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD);
|
||||
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eShape, OBJECT_SELF));
|
||||
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF));
|
||||
}
|
||||
DeleteAIConstant(AI_POLYMORPH_INTO);// We set it to invalid (sets to 0).
|
||||
}
|
||||
// First, we check AOE spells...
|
||||
if(GetObjectType(oDamager) == OBJECT_TYPE_AREA_OF_EFFECT)
|
||||
{
|
||||
// Set the damage done by it (the last damage)
|
||||
// Set to the tag of the AOE, prefixed AI style to be sure.
|
||||
// - Note, doesn't matter about things like
|
||||
if(nDamage > 0)
|
||||
{
|
||||
// Set it to object to string, which we will delete later anywho.
|
||||
SetAIInteger(ObjectToString(oDamager), nDamage);
|
||||
}
|
||||
}
|
||||
// Hostile attacker...but it doesn't matter (at the moment) if they even
|
||||
// did damage.
|
||||
// * GetIgnoreNoFriend() wrappers DM, Validity, Faction Equal and Dead checks in one
|
||||
else if(!GetIgnoreNoFriend(oDamager))
|
||||
{
|
||||
// Adjust automatically if set. (and not an AOE)
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER))
|
||||
{
|
||||
if(!GetIsEnemy(oDamager) && !GetFactionEqual(oDamager))
|
||||
{
|
||||
AdjustReputation(oDamager, OBJECT_SELF, -100);
|
||||
}
|
||||
}
|
||||
|
||||
// Turn of hiding, a timer to activate Hiding in the main file. This is
|
||||
// done in each of the events, with the opposition checking seen/heard.
|
||||
TurnOffHiding(oDamager);
|
||||
|
||||
// Did they do damage to use? (IE: No DR) Some things are inapproprate
|
||||
// to check if no damage was actually done.
|
||||
if(nDamage > 0)
|
||||
{
|
||||
// Speak the damaged string, if applicable.
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
SpeakArrayString(AI_TALK_ON_DAMAGED);
|
||||
}
|
||||
// 1.4 note: These two variables are currently *unused* apart from
|
||||
// healing. When healing a being (even another NPC) they are checked
|
||||
// for massive damage. Can not bother to set the highest damager for now.
|
||||
// NEW:
|
||||
int nHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT);
|
||||
if(nDamage >= nHighestDamage)
|
||||
{
|
||||
SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, nDamage);
|
||||
}
|
||||
|
||||
/* OLD:
|
||||
|
||||
// Get the previous highest damager, and highest damage amount
|
||||
object oHighestDamager = GetAIObject(AI_HIGHEST_DAMAGER);
|
||||
int nHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT);
|
||||
// Set the highest damager, if they are seen or heard, and have done loads.
|
||||
if((GetObjectSeen(oDamager) || GetObjectHeard(oDamager)) &&
|
||||
nDamage >= nHighestDamage || !GetIsObjectValid(oHighestDamager))
|
||||
{
|
||||
SetAIObject(AI_HIGHEST_DAMAGER, oDamager);
|
||||
SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, nDamage);
|
||||
}
|
||||
// Else, if the original was not valid...or not seen/heard, we
|
||||
// delete it so we don't bother to use it later.
|
||||
else if(!GetIsObjectValid(oHighestDamager) ||
|
||||
(!GetObjectSeen(oHighestDamager) && !GetObjectHeard(oHighestDamager)))
|
||||
{
|
||||
DeleteAIObject(AI_HIGHEST_DAMAGER);
|
||||
DeleteAIInteger(AI_HIGHEST_DAMAGE_AMOUNT);
|
||||
}
|
||||
*/
|
||||
|
||||
// Get all the physical damage. Elemental damage is then nDamage minus
|
||||
// the physical damage.
|
||||
int nPhysical = GetDamageDealtByType(DAMAGE_TYPE_BASE_WEAPON |
|
||||
DAMAGE_TYPE_BLUDGEONING |
|
||||
DAMAGE_TYPE_PIERCING |
|
||||
DAMAGE_TYPE_SLASHING);
|
||||
// If they are all -1, then we make nPhysical 0.
|
||||
if(nPhysical <= -1) nPhysical = 0;
|
||||
|
||||
// Physical damage - only sets if the last damager is the last attacker.
|
||||
if(GetAIObject(AI_STORED_LAST_ATTACKER) == oDamager)
|
||||
{
|
||||
// Get the previous highest damage and test it
|
||||
if(nPhysical > GetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT))
|
||||
{
|
||||
// If higher, and was a melee/ranged attacker, set it.
|
||||
// This does include other additional physical damage - EG:
|
||||
// weapon property: Bonus Damage.
|
||||
SetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT, nPhysical);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the max elemental damage done, for better use of elemental
|
||||
// protections. This is set for the most damage...so it could be
|
||||
// 1 (for a +1 fire weapon, any number of hits) or over 50 (good
|
||||
// fireball/flame storm etc.)
|
||||
int nElemental = nDamage - nPhysical;
|
||||
if(nElemental > GetAIInteger(MAX_ELEMENTAL_DAMAGE))
|
||||
{
|
||||
SetAIInteger(MAX_ELEMENTAL_DAMAGE, nElemental);
|
||||
}
|
||||
// Set the last damage done, may set to 0 of course :-P
|
||||
// * This is only set if they did damage us at all, however.
|
||||
SetAIInteger(LAST_ELEMENTAL_DAMAGE, nElemental);
|
||||
|
||||
// Morale: We may get a penalty if it does more than a cirtain amount of HP damage.
|
||||
// Other: We set highest damager and amount.
|
||||
if(!GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER))
|
||||
{
|
||||
// Get penalty and how much damage at once needs to be done
|
||||
int nPenalty = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_PENALTY, 6, 50, 1);
|
||||
int nToDamage = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_FOR_MORALE_PENALTY, GetMaxHitPoints()/6, GetMaxHitPoints(), 1);
|
||||
if(nDamage > nToDamage)
|
||||
{
|
||||
// 61: "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(iPenalty)
|
||||
DebugActionSpeakByInt(61, OBJECT_INVALID, nPenalty);
|
||||
// Apply penalty
|
||||
SetMoralePenalty(nPenalty, 300.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we are not attacking anything, and not in combat, react!
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// 62: "[Damaged] Not in combat: DCR [Damager]" + GetName(oDamager)
|
||||
DebugActionSpeakByInt(62, oDamager);
|
||||
|
||||
// Check if they are in the same area. Can be a left AOE spell.
|
||||
// Don't attack purposly across area's.
|
||||
if(GetArea(oDamager) == GetArea(OBJECT_SELF))
|
||||
{
|
||||
// Shout to allies to attack the enemy who attacked me
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
|
||||
DetermineCombatRound(oDamager);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
DetermineCombatRound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
// Else it is friendly, or invalid damager
|
||||
else
|
||||
{
|
||||
// Still will react - eg: A left AOE spell (which might mean a battle
|
||||
// just happened)
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Shout to allies to attack generally. No target to specifically attack,
|
||||
// as it is an ally.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
// 63: [Damaged] Not in combat: DCR. Ally hit us. [Damager(Ally?)]" + GetName(oDamager)
|
||||
DebugActionSpeakByInt(63, oDamager);
|
||||
DetermineCombatRound();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
// User defined event - for normally immoral creatures.
|
||||
if(GetCurrentHitPoints() == 1)
|
||||
{
|
||||
// Fire the immortal damaged at 1 HP event.
|
||||
FireUserEvent(AI_FLAG_UDE_DAMAGED_AT_1_HP, EVENT_DAMAGED_AT_1_HP);
|
||||
}
|
||||
// Fire End of Damaged event
|
||||
FireUserEvent(AI_FLAG_UDE_DAMAGED_EVENT, EVENT_DAMAGED_EVENT);
|
||||
}
|
164
_module/nss/j_ai_ondeath.nss
Normal file
164
_module/nss/j_ai_ondeath.nss
Normal file
@@ -0,0 +1,164 @@
|
||||
/*/////////////////////// [On Death] ///////////////////////////////////////////
|
||||
Filename: J_AI_OnDeath or nw_c2_default7
|
||||
///////////////////////// [On Death] ///////////////////////////////////////////
|
||||
Speeded up no end, when compiling, with seperate Include.
|
||||
Cleans up all un-droppable items, all ints and all local things when destroyed.
|
||||
|
||||
Check down near the bottom for a good place to add XP or corpse lines ;-)
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added in Turn of corpses toggle
|
||||
- Added in appropriate space for XP awards, marked with ideas (effect death)
|
||||
1.4 - Removed the redudnant notes on the "You have gained 0 experience" message
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
You can edit this for experience, there is a seperate section for it.
|
||||
|
||||
It will use DeathCheck to execute a cleanup-and-destroy script, that removes
|
||||
any coprse, named "j_ai_destroyself".
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetLastKiller.
|
||||
///////////////////////// [On Death] /////////////////////////////////////////*/
|
||||
|
||||
// We only require the constants/debug file. We have 1 function, not worth another include.
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
// We need a wrapper. If the amount of deaths, got in this, is not equal to iDeaths,
|
||||
// we don't execute the script, else we do. :-P
|
||||
void DeathCheck(int nDeaths);
|
||||
|
||||
void main()
|
||||
{
|
||||
// If we are set to, don't fire this script at all
|
||||
if(GetAIInteger(I_AM_TOTALLY_DEAD)) return;
|
||||
|
||||
// Pre-death-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_DEATH_PRE_EVENT, EVENT_DEATH_PRE_EVENT)) return;
|
||||
|
||||
// Note: No AI on/off check here.
|
||||
|
||||
// Who killed us? (alignment changing, debug, XP).
|
||||
object oKiller = GetLastKiller();
|
||||
|
||||
// Stops if we just applied EffectDeath to ourselves.
|
||||
if(GetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH)) return;
|
||||
|
||||
// Special: To stop giving out multiple amounts of XP, we use EffectDeath
|
||||
// to change the killer, so the XP systems will NOT award MORE XP.
|
||||
// - Even the default one suffers from this!
|
||||
if(GetAIInteger(WE_HAVE_DIED_ONCE))
|
||||
{
|
||||
if(!GetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH))
|
||||
{
|
||||
// Don't apply effect death to self more then once per 2 seconds.
|
||||
SetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH, 2.0);
|
||||
// This should make the last killer us.
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), OBJECT_SELF);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(GetMaxHitPoints()), OBJECT_SELF);
|
||||
}
|
||||
}
|
||||
else if(oKiller != OBJECT_SELF)
|
||||
{
|
||||
// Set have died once, stops giving out mulitple amounts of XP.
|
||||
SetAIInteger(WE_HAVE_DIED_ONCE, TRUE);
|
||||
|
||||
/*/////////////////////// [Experience] /////////////////////////////////////////
|
||||
THIS is the place for it, below this comment.
|
||||
|
||||
It is useful to use GetFirstFactionMember (and Next), GiveXPToCreature,
|
||||
GetXP, SetXP, GetChallengeRating (of self) all are really useful.
|
||||
|
||||
Bug note: GetFirstFactionMember/Next with the PC parameter means either ONLY PC,
|
||||
and so NPC henchmen, unless FALSE is used, will not be even recognised.
|
||||
///////////////////////// [Experience] ///////////////////////////////////////*/
|
||||
// Do XP things (Use object "oKiller" for who killed us).
|
||||
|
||||
|
||||
|
||||
/*/////////////////////// [Experience] ///////////////////////////////////////*/
|
||||
}
|
||||
|
||||
// Note: Here we do a simple way of checking how many times we have died.
|
||||
// Nothing special. Debugging most useful aspect.
|
||||
int nDeathCounterNew = GetAIInteger(AMOUNT_OF_DEATHS);
|
||||
nDeathCounterNew++;
|
||||
SetAIInteger(AMOUNT_OF_DEATHS, nDeathCounterNew);
|
||||
|
||||
// Here is the last time (in game seconds) we died. It is used in the executed script
|
||||
// to make sure we don't prematurly remove areselves.
|
||||
|
||||
// We may want some sort of visual effect - like implosion or something, to fire.
|
||||
int nDeathEffect = GetAIConstant(AI_DEATH_VISUAL_EFFECT);
|
||||
|
||||
// Valid constants from 0 and up. Apply to our location (not to us, who will go!)
|
||||
if(nDeathEffect >= 0)
|
||||
{
|
||||
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(nDeathEffect), GetLocation(OBJECT_SELF));
|
||||
}
|
||||
// Default Commoner alignment changing. (If the commoner is not evil!)
|
||||
if(GetLevelByClass(CLASS_TYPE_COMMONER) > 0 &&
|
||||
GetAlignmentGoodEvil(OBJECT_SELF) != ALIGNMENT_EVIL &&
|
||||
!GetSpawnInCondition(AI_FLAG_OTHER_NO_COMMONER_ALIGNMENT_CHANGE, AI_OTHER_MASTER))
|
||||
{
|
||||
if(GetIsPC(oKiller))
|
||||
{
|
||||
AdjustAlignment(oKiller, ALIGNMENT_EVIL, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it is a summon, henchmen or familar of a PC, we adust the PC itself
|
||||
// Clever, eh?
|
||||
object oMaster = GetMaster(oKiller);
|
||||
if(GetIsObjectValid(oMaster) && GetIsPC(oMaster))
|
||||
{
|
||||
AdjustAlignment(oMaster, ALIGNMENT_EVIL, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Always shout when we are killed. Reactions - Morale penalty, and
|
||||
// attack the killer.
|
||||
AISpeakString(AI_SHOUT_I_WAS_KILLED);
|
||||
|
||||
// Speaks the set death speak, like "AGGGGGGGGGGGGGGGGGGG!! NOOOO!" for instance :-)
|
||||
// Note for 1.4: No need for "CanSpeak()" for this, of course.
|
||||
SpeakArrayString(AI_TALK_ON_DEATH);
|
||||
|
||||
// First check - do we use "destroyable corpses" or not? (default, yes)
|
||||
if(!GetSpawnInCondition(AI_FLAG_OTHER_TURN_OFF_CORPSES, AI_OTHER_MASTER))
|
||||
{
|
||||
// We will actually dissapear after 30.0 seconds if not raised.
|
||||
int nTime = GetAIInteger(AI_CORPSE_DESTROY_TIME);
|
||||
if(nTime == 0) // Error checking
|
||||
{
|
||||
nTime = 30;
|
||||
}
|
||||
// 64: "[Death] Checking corpse status in " + IntToString(nTime) + " [Killer] " + GetName(oKiller) + " [Times Died Now] " + IntToString(nDeathCounterNew)
|
||||
DebugActionSpeakByInt(64, oKiller, nTime, IntToString(nDeathCounterNew));
|
||||
// Delay check
|
||||
DelayCommand(IntToFloat(nTime), DeathCheck(nDeathCounterNew));
|
||||
}
|
||||
else
|
||||
{
|
||||
/************************ [Alternative Corpses] ********************************
|
||||
This is where you can add some alternative corpse code - EG looting
|
||||
and so on, without disrupting the rest of the AI (as the corpses
|
||||
are turned off).
|
||||
************************* [Alternative Corpses] *******************************/
|
||||
// Add alternative corpse code here
|
||||
|
||||
|
||||
/************************ [Alternative Corpses] *******************************/
|
||||
}
|
||||
// Signal the death event.
|
||||
FireUserEvent(AI_FLAG_UDE_DEATH_EVENT, EVENT_DEATH_EVENT);
|
||||
}
|
||||
|
||||
// We need a wrapper. If the amount of deaths, got in this, is not equal to iDeaths,
|
||||
// we don't execute the script, else we do. :-P
|
||||
void DeathCheck(int nDeaths)
|
||||
{
|
||||
// Do the deaths imputted equal the amount we have suffered?
|
||||
if(GetAIInteger(AMOUNT_OF_DEATHS) == nDeaths)
|
||||
{
|
||||
// - This now includes a check for Bioware's lootable functions and using them.
|
||||
ExecuteScript(FILE_DEATH_CLEANUP, OBJECT_SELF);
|
||||
}
|
||||
}
|
85
_module/nss/j_ai_ondisturbed.nss
Normal file
85
_module/nss/j_ai_ondisturbed.nss
Normal file
@@ -0,0 +1,85 @@
|
||||
/*/////////////////////// [On Disturbed] ///////////////////////////////////////
|
||||
Filename: J_AI_OnDisturbed or nw_c2_default8
|
||||
///////////////////////// [On Disturbed] ///////////////////////////////////////
|
||||
This will attack pickpockets, and inventory disturbers. Note: Stupidly, Bioware
|
||||
made this only affect the creature by stealing. Still, oh well :-(
|
||||
|
||||
This means that the only event which fires it is pickpocketing.
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Changed why we determine combat round
|
||||
- Any change in inventory will trigger appropriate SetWeapons again.
|
||||
- Added turn of hide things.
|
||||
1.4 - Cleaned up a bit. Removed unused declared variable.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Only fired by stealing, great. Oh well, it will attack any disturber anyway.
|
||||
|
||||
It *might* not be fired if the natural spot check to notice a theft doesn't
|
||||
work. No idea personally.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetInventoryDisturbItem, GetLastDisturbed,
|
||||
GetInventoryDisturbType (I think it is always be stolen :-( ).
|
||||
///////////////////////// [On Disturbed] /////////////////////////////////////*/
|
||||
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-disturbed-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_DISTURBED_PRE_EVENT, EVENT_DISTURBED_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
// Declare major variables
|
||||
object oDisturber = GetLastDisturbed();
|
||||
object oItem = GetInventoryDisturbItem();
|
||||
int nType = GetInventoryDisturbType();
|
||||
int nBase = GetBaseItemType(oItem);
|
||||
|
||||
// We will reset weapons if it is a weapon.
|
||||
// Reset weapons, or specifically healers kits.
|
||||
if(GetIsObjectValid(oItem))
|
||||
{
|
||||
// Kits
|
||||
if(nBase == BASE_ITEM_HEALERSKIT)
|
||||
{
|
||||
SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, 2);
|
||||
ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF);
|
||||
}
|
||||
else // Think it is a weapon. Saves time :-)
|
||||
{
|
||||
SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, 1);
|
||||
ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF);
|
||||
}
|
||||
}
|
||||
// Fight! Or search!
|
||||
if(!GetIgnoreNoFriend(oDisturber) &&
|
||||
(nType == INVENTORY_DISTURB_TYPE_STOLEN || GetIsEnemy(oDisturber)))
|
||||
{
|
||||
// Turn of hiding, a timer to activate Hiding in the main file. This is
|
||||
// done in each of the events, with the opposition checking seen/heard.
|
||||
TurnOffHiding(oDisturber);
|
||||
|
||||
// Can we attack?
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Someone specific to attack
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
|
||||
// One debug speak. We always do one.
|
||||
// 65: "[Disturbed] (pickpocket) Attacking Enemy Distrube [Disturber] " + GetName(oTarget) + " [Type] " + IntToString(iType)
|
||||
DebugActionSpeakByInt(65, oDisturber, nType);
|
||||
|
||||
// Attack the disturber
|
||||
DetermineCombatRound(oDisturber);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get allies interested.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
|
||||
// Fire End-heartbeat-UDE
|
||||
FireUserEvent(AI_FLAG_UDE_DISTURBED_EVENT, EVENT_DISTURBED_EVENT);
|
||||
}
|
114
_module/nss/j_ai_onheartbeat.nss
Normal file
114
_module/nss/j_ai_onheartbeat.nss
Normal file
@@ -0,0 +1,114 @@
|
||||
/*/////////////////////// [On Heartbeat] ///////////////////////////////////////
|
||||
Filename: nw_c2_default1 or J_AI_OnHeartbeat
|
||||
///////////////////////// [On Heartbeat] ///////////////////////////////////////
|
||||
Removed stupid stuff, special behaviour, sleep.
|
||||
|
||||
Also, note please, I removed waypoints and day/night posting from this.
|
||||
It can be re-added if you like, but it does reduce heartbeats.
|
||||
|
||||
Added in better checks to see if we should fire this script. Stops early if
|
||||
some conditions (like we can't move, low AI settings) are set.
|
||||
|
||||
Hint: If nothing is used within this script, either remove it from creatures
|
||||
or create one witch is blank, with just a "void main(){}" at the top.
|
||||
|
||||
Hint 2: You could add this very small file to your catche of scripts in the
|
||||
module properties, as it runs on every creature every 6 seconds (ow!)
|
||||
|
||||
This also uses a system of Execute Script :-D This means the heartbeat, when
|
||||
compiled, should be very tiny.
|
||||
|
||||
Note: NO Debug strings!
|
||||
Note 2: Remember, I use default SoU Animations/normal animations. As it is
|
||||
executed, we can check the prerequisists here, and then do it VIA
|
||||
execute script.
|
||||
|
||||
-Working- Best possible, fast compile.
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added more "buffs" to fast buff.
|
||||
- Fixed animations (they both WORK and looping ones do loop right!)
|
||||
- Loot behaviour!
|
||||
- Randomly moving nearer a PC in 25M if set.
|
||||
- Removed silly day/night optional setting. Anything we can remove, is a good idea.
|
||||
1.4 - Removed AI level setting. Not good to use, I mistakenly added it.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This fires off every 6 seconds (with PCs in the area, or AI_LEVEL_HIGH without)
|
||||
and therefore is intensive.
|
||||
|
||||
It fires of ExecutesScript things for the different parts - saves CPU stuff
|
||||
if the bits are not used.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: Basically, none. Nothing activates this script. Fires every 6 seconds.
|
||||
///////////////////////// [On Heartbeat] /////////////////////////////////////*/
|
||||
|
||||
// - This includes J_Inc_Constants
|
||||
#include "J_INC_HEARTBEAT"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Special - Runner from the leader shouts, each heartbeat, to others to get thier
|
||||
// attention that they are being attacked.
|
||||
// - Includes fleeing making sure (so it resets the ActionMoveTo each 6 seconds -
|
||||
// this is not too bad)
|
||||
// - Includes door bashing stop heartbeat
|
||||
if(PerformSpecialAction()) return;
|
||||
|
||||
// Pre-heartbeat-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, EVENT_HEARTBEAT_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff() || GetSpawnInCondition(AI_FLAG_OTHER_LAG_IGNORE_HEARTBEAT, AI_OTHER_MASTER)) return;
|
||||
|
||||
// Define the enemy and player to use.
|
||||
object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
|
||||
object oPlayer = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
|
||||
|
||||
// We can skip to the end if we are in combat, or something...
|
||||
if(!JumpOutOfHeartBeat() && // We don't stop due to effects.
|
||||
!GetIsInCombat() && // We are not in combat.
|
||||
!GetIsObjectValid(GetAttackTarget()) && // Second combat check.
|
||||
!GetObjectSeen(oEnemy)) // Nearest enemy is not seen.
|
||||
{
|
||||
// Fast buffing...if we have the spawn in condition...
|
||||
if(GetSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER) &&
|
||||
GetIsObjectValid(oEnemy) && GetDistanceToObject(oEnemy) <= 40.0)
|
||||
{
|
||||
// ...we may do an advanced buff. If we cannot see/hear oEnemy, but oEnemy
|
||||
// is within 40M, we cast many defensive spells instantly...
|
||||
ExecuteScript(FILE_HEARTBEAT_TALENT_BUFF, OBJECT_SELF);
|
||||
//...if TRUE (IE it does something) we turn of future calls.
|
||||
DeleteSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER);
|
||||
// This MUST STOP the heartbeat event - else, the actions may be interrupted.
|
||||
return;
|
||||
}
|
||||
// Execute waypoints file if we have waypoints set up.
|
||||
if(GetWalkCondition(NW_WALK_FLAG_CONSTANT))
|
||||
{
|
||||
ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF);
|
||||
}
|
||||
// We can't have any waypoints for the other things
|
||||
else
|
||||
{
|
||||
// We must have animations set, and not be "paused", so doing a
|
||||
// longer looping one
|
||||
// - Need a valid player.
|
||||
if(GetIsObjectValid(oPlayer) && !IsInConversation(OBJECT_SELF))
|
||||
{
|
||||
// We may search for PC enemies, 25% chance to move closer to PC's
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_SEARCH_IF_ENEMIES_NEAR, AI_OTHER_MASTER) &&
|
||||
!GetLocalTimer(AI_TIMER_SEARCHING) && d4() == 1)
|
||||
{
|
||||
ExecuteScript(FILE_HEARTBEAT_WALK_TO_PC, OBJECT_SELF);
|
||||
}
|
||||
// Else, Do we have any animations to speak of?
|
||||
// If we have a nearby PC, we do animations.
|
||||
else if(GetHasValidAnimations())
|
||||
{
|
||||
ExecuteScript(FILE_HEARTBEAT_ANIMATIONS, OBJECT_SELF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fire End-heartbeat-UDE
|
||||
FireUserEvent(AI_FLAG_UDE_HEARTBEAT_EVENT, EVENT_HEARTBEAT_EVENT);
|
||||
}
|
220
_module/nss/j_ai_onpercieve.nss
Normal file
220
_module/nss/j_ai_onpercieve.nss
Normal file
@@ -0,0 +1,220 @@
|
||||
/*/////////////////////// [On Percieve] ////////////////////////////////////////
|
||||
Filename: J_AI_OnPercieve or nw_c2_default2
|
||||
///////////////////////// [On Percieve] ////////////////////////////////////////
|
||||
If the target is an enemy, attack
|
||||
Will determine combat round on that person, is an enemy, basically.
|
||||
Includes shouting for a big radius - if the spawn in condition is set to this.
|
||||
|
||||
NOTE: Debug strings in this file will be uncommented for speed by default.
|
||||
- It is one of the most intensive scripts as it runs so often.
|
||||
- Attempted to optimise as much as possible.
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - We include j_inc_other_ai to initiate combat (or go into combat again)
|
||||
- j_inc_other_ai holds all other needed functions/integers ETC.
|
||||
- Turn off hide things.
|
||||
- Added "Only attack if attacked"
|
||||
- Removed special conversation things. Almost no one uses them, and the taunt system is easier.
|
||||
- Should now search around if they move to a dead body, and only once they get there.
|
||||
1.4 - TO DO:
|
||||
|
||||
1. Perception needs checking - attacking outside perception ranges!
|
||||
2. Vanishing targets, etc. test, improve.
|
||||
3. Problems with dispelling invisibility. Maybe either do change the line to create placable, or, of course, cast at location (dispells cannot be metamagiked or whatever) Source
|
||||
4. No Effect Type Ethereal. Source
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
It fires:
|
||||
|
||||
- When a creature enters it perception range (Set in creature properties) and
|
||||
is seen or heard.
|
||||
* Tests show (and in general) it fires HEARD first, then immediantly SEEN if,
|
||||
of course, they are visible. Odd really, but true.
|
||||
- When a creature uses invisiblity/leaves the area in the creatures perception
|
||||
range
|
||||
- When a creature appears suddenly, already in the perception range (not
|
||||
the other way round, normally)
|
||||
- When a creature moves out of the creatures perception range, and therefore
|
||||
becomes unseen.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetLastPerceived, GetLastPerceptionSeen, GetLastPerceptionHeard,
|
||||
GetLastPerceptionVanished, GetLastPerceptionInaudible.
|
||||
///////////////////////// [On Percieve] //////////////////////////////////////*/
|
||||
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-percieve-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_PERCIEVE_PRE_EVENT, EVENT_PERCIEVE_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
// Declare main things.
|
||||
// - We declare OUTSIDE if's JUST IN CASE!
|
||||
object oPerceived = GetLastPerceived();
|
||||
object oAttackTarget = GetAttackTarget();
|
||||
// 1.4: Very rarely is our attack target valid, so we will set it to
|
||||
// what we would have melee attacked when DCR was called.
|
||||
if(GetIgnoreNoFriend(oAttackTarget) || oAttackTarget == OBJECT_SELF)
|
||||
{
|
||||
oAttackTarget = GetAIObject(AI_LAST_MELEE_TARGET);
|
||||
}
|
||||
int bSeen = GetLastPerceptionSeen();
|
||||
int bHeard = GetLastPerceptionHeard();
|
||||
int bVanished = GetLastPerceptionVanished();
|
||||
int bInaudiable = GetLastPerceptionInaudible();
|
||||
|
||||
// Debug
|
||||
DebugActionSpeak("*** PER ***: " + GetName(oPerceived) + "| SEEN: " + IntToString(bSeen) +
|
||||
"| HEARD: " + IntToString(bHeard) + "| VANISHED: " + IntToString(bVanished) +
|
||||
"| INAUDIABLE: " + IntToString(bInaudiable));
|
||||
|
||||
// Need to be valid and not ignorable.
|
||||
if(GetIsObjectValid(oPerceived) &&
|
||||
!GetIsDM(oPerceived) &&
|
||||
!GetIgnore(oPerceived))
|
||||
{
|
||||
// First, easy enemy checks.
|
||||
if(GetIsEnemy(oPerceived) && !GetFactionEqual(oPerceived))
|
||||
{
|
||||
DebugActionSpeak("*** PER *** ENEMY");
|
||||
|
||||
// Turn of hiding, a timer to activate Hiding in the main file. This is
|
||||
// done in each of the events, with the opposition checking seen/heard.
|
||||
TurnOffHiding(oPerceived);
|
||||
|
||||
// Well, are we both inaudible and vanished?
|
||||
// * the GetLastPerception should only say what specific event has fired!
|
||||
if(bVanished || bInaudiable)
|
||||
{
|
||||
DebugActionSpeak("*** PER *** VANISHED OR INAUDIBLE");
|
||||
// If they just became invisible because of the spell
|
||||
// invisiblity, or improved invisiblity...we set a local object.
|
||||
// - Beta: Added in ethereal as well.
|
||||
if(GetHasEffect(EFFECT_TYPE_INVISIBILITY, oPerceived) ||
|
||||
GetHasEffect(EFFECT_TYPE_SANCTUARY, oPerceived) ||
|
||||
GetStealthMode(oPerceived) == STEALTH_MODE_ACTIVATED)
|
||||
{
|
||||
// Set object, AND the location they went invisible!
|
||||
SetAIObject(AI_LAST_TO_GO_INVISIBLE, oPerceived);
|
||||
// We also set thier location for AOE dispelling - same name
|
||||
SetAILocation(AI_LAST_TO_GO_INVISIBLE, GetLocation(oPerceived));
|
||||
}
|
||||
|
||||
// If they were our target, follow! >:-D
|
||||
// - Optional, on spawn option, for following through areas.
|
||||
if(oAttackTarget == oPerceived)
|
||||
{
|
||||
DebugActionSpeak("*** PER *** VANISHED OR INAUDIBLE AND IS CURRENT TARGET");
|
||||
// This means they have exited the area! follow!
|
||||
if(GetArea(oPerceived) != GetArea(OBJECT_SELF))
|
||||
{
|
||||
ClearAllActions();
|
||||
// 51: "[Perception] Our Enemy Target changed areas. Stopping, moving too...and attack... [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(51, oPerceived);
|
||||
// Call to stop silly moving to enemies if we are fleeing
|
||||
ActionMoveToEnemy(oPerceived);
|
||||
}
|
||||
// - Added check for not casting a spell. If we are, we finnish
|
||||
// (EG: AOE spell) and automatically carry on.
|
||||
// 1.4: If we are using a targetted spell, we do cancle our
|
||||
// spellcasting if it is them.
|
||||
else if(GetCurrentAction() != ACTION_CASTSPELL ||
|
||||
GetAttackTarget() == oPerceived)
|
||||
{
|
||||
ClearAllActions();
|
||||
// 52: "[Perception] Enemy Vanished (Same area) Retargeting/Searching [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(52, oPerceived);
|
||||
DetermineCombatRound(oPerceived);
|
||||
}
|
||||
}
|
||||
}// End if just gone out of perception
|
||||
// ELSE they have been SEEN or HEARD. We don't check specifics.
|
||||
else //if(bSeen || bHeard)
|
||||
{
|
||||
// If they have been made seen, and they are our attack target,
|
||||
// we must re-do combat round - unless we are casting a spell.
|
||||
if(bSeen && GetCurrentAction() != ACTION_CASTSPELL &&
|
||||
(oAttackTarget == oPerceived || !GetObjectSeen(oAttackTarget)))
|
||||
{
|
||||
// 53: "[Perception] Enemy seen, and was old enemy/cannot see current. Re-evaluating (no spell) [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(53, oPerceived);
|
||||
DetermineCombatRound(oPerceived);
|
||||
|
||||
// Shout to allies to attack oPerceived
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
// Else We check if we are already attacking.
|
||||
else if(!CannotPerformCombatRound() &&
|
||||
!GetSpawnInCondition(AI_FLAG_OTHER_ONLY_ATTACK_IF_ATTACKED, AI_OTHER_MASTER))
|
||||
{
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
// Special shout, d1000 though!
|
||||
SpeakArrayString(AI_TALK_ON_PERCIEVE_ENEMY, TRUE);
|
||||
}
|
||||
|
||||
// Stop stuff because of facing point - New enemy
|
||||
HideOrClear();
|
||||
|
||||
// Get all allies in 60M to come to thier aid. Talkvolume silent
|
||||
// shout does not seem to work well.
|
||||
// - void function. Checks for the spawn int. in it.
|
||||
// - Turns it off in it too (5 minutes - 1.4)
|
||||
// - Variable range On Spawn
|
||||
ShoutBossShout(oPerceived);
|
||||
|
||||
// 54: "[Perception] Enemy Seen. Not in combat, attacking. [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(54, oPerceived);
|
||||
|
||||
// 1.4 change: SetFacingPoint(GetPosition(oPerceived));
|
||||
// Is now part of DetermineCombatRound().
|
||||
// * This means other events will work similarily.
|
||||
DetermineCombatRound(oPerceived);
|
||||
|
||||
// Warn others
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Else, they are an equal faction, or not an enemy (or both)
|
||||
else
|
||||
{
|
||||
// If they are dead, or fighting, eg: we saw something on
|
||||
// waypoints, we charge in to investigate.
|
||||
// * Higher intelligence will buff somewhat as well!
|
||||
if((GetIsDead(oPerceived) || GetIsInCombat(oPerceived)) &&
|
||||
(bSeen || bHeard))
|
||||
{
|
||||
if(GetIsDead(oPerceived))
|
||||
{
|
||||
// 55: "[Perception] Percieved Dead Friend! Moving into investigate [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(55, oPerceived);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 56: "[Perception] Percieved Alive Fighting Friend! Moving to and attacking. [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(56, oPerceived);
|
||||
}
|
||||
// Check if we can attack
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Hide or clear actions
|
||||
HideOrClear();
|
||||
|
||||
// If we were called to arms, react
|
||||
CallToArmsResponse(oPerceived);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Warn others even if we don't, or cannot, attack
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fire End of Percieve event
|
||||
FireUserEvent(AI_FLAG_UDE_PERCIEVE_EVENT, EVENT_PERCIEVE_EVENT);
|
||||
}
|
136
_module/nss/j_ai_onphiattack.nss
Normal file
136
_module/nss/j_ai_onphiattack.nss
Normal file
@@ -0,0 +1,136 @@
|
||||
/*/////////////////////// [On Phisical Attacked] ///////////////////////////////
|
||||
Filename: J_AI_OnPhiAttack or nw_c2_default5
|
||||
///////////////////////// [On Phisical Attacked] ///////////////////////////////
|
||||
On Attacked
|
||||
No checking for fleeing or warnings.
|
||||
Very boring really!
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added hiding things
|
||||
1.4 - Missing Silent Shouts have been added.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Got some simple Knockdown timer, so that we use heal sooner if we keep getting
|
||||
a creature who is attempting to knock us down.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetLastAttacker, GetLastWeaponUsed, GetLastAttackMode, GetLastAttackType
|
||||
///////////////////////// [On Phisical Attacked] /////////////////////////////*/
|
||||
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-attacked-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_ATTACK_PRE_EVENT, EVENT_ATTACK_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
// Set up objects.
|
||||
object oAttacker = GetLastAttacker();
|
||||
object oWeapon = GetLastWeaponUsed(oAttacker);
|
||||
//int nMode = GetLastAttackMode(oAttacker); // Currently unused
|
||||
int nAttackType = GetLastAttackType(oAttacker);
|
||||
|
||||
// Check if they are valid, a DM, we are ignoring them, they are dead now, or invalid
|
||||
if(!GetIgnoreNoFriend(oAttacker))
|
||||
{
|
||||
// Adjust automatically if set.
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER))
|
||||
{
|
||||
if(!GetIsEnemy(oAttacker))
|
||||
{
|
||||
AdjustReputation(oAttacker, OBJECT_SELF, -100);
|
||||
}
|
||||
}
|
||||
|
||||
// If we were attacked by knockdown, for a timer of X seconds, we make
|
||||
// sure we attempt healing at a higher level.
|
||||
if(!GetLocalTimer(AI_TIMER_KNOCKDOWN) &&
|
||||
(nAttackType == SPECIAL_ATTACK_IMPROVED_KNOCKDOWN ||
|
||||
nAttackType == SPECIAL_ATTACK_KNOCKDOWN) &&
|
||||
!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_KNOCKDOWN) &&
|
||||
GetBaseAttackBonus(oAttacker) + 20 >= GetAC(OBJECT_SELF))
|
||||
{
|
||||
SetLocalTimer(AI_TIMER_KNOCKDOWN, 30.0);
|
||||
}
|
||||
|
||||
// Set last hostile, valid attacker (Used in the On Damaged event)
|
||||
SetAIObject(AI_STORED_LAST_ATTACKER, oAttacker);
|
||||
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
// Speak the phisically attacked string, if applicable.
|
||||
// Speak the damaged string, if applicable.
|
||||
SpeakArrayString(AI_TALK_ON_PHISICALLY_ATTACKED);
|
||||
}
|
||||
|
||||
// Turn of hiding, a timer to activate Hiding in the main file. This is
|
||||
// done in each of the events, with the opposition checking seen/heard.
|
||||
TurnOffHiding(oAttacker);
|
||||
|
||||
// We set if we are attacked in HTH onto a low-delay timer.
|
||||
// - Not currently used
|
||||
/*if(!GetLocalTimer(AI_TIMER_ATTACKED_IN_HTH))
|
||||
{
|
||||
// If the weapon is not ranged, or is not valid, set the timer.
|
||||
if(!GetIsObjectValid(oWeapon) ||
|
||||
!GetWeaponRanged(oWeapon))
|
||||
{
|
||||
SetLocalTimer(AI_TIMER_ATTACKED_IN_HTH, f18);
|
||||
}
|
||||
}*/
|
||||
|
||||
// If we are not fighting, and they are in the area, attack. Else, determine anyway.
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Must be in our area to go after now.
|
||||
if(GetArea(oAttacker) == GetArea(OBJECT_SELF))
|
||||
{
|
||||
// 59: "[Phisically Attacked] Attacking back. [Attacker(enemy)] " + GetName(oAttacker)
|
||||
DebugActionSpeakByInt(59, oAttacker);
|
||||
|
||||
// Attack the attacker
|
||||
DetermineCombatRound(oAttacker);
|
||||
|
||||
// Shout to allies to attack the enemy who attacked me
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
// 60: "[Phisically Attacked] Not same area. [Attacker(enemy)] " + GetName(oAttacker)
|
||||
DebugActionSpeakByInt(60, oAttacker);
|
||||
|
||||
// May find another hostile to attack...
|
||||
DetermineCombatRound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
// Else, invalid, DM, ally, etc...must be prepared at least (could be
|
||||
// they are charmed or something!)
|
||||
else
|
||||
{
|
||||
// If we are not fighting, prepare for battle. Something bad must have
|
||||
// happened.
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Respond to oAttacker as if they shouted for help.
|
||||
IWasAttackedResponse(oAttacker);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
|
||||
// Fire End of Attacked event
|
||||
FireUserEvent(AI_FLAG_UDE_ATTACK_EVENT, EVENT_ATTACK_EVENT);
|
||||
}
|
84
_module/nss/j_ai_onrest.nss
Normal file
84
_module/nss/j_ai_onrest.nss
Normal file
@@ -0,0 +1,84 @@
|
||||
/*/////////////////////// [On Rested] //////////////////////////////////////////
|
||||
Filename: J_AI_OnRest or nw_c2_defaulta
|
||||
///////////////////////// [On Rested] //////////////////////////////////////////
|
||||
This will play the sitting animation for 6 seconds, just something for resting.
|
||||
Also, walks waypoints (as resting would stop this) :-) and signals event (if so be)
|
||||
Feel free to edit.
|
||||
|
||||
It does have the spell trigger information resetting, however. This can
|
||||
only be removed if they have no spell triggers, although it is hardly worth it.
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added sitting.
|
||||
1.4 - Will be editing this down. No need to reset anything on rest, for a
|
||||
better working AI.
|
||||
IDEA: Change so that we will work through all spells/feats in order.
|
||||
If, at cirtain levels, we do not have any spells to cast from that
|
||||
level (set in a global stored integer in the general AI) we ignore all
|
||||
spells in that level. Same for each talent category (no need to use
|
||||
talents for them in the spawn script).
|
||||
|
||||
If not in combat (EG: In heartbeat) we reset the integers saying "don't
|
||||
bother checking those spells" to false.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This fires once, at the END of resting.
|
||||
|
||||
If ClearAllActions is added, the resting is actually stopped, or so it seems.
|
||||
|
||||
It doesn't fire more then once.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: None, it seems.
|
||||
///////////////////////// [On Rested] ////////////////////////////////////////*/
|
||||
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
// Resets all spell triggers used for sString
|
||||
void LoopResetTriggers(string sString, object oTrigger);
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-rest-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_RESTED_PRE_EVENT, EVENT_RESTED_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
// Simple debug.
|
||||
// 66: "[Rested] Resting. Type: " + IntToString(GetLastRestEventType())
|
||||
DebugActionSpeakByInt(66, OBJECT_INVALID, GetLastRestEventType());
|
||||
|
||||
// Reset all spell triggers.
|
||||
// Set all triggers
|
||||
object oTrigger = GetAIObject(AI_SPELL_TRIGGER_CREATURE);
|
||||
if(GetIsObjectValid(oTrigger))
|
||||
{
|
||||
LoopResetTriggers(SPELLTRIGGER_NOT_GOT_FIRST_SPELL, oTrigger);
|
||||
LoopResetTriggers(SPELLTRIGGER_DAMAGED_AT_PERCENT, oTrigger);
|
||||
LoopResetTriggers(SPELLTRIGGER_IMMOBILE, oTrigger);
|
||||
LoopResetTriggers(SPELLTRIGGER_START_OF_COMBAT, oTrigger);
|
||||
}
|
||||
// Some sitting for a few seconds.
|
||||
ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS, 1.0, 6.0);
|
||||
DelayCommand(9.0, ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF));
|
||||
|
||||
// Fire End-heartbeat-UDE
|
||||
FireUserEvent(AI_FLAG_UDE_RESTED_EVENT, EVENT_RESTED_EVENT);
|
||||
}
|
||||
|
||||
// Resets all spell triggers used for sString
|
||||
void LoopResetTriggers(string sString, object oTrigger)
|
||||
{
|
||||
int nCnt, bBreak, bUsed;
|
||||
for(nCnt = 1; bBreak != TRUE; nCnt++)
|
||||
{
|
||||
// Check max for this setting
|
||||
bUsed = GetLocalInt(oTrigger, sString + USED);
|
||||
if(bUsed)
|
||||
{
|
||||
DeleteLocalInt(oTrigger, sString + USED);
|
||||
}
|
||||
else
|
||||
{
|
||||
bBreak = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
644
_module/nss/j_ai_onspawn.nss
Normal file
644
_module/nss/j_ai_onspawn.nss
Normal file
@@ -0,0 +1,644 @@
|
||||
/*/////////////////////// [On Spawn] ///////////////////////////////////////////
|
||||
Filename: J_AI_OnSpawn or nw_c2_default9
|
||||
///////////////////////// [On Spawn] ///////////////////////////////////////////
|
||||
This file contains options that will determine some AI behaviour, and a lot
|
||||
of toggles for turning things on/off. A big read, but might be worthwhile.
|
||||
|
||||
The documentation is actually fully in the readme files, under the name
|
||||
"On Spawn.html", under "AI File Explanations".
|
||||
|
||||
The order of the options:
|
||||
|
||||
- Important Spawn Settings N/A
|
||||
- Targeting & Fleeing (AI_TARGETING_FLEE_MASTER)
|
||||
- Fighting & Spells (AI_COMBAT_MASTER)
|
||||
- Other Combat - Healing, Skills & Bosses (AI_OTHER_COMBAT_MASTER)
|
||||
- Other - Death corpses, minor things (AI_OTHER_MASTER)
|
||||
- User Defined (AI_UDE_MASTER)
|
||||
- Shouts N/A
|
||||
- Default Bioware settings (WP's, Anims) (NW_GENERIC_MASTER)
|
||||
|
||||
The OnSpawn file is a settings file. These things are set onto a creature, to
|
||||
define cirtain actions. If more than one creature has this script, they all
|
||||
use the settings, unless If/Else statements are used somehow. There is also
|
||||
the process of setting any spells/feats availible, and hiding and walk waypoints
|
||||
are started.
|
||||
|
||||
Other stuff:
|
||||
- Targeting is imporant :-D
|
||||
- If you delete this script, there is a template for the On Spawn file
|
||||
in the zip it came in, for use in the "scripttemplate" directory.
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
Note: I have removed:
|
||||
- Default "Teleporting" and exit/return (this seemed bugged anyway, or useless)
|
||||
- Spawn in animation. This can be, of course, re-added.
|
||||
- Day/night posting. This is uneeded, with a changed walk waypoints that does it automatically.
|
||||
|
||||
1.0-1.2 - Used short amount of spawn options.
|
||||
1.3 - All constants names are changed, I am afraid.
|
||||
- Added Set/Delete/GetAIInteger/Constant/Object. This makes sure that the AI
|
||||
doesn't ever interfere with other things - it pre-fixes all stored things
|
||||
with AI_INTEGER_ (and so on)
|
||||
1.4 - TO DO: Clear up some old non-working ones
|
||||
- Added in User Defined part of the script, an auto-turn-off-spells for
|
||||
Ranger and Paladin classes. Need to test - perhaps 1.64 fixed it?
|
||||
|
||||
|
||||
Spawn options changed:
|
||||
- Removed AI level settings (can still be done manually)
|
||||
- Added optional (and off by default) fear-visual for fleeing
|
||||
|
||||
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Note: You can do without all the comments (it may be that you don't want
|
||||
the extra KB it adds or something, although it does not at all slow down a module)
|
||||
so as long as you have these at the end:
|
||||
|
||||
AI_SetUpEndOfSpawn();
|
||||
DelayCommand(2.0, SpawnWalkWayPoints());
|
||||
|
||||
Oh, and the include file (Below, "j_inc_spawnin") must be at the top like
|
||||
here. Also recommended is the AI_INTELLIGENCE and AI_MORALE being set (if
|
||||
not using custom AI).
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetIsEncounterCreature
|
||||
///////////////////////// [On Spawn] /////////////////////////////////////////*/
|
||||
|
||||
// Treasure Includes - See end of spawn for uncomment options.
|
||||
|
||||
//#include "nw_o2_coninclude"
|
||||
// Uncomment this if you want default NwN Treasure - Uses line "GenerateNPCTreasure()" at the end of spawn.
|
||||
// - This generates random things from the default pallet based on the creatures level + race
|
||||
|
||||
//#include "x0_i0_treasure"
|
||||
// Uncomment this if you want the SoU Treasure - Uses line "CTG_GenerateNPCTreasure()" at the end of spawn.
|
||||
// - This will spawn treasure based on chests placed in the module. See "x0_i0_treasure" for more information.
|
||||
|
||||
// This is required for all spawn in options!
|
||||
#include "J_INC_SPAWNIN"
|
||||
|
||||
void main()
|
||||
{
|
||||
/************************ [Important Spawn Settings] **************************/
|
||||
SetAIInteger(AI_INTELLIGENCE, 10);
|
||||
// Intelligence value of the creauture. Can be 1-10, read readme's for help.
|
||||
SetAIInteger(AI_MORALE, 10);
|
||||
// Will save (See readme). Remember: -1 or below means they always flee.
|
||||
//SetCustomAIFileName("CUSTOM_AI_FILE");
|
||||
// Sets our custom AI file. Really, only animation settings will apply when this is set.
|
||||
// - Can sort actions against a imputted target (EG: On Percieved enemy) by
|
||||
// "GetLocalObject(OBJECT_SELF, "AI_TEMP_SET_TARGET");"
|
||||
/************************ [Important Spawn Settings] **************************/
|
||||
|
||||
/************************ [Targeting] ******************************************
|
||||
All targeting settings.
|
||||
************************* [Targeting] *****************************************/
|
||||
//SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_LOWER_HP, AI_TARGETING_FLEE_MASTER);
|
||||
// We only attack the lowest current HP.
|
||||
//SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_LOWER_AC, AI_TARGETING_FLEE_MASTER);
|
||||
// We only attack the lowest AC (as in 1.2).
|
||||
//SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_LOWER_HD, AI_TARGETING_FLEE_MASTER);
|
||||
// Target the lowest hit dice
|
||||
//SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_MAGE_CLASSES, AI_TARGETING_FLEE_MASTER);
|
||||
// We go straight for mages/sorcerors. Nearest one.
|
||||
//SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_ARCHERS, AI_TARGETING_FLEE_MASTER);
|
||||
// We go for the nearest enemy with a ranged weapon equipped.
|
||||
//SetSpawnInCondition(AI_FLAG_TARGETING_LIKE_PCS, AI_TARGETING_FLEE_MASTER);
|
||||
// We go for the nearest seen PC enemy.
|
||||
|
||||
//SetAIConstant(AI_FAVOURED_ENEMY_RACE, RACIAL_TYPE_HUMAN);
|
||||
// The AI attacks the nearest enemy, seen, of this race. Use the RACIAL_* constants.
|
||||
//SetAIConstant(AI_FAVOURED_ENEMY_CLASS, CLASS_TYPE_BARD);
|
||||
// The AI attacks the nearest enemy, seen, of this class. Use the CLASS_* constants.
|
||||
|
||||
// Target changing - see readme for info.
|
||||
//SetAIInteger(AI_MAX_TURNS_TO_ATTACK_ONE_TARGET, 6);
|
||||
// Maximum rounds to attack the current target, before re-checking.
|
||||
// % Chance to re-set each target type each round (Could result in current target still)
|
||||
//SetAIInteger(AI_MELEE_LAST_TO_NEW_TARGET_CHANCE, 20);
|
||||
//SetAIInteger(AI_RANGED_LAST_TO_NEW_TARGET_CHANCE, 20);
|
||||
//SetAIInteger(AI_SPELL_LAST_TO_NEW_TARGET_CHANCE, 20);
|
||||
|
||||
// We only target PC's if there are any in range if this is set
|
||||
//SetSpawnInCondition(AI_FLAG_TARGETING_FILTER_FOR_PC_TARGETS, AI_TARGETING_FLEE_MASTER);
|
||||
|
||||
// Main explanation of AI_SetAITargetingValues, see the AI readme (spawn file)
|
||||
// - Remember, uncommenting one will just ignore it (so will never check target's
|
||||
// AC without TARGETING_AC on)
|
||||
|
||||
AI_SetAITargetingValues(TARGETING_MANTALS, TARGET_LOWER, 1, 12);
|
||||
// Spell mantals are checked only for the spell target. Either Absense of or got any.
|
||||
AI_SetAITargetingValues(TARGETING_RANGE, TARGET_HIGHER, 2, 9);
|
||||
// Range - very imporant! Basis for all ranged/spell attacks.
|
||||
AI_SetAITargetingValues(TARGETING_AC, TARGET_LOWER, 2, 6);
|
||||
// AC is used for all phisical attacks. Lower targets lower (By default).
|
||||
AI_SetAITargetingValues(TARGETING_SAVES, TARGET_LOWER, 2, 4);
|
||||
// Used for spell attacks. Saves are sorta a AC versus spells.
|
||||
|
||||
// Phisical protections. Used by spells, ranged and melee.
|
||||
// Jasperre - simple check if we are a fighter (hit lower phisicals) or a
|
||||
// mage (attack higher!)
|
||||
if(GetBaseAttackBonus(OBJECT_SELF) > ((GetHitDice(OBJECT_SELF)/2) + 1))
|
||||
{
|
||||
// Fighter/Clerics (It is over a mages BAB + 1 (IE 0.5 BAB/Level) target lower
|
||||
AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_LOWER, 2, 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mages target higher (so dispel/elemental attack those who fighters
|
||||
// cannot hit as much). (the lowest BAB, under half our hit dice in BAB)
|
||||
AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_HIGHER, 1, 5);
|
||||
}
|
||||
// Base attack bonus. Used for spells and phisical attacks. Checked with GetBaseAttackBonus.
|
||||
AI_SetAITargetingValues(TARGETING_BAB, TARGET_LOWER, 1, 4);
|
||||
// Hit dice - how powerful in levels the enemy is. Used for all checks.
|
||||
AI_SetAITargetingValues(TARGETING_HITDICE, TARGET_LOWER, 1, 3);
|
||||
|
||||
//AI_SetAITargetingValues(TARGETING_HP_PERCENT, TARGET_LOWER, 1, 3);
|
||||
//AI_SetAITargetingValues(TARGETING_HP_CURRENT, TARGET_LOWER, 1, 3);
|
||||
//AI_SetAITargetingValues(TARGETING_HP_MAXIMUM, TARGET_LOWER, 1, 3);
|
||||
// The HP's are the last thing to choose a target with.
|
||||
/************************ [Targeting] *****************************************/
|
||||
|
||||
/************************ [Fleeing] ********************************************
|
||||
Fleeing - these are toggled on/off by FEARLESS flag.
|
||||
|
||||
3 or under intelligence will just run away. 4 or more will know where allies
|
||||
are, and if there are none, will not run.
|
||||
************************* [Fleeing] *******************************************/
|
||||
SetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER);
|
||||
// Forces them to not flee. This may be set with AI_SetMaybeFearless at the end.
|
||||
//SetSpawnInCondition(AI_FLAG_FLEEING_NEVER_FIGHT_IMPOSSIBLE_ODDS, AI_TARGETING_FLEE_MASTER);
|
||||
// This will make the creature never fight against impossible odds (8HD+ different)
|
||||
//SetSpawnInCondition(AI_FLAG_FLEEING_TURN_OFF_GROUP_MORALE, AI_TARGETING_FLEE_MASTER);
|
||||
// This turns OFF any sort of group morale bonuses.
|
||||
|
||||
//SetAIInteger(AMOUNT_OF_HD_DIFFERENCE_TO_CHECK, -2);
|
||||
// If enemy is within this amount of HD, we do not check morale.
|
||||
//SetAIInteger(BASE_MORALE_SAVE, 20);
|
||||
// Base DC of the will save. It is set to 20 + HD difference - Morale - Group morale mod.
|
||||
//SetAIInteger(HP_PERCENT_TO_CHECK_AT, 80);
|
||||
// %HP needed to be at to check morale. This doesn't affect "Never fight impossible odds"
|
||||
//SetSpawnInCondition(AI_FLAG_FLEEING_NO_OVERRIDING_HP_AMOUNT, AI_TARGETING_FLEE_MASTER);
|
||||
// This will turn off overriding HP checks. AI may decide to run even
|
||||
// not at the %HP above, this turns the checks off.
|
||||
|
||||
//SetAIInteger(AI_DAMAGE_AT_ONCE_FOR_MORALE_PENALTY, GetMaxHitPoints()/6);
|
||||
// Damage needed to be done at once to get a massive morale penalty (Below)
|
||||
//SetAIInteger(AI_DAMAGE_AT_ONCE_PENALTY, 6);
|
||||
// Penalty for the above, set for some time to negativly affect morale. Added to save DC for fleeing.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_FLEEING_FLEE_TO_NEAREST_NONE_SEEN, AI_TARGETING_FLEE_MASTER);
|
||||
// If set, just runs to nearest non-seen ally, and removes the loop for a good group of allies to run to.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_FLEEING_FLEE_TO_OBJECT, AI_TARGETING_FLEE_MASTER);
|
||||
// They will flee to the nearest object of the tag below, if set.
|
||||
//SetLocalString(OBJECT_SELF, AI_FLEE_OBJECT, "BOSS_TAG_OR_WHATEVER");
|
||||
// This needs setting if the above is to work.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_FLEEING_USE_VISUAL_EFFECT, AI_TARGETING_FLEE_MASTER);
|
||||
// If this is on, we play a visual effect while we flee.
|
||||
/************************ [Fleeing] *******************************************/
|
||||
|
||||
/************************ [Combat - Fighters] **********************************
|
||||
Fighter (Phiscal attacks, really) specific stuff - disarmed weapons, better
|
||||
at hand to hand, and archer behaviour.
|
||||
************************* [Combat - Fighters] *********************************/
|
||||
SetSpawnInCondition(AI_FLAG_COMBAT_PICK_UP_DISARMED_WEAPONS, AI_COMBAT_MASTER);
|
||||
// This sets to pick up weapons which are disarmed.
|
||||
|
||||
//SetAIInteger(AI_RANGED_WEAPON_RANGE, 3);
|
||||
// This is the range at which they go into melee (from using a ranged weapon). Default is 3 or 5.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_BETTER_AT_HAND_TO_HAND, AI_COMBAT_MASTER);
|
||||
// Set if you want them to move forwards into HTH sooner. Will always
|
||||
// if the enemy is a mage/archer, else % based on range.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ATTACKING, AI_COMBAT_MASTER);
|
||||
// For archers. If they have ally support, they'd rather move back & shoot then go into HTH.
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_MOVE_BACK, AI_COMBAT_MASTER);
|
||||
// This forces the move back from attackers, and shoot bows. Very small chance to go melee.
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_ARCHER_ALWAYS_USE_BOW, AI_COMBAT_MASTER);
|
||||
// This will make the creature ALWAYs use any bows it has. ALWAYS.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_NO_GO_FOR_THE_KILL, AI_COMBAT_MASTER);
|
||||
// Turns off any attempts to kill dying PCs, or attack low hit point people.
|
||||
// This is only ever attempted at 9 or 10 intelligence anyway.
|
||||
/************************ [Combat - Fighters] *********************************/
|
||||
|
||||
/************************ [Combat - Spell Casters] *****************************
|
||||
Spellcaster AI has been improved significantly. As well as adding all new spells,
|
||||
now spellcasters more randomly choose spells from the same level (EG: they
|
||||
may choose not to cast magic missile, and cast negative energy ray instead).
|
||||
|
||||
There are also options here for counterspelling, fast buffing, Cheat cast spells,
|
||||
dispelling, spell triggers, long ranged spells first, immunity toggles, and AOE settings.
|
||||
************************* [Combat - Spell Casters] ****************************/
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_LONGER_RANGED_SPELLS_FIRST, AI_COMBAT_MASTER);
|
||||
// Casts spells only if the caster would not move into range to cast them.
|
||||
// IE long range spells, then medium, then short (unless the enemy comes to us!)
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER);
|
||||
// When an enemy comes in 40M, we fast-cast many defensive spells, as if prepared.
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_SUMMON_FAMILIAR, AI_COMBAT_MASTER);
|
||||
// The caster summons thier familiar/animal companion. Either a nameless Bat or Badger respectivly.
|
||||
|
||||
// Counterspelling/Dispelling...
|
||||
// It checks for these classes within the 20M counterspell range.
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_COUNTER_SPELL_ARCANE, AI_COMBAT_MASTER);
|
||||
// If got dispels, it counterspells Arcane (Mage/Sorceror) spellcasters.
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_COUNTER_SPELL_DIVINE, AI_COMBAT_MASTER);
|
||||
// If got dispels, it counterspells Divine (Cleric/Druid) spellcasters.
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_COUNTER_SPELL_ONLY_IN_GROUP, AI_COMBAT_MASTER);
|
||||
// Recommended. Only counterspells with 5+ allies in group.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_DISPEL_MAGES_MORE, AI_COMBAT_MASTER);
|
||||
// Targets seen mages to dispel, else uses normal spell target.
|
||||
SetSpawnInCondition(AI_FLAG_COMBAT_DISPEL_IN_ORDER, AI_COMBAT_MASTER);
|
||||
// This will make the mage not dispel just anything all the time, but important (spell-stopping)
|
||||
// things first, others later, after some spells. If off, anything is dispelled.
|
||||
|
||||
// AOE's
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_NEVER_HIT_ALLIES, AI_COMBAT_MASTER);
|
||||
// Override toggle. Forces to never cast AOE's if it will hit an ally + harm them.
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_AOE_DONT_MIND_IF_THEY_SURVIVE, AI_COMBAT_MASTER);
|
||||
// Allies who will survive the blast are ignored for calculating best target.
|
||||
//SetAIInteger(AI_AOE_ALLIES_LOWEST_IN_AOE, 3);
|
||||
// Defualt: 3. If amount of allies in blast radius are equal or more then
|
||||
// this, then that location is ignored.
|
||||
//SetAIInteger(AI_AOE_HD_DIFFERENCE, -8);
|
||||
// Very weak allies (who are not comparable to us) are ignored if we would hit them.
|
||||
|
||||
// For these 2, if neither are set, the AI will choose AOE more if there are
|
||||
// lots of enemies, or singles if there are not many.
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_SINGLE_TARGETING, AI_COMBAT_MASTER);
|
||||
// For Same-level spells, single target spells are used first.
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_MANY_TARGETING, AI_COMBAT_MASTER);
|
||||
// For Same-level spells, AOE spells are used first.
|
||||
|
||||
SetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_INSTANT_DEATH_SPELLS, AI_COMBAT_MASTER);
|
||||
// A few Death spells may be cast top-prioritory if the enemy will always fail saves.
|
||||
SetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_SUMMON_TARGETING, AI_COMBAT_MASTER);
|
||||
// Will use a better target to summon a creature at (EG: Ranged attacker)
|
||||
SetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_IMMUNITY_CHECKING, AI_COMBAT_MASTER);
|
||||
// Turns On "GetIsImmune" checks. Auto on for 7+ Intel.
|
||||
SetSpawnInCondition(AI_FLAG_COMBAT_IMPROVED_SPECIFIC_SPELL_IMMUNITY, AI_COMBAT_MASTER);
|
||||
// Turns On checks for Globes & levels of spells. Auto on for 9+ Intel.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_MORE_ALLY_BUFFING_SPELLS, AI_COMBAT_MASTER);
|
||||
// This will make the caster buff more allies - or, in fact, use spells
|
||||
// to buff allies which they might have not used before.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_USE_ALL_POTIONS, AI_COMBAT_MASTER);
|
||||
// Uses all buffing spells before melee.
|
||||
|
||||
//SetAICheatCastSpells(SPELL_MAGIC_MISSILE, SPELL_ICE_DAGGER, SPELL_HORIZIKAULS_BOOM, SPELL_MELFS_ACID_ARROW, SPELL_NEGATIVE_ENERGY_RAY, SPELL_FLAME_ARROW);
|
||||
// Special: Mages cast for ever with this set.
|
||||
|
||||
// Spell triggers
|
||||
//SetSpellTrigger(SPELLTRIGGER_NOT_GOT_FIRST_SPELL, FALSE, 1, SPELL_PREMONITION);
|
||||
// This is just an example. See readme for more info.
|
||||
|
||||
/************************ [Combat - Spell Casters] ****************************/
|
||||
|
||||
/************************ [Combat - Dragons] ***********************************
|
||||
I have a fondness for dragons - in NWN they are deprived of many abilities. Here
|
||||
are some new ones for your enjoyment! Switches and flying for ANYTHING! :-)
|
||||
************************* [Combat - Dragons] **********************************/
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_COMBAT_NO_WING_BUFFET, AI_COMBAT_MASTER);
|
||||
//This sets so there is no Dragon wing buffet. Readme has details of it.
|
||||
//SetAIInteger(AI_DRAGON_FREQUENCY_OF_BUFFET, 3);
|
||||
// Min. Amount of Rounds between each buffet. See readme for counter defaults. Def: 3
|
||||
//SetAIInteger(AI_DRAGON_FREQUENCY_OF_BREATH, 3);
|
||||
// Min. Amount of Rounds between each breath use. See readme for counter defaults. Def: 3
|
||||
|
||||
// Default checks for dragon flying automatic turning on of flying.
|
||||
if(GetLevelByClass(CLASS_TYPE_DRAGON) || GetRacialType(OBJECT_SELF) == RACIAL_TYPE_DRAGON)
|
||||
{
|
||||
SetSpawnInCondition(AI_FLAG_COMBAT_FLYING, AI_COMBAT_MASTER);
|
||||
// This turns ON combat flying. I think anything winged looks A-OK. See readme for info.
|
||||
}
|
||||
/************************ [Combat - Dragons] **********************************/
|
||||
|
||||
/************************ [Combat Other - Healers/Healing] *********************
|
||||
Healing behaviour - not specifically clerics. See readme.
|
||||
************************* [Combat Other - Healers/Healing] ********************/
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_HEAL_AT_PERCENT_NOT_AMOUNT, AI_OTHER_COMBAT_MASTER);
|
||||
// if this is set, we ignore the amount we need to be damaged, as long
|
||||
// as we are under AI_HEALING_US_PERCENT.
|
||||
//SetAIInteger(AI_HEALING_US_PERCENT, 50);
|
||||
// % of HP we need to be at until we heal us at all. Default: 50
|
||||
//SetAIInteger(AI_HEALING_ALLIES_PERCENT, 60);
|
||||
// % of HP allies would need to be at to heal them Readme = info. Default: 60
|
||||
SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_WILL_RAISE_ALLIES_IN_BATTLE, AI_OTHER_COMBAT_MASTER);
|
||||
// Turns on rasing dead with Resurrection/Raise dead.
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_CURING, AI_OTHER_COMBAT_MASTER);
|
||||
// This turns off all healing.
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_ONLY_CURE_SELF, AI_OTHER_COMBAT_MASTER);
|
||||
// This turns off ally healing.
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_ONLY_RESTORE_SELF, AI_OTHER_COMBAT_MASTER);
|
||||
// This turns off ally restoring (Remove/Restoration).
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_USE_BAD_HEALING_SPELLS, AI_OTHER_COMBAT_MASTER);
|
||||
// This forces all cure spells to be used, check readme.
|
||||
//SetAIInteger(SECONDS_BETWEEN_STATUS_CHECKS, 30);
|
||||
// Seconds between when we loop everyone for bad effects like Fear/stun ETC. If not set, done each round.
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GIVE_POTIONS_TO_HELP, AI_OTHER_COMBAT_MASTER);
|
||||
// ActionGiveItem standard healing potion's to allies who need them, if they possess them.
|
||||
|
||||
/************************ [Combat Other - Healers/Healing] ********************/
|
||||
|
||||
/************************ [Combat Other - Skills] ******************************
|
||||
Skills are a part of fighting - EG Taunt. These are mainly on/off switches.
|
||||
A creature will *may* use it if they are not set to "NO_" for the skill.
|
||||
************************* [Combat Other - Skills] *****************************/
|
||||
|
||||
// "NO" - This is for forcing the skill NEVER to be used by the combat AI.
|
||||
// "FORCE" - This forces it on (and to be used), except if they have no got the skill.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PICKPOCKETING, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_PICKPOCKETING, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_TAUNTING, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_TAUNTING, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_EMPATHY, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_EMPATHY, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_HIDING, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_USING_HEALING_KITS, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_PARRYING, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_PARRYING, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_SEARCH, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_SEARCH, AI_OTHER_COMBAT_MASTER);
|
||||
// - Concentration - special notes in the readme
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_CONCENTRATION, AI_OTHER_COMBAT_MASTER);
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_CONCENTRATION, AI_OTHER_COMBAT_MASTER);
|
||||
|
||||
/************************ [Combat Other - Skills] *****************************/
|
||||
|
||||
/************************ [Combat Other - Leaders] *****************************
|
||||
Leaders/Bosses can be set to issue some orders and inspire more morale - and bring
|
||||
a lot of allies to a battle at once!
|
||||
************************* [Combat Other - Leaders] ****************************/
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER);
|
||||
// Special leader. Can issuse some orders. See readme for details.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_COMBAT_BOSS_MONSTER_SHOUT, AI_OTHER_COMBAT_MASTER);
|
||||
// Boss shout. 1 time use - calls all creatures in X meters (below) for battle!
|
||||
//SetAIInteger(AI_BOSS_MONSTER_SHOUT_RANGE, 60);
|
||||
// Defaults to a 60 M range. This can change it. Note: 1 toolset square = 10M.
|
||||
|
||||
/************************ [Combat Other - Leaders] ****************************/
|
||||
|
||||
/************************ [Other - Behaviour/Generic] **************************
|
||||
This is generic behaviours - alright, really it is all things that cannot
|
||||
really be categorised.
|
||||
************************* [Other - Behaviour/Generic] *************************/
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_NO_CLEAR_ACTIONS_BEFORE_CONVERSATION, AI_OTHER_MASTER);
|
||||
// No ClearAllActions() before BeginConversation. May keep a creature sitting.
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_NO_POLYMORPHING, AI_OTHER_MASTER);
|
||||
// This will stop all polymorphing spells feats from being used.
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_CHEAT_MORE_POTIONS, AI_OTHER_MASTER);
|
||||
// If at low HP, and no potion, create one and use it.
|
||||
//SetAIConstant(AI_POLYMORPH_INTO, POLYMORPH_TYPE_WEREWOLF);
|
||||
// Polymorph to this creature when damaged (once, natural effect).
|
||||
|
||||
//AI_CreateRandomStats(-3, 3, 6);
|
||||
// Create (Effect-applied) random statistics.
|
||||
//AI_CreateRandomOther(-2, 2, -2, 2, -2, 2, -2, 2);
|
||||
// Create (Effect-applied) random HP, saves, AC.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION, AI_OTHER_MASTER);
|
||||
// This will store our spawn location, and then move back there after combat.
|
||||
SetSpawnInCondition(AI_FLAG_OTHER_DONT_RESPOND_TO_EMOTES, AI_OTHER_MASTER);
|
||||
// This will ignore ALL chat by PC's (Enemies) who speak actions in Stars - *Bow*
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_DONT_SHOUT, AI_OTHER_MASTER);
|
||||
// Turns off all silent talking NPC's do to other NPC's.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_SEARCH_IF_ENEMIES_NEAR, AI_OTHER_MASTER);
|
||||
// Move randomly closer to enemies in range set below.
|
||||
//SetAIInteger(AI_SEARCH_IF_ENEMIES_NEAR_RANGE, 25);
|
||||
// This is the range creatures use, in metres.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_ONLY_ATTACK_IF_ATTACKED, AI_OTHER_MASTER);
|
||||
// One shot. We won't instantly attack a creature we see. See readme.
|
||||
|
||||
//SetAIInteger(AI_DOOR_INTELLIGENCE, 1);
|
||||
// 3 Special "What to do with Doors" settings. See readme. Good for animals.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_REST_AFTER_COMBAT, AI_OTHER_MASTER);
|
||||
// When combat is over, creature rests. Useful for replenising health.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_NO_PLAYING_VOICE_CHAT, AI_OTHER_MASTER);
|
||||
// Stops any use of "PlayVoiceChat". Use with Custom speakstrings.
|
||||
|
||||
/*** Death settings - still under AI_OTHER_MASTER ***/
|
||||
|
||||
//AI_SetDeathResRef("Resref Here");
|
||||
// Creates a creature from the string set. Instantly destroys this creatures body on death.
|
||||
|
||||
//SetAIConstant(AI_DEATH_VISUAL_EFFECT, VFX_FNF_IMPLOSION);
|
||||
// Fires this visual effect number instantly on death. Use FNF and IMP ones.
|
||||
|
||||
//SetAIInteger(AI_CORPSE_DESTROY_TIME, 30);
|
||||
// Seconds before body finally gets destroyed. Used for Clerical Raise Dead on NPC's.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_TURN_OFF_CORPSES, AI_OTHER_MASTER);
|
||||
// This turns off the SetDestroyable() usually performed, and the above timer.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_USE_BIOWARE_LOOTING, AI_OTHER_MASTER);
|
||||
// Makes the death file use Bioware's cool SetLootable() feature when corpses would disappear.
|
||||
|
||||
/*** Lag and a few performance settings - still under AI_OTHER_MASTER ***/
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_ITEMS, AI_OTHER_MASTER);
|
||||
// The creature doesn't check for, or use any items that cast spells.
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_SPELLS, AI_OTHER_MASTER);
|
||||
//The creature doesn't ever cast spells (and never checks them)
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_LISTENING, AI_OTHER_MASTER);
|
||||
// The creature doesn't have SetListening() set. Turns of the basic listening for shouts.
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_LAG_EQUIP_MOST_DAMAGING, AI_OTHER_MASTER);
|
||||
// Uses EquipMostDamaging(), like Bioware code. No shield/second weapon equipped.
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_CURING_ALLIES, AI_OTHER_MASTER);
|
||||
// This will stop checks for and curing of allies ailments.
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_LAG_IGNORE_HEARTBEAT, AI_OTHER_MASTER);
|
||||
// Stops the heartbeat running (Except Pre-Heartbeat-event).
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_LAG_TARGET_NEAREST_ENEMY, AI_OTHER_MASTER);
|
||||
// Ignores targeting settings. VERY good for lag/bad AI. Attacks nearest seen enemy.
|
||||
|
||||
/************************ [Other - Behaviour/Generic] *************************/
|
||||
|
||||
/************************ [User Defined and Shouts] ****************************
|
||||
The user defined events, set up to fire here.
|
||||
- New "Start combat attack" and "End Combat Attack" events
|
||||
- New "Pre" events. Use these to optionally stop a script from firing
|
||||
under cirtain circumstances as well! (Read nw_c2_defaultd or j_ai_onuserdef)
|
||||
(User Defined Event = UDE)
|
||||
************************* [User Defined and Shouts] ***************************/
|
||||
|
||||
// This is REQUIRED if we use any Pre-events. If not there, it will default
|
||||
// to the default User Defined Event script for the default AI.
|
||||
SetCustomUDEFileName("k_ai_onuserdef");
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_HEARTBEAT_EVENT, AI_UDE_MASTER); // UDE 1001
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, AI_UDE_MASTER); // UDE 1021
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_PERCIEVE_EVENT, AI_UDE_MASTER); // UDE 1002
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_PERCIEVE_PRE_EVENT, AI_UDE_MASTER); // UDE 1022
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_END_COMBAT_ROUND_EVENT, AI_UDE_MASTER); // UDE 1003
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_END_COMBAT_ROUND_PRE_EVENT, AI_UDE_MASTER); // UDE 1023
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_ON_DIALOGUE_EVENT, AI_UDE_MASTER); // UDE 1004
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_ON_DIALOGUE_PRE_EVENT, AI_UDE_MASTER); // UDE 1024
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_ATTACK_EVENT, AI_UDE_MASTER); // UDE 1005
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_ATTACK_PRE_EVENT, AI_UDE_MASTER); // UDE 1025
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_DAMAGED_EVENT, AI_UDE_MASTER); // UDE 1006
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_DAMAGED_PRE_EVENT, AI_UDE_MASTER); // UDE 1026
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_DEATH_EVENT, AI_UDE_MASTER); // UDE 1007
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_DEATH_PRE_EVENT, AI_UDE_MASTER); // UDE 1027
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_DISTURBED_EVENT, AI_UDE_MASTER); // UDE 1008
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_DISTURBED_PRE_EVENT, AI_UDE_MASTER); // UDE 1028
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_RESTED_EVENT, AI_UDE_MASTER); // UDE 1009
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_RESTED_PRE_EVENT, AI_UDE_MASTER); // UDE 1029
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_SPELL_CAST_AT_EVENT, AI_UDE_MASTER); // UDE 1011
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_SPELL_CAST_AT_PRE_EVENT, AI_UDE_MASTER); // UDE 1031
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_ON_BLOCKED_EVENT, AI_UDE_MASTER); // UDE 1015
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_ON_BLOCKED_PRE_EVENT, AI_UDE_MASTER); // UDE 1035
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_COMBAT_ACTION_EVENT, AI_UDE_MASTER); // UDE 1012
|
||||
// Fires when we have finnished all combat actions.
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_COMBAT_ACTION_PRE_EVENT, AI_UDE_MASTER); // UDE 1032
|
||||
// This fires at the start of DetermineCombatRound() *IF they can do an action*.
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_DAMAGED_AT_1_HP, AI_UDE_MASTER); // UDE 1014
|
||||
// Fires when we are damaged, and are at 1 HP. Use for immortal-flagged creatures.
|
||||
|
||||
/*** Speakstrings - as it were, said under cirtain conditions % chance each time ***/
|
||||
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_CONVERSATION, 100, 4, "Hello there", "I hope you enjoy your stay", "Do you work here too?", "*Hic*");
|
||||
// On Conversation - see readme. Replaces BeginConversation().
|
||||
|
||||
// Morale
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_MORALE_BREAK, 100, 3, "No more!", "I'm outta here!", "Catch me if you can!");
|
||||
// Spoken at running point, if they run to a group of allies.
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_CANNOT_RUN, 100, 3, "Never give up! Never surrender!", "I've no where to run, so make my day!", "RRRAAAAA!!!");
|
||||
// Spoken at running point, if they can find no ally to run to, and 4+ Intelligence. See readme
|
||||
//AI_SetSpawnInSpeakValue(AI_TALK_ON_STUPID_RUN, "Ahhhhgggg! NO MORE! Run!!");
|
||||
// As above, when morale breaks + no ally, but they panic and run from enemy at 3 or less intelligence.
|
||||
|
||||
// Combat
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_COMBAT_ROUND_EQUAL, 5, 4, "Come on!", "You won't win!", "We are not equals! I am better!", "Nothing will stop me!");
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_COMBAT_ROUND_THEM_OVER_US, 5, 4, "I'll try! try! and try again!", "Tough man, are we?", "Trying out your 'skills'? Pathetic excuse!", "Nothing good will come from killing me!");
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_COMBAT_ROUND_US_OVER_THEM, 5, 4, "My strength is mighty then yours!", "You will definatly die!", "NO chance for you!", "No mercy! Not for YOU!");
|
||||
// Spoken each DetermineCombatRound. % is /1000. See readme for Equal/Over/Under values.
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_TAUNT, 100, 3, "You're going down!", "No need to think, let my blade do it for you!", "Time to meet your death!");
|
||||
// If the creature uses thier skill, taunt, on an enemy this will be said.
|
||||
|
||||
// Event-driven.
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_PERCIEVE_ENEMY, 70, 6, "Stand and fight, lawbreaker!", "Don't run from the law!", "I have my orders!", "I am ready for violence!", "CHARGE!", "Time you died!");
|
||||
// This is said when they see/hear a new enemy, and start attacking them.
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_DAMAGED, 20, 2, "Ouch, damn you!", "Haha! Nothing will stop me!");
|
||||
// A random value is set to speak when damaged, and may fire same time as below ones.
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_PHISICALLY_ATTACKED, 20, 2, "Hah! Mear weapons won't defeat me!", "Pah! You cannot defeat me with such rubbish!");
|
||||
// This is said when an enemy attacks the creature with a melee/ranged weapon.
|
||||
//AI_SetSpawnInSpeakArray(AI_TALK_ON_HOSTILE_SPELL_CAST_AT, 20, 2, "No one spell will stop me!", "Is that all you have!?!");
|
||||
// This is said when an enemy attacks the creature with a hostile spell.
|
||||
//AI_SetSpawnInSpeakValue(AI_TALK_ON_DEATH, "Agggggg!");
|
||||
// This will ALWAYS be said, whenever the creature dies.
|
||||
|
||||
// Specific potion ones.
|
||||
//AI_SetSpawnInSpeakValue(AI_TALK_WE_PASS_POTION, "Here! Catch!");
|
||||
// This will be spoken when the creature passes a potion to an ally. See readme.
|
||||
//AI_SetSpawnInSpeakValue(AI_TALK_WE_GOT_POTION, "Got it!");
|
||||
// This will be spoken by the creature we pass the potion too, using AssignCommand().
|
||||
|
||||
// Leader ones
|
||||
//AI_SetSpawnInSpeakValue(AI_TALK_ON_LEADER_SEND_RUNNER, "Quickly! We need help!");
|
||||
// This will be said when the leader, if this creature, sends a runner.
|
||||
//AI_SetSpawnInSpeakValue(AI_TALK_ON_LEADER_ATTACK_TARGET, "Help attack this target!");
|
||||
// When the leader thinks target X should be attacked, it will say this.
|
||||
//AI_SetSpawnInSpeakValue(AI_TALK_ON_LEADER_BOSS_SHOUT, "Come my minions! To battle!");
|
||||
// This will be said when the leader, if this creature, sees an enemy and uses his "Boss Monster Shout", if turned on.
|
||||
|
||||
|
||||
/************************ [User Defined and Shouts] ***************************/
|
||||
|
||||
/************************ [Bioware: Animations/Waypoints/Treasure] *************
|
||||
All Bioware Stuff. I'd check out "x0_c2_spwn_def" for the SoU/Hordes revisions.
|
||||
************************* [Bioware: Animations/Waypoints/Treasure] ************/
|
||||
|
||||
// SetSpawnInCondition(NW_FLAG_STEALTH, NW_GENERIC_MASTER);
|
||||
// SetSpawnInCondition(NW_FLAG_SEARCH, NW_GENERIC_MASTER);
|
||||
// Uses said skill while WalkWaypoints()
|
||||
|
||||
// SetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING, NW_GENERIC_MASTER);
|
||||
// Separate the NPC's waypoints into day & night. See comment in "nw_i0_generic" for use.
|
||||
|
||||
// SetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS, NW_GENERIC_MASTER);
|
||||
// This will cause an NPC to use common animations it possesses,
|
||||
// and use social ones to any other nearby friendly NPCs.
|
||||
// SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS, NW_GENERIC_MASTER);
|
||||
// Same as above, except NPC will wander randomly around the area.
|
||||
|
||||
// SetAnimationCondition(NW_ANIM_FLAG_IS_CIVILIZED);
|
||||
// Interacts with placeables + More civilized actions. See Readme.
|
||||
// SetAnimationCondition(NW_ANIM_FLAG_CHATTER);
|
||||
// Will use random voicechats during animations, if Civilized
|
||||
// SetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE);
|
||||
// Will move around the area a bit more, if using Immobile Animations. See readme.
|
||||
|
||||
// Treasure generating.
|
||||
//CTG_GenerateNPCTreasure();
|
||||
// SoU. Requires "x0_i0_treasure" to be uncommented. See readme.
|
||||
//GenerateNPCTreasure();
|
||||
// Default NwN. Requires "nw_o2_coninclude" to be uncommented. See readme.
|
||||
|
||||
/************************ [Bioware: Animations/Waypoints/Treasure] ************/
|
||||
|
||||
// AI Behaviour. DO NOT CHANGE! DO NOT CHANGE!!!
|
||||
AI_SetUpEndOfSpawn();
|
||||
// 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!
|
||||
|
||||
/************************ [User] ***********************************************
|
||||
This is the ONLY place you should add user things, on spawn, such as
|
||||
visual effects or anything, as it is after SetUpEndOfSpawn. By default, this
|
||||
does have encounter animations on. This is here, so is easily changed :-D
|
||||
|
||||
Be careful otherwise.
|
||||
|
||||
Notes:
|
||||
- SetListening is already set to TRUE, unless AI_FLAG_OTHER_LAG_NO_LISTENING is on.
|
||||
- SetListenPattern's are set from 0 to 7.
|
||||
- You can use the wrappers AI_SpawnInInstantVisual and AI_SpawnInPermamentVisual
|
||||
for visual effects (Instant/Permament as appropriate).
|
||||
************************* [User] **********************************************/
|
||||
// Example (and default) of user addition:
|
||||
// - If we are from an encounter, set mobile (move around) animations.
|
||||
if(GetIsEncounterCreature())
|
||||
{
|
||||
SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS, NW_GENERIC_MASTER);
|
||||
}
|
||||
// Leave this in if you use the variable for creature attacks, as for golems. Bioware's code.
|
||||
int nNumber = GetLocalInt(OBJECT_SELF, "CREATURE_VAR_NUMBER_OF_ATTACKS");
|
||||
if(nNumber > 0)
|
||||
{
|
||||
SetBaseAttackBonus(nNumber);
|
||||
}
|
||||
|
||||
// If we are a ranger or paladin class, do not cast spells. This can be
|
||||
// manually removed if wished. To get the spells they have working correctly,
|
||||
// remove this, and use Monster Abilties instead of thier normal class spells.
|
||||
// if(GetLevelByClass(CLASS_TYPE_RANGER) >= 1 || GetLevelByClass(CLASS_TYPE_PALADIN) >= 1)
|
||||
// {
|
||||
// SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_SPELLS, AI_OTHER_MASTER);
|
||||
// }
|
||||
|
||||
/************************ [User] **********************************************/
|
||||
|
||||
// Note: You shouldn't really remove this, even if they have no waypoints.
|
||||
DelayCommand(2.0, SpawnWalkWayPoints());
|
||||
// Delayed walk waypoints, as to not upset instant combat spawning.
|
||||
// This will also check if to change to day/night posts during the walking, no heartbeats.
|
||||
}
|
493
_module/nss/j_ai_onspellcast.nss
Normal file
493
_module/nss/j_ai_onspellcast.nss
Normal file
@@ -0,0 +1,493 @@
|
||||
/*/////////////////////// [On Spell Cast At] ///////////////////////////////////
|
||||
Filename: j_ai_onspellcast or nw_c2_defaultb
|
||||
///////////////////////// [On Spell Cast At] ///////////////////////////////////
|
||||
What does this do? Well...
|
||||
- Any AOE spell effects are set in a timer, so we can react to them right
|
||||
- Reacts to hostile casters, or allies in combat
|
||||
|
||||
And the normal attack :-)
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added special AOE checks.
|
||||
- Hide checks.
|
||||
1.4 - Added more silent shouts. Edited the formatting. Moved a few things around.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This is fired when EventSpellCastAt(object oCaster, int nSpell, int bHarmful=TRUE)
|
||||
is signaled on the creature.
|
||||
|
||||
GetLastSpellCaster() = oCaster (Door, Placeable, Creature who cast it)
|
||||
GetLastSpell() = nSpell (The spell cast at us)
|
||||
GetLastSpellHarmful()= bHarmful (If it is harmful!)
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetLastSpellCaster, GetLastSpellHarmful GetLastSpell()
|
||||
///////////////////////// [On Spell Cast At] /////////////////////////////////*/
|
||||
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
// Sets a local timer if the spell is an AOE one
|
||||
void SetAOESpell(int nSpellCast, object oCaster);
|
||||
// Gets the nearest AOE cast by oCaster, of sTag.
|
||||
object GetNearestAOECastBy(string sTag, object oCaster);
|
||||
// Gets the amount of protections we have - IE globes
|
||||
int GetOurSpellLevelImmunity();
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-spell cast at-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_SPELL_CAST_AT_PRE_EVENT, EVENT_SPELL_CAST_AT_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
object oCaster = GetLastSpellCaster();
|
||||
int bHarmful = GetLastSpellHarmful();
|
||||
int nSpellCast = GetLastSpell();
|
||||
object oAttackerOfCaster;
|
||||
|
||||
// If harmful, we set the spell to a timer, if an AOE one.
|
||||
if(bHarmful && GetIsObjectValid(oCaster))
|
||||
{
|
||||
// Might set AOE spell to cast.
|
||||
SetAOESpell(nSpellCast, oCaster);
|
||||
}
|
||||
// If not a creature, probably an AOE or trap.
|
||||
if(GetObjectType(oCaster) != OBJECT_TYPE_CREATURE)
|
||||
{
|
||||
// 67: "[Spell] Caster isn't a creature! May look for target [Caster] " + GetName(oCaster)
|
||||
DebugActionSpeakByInt(67, oCaster);
|
||||
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
// Attack anyone else around
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Determine Combat Round
|
||||
DetermineCombatRound();
|
||||
}
|
||||
}
|
||||
// If a friend, or dead, or a DM, or invalid, or self, we ignore them.
|
||||
else if(!GetIgnoreNoFriend(oCaster) && oCaster != OBJECT_SELF)
|
||||
{
|
||||
// 1.3 changes here:
|
||||
// - We do NOT need to know if it is hostile or not, except if it is hostile
|
||||
// and they are not our faction! We do, however, use bHarmful for speakstrings.
|
||||
|
||||
// If harmful, we attack anyone! (and if is enemy)
|
||||
// 1.4: Faction equal check in GetIgnoreNoFriend()
|
||||
if(bHarmful || GetIsEnemy(oCaster))
|
||||
{
|
||||
// Spawn in condition hostile thingy
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER))
|
||||
{
|
||||
if(!GetIsEnemy(oCaster))
|
||||
{
|
||||
AdjustReputation(oCaster, OBJECT_SELF, -100);
|
||||
}
|
||||
}
|
||||
|
||||
if(bHarmful)
|
||||
{
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
// Hostile spell speaksting, if set.
|
||||
SpeakArrayString(AI_TALK_ON_HOSTILE_SPELL_CAST_AT);
|
||||
}
|
||||
}
|
||||
|
||||
// Turn of hiding check
|
||||
TurnOffHiding(oCaster);
|
||||
|
||||
// We attack
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// 68: "[Spell:Enemy/Hostile] Not in combat. Attacking: [Caster] " + GetName(oCaster)
|
||||
DebugActionSpeakByInt(68, oCaster);
|
||||
DetermineCombatRound(oCaster);
|
||||
}
|
||||
|
||||
// Shout to allies to attack the enemy who attacked me, got via. Last Hostile Actor.
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
// Else, was neutral perhaps. Don't attack them anyway.
|
||||
else
|
||||
{
|
||||
// 69: "[Spell] (ally). Not in combat. May Attack/Move [Caster] " + GetName(oCaster)
|
||||
DebugActionSpeakByInt(69, oCaster);
|
||||
|
||||
// Set special action to investigate - as if this event was triggered
|
||||
// by I_WAS_ATTACKED.
|
||||
|
||||
// If we are already attacking, we do not move
|
||||
if(CannotPerformCombatRound())
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We react as if the caster, a neutral, called for help ala
|
||||
// I_WAS_ATTACKED (they might not have, might just be
|
||||
// preperation for something), but normally, this is a neutral
|
||||
// casting a spell. Do not respond to PC's.
|
||||
if(!GetIsPC(oCaster))
|
||||
{
|
||||
IWasAttackedResponse(oCaster);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If they are not a faction equal, and valid, we help them.
|
||||
else if(GetIsObjectValid(oCaster) && GetFactionEqual(oCaster))
|
||||
{
|
||||
IWasAttackedResponse(oCaster);
|
||||
}
|
||||
// Fire End-spell cast at-UDE
|
||||
FireUserEvent(AI_FLAG_UDE_SPELL_CAST_AT_EVENT, EVENT_SPELL_CAST_AT_EVENT);
|
||||
}
|
||||
|
||||
// Sets a local timer if the spell is an AOE one
|
||||
void SetAOESpell(int nSpellCast, object oCaster)
|
||||
{
|
||||
// Check it is one we can check
|
||||
int bStop = TRUE;
|
||||
switch(nSpellCast)
|
||||
{
|
||||
case SPELL_ACID_FOG:
|
||||
case SPELL_MIND_FOG:
|
||||
case SPELL_STORM_OF_VENGEANCE:
|
||||
case SPELL_GREASE:
|
||||
case SPELL_CREEPING_DOOM:
|
||||
case SPELL_SILENCE:
|
||||
case SPELL_BLADE_BARRIER:
|
||||
case SPELL_CLOUDKILL:
|
||||
case SPELL_STINKING_CLOUD:
|
||||
case SPELL_WALL_OF_FIRE:
|
||||
case SPELL_INCENDIARY_CLOUD:
|
||||
case SPELL_ENTANGLE:
|
||||
case SPELL_EVARDS_BLACK_TENTACLES:
|
||||
case SPELL_CLOUD_OF_BEWILDERMENT:
|
||||
case SPELL_STONEHOLD:
|
||||
case SPELL_VINE_MINE:
|
||||
case SPELL_SPIKE_GROWTH:
|
||||
case SPELL_VINE_MINE_HAMPER_MOVEMENT:
|
||||
case SPELL_VINE_MINE_ENTANGLE:
|
||||
{
|
||||
bStop = FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Check immune level
|
||||
int nImmuneLevel = GetOurSpellLevelImmunity();
|
||||
if(nImmuneLevel >= 9)
|
||||
{
|
||||
bStop = TRUE;
|
||||
}
|
||||
// Check
|
||||
if(bStop == TRUE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// We do use intelligence here...
|
||||
int nAIInt = GetBoundriedAIInteger(AI_INTELLIGENCE);
|
||||
int bIgnoreSaves;
|
||||
int bIgnoreImmunities;
|
||||
object oAOE;
|
||||
|
||||
// If it is low, we ignore all things that we could ignore with it...
|
||||
if(nAIInt <= 3)
|
||||
{
|
||||
bIgnoreSaves = TRUE;
|
||||
bIgnoreImmunities = TRUE;
|
||||
}
|
||||
// Average ignores saves
|
||||
else if(nAIInt <= 7)
|
||||
{
|
||||
bIgnoreSaves = TRUE;
|
||||
bIgnoreImmunities = FALSE;
|
||||
}
|
||||
// Else, we do both.
|
||||
else
|
||||
{
|
||||
bIgnoreSaves = FALSE;
|
||||
bIgnoreImmunities = FALSE;
|
||||
}
|
||||
|
||||
int bSetAOE = FALSE;// TRUE means set to timer
|
||||
int nSaveDC = 11;
|
||||
|
||||
// Get the caster DC, the most out of WIS, INT or CHA...
|
||||
int nInt = GetAbilityModifier(ABILITY_INTELLIGENCE, oCaster);
|
||||
int nWis = GetAbilityModifier(ABILITY_WISDOM, oCaster);
|
||||
int nCha = GetAbilityModifier(ABILITY_CHARISMA, oCaster);
|
||||
|
||||
if(nInt > nWis && nInt > nCha)
|
||||
{
|
||||
nSaveDC += nInt;
|
||||
}
|
||||
else if(nWis > nCha)
|
||||
{
|
||||
nSaveDC += nWis;
|
||||
}
|
||||
else
|
||||
{
|
||||
nSaveDC += nCha;
|
||||
}
|
||||
// Note:
|
||||
// - No reaction type/friendly checks. Signal Event is only fired if the
|
||||
// spell WILL pierce any PvP/Friendly/Area settings
|
||||
|
||||
// We check immunities here, please note...
|
||||
switch(nSpellCast)
|
||||
{
|
||||
// First: IS GetIsReactionTypeHostile ones.
|
||||
case SPELL_EVARDS_BLACK_TENTACLES:
|
||||
// Fortitude save, but if we are immune to the hits, its impossible to hurt us
|
||||
{
|
||||
// If save immune OR AC immune, we ignore this.
|
||||
if(25 >= GetAC(OBJECT_SELF) && nImmuneLevel < 4 &&
|
||||
((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 2) || bIgnoreSaves))
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
// Nearest string of tag
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_EVARDS_BLACK_TENTACLES, oCaster);
|
||||
}
|
||||
}
|
||||
case SPELL_SPIKE_GROWTH:
|
||||
case SPELL_VINE_MINE_HAMPER_MOVEMENT:
|
||||
// d4 damage. LOTS of speed loss.
|
||||
// Reflex save, or immunity, would stop the speed
|
||||
{
|
||||
if(nImmuneLevel < 3 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MOVEMENT_SPEED_DECREASE) || bIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 5) || bIgnoreSaves))
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
// Both use ENTANGLE AOE's
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_ENTANGLE, oCaster);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPELL_ENTANGLE:
|
||||
case SPELL_VINE_MINE_ENTANGLE:
|
||||
{
|
||||
if(nImmuneLevel < 1 &&
|
||||
(!GetHasFeat(FEAT_WOODLAND_STRIDE) || bIgnoreImmunities) &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || bIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 4) || bIgnoreSaves))
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
// Both use ENTANGLE AOE's
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_ENTANGLE, oCaster);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPELL_WEB:
|
||||
{
|
||||
if(nImmuneLevel < 1 &&
|
||||
(!GetHasFeat(FEAT_WOODLAND_STRIDE) || bIgnoreImmunities) &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || bIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 4) || bIgnoreSaves))
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
// Web AOE
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_WEB, oCaster);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Fort save
|
||||
case SPELL_STINKING_CLOUD:
|
||||
{
|
||||
if(nImmuneLevel < 3 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_POISON) || bIgnoreImmunities) &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_DAZED) || bIgnoreImmunities) &&
|
||||
((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 6) || bIgnoreSaves))
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
// Stinking cloud persistant AOE.
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGSTINK, oCaster);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Fort save
|
||||
case SPELL_CLOUD_OF_BEWILDERMENT:
|
||||
{
|
||||
if(nImmuneLevel < 2 &&
|
||||
((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 7) || bIgnoreSaves))
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
// Bewilderment cloud persistant AOE.
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGBEWILDERMENT, oCaster);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Special: Mind save is the effect.
|
||||
case SPELL_STONEHOLD:
|
||||
{
|
||||
if(nImmuneLevel < 6 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MIND_SPELLS) || bIgnoreImmunities) &&
|
||||
((GetWillSavingThrow(OBJECT_SELF) < nSaveDC + 7) || bIgnoreSaves))
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
// Stonehold persistant AOE.
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_STONEHOLD, oCaster);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Special: EFFECT_TYPE_SAVING_THROW_DECREASE is the effect.
|
||||
case SPELL_MIND_FOG:
|
||||
{
|
||||
if(nImmuneLevel < 5 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_SAVING_THROW_DECREASE) || bIgnoreImmunities) &&
|
||||
((GetWillSavingThrow(OBJECT_SELF) < nSaveDC + 6) || bIgnoreSaves))
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
// Mind fog
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGMIND, oCaster);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Special: Feats, knockdown
|
||||
case SPELL_GREASE:
|
||||
{
|
||||
if(nImmuneLevel < 1 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_KNOCKDOWN) || bIgnoreImmunities) &&
|
||||
(!GetHasFeat(FEAT_WOODLAND_STRIDE, OBJECT_SELF) || bIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 2) || bIgnoreSaves))
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
// Grease
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_GREASE, oCaster);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// All other ReactionType ones. Some have different saves though!
|
||||
case SPELL_BLADE_BARRIER: // Reflex
|
||||
case SPELL_INCENDIARY_CLOUD:// reflex
|
||||
case SPELL_WALL_OF_FIRE:// Reflex
|
||||
{
|
||||
if(nImmuneLevel < 6 &&
|
||||
(((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 6) &&
|
||||
!GetHasFeat(FEAT_IMPROVED_EVASION) &&
|
||||
!GetHasFeat(FEAT_EVASION)) || bIgnoreSaves))
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
if(nSpellCast == SPELL_BLADE_BARRIER)
|
||||
{
|
||||
// BB
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_WALLBLADE, oCaster);
|
||||
}
|
||||
else if(nSpellCast == SPELL_INCENDIARY_CLOUD)
|
||||
{
|
||||
// Fog of fire
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGFIRE, oCaster);
|
||||
}
|
||||
else if(nSpellCast == SPELL_WALL_OF_FIRE)
|
||||
{
|
||||
// Wall of fire
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_WALLFIRE, oCaster);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPELL_ACID_FOG: // Fort: Half. No check, always damages.
|
||||
case SPELL_CLOUDKILL:// No save!
|
||||
case SPELL_CREEPING_DOOM: // No save!
|
||||
{
|
||||
if(nImmuneLevel < 6)
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
if(nSpellCast == SPELL_ACID_FOG)
|
||||
{
|
||||
// Acid fog
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGACID, oCaster);
|
||||
}
|
||||
else if(nSpellCast == SPELL_CLOUDKILL)
|
||||
{
|
||||
// Cloud Kill
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGKILL, oCaster);
|
||||
}
|
||||
else if(nSpellCast == SPELL_CREEPING_DOOM)
|
||||
{
|
||||
// Creeping doom
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_CREEPING_DOOM, oCaster);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Storm - because the AI likes it, we stay in it if it is ours :-)
|
||||
case SPELL_STORM_OF_VENGEANCE: // Reflex partial. No check, always damages.
|
||||
{
|
||||
if(oCaster != OBJECT_SELF && nImmuneLevel < 9)
|
||||
{
|
||||
bSetAOE = TRUE;
|
||||
// Storm of vengance
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_STORM, oCaster);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(bSetAOE)
|
||||
{
|
||||
if(!GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast)))
|
||||
{
|
||||
SetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast), 18.0);
|
||||
// Set nearest AOE
|
||||
if(GetIsObjectValid(oAOE))
|
||||
{
|
||||
// Set nearest AOE of this spell to the local
|
||||
object oNearest = GetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast));
|
||||
if(GetDistanceToObject(oAOE) < GetDistanceToObject(oNearest) ||
|
||||
!GetIsObjectValid(oNearest))
|
||||
{
|
||||
SetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast), oAOE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Gets the nearest AOE cast by oCaster, of sTag.
|
||||
object GetNearestAOECastBy(string sTag, object oCaster)
|
||||
{
|
||||
int nCnt = 1;
|
||||
object oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, nCnt);
|
||||
object oReturn = OBJECT_INVALID;
|
||||
// Loop
|
||||
while(GetIsObjectValid(oAOE) && !GetIsObjectValid(oReturn))
|
||||
{
|
||||
// Check creator
|
||||
if(GetAreaOfEffectCreator(oAOE) == oCaster)
|
||||
{
|
||||
oReturn = oAOE;
|
||||
}
|
||||
nCnt++;
|
||||
oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, nCnt);
|
||||
}
|
||||
return oReturn;
|
||||
}
|
||||
|
||||
// Gets the amount of protections we have - IE globes
|
||||
int GetOurSpellLevelImmunity()
|
||||
{
|
||||
int nNatural = GetLocalInt(OBJECT_SELF, AI_SPELL_IMMUNE_LEVEL);
|
||||
// Stop here, if natural is over 4
|
||||
if(nNatural > 4) return nNatural;
|
||||
|
||||
// Big globe affects 4 or lower spells
|
||||
if(GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, OBJECT_SELF) || nNatural >= 4)
|
||||
return 4;
|
||||
// Minor globe is 3 or under
|
||||
if(GetHasSpellEffect(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, OBJECT_SELF) ||
|
||||
// Shadow con version
|
||||
GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE, OBJECT_SELF) ||
|
||||
nNatural >= 3)
|
||||
return 3;
|
||||
// 2 and under is ethereal visage.
|
||||
if(GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, OBJECT_SELF) || nNatural >= 2)
|
||||
return 2;
|
||||
// Ghostly Visarge affects 1 or 0 level spells, and any spell immunity.
|
||||
if(GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, OBJECT_SELF) || nNatural >= 1 ||
|
||||
// Or shadow con version.
|
||||
GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE, OBJECT_SELF))
|
||||
return 1;
|
||||
// Return nNatural, which is 0-9
|
||||
return FALSE;
|
||||
}
|
326
_module/nss/j_ai_onuserdef.nss
Normal file
326
_module/nss/j_ai_onuserdef.nss
Normal file
@@ -0,0 +1,326 @@
|
||||
/*/////////////////////// [On User Defined] ////////////////////////////////////
|
||||
Filename: J_AI_OnUserDef or nw_c2_defaultd
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
1.4 Adds proper Pre-event functionality. Use this to make sure you keep the
|
||||
AI working, but making small additions using this event.
|
||||
|
||||
Can be deleted to save space if you want :-)
|
||||
|
||||
How to use user defined events (brief):
|
||||
|
||||
There are a set of optional Spawn In values you can set within the spawn file.
|
||||
If you set one of the Events to fire, it will activate this script. Then,
|
||||
under the correct choice (EG I choose the Pre-Heartbeat event, then I
|
||||
uncomment the line "SetSpawnInCondition(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, AI_UDE_MASTER);"
|
||||
and find, in this file, the section with EVENT_HEARTBEAT_PRE_EVENT above it).
|
||||
add in whatever to do.
|
||||
|
||||
With my Pre-heartbeat example, if I wanted it to check for a PC, then
|
||||
check for a combat dummy, and attack it, I'd add this between the brackets:
|
||||
|
||||
// Code:
|
||||
|
||||
// Not in combat, of course!
|
||||
if(!GetIsInCombat())
|
||||
{
|
||||
// Function in j_inc_npc_attack to get nearest PC
|
||||
object oPC = GetNearestPCCreature();
|
||||
// Why check for a PC? Well, it saves memory
|
||||
if(GetIsObjectValid(oPC) && GetDistanceToObject(oPC) <= 40.0)
|
||||
{
|
||||
object oDummy = GetNearestObjectByTag("DUMMY");
|
||||
if(GetIsObjectValid(oDummy))
|
||||
{
|
||||
ClearAllActions();
|
||||
ActionAttack(oDummy);
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_HEARTBEAT_PRE_EVENT);
|
||||
// Stop rest of script
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End code
|
||||
|
||||
Simple, no?
|
||||
|
||||
You can delete sections you don't need, and is recommended as long as you know
|
||||
how to use User Defined events.
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added in with some documentation
|
||||
1.4 - Changed Pre-events. Now, it uses Execute Script. Will need to set
|
||||
a special string on the creature to now what script to fire.
|
||||
- It means they work correctly, however!
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: Dependant on event. See seperate event scripts.
|
||||
///////////////////////// [On User Defined] //////////////////////////////////*/
|
||||
|
||||
// This contains a lot of useful things.
|
||||
// - Combat starting
|
||||
// - Constant values
|
||||
// - Get/Set spawn in values.
|
||||
#include "J_INC_OTHER_AI"
|
||||
// This contains some useful things to get NPC's to attack and so on.
|
||||
#include "J_INC_NPC_ATTACK"
|
||||
|
||||
/************************ [UDE Values] *****************************************
|
||||
These are uneeded, but here for reference. Use the constants in the file
|
||||
"j_inc_constants" like "EVENT_HEARTBEAT_PRE_EVENT" which is classed as 1021.
|
||||
* The normal death event might not fire before the creature has vanished.
|
||||
Use the Pre-event (but with no stopping the death event) if you want a special
|
||||
death event to happen.
|
||||
|
||||
Name Normal-End event - Pre-Event
|
||||
Heartbeat Event 1001 1021
|
||||
Percieve Event 1002 1022
|
||||
Combat Round Event 1003 1023
|
||||
Dialog Event 1004 1024
|
||||
Attack Event 1005 1025
|
||||
Damaged Event 1006 1026
|
||||
Death Event 1007 1027
|
||||
Disturbed Event 1008 1028
|
||||
Rested Event 1009 1029
|
||||
Spell Cast At Event 1011 1031
|
||||
Combat Action Event 1012 1032
|
||||
Damaged 1HP Event 1014 -
|
||||
Blocked Event 1015 1035
|
||||
************************* [UDE Values] ****************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// Get the user defined number.
|
||||
// * NOTE: YOU MUST USE AI_GetUDENumber(), not GetUserDefinedEventNumber()!
|
||||
int nEvent = AI_GetUDENumber();
|
||||
|
||||
// Events.
|
||||
switch(nEvent)
|
||||
{
|
||||
// Event Heartbeat
|
||||
// Arguments: Basically, none. Nothing activates this script. Fires every 6 seconds.
|
||||
case EVENT_HEARTBEAT_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the On Heartbeat file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_HEARTBEAT_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_HEARTBEAT_EVENT:
|
||||
{
|
||||
// This fires after the rest of the On Heartbeat file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Percieve
|
||||
// Arguments: GetLastPerceived, GetLastPerceptionSeen, GetLastPerceptionHeard,
|
||||
// GetLastPerceptionVanished, GetLastPerceptionInaudible.
|
||||
case EVENT_PERCIEVE_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the On Percieve file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_PERCIEVE_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_PERCIEVE_EVENT:
|
||||
{
|
||||
// This fires after the rest of the On Percieve file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Combat Round End
|
||||
// Arguments: GetAttackTarget, GetLastHostileActor, GetAttemptedAttackTarget,
|
||||
// GetAttemptedSpellTarget (Or these are useful at least!)
|
||||
case EVENT_END_COMBAT_ROUND_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the On Combat Round End file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_END_COMBAT_ROUND_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_END_COMBAT_ROUND_EVENT:
|
||||
{
|
||||
// This fires after the rest of the On Combat Round End file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Dialogue
|
||||
// Arguments: GetListenPatternNumber, GetLastSpeaker, TestStringAgainstPattern,
|
||||
// GetMatchedSubstring (I think),
|
||||
case EVENT_ON_DIALOGUE_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the dialog file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_ON_DIALOGUE_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_ON_DIALOGUE_EVENT:
|
||||
{
|
||||
// This fires after the rest of the dialog file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Attacked
|
||||
// Arguments: GetLastAttacker, GetLastWeaponUsed, GetLastAttackMode,
|
||||
// GetLastAttackType
|
||||
case EVENT_ATTACK_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the Attacked file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_ATTACK_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_ATTACK_EVENT:
|
||||
{
|
||||
// This fires after the rest of the Attacked file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Damaged
|
||||
// Arguments: GetTotalDamageDealt, GetLastDamager, GetCurrentHitPoints
|
||||
// (and max), GetDamageDealtByType
|
||||
case EVENT_DAMAGED_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the damaged file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_DAMAGED_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_DAMAGED_EVENT:
|
||||
{
|
||||
// This fires after the rest of the damaged file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Death
|
||||
// Arguments: GetLastKiller
|
||||
case EVENT_DEATH_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the death file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_DEATH_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_DEATH_EVENT:
|
||||
{
|
||||
// This fires after the rest of the death file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Distrubed
|
||||
// Arguments: GetInventoryDisturbItem, GetLastDisturbed,
|
||||
// GetInventoryDisturbType (should always be stolen :-( ).
|
||||
case EVENT_DISTURBED_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the disturbed file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_DISTURBED_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_DISTURBED_EVENT:
|
||||
{
|
||||
// This fires after the rest of the disturbed file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Rested
|
||||
// Arguments: None
|
||||
// Note: Not sure if this fires at the end of rest event, but the actual
|
||||
// duration of the rest is 0, so you never "see" it.
|
||||
case EVENT_RESTED_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the rested file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_RESTED_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_RESTED_EVENT:
|
||||
{
|
||||
// This fires after the rest of the rested file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Spell cast at
|
||||
// Arguments: GetLastSpellCaster, GetLastSpellHarmful GetLastSpell()
|
||||
case EVENT_SPELL_CAST_AT_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the Spell Cast At file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_SPELL_CAST_AT_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_SPELL_CAST_AT_EVENT:
|
||||
{
|
||||
// This fires after the rest of the Spell Cast At End file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Blocked
|
||||
// Arguements: GetBlockingDoor, GetIsDoorActionPossible, GetLocked,
|
||||
// GetLockKeyRequired, GetLockKeyTag, GetLockUnlockDC, GetPlotFlag.
|
||||
case EVENT_ON_BLOCKED_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the on blocked file does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_ON_BLOCKED_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_ON_BLOCKED_EVENT:
|
||||
{
|
||||
// This fires after the rest of the on blocked file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Combat Action
|
||||
// Arguments: GetAttackTarget(), and lots of others.
|
||||
// Note: Fires when DetermineCombatRound runs to perform an action.
|
||||
case EVENT_COMBAT_ACTION_PRE_EVENT:
|
||||
{
|
||||
// This fires before the rest of the Determine Combat Round call does
|
||||
|
||||
// Exit (Stop the rest of the script)
|
||||
SetToExitFromUDE(EVENT_COMBAT_ACTION_PRE_EVENT);
|
||||
}
|
||||
break;
|
||||
case EVENT_COMBAT_ACTION_EVENT:
|
||||
{
|
||||
// This fires after the rest of the Determine Combat Round call does
|
||||
// Calling ClearAllActions should stop any actions added in the call.
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// Event Damaged at 1 HP.
|
||||
// Arguments: None really.
|
||||
// Note: Fires OnDamaged, when we have exactly 1HP. Use for Immortal Creatures.
|
||||
case EVENT_DAMAGED_AT_1_HP:
|
||||
{
|
||||
// This fires after the rest of the On Combat Round End file does
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
// End all in-built events. Add more in here, if you wish.
|
||||
}
|
||||
}
|
@@ -1,19 +1,21 @@
|
||||
/************************ [Set Weapons] ****************************************
|
||||
Filename: j_ai_setweapons
|
||||
************************* [Set Weapons] ****************************************
|
||||
/*/////////////////////// [Set Weapons] ////////////////////////////////////////
|
||||
Filename: J_AI_SetWeapons
|
||||
///////////////////////// [Set Weapons] ////////////////////////////////////////
|
||||
Executed to re-set any weapons, or set them at spawn, using ExecuteScript.
|
||||
|
||||
It isn't included in the generic AI or onspawn to try and speed it up a little
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added to a new file, removed from spawn include.
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Nothing changed here. Include file might have changed however.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
It can be easily re-added to the spawn include, however, the generic AI calls
|
||||
it so little, that it may well be useful to keep a seperate file anyway.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: RESET_HEALING_KITS
|
||||
************************* [Set Weapons] ***************************************/
|
||||
///////////////////////// [Set Weapons] //////////////////////////////////////*/
|
||||
|
||||
#include "J_INC_SETWEAPONS"
|
||||
|
||||
#include "j_inc_setweapons"
|
||||
void main()
|
||||
{
|
||||
if(GetAIInteger(RESET_HEALING_KITS))
|
||||
|
@@ -1,17 +1,18 @@
|
||||
/************************ [Resume Waypoint Walking] ****************************
|
||||
/*/////////////////////// [Resume Waypoint Walking] ////////////////////////////
|
||||
Filename: j_ai_walkwaypoin
|
||||
************************* [Resume Waypoint Walking] ****************************
|
||||
///////////////////////// [Resume Waypoint Walking] ////////////////////////////
|
||||
Executed On Spawn, and from the end of combat, to resume walking
|
||||
|
||||
Notes:
|
||||
Needed my own file as to execute and be sure it exsisted. This means
|
||||
the Non-override version will not use 2 different waypoint files most of the
|
||||
time.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.0 - Added
|
||||
1.3 - Changed to SoU waypoints. fired from End of Spawn and heartbeat.
|
||||
It also returns to start location if set.
|
||||
************************* [Workings] *******************************************
|
||||
1.4 -
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Might change to SoU waypoints, this, at the moment, will just
|
||||
walk normal waypoints.
|
||||
|
||||
@@ -48,18 +49,21 @@
|
||||
Waypoints can be between areas and creatures will move there, if you set a
|
||||
global integer variable called X2_SWITCH_CROSSAREA_WALKWAYPOINTS on your
|
||||
module to 1.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: WAYPOINT_RUN, WAYPOINT_PAUSE are set On Spawn to remember
|
||||
the pause/run actions.
|
||||
************************* [Resume Waypoint Walking] ***************************/
|
||||
///////////////////////// [Resume Waypoint Walking] //////////////////////////*/
|
||||
|
||||
#include "j_inc_debug"
|
||||
#include "NW_I0_GENERIC"
|
||||
#include "J_INC_DEBUG"
|
||||
|
||||
const string WAYPOINT_RUN = "WAYPOINT_RUN";
|
||||
const string WAYPOINT_PAUSE = "WAYPOINT_PAUSE";
|
||||
const int AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION = 0x00020000;
|
||||
const string AI_OTHER_MASTER = "AI_OTHER_MASTER";
|
||||
const string AI_LOCATION = "AI_LOCATION";
|
||||
const string AI_RETURN_TO_POINT = "AI_RETURN_TO_POINT";
|
||||
|
||||
|
||||
// For return to.
|
||||
int AI_GetSpawnInCondition(int nCondition, string sName, object oTarget = OBJECT_SELF);
|
||||
@@ -69,7 +73,7 @@ void main()
|
||||
// FIRST, if we are meant to move back to the start location, do it.
|
||||
if(AI_GetSpawnInCondition(AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION, AI_OTHER_MASTER))
|
||||
{
|
||||
location lReturnPoint = GetLocalLocation(OBJECT_SELF, "AI_RETURN_TO_POINT");
|
||||
location lReturnPoint = GetLocalLocation(OBJECT_SELF, AI_LOCATION + AI_RETURN_TO_POINT);
|
||||
object oReturnArea = GetAreaFromLocation(lReturnPoint);
|
||||
if(GetIsObjectValid(oReturnArea))
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [Dragon Wing Buffet] *********************************
|
||||
/*/////////////////////// [Ability - Dragon Wing Buffet] ///////////////////////
|
||||
Filename: J_AI_WingBuffet
|
||||
************************* [Dragon Wing Buffet] *********************************
|
||||
///////////////////////// [Ability - Dragon Wing Buffet] ///////////////////////
|
||||
"The dragon will launch into the air, knockdown
|
||||
all opponents who fail a Reflex Save and then
|
||||
land on one of those opponents doing damage
|
||||
@@ -9,71 +9,90 @@
|
||||
This is modified by Jasperre for use by Dragons in the AI. Instead of
|
||||
crashing, using effect appear, disspear, it just uses effect appear.
|
||||
|
||||
************************* [History] ********************************************
|
||||
Version 1.3 changes
|
||||
- Made the "action attack" work better, getting the nearest
|
||||
seen and heard instead of the nearest (which may not be seen or heard).
|
||||
- Added in random damage for each target!
|
||||
- Faction Equal as well as GetIsFriend check.
|
||||
************************* [Workings] *******************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Made the "action attack" work better, getting the nearest
|
||||
seen and heard instead of the nearest (which may not be seen or heard).
|
||||
- Added in random damage for each target!
|
||||
- Faction Equal as well as GetIsFriend check.
|
||||
1.4 - Cleaned it up a bit, to be more readable.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Executed via. ExecuteScript from the AI file, it is seperate because it is
|
||||
almost a new AI ability.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A
|
||||
************************* [Dragon Wing Buffet] ********************************/
|
||||
///////////////////////// [Ability - Dragon Wing Buffet] /////////////////////*/
|
||||
|
||||
void main()
|
||||
{
|
||||
//Declare major variables
|
||||
// Stop the creature's actions.
|
||||
ClearAllActions();// To rid errors.
|
||||
effect eKnockDown = EffectKnockdown();
|
||||
|
||||
// Declare major variables
|
||||
int nDamage;
|
||||
int nDC = GetHitDice(OBJECT_SELF);
|
||||
effect eDam;
|
||||
effect eVis = EffectVisualEffect(VFX_IMP_PULSE_WIND);
|
||||
// Use a delay based on range,
|
||||
float fDelay;
|
||||
location lSelf = GetLocation(OBJECT_SELF);
|
||||
string sMessage = GetName(OBJECT_SELF) + " is using its wing buffet against you!";
|
||||
location lTarget;
|
||||
float fRandomKnockdown;
|
||||
// Use a delay based on range,
|
||||
float fDelay;
|
||||
|
||||
// Declare effects
|
||||
effect eDam;
|
||||
effect eKnockDown = EffectKnockdown();
|
||||
effect eVis = EffectVisualEffect(VFX_IMP_PULSE_WIND);
|
||||
|
||||
// Pulse of wind applied...
|
||||
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lSelf);
|
||||
//Apply the VFX impact and effects
|
||||
//Get first target in spell area
|
||||
|
||||
// Get first target in spell area
|
||||
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lSelf);
|
||||
while(GetIsObjectValid(oTarget))
|
||||
{
|
||||
// Get thier location (for visual) and the delay.
|
||||
lTarget = GetLocation(oTarget);
|
||||
fDelay = GetDistanceToObject(oTarget)/20.0;
|
||||
|
||||
// Wind pulse to all
|
||||
DelayCommand(fDelay, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, lTarget));
|
||||
//Get next target in spell area
|
||||
|
||||
// Do not effect allies.
|
||||
if(!GetIsFriend(oTarget) && !GetFactionEqual(oTarget))
|
||||
{
|
||||
// Send a message about the wing buffet (allies do not see this)
|
||||
SendMessageToPC(oTarget, sMessage);
|
||||
|
||||
// Huge creatures (IE: Dragon size) are not affected.
|
||||
if(GetCreatureSize(oTarget) != CREATURE_SIZE_HUGE)
|
||||
{
|
||||
// A standard (not spell) reflex save negates the damage and knockdown
|
||||
if(!ReflexSave(oTarget, nDC))
|
||||
{
|
||||
// Randomise damage. (nDC = Hit dice)
|
||||
nDamage = Random(nDC) + 11;
|
||||
|
||||
// Define the damage
|
||||
eDam = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING);
|
||||
// Randomise knockdown, to minimum of 6.0 (1.0/2 = 0.5. + 5.5 = 6.0)
|
||||
|
||||
// Randomise knockdown duration, to minimum of 6.0 (1.0/2 = 0.5. + 5.5 = 6.0)
|
||||
fRandomKnockdown = 5.5 + ((IntToFloat(Random(30)) + 1.0)/10.0);
|
||||
|
||||
// We'll have a windy effect..depending on range
|
||||
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
|
||||
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockDown, oTarget, fRandomKnockdown));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get next target in spell area
|
||||
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lSelf);
|
||||
}
|
||||
|
||||
// Do a great flapping wings on land effect.
|
||||
effect eAppear = EffectAppear();
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eAppear, OBJECT_SELF);
|
||||
// Attack the nearest seen (so not to stand there for 6 seconds).
|
||||
|
||||
// Attack the nearest seen (so not to stand there for 6 seconds, but get
|
||||
// back in the action!).
|
||||
object oNearest = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
if(GetIsObjectValid(oNearest))
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [Dragon Flying] **************************************
|
||||
/*/////////////////////// [Ability - Dragon Flying] ////////////////////////////
|
||||
Filename: J_AI_WingFlying
|
||||
************************* [Dragon Flying] **************************************
|
||||
///////////////////////// [Ability - Dragon Flying] ////////////////////////////
|
||||
Hey, a dragon can fly (if we are set to, mind you!) this is executed from
|
||||
the default AI, using local objects to "fly" to, a duration based on the
|
||||
distance between the 2 places.
|
||||
@@ -13,10 +13,11 @@
|
||||
- Can be used with NPC's who are not dragons, but if they are not huge,
|
||||
the damage is not done (only the pulses at thier location and the target
|
||||
location)
|
||||
************************* [History] ********************************************
|
||||
Version 1.3
|
||||
- Added
|
||||
************************* [Workings] *******************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added
|
||||
1.4 - Added an actual spell event fire for the damage. It might not have
|
||||
registered with some hostile monsters otherwise! (EG: DR)
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Executed via. ExecuteScript from the AI file, it is seperate because it is
|
||||
almost a new AI ability.
|
||||
|
||||
@@ -24,11 +25,11 @@
|
||||
1M between targets. Not too much, but enough.
|
||||
|
||||
Does damage to landing and taking off sites too :-)
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A
|
||||
************************* [Dragon Flying] *************************************/
|
||||
///////////////////////// [Ability - Dragon Flying] //////////////////////////*/
|
||||
|
||||
#include "j_inc_constants"
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
// Damages area with blast of flying
|
||||
void DoDamageToArea(location lLocation);
|
||||
@@ -55,7 +56,7 @@ void main()
|
||||
if(GetCreatureSize(OBJECT_SELF) == CREATURE_SIZE_HUGE)
|
||||
{
|
||||
// Damage instantly
|
||||
DelayCommand(f1, DoDamageToArea(lSelf));
|
||||
DelayCommand(1.0, DoDamageToArea(lSelf));
|
||||
// Delay the jump down damage - a little extra delay mind you.
|
||||
DelayCommand(fDuration + 1.2, DoDamageToArea(lJumpTo));
|
||||
}
|
||||
@@ -64,7 +65,7 @@ void main()
|
||||
// Visual effects only
|
||||
effect eImpact = EffectVisualEffect(VFX_IMP_PULSE_WIND);
|
||||
// Pulse of wind applied...
|
||||
DelayCommand(f1, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lSelf));
|
||||
DelayCommand(1.0, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lSelf));
|
||||
// Delay the new wind
|
||||
DelayCommand(fDuration + 1.2, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eImpact, lJumpTo));
|
||||
}
|
||||
@@ -72,7 +73,7 @@ void main()
|
||||
DelayCommand(fDuration + 1.5, ActionAttack(oJumpTo));
|
||||
|
||||
effect eFly = EffectDisappearAppear(lJumpTo);
|
||||
DelayCommand(f1, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFly, OBJECT_SELF, fDuration - f1));
|
||||
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFly, OBJECT_SELF, fDuration - 1.0));
|
||||
}
|
||||
|
||||
// Damages area with blast of flying
|
||||
@@ -109,6 +110,10 @@ void DoDamageToArea(location lLocation)
|
||||
// Can't knock over huge things!
|
||||
if(GetCreatureSize(oTarget) != CREATURE_SIZE_HUGE)
|
||||
{
|
||||
// Signal spell cast at event
|
||||
// * Using: SPELLABILITY_DRAGON_WING_BUFFET - just so something is used
|
||||
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELLABILITY_DRAGON_WING_BUFFET));
|
||||
|
||||
// Reflex save for damage
|
||||
if(!ReflexSave(oTarget, nDC))
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,28 +1,27 @@
|
||||
/************************ [Debug] **********************************************
|
||||
/*/////////////////////// [Include - Debugging] ////////////////////////////////
|
||||
Filename: J_Inc_Debug
|
||||
************************* [Debug] **********************************************
|
||||
///////////////////////// [Include - Debugging] ////////////////////////////////
|
||||
This contains DebugActionSpeak, the debug function.
|
||||
|
||||
Makes it easier to uncomment debug lines.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added
|
||||
************************* [Workings] *******************************************
|
||||
- In beta, changed it so this file controls all debug strings. Just
|
||||
uncomment them and recompile to turn it on/off.
|
||||
1.4 - TO DO: Added some more debug strings I use
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
DebugActionSpeak normally writes a timestamped log entry, and speak a silent
|
||||
string Server Admins can hear.
|
||||
|
||||
To Do: Might make it more generic debug lines, where you can uncomment all
|
||||
"XX" lines HERE, not in the files, so it compiles without them, and only
|
||||
need an integer to speak one.
|
||||
|
||||
1.3 added:
|
||||
- DebugActionSpeakByInt(int iInteger);
|
||||
- Removes many strings into this file
|
||||
- Can easily comment out all string so they are not added to compiled
|
||||
scripts if debugging unused (This saves space on compiled files :-D )
|
||||
- Always uncomment the right bits if not using any debugging.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A
|
||||
************************* [Debug] *********************************************/
|
||||
///////////////////////// [Include - Debugging] //////////////////////////////*/
|
||||
|
||||
// This will speak a cirtain integer number string (similar to a dialog reference).
|
||||
// - I (Jass) have just moved all strings I used all the time into here, so
|
||||
@@ -30,7 +29,7 @@
|
||||
// - The numbers have no reference to much really.
|
||||
// - Calls DebugActionSpeak!
|
||||
// - See J_INC_DEBUG to uncomment/recomment in
|
||||
void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iInput = FALSE, string sInput = "");
|
||||
void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int nInput = FALSE, string sInput = "");
|
||||
|
||||
// Speaks and stamps a debug string.
|
||||
// - See J_INC_DEBUG to uncomment/recomment the debug strings.
|
||||
@@ -43,13 +42,13 @@ void DebugActionSpeak(string sString);
|
||||
// - The numbers have no reference to much really.
|
||||
// - Calls DebugActionSpeak!
|
||||
// - See J_INC_DEBUG to uncomment/recomment in
|
||||
void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iInput = FALSE, string sInput = "")
|
||||
void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int nInput = FALSE, string sInput = "")
|
||||
{
|
||||
// TO UNCOMMENT/COMMENT:
|
||||
// - Add/Remove in "//" before the next lines "/*"
|
||||
// - Recompile all files
|
||||
|
||||
/*
|
||||
///*
|
||||
|
||||
string sDebug;
|
||||
switch(iInteger)
|
||||
@@ -58,22 +57,22 @@ void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iIn
|
||||
case 1: sDebug = "[DCR:Melee] Most Damaging Weapon. Target: " + GetName(oInput); break;
|
||||
case 2: sDebug = "[DCR:Melee] Most Damaging as Not Effective"; break;
|
||||
case 3: sDebug = "[DCR:Melee] Melee Code. No valid melee target/Dead. Exiting"; break;
|
||||
case 4: sDebug = "[DCR:Melee] Melee attack. [Target] " + GetName(oInput) + " [Feat/Attack] " + IntToString(iInput); break;
|
||||
case 4: sDebug = "[DCR:Melee] Melee attack. [Target] " + GetName(oInput) + " [Feat/Attack] " + IntToString(nInput); break;
|
||||
case 5: sDebug = "[DCR:Caster] Defensive Casting Mode ON [Enemy] " + GetName(oInput); break;
|
||||
case 6: sDebug = "[DCR:Caster] Moving away from AOO's. [Enemy] " + GetName(oInput); break;
|
||||
case 7: sDebug = "[DCR:Casting] Talent(item) [TalentID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 8: sDebug = "[DCR:Casting] Workaround for Spontaeous [SpellID] " + IntToString(iInput) + " [Target] " + GetName(oInput); break;
|
||||
case 9: sDebug = "[DCR:Casting] NormalSpell [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 10: sDebug = "[DCR:Casting] TalentSpell. [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 11: sDebug = "[DCR:Casting] SubSpecialSpell. [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 12: sDebug = "[DCR:Casting] NormalRandomSpell. [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 13: sDebug = "[DCR:Casting] Backup spell caught: " + IntToString(iInput); break;
|
||||
case 14: sDebug = "[DCR:Feat] [ID] " + IntToString(iInput) + " [Enemy] " + GetName(oInput); break;
|
||||
case 15: sDebug = "[DCR:Casting] Grenade [ID] " + IntToString(iInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 7: sDebug = "[DCR:Casting] Talent(item) [TalentID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 8: sDebug = "[DCR:Casting] Workaround for Spontaeous [SpellID] " + IntToString(nInput) + " [Target] " + GetName(oInput); break;
|
||||
case 9: sDebug = "[DCR:Casting] NormalSpell [ID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 10: sDebug = "[DCR:Casting] TalentSpell. [ID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 11: sDebug = "[DCR:Casting] SubSpecialSpell. [ID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 12: sDebug = "[DCR:Casting] NormalRandomSpell. [ID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 13: sDebug = "[DCR:Casting] Backup spell caught: " + IntToString(nInput); break;
|
||||
case 14: sDebug = "[DCR:Feat] [ID] " + IntToString(nInput) + " [Enemy] " + GetName(oInput); break;
|
||||
case 15: sDebug = "[DCR:Casting] Grenade [ID] " + IntToString(nInput) + " [Target] " + GetName(oInput) + " [Location] " + sInput; break;
|
||||
case 16: sDebug = "[AOE Call] Moving out of/Dispeling an AOE. [Tag] " + GetTag(oInput); break;
|
||||
case 17: sDebug = "[DCR:Special] Darkness + Caster. No seen enemy. Dispel/Move."; break;
|
||||
case 18: sDebug = "[DRC:Talent] Using Talent (Healing). [TalentID] " + IntToString(iInput) + " [Target] " + GetName(oInput); break;
|
||||
case 19: sDebug = "[DCR:Healing] (Should) Healing [Target]" + GetName(oInput) + " [CurrentHP|Max|ID|Rank|Power] " + IntToString(iInput); break;
|
||||
case 18: sDebug = "[DRC:Talent] Using Talent (Healing). [TalentID] " + IntToString(nInput) + " [Target] " + GetName(oInput); break;
|
||||
case 19: sDebug = "[DCR:Healing] (Should) Healing [Target]" + GetName(oInput) + " [CurrentHP|Max|ID|Rank|Power] " + IntToString(nInput); break;
|
||||
case 20: sDebug = "[DCR Healing] Boss Action, create Critical Wounds potion"; break;
|
||||
case 21: sDebug = "[DCR:Casting] Healing self with healing kit, [Kit] " + GetName(oInput); break;
|
||||
case 22: sDebug = "[DCR:Feat] Summoning my familiar"; break;
|
||||
@@ -86,18 +85,18 @@ void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iIn
|
||||
case 29: sDebug = "[DCR:Bard Song] Using"; break;
|
||||
case 30: sDebug = "[DCR:Bard Curse Song] Using"; break;
|
||||
case 31: sDebug = "[DCR:All Spells] Error! No casting (No spells, items, target Etc)."; break;
|
||||
case 32: sDebug = "[DCR:All Spells] [Modifier|BaseDC|SRA] " + IntToString(iInput); break;
|
||||
case 33: sDebug = "[DCR:Casting] Cheat Spell. End of Spells. [Spell] " + IntToString(iInput) + "[Target]" + GetName(oInput); break;
|
||||
case 32: sDebug = "[DCR:All Spells] [Modifier|BaseDC|SRA] " + IntToString(nInput); break;
|
||||
case 33: sDebug = "[DCR:Casting] Cheat Spell. End of Spells. [Spell] " + IntToString(nInput) + "[Target]" + GetName(oInput); break;
|
||||
case 34: sDebug = "[DCR:All Spells] Ranged Spells. Should use closer spells/move nearer"; break;
|
||||
case 35: sDebug = "[DCR:Dragon] Breath weapon & attacking [Breath ID] " + IntToString(iInput) + " [Target] " + GetName(oInput); break;
|
||||
case 35: sDebug = "[DCR:Dragon] Breath weapon & attacking [Breath ID] " + IntToString(nInput) + " [Target] " + GetName(oInput); break;
|
||||
case 36: sDebug = "[DCR:Dragon] Wing Buffet [Target] " + GetName(oInput); break;
|
||||
case 37: sDebug = "[DCR:Beholder] Teleport"; break;
|
||||
case 38: sDebug = "[DCR:Beholder] Rays"; break;
|
||||
case 39: sDebug = "[DCR:Targeting] No valid enemies in sight, moving to allies target's. [Target] " + GetName(oInput); break;
|
||||
case 40: sDebug = "[DCR:Targeting] Override Target Seen. [Name]" + GetName(oInput); break;
|
||||
case 41: sDebug = "[DCR:Targeting] No seen in LOS, Attempting to MOVE to something [Target]" + GetName(oInput); break;
|
||||
case 42: sDebug = "[DCR:Skill] Using agressive skill (+Attack). [Skill] " + IntToString(iInput) + " [Enemy]" + GetName(oInput); break;
|
||||
case 43: sDebug = "[DCR:Pre-Melee Spells] All Potions Using. [Spell ID] " + IntToString(iInput); break;
|
||||
case 42: sDebug = "[DCR:Skill] Using agressive skill (+Attack). [Skill] " + IntToString(nInput) + " [Enemy]" + GetName(oInput); break;
|
||||
case 43: sDebug = "[DCR:Pre-Melee Spells] All Potions Using. [Spell ID] " + IntToString(nInput); break;
|
||||
case 44: sDebug = "[DCR:Pre-Melee Spells] True Strike Emptive attack [Target] " + GetName(oInput); break;
|
||||
case 45: sDebug = "[DCR:CounterSpell] Counterspelling. [Target] " + GetName(oInput); break;
|
||||
case 46: sDebug = "[DRC] START [Intruder]" + GetName(oInput); break;
|
||||
@@ -119,26 +118,26 @@ void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iIn
|
||||
case 59: sDebug = "[Phisically Attacked] Attacking back. [Attacker(enemy)] " + GetName(oInput); break;
|
||||
case 60: sDebug = "[Phisically Attacked] Not same area. [Attacker(enemy)] " + GetName(oInput); break;
|
||||
// Damaged
|
||||
case 61: sDebug = "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(iInput); break;
|
||||
case 61: sDebug = "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(nInput); break;
|
||||
case 62: sDebug = "[Damaged] Not in combat: DCR [Damager]" + GetName(oInput); break;
|
||||
case 63: sDebug = "[Damaged] Not in combat: DCR. Ally hit us. [Damager(Ally?)]" + GetName(oInput); break;
|
||||
// Death
|
||||
case 64: sDebug = "[Death] Checking corpse status in " + IntToString(iInput) + " [Killer] " + GetName(oInput) + " [Times Died Now] " + sInput; break;
|
||||
case 64: sDebug = "[Death] Checking corpse status in " + IntToString(nInput) + " [Killer] " + GetName(oInput) + " [Times Died Now] " + sInput; break;
|
||||
// Disturbed
|
||||
case 65: sDebug = "[Disturbed] (pickpocket) Attacking Enemy [Disturber] " + GetName(oInput) + " [Type] " + IntToString(iInput); break;
|
||||
case 65: sDebug = "[Disturbed] (pickpocket) Attacking Enemy [Disturber] " + GetName(oInput) + " [Type] " + IntToString(nInput); break;
|
||||
// Rest
|
||||
case 66: sDebug = "[Rested] Resting. [Type(should be invalid)] " + IntToString(iInput); break;
|
||||
case 66: sDebug = "[Rested] Resting. [Type(should be invalid)] " + IntToString(nInput); break;
|
||||
// Spell Cast at
|
||||
case 67: sDebug = "[Spell] Caster isn't a creature! May look for target [Caster] " + GetName(oInput); break;
|
||||
case 68: sDebug = "[Spell:Enemy/Hostile] Not in combat. Attacking: [Caster] " + GetName(oInput); break;
|
||||
case 69: sDebug = "[Spell] (ally). Not in combat. May Attack/Move [Caster] " + GetName(oInput); break;
|
||||
// Spell Other AI
|
||||
// - Shouts
|
||||
case 70: sDebug = "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput); break;
|
||||
case 70: sDebug = "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(nInput) + " [Shouter] " + GetName(oInput); break;
|
||||
// Constants
|
||||
// - Search
|
||||
case 71: sDebug = "[Search] Resting"; break;
|
||||
case 72: sDebug = "[Search] Searching, No one to attack. [Time] " + sInput; break;
|
||||
case 72: sDebug = "[Search] Searching, No one to attack. [Rounds Remaining] " + IntToString(nInput) + ". [Possible target] " + GetName(oInput); break;
|
||||
// - DCR
|
||||
case 73: sDebug = "[Call for DCR] Default AI [Pre-Set Target]" + GetName(oInput); break;
|
||||
case 74: sDebug = "[Call for DCR] Custom AI [" + sInput + "] [Pre-Set Target]" + GetName(oInput); break;
|
||||
@@ -160,14 +159,14 @@ void DebugActionSpeakByInt(int iInteger, object oInput = OBJECT_INVALID, int iIn
|
||||
void DebugActionSpeak(string sString)
|
||||
{
|
||||
// You MUST uncomment this line, IF you use either of the below things
|
||||
//string sNew = "[Debug]" + GetName(OBJECT_SELF) + "[ObjectID]" + ObjectToString(OBJECT_SELF) + " [Debug] " + sString;
|
||||
string sNew = "[Debug]" + GetName(OBJECT_SELF) + "[ObjectID]" + ObjectToString(OBJECT_SELF) + " [Debug] " + sString;
|
||||
|
||||
// Note, uncomment this, so that DM's can hear the debug speaks, normally it is
|
||||
// only server admins who can hear the debug. If you are not testing, it might
|
||||
// be best to keep this uncommented.
|
||||
// Futher: - Must have debug mode set to 1
|
||||
// - Only the server admin can seem to see this.
|
||||
//SpeakString(sNew, TALKVOLUME_SILENT_TALK);
|
||||
// SpeakString(sNew, TALKVOLUME_TALK);
|
||||
|
||||
// Note, uncomment this line to send a message to the first PC in the module.
|
||||
// - Useful for singleplayer testing
|
||||
@@ -176,13 +175,13 @@ void DebugActionSpeak(string sString)
|
||||
// This writes the entry to the log, very important, if debugging
|
||||
// Futher: - If left up for a long time, logs can get very big with the AI
|
||||
// - Use to find problems in the AI and report to me :-D (Jasperre)
|
||||
//WriteTimestampedLogEntry(sNew);
|
||||
WriteTimestampedLogEntry(sNew);
|
||||
}
|
||||
|
||||
// Debug: To compile this script full, uncomment all of the below.
|
||||
/*
|
||||
/* - Add two "/"'s at the start of this line
|
||||
void main()
|
||||
{
|
||||
DebugActionSpeak("Test");
|
||||
return;
|
||||
}
|
||||
*/
|
||||
//*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,29 @@
|
||||
/************************ [Heartbeat Include] **********************************
|
||||
Filename: J_Inc_Heartbeat
|
||||
************************* [Heartbeat Include] **********************************
|
||||
/*/////////////////////// [Include - Heartbeat] ////////////////////////////////
|
||||
Filename: J_INC_Heartbeat
|
||||
///////////////////////// [Include - Heartbeat] ////////////////////////////////
|
||||
This contains any heartbeat function calls.
|
||||
|
||||
Note that the heartbeat uses ExecuteScript for larget behaviours that are
|
||||
better split up so the heartbeat is as tiny as possible.
|
||||
************************* [History] ********************************************
|
||||
1.3 After Beta - Added
|
||||
************************* [Workings] *******************************************
|
||||
This is included in nw_c2_default1 and j_ai_onheartbeat.
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - After Beta - Added
|
||||
1.4 - TO DO
|
||||
- Add in some function (see rest script) that resets if we are not in
|
||||
combat
|
||||
- Some more of the things we should do even if interrupted not the
|
||||
heartbeat.
|
||||
|
||||
Contains things like in j_inc_other_ai
|
||||
************************* [Arguments] ******************************************
|
||||
- Have moved "after combat searching" into here. It isn't long - but
|
||||
it is more reliable. The special action is cancled if there is combat
|
||||
going on, of course.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This is included in nw_c2_default1 and J_AI_OnHeartbeat.
|
||||
|
||||
Contains things like in J_INC_OTHER_AI, but only for the heartbeat event.
|
||||
Keeps it cleaner to read.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A
|
||||
************************* [Heartbeat Include] *********************************/
|
||||
///////////////////////// [Include - Heartbeat] //////////////////////////////*/
|
||||
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
@@ -23,8 +33,6 @@ const string sWalkwayVarname = "NW_WALK_CONDITION";
|
||||
const int NW_WALK_FLAG_CONSTANT = 0x00000002;
|
||||
|
||||
// Checks:
|
||||
// * Dead
|
||||
// * Uncommandable
|
||||
// * No valid location
|
||||
// * Petrified, paralised, ETC.
|
||||
// Note: If sleep is found, it may apply Zzzz randomly, as well as stopping.
|
||||
@@ -42,68 +50,82 @@ int GetWalkCondition(int nCondition, object oCreature=OBJECT_SELF);
|
||||
// - Invisiblity (best)
|
||||
// - Haste/Expeditious Retreat
|
||||
void ActionCastFleeingSpells();
|
||||
// Cast fleeing spells.
|
||||
// - Invisiblity (best)
|
||||
// - Haste/Expeditious Retreat
|
||||
void ActionCastMoveToCombatSpells();
|
||||
|
||||
// Attempt to cast iSpell. TRUE if true.
|
||||
int FleeingSpellCast(int iSpell);
|
||||
// Attempt to cast nSpell. TRUE if true.
|
||||
// Searching and fleeing spells use this.
|
||||
int HeartbeatSpellCast(int nSpell);
|
||||
|
||||
// Used in Search(). This apply Trueseeing, See invisibility, or Invisiblity purge
|
||||
// if we have neither of the 3 on us.
|
||||
void SearchSpells();
|
||||
|
||||
// Returns TRUE if any of the animation settings are on.
|
||||
int GetHasValidAnimations();
|
||||
|
||||
// Checks:
|
||||
// * No valid location
|
||||
// * Petrified, paralised, ETC.
|
||||
// Note: If sleep is found, it may apply Zzzz randomly, as well as stopping.
|
||||
int JumpOutOfHeartBeat()
|
||||
{
|
||||
// What to return
|
||||
int iReturn = FALSE;
|
||||
int bReturn = FALSE;
|
||||
// Checks:
|
||||
// * Dead + Uncommandable are in GetAIOff
|
||||
// * No valid location
|
||||
// * Petrified, paralised, ETC.
|
||||
// Note: If sleep is found, it may apply Zzzz randomly, as well as stopping.
|
||||
|
||||
// Effect checking
|
||||
effect eCheck = GetFirstEffect(OBJECT_SELF);
|
||||
int iEffectType;
|
||||
while(GetIsEffectValid(eCheck) && iReturn == FALSE)
|
||||
int nEffectType;
|
||||
while(GetIsEffectValid(eCheck) && bReturn == FALSE)
|
||||
{
|
||||
iEffectType = GetEffectType(eCheck);
|
||||
nEffectType = GetEffectType(eCheck);
|
||||
// Sleep is special
|
||||
if(iEffectType == EFFECT_TYPE_SLEEP)
|
||||
if(nEffectType == EFFECT_TYPE_SLEEP)
|
||||
{
|
||||
iReturn = i2;// This immediantly breaks.
|
||||
bReturn = 2;// This immediantly breaks.
|
||||
}
|
||||
// ALL these stop heartbeat.
|
||||
else if(iEffectType == EFFECT_TYPE_PARALYZE || iEffectType == EFFECT_TYPE_STUNNED ||
|
||||
iEffectType == EFFECT_TYPE_FRIGHTENED || /* Removed sleep above */
|
||||
iEffectType == EFFECT_TYPE_TURNED || iEffectType == EFFECT_TYPE_PETRIFY ||
|
||||
iEffectType == EFFECT_TYPE_DAZED || iEffectType == EFFECT_TYPE_TIMESTOP ||
|
||||
iEffectType == EFFECT_TYPE_DISAPPEARAPPEAR || iEffectType == EFFECT_TYPE_CHARMED ||
|
||||
iEffectType == EFFECT_TYPE_DOMINATED || iEffectType == EFFECT_TYPE_CONFUSED)
|
||||
else if(nEffectType == EFFECT_TYPE_PARALYZE || nEffectType == EFFECT_TYPE_STUNNED ||
|
||||
nEffectType == EFFECT_TYPE_FRIGHTENED || /* Removed sleep above */
|
||||
nEffectType == EFFECT_TYPE_TURNED || nEffectType == EFFECT_TYPE_PETRIFY ||
|
||||
nEffectType == EFFECT_TYPE_DAZED || nEffectType == EFFECT_TYPE_TIMESTOP ||
|
||||
nEffectType == EFFECT_TYPE_DISAPPEARAPPEAR || nEffectType == EFFECT_TYPE_CHARMED ||
|
||||
nEffectType == EFFECT_TYPE_DOMINATED || nEffectType == EFFECT_TYPE_CONFUSED)
|
||||
{
|
||||
iReturn = i1;// 1 = No Zzz. We continue to check for Zzz as well.
|
||||
bReturn = 1;// 1 = No Zzz. We continue to check for Zzz as well.
|
||||
}
|
||||
eCheck = GetNextEffect(OBJECT_SELF);
|
||||
}
|
||||
// Do we fire the heartbeat event?
|
||||
if(iReturn != FALSE)
|
||||
if(bReturn != FALSE)
|
||||
{
|
||||
// If it is sleep... Zzzzz sometimes.
|
||||
if(iReturn == i2 && d6() == i1)
|
||||
if(bReturn == 2 && d6() == 1)
|
||||
{
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT,
|
||||
EffectVisualEffect(VFX_IMP_SLEEP),
|
||||
OBJECT_SELF);
|
||||
}
|
||||
FireUserEvent(
|
||||
AI_FLAG_UDE_HEARTBEAT_EVENT,
|
||||
EVENT_HEARTBEAT_EVENT);// Fire event 1001
|
||||
// Fire event 1001
|
||||
FireUserEvent(AI_FLAG_UDE_HEARTBEAT_EVENT, EVENT_HEARTBEAT_EVENT);
|
||||
}
|
||||
return iReturn;
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
// This checks fleeing, door bashing and so on, to stop the heartbeat
|
||||
// and perform the override special action, rather then run normal behaviour.
|
||||
int PerformSpecialAction()
|
||||
{
|
||||
int iAction = GetCurrentSetAction();
|
||||
int nAction = GetCurrentSetAction();
|
||||
object oTarget = GetAttackTarget();
|
||||
object oRunTarget;
|
||||
switch(iAction)
|
||||
switch(nAction)
|
||||
{
|
||||
// - Leader has made me a runner. I must run to a nearby group calling
|
||||
// for help to get more men
|
||||
@@ -116,7 +138,7 @@ int PerformSpecialAction()
|
||||
{
|
||||
// Stop thinking we are a runner if we can see the run target
|
||||
ResetCurrentAction();
|
||||
AISpeakString(HELP_MY_FRIEND);
|
||||
AISpeakString(AI_SHOUT_HELP_MY_FRIEND);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
@@ -124,7 +146,7 @@ int PerformSpecialAction()
|
||||
// Else run to them
|
||||
if(GetObjectHeard(oRunTarget))
|
||||
{
|
||||
AISpeakString(HELP_MY_FRIEND);
|
||||
AISpeakString(AI_SHOUT_HELP_MY_FRIEND);
|
||||
}
|
||||
ClearAllActions();
|
||||
ActionMoveToObject(oRunTarget, TRUE);
|
||||
@@ -149,26 +171,34 @@ int PerformSpecialAction()
|
||||
// at higher intelligence) things like Expeditious retreat.
|
||||
// - Only used once - one invisibility or haste. Deleted above.
|
||||
ActionCastFleeingSpells();
|
||||
ActionForceFollowObject(oRunTarget, f3);
|
||||
ActionForceFollowObject(oRunTarget, 3.0);
|
||||
}
|
||||
else if(GetObjectSeen(oRunTarget))
|
||||
{
|
||||
// If we see the flee target, reset targets
|
||||
ResetCurrentAction();
|
||||
|
||||
// We will delete the local int (set to TRUE) which we
|
||||
// stopped fleeing spells from
|
||||
// stopped fleeing spells from being used
|
||||
DeleteAIInteger(AI_HEARTBEAT_FLEE_SPELLS);
|
||||
// Speak to allies to come :-)
|
||||
AISpeakString(HELP_MY_FRIEND);
|
||||
// Return FALSE.
|
||||
return FALSE;
|
||||
AISpeakString(AI_SHOUT_HELP_MY_FRIEND);
|
||||
|
||||
// Also reset visual effect
|
||||
RemoveFleeingVisual();
|
||||
|
||||
// And attack/heal self
|
||||
ClearAllActions();
|
||||
DetermineCombatRound();
|
||||
// Return TRUE, we attacked
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Else flee!
|
||||
if(GetObjectHeard(oRunTarget))
|
||||
{
|
||||
AISpeakString(HELP_MY_FRIEND);
|
||||
AISpeakString(AI_SHOUT_HELP_MY_FRIEND);
|
||||
}
|
||||
ClearAllActions();
|
||||
// New - cast fleeing spells. Important (and only used
|
||||
@@ -181,34 +211,53 @@ int PerformSpecialAction()
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if we have bad intellgence, and we will run away
|
||||
// from the nearest enemy if heard.
|
||||
if(GetAIInteger(AI_INTELLIGENCE) <= i3)
|
||||
// Check if we have bad intellgence, if we have, we will run away
|
||||
// from the nearest enemy we can see or hear.
|
||||
if(GetAIInteger(AI_INTELLIGENCE) <= 3)
|
||||
{
|
||||
oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
if(!GetIsObjectValid(oRunTarget))
|
||||
{
|
||||
oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
if(!GetIsObjectValid(oRunTarget))
|
||||
{
|
||||
oRunTarget = GetLastHostileActor();
|
||||
if(!GetIsObjectValid(oRunTarget) || GetIsDead(oRunTarget))
|
||||
{
|
||||
// If we do not have anyone to run from, stop
|
||||
ResetCurrentAction();
|
||||
return FALSE;
|
||||
// Speak to allies to come :-)
|
||||
AISpeakString(AI_SHOUT_HELP_MY_FRIEND);
|
||||
// Also reset visual effect
|
||||
RemoveFleeingVisual();
|
||||
// And attack/heal self
|
||||
ClearAllActions();
|
||||
DetermineCombatRound();
|
||||
// Return TRUE, we attacked
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Run from enemy
|
||||
// Run from enemy (1.4: Was oTarget, now oRunTarget)
|
||||
ClearAllActions();
|
||||
ActionMoveAwayFromObject(oTarget, TRUE, f50);
|
||||
ActionMoveAwayFromObject(oRunTarget, TRUE, 50.0);
|
||||
return TRUE;
|
||||
}
|
||||
// If we see the flee target, reset targets
|
||||
ResetCurrentAction();
|
||||
return FALSE;
|
||||
// Speak to allies to come :-)
|
||||
AISpeakString(AI_SHOUT_HELP_MY_FRIEND);
|
||||
// Also reset visual effect
|
||||
RemoveFleeingVisual();
|
||||
// And attack/heal self
|
||||
ClearAllActions();
|
||||
DetermineCombatRound();
|
||||
// Return TRUE, we attacked/healed
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// If this is set, we are usually in combat - and must move out of an AOE.
|
||||
case AI_SPECIAL_ACTIONS_MOVE_OUT_OF_AOE:
|
||||
{
|
||||
// We must be X distance away from a cirtain AOE, if we are not, we
|
||||
@@ -233,6 +282,203 @@ int PerformSpecialAction()
|
||||
}
|
||||
}
|
||||
break;
|
||||
// If this is the one, we will search around for enemies - usually done
|
||||
// at the end of a combat round, it is more reliable here.
|
||||
case AI_SPECIAL_ACTIONS_SEARCH_AROUND:
|
||||
{
|
||||
// If we are in combat, delete this special thing, and return FALSE
|
||||
if(GetIsObjectValid(GetAttemptedSpellTarget()) ||
|
||||
GetIsObjectValid(GetAttemptedAttackTarget()) ||
|
||||
GetIsObjectValid(GetAttackTarget()))
|
||||
{
|
||||
// Reset, and return FALSE.
|
||||
ResetCurrentAction();
|
||||
return FALSE;
|
||||
}
|
||||
// Added this so special actions do not get ignored (EG: healkitting)
|
||||
// It will not do anything, but no heartbeat will be performed. These
|
||||
// kind of actions happen at the end of combat (healing self of damage ETC)
|
||||
// So, basically, will keep in mind it's still searching, but will leave
|
||||
// it until no busy actions are being done.
|
||||
else if(GetIsBusyWithAction())
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// We search for a cirtain number of rounds, set in the generic AI
|
||||
// file, when we first start searching, or restart even. The generic
|
||||
// AI will not actually do search actions, and if it finds no enemy,
|
||||
// will probably just increase the integer to do more search rounds.
|
||||
// * Will be intelligence + 2 to start.
|
||||
int nRoundsRemaining = GetAIInteger(AI_SEARCH_ROUNDS_REMAINING);
|
||||
// Decrease rounds remaining
|
||||
nRoundsRemaining--;
|
||||
// Set new one onto us to use next time
|
||||
SetAIInteger(AI_SEARCH_ROUNDS_REMAINING, nRoundsRemaining);
|
||||
// * Note: If nRoundsRemaining is 0 at the end of this function, we
|
||||
// will remove this action as the current special one.
|
||||
|
||||
// Get the target to move to/around
|
||||
// * Can be invalid, but usually the creature we just killed or noticed
|
||||
// lying on the ground.
|
||||
object oTarget = GetAIObject(AI_SEARCH_TARGET);
|
||||
|
||||
// Stop now (Small amounts of movement each time seem more cautious)
|
||||
ClearAllActions();
|
||||
|
||||
// Check some spells. Cast one if we have no true seeing ETC.
|
||||
SearchSpells();
|
||||
|
||||
// Stealth/search.
|
||||
int bStealth = GetStealthMode(OBJECT_SELF);
|
||||
int bSearch = GetDetectMode(OBJECT_SELF);
|
||||
|
||||
// We perfere to hide again if we search if set to...sneaky!
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER))
|
||||
{
|
||||
if(bStealth != STEALTH_MODE_ACTIVATED)
|
||||
{
|
||||
SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are hiding, stop to search (we shouldn't be - who knows?)
|
||||
if(bStealth == STEALTH_MODE_ACTIVATED)
|
||||
{
|
||||
SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, FALSE);
|
||||
}
|
||||
// And search!
|
||||
if(bSearch != DETECT_MODE_ACTIVE && !GetHasFeat(FEAT_KEEN_SENSE))
|
||||
{
|
||||
SetActionMode(OBJECT_SELF, ACTION_MODE_DETECT, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// We check around the target, if there is one.
|
||||
if(GetIsObjectValid(oTarget))
|
||||
{
|
||||
// Move to the location of oTarget
|
||||
ActionMoveToLocation(GetLocation(oTarget));
|
||||
|
||||
// If it is a chest ETC. We close it.
|
||||
if(GetIsOpen(oTarget))
|
||||
{
|
||||
if(GetObjectType(oTarget) == OBJECT_TYPE_DOOR)
|
||||
{
|
||||
ActionCloseDoor(oTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Close it
|
||||
ActionDoCommand(DoPlaceableObjectAction(oTarget, PLACEABLE_ACTION_USE));
|
||||
}
|
||||
}
|
||||
}
|
||||
// We will get nearest enemy at the very least
|
||||
else
|
||||
{
|
||||
// Use nearest heard
|
||||
object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
|
||||
OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD);
|
||||
if(GetIsObjectValid(oEnemy))
|
||||
{
|
||||
// Move to location
|
||||
ActionMoveToLocation(GetLocation(oEnemy));
|
||||
}
|
||||
}
|
||||
// Note: Here, we will return to spawn location after moving to the
|
||||
// object, if it is a valid setting, else we do the normal randomwalk
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_RETURN_TO_SPAWN_LOCATION, AI_OTHER_MASTER))
|
||||
{
|
||||
ActionMoveToLocation(GetAILocation(AI_RETURN_TO_POINT));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 72: "[Search] Searching, No one to attack. [Rounds Remaining] " + IntToString(nRoundsRemaining) + ". [Possible target] " + GetName(oTarget)
|
||||
DebugActionSpeakByInt(72, oTarget, nRoundsRemaining);
|
||||
// Randomly walk.
|
||||
ActionRandomWalk();
|
||||
}
|
||||
// If we have 0 rounds left of searching time, we turn of this special
|
||||
// action, walk waypoints, and probably rest.
|
||||
if(nRoundsRemaining == 0)
|
||||
{
|
||||
// Rest after combat?
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_REST_AFTER_COMBAT, AI_OTHER_MASTER))
|
||||
{
|
||||
// 71: "[Search] Resting"
|
||||
DebugActionSpeakByInt(71);
|
||||
// Yes - we use ActionRest(). It can possibly still fail if
|
||||
// enemies are still around!
|
||||
ActionRest();
|
||||
ActionWait(1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Else, just execute Walk Waypoints
|
||||
ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF);
|
||||
}
|
||||
// Delete this special action
|
||||
ResetCurrentAction();
|
||||
}
|
||||
// If we havn't bailed out early and returned FALSE (do normal hb) we
|
||||
// will return TRUE, we have something to do at least.
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
// Move to combat - we buff (and only buff again after 1 minute of running)
|
||||
// and either follow the person who wants us to help them, or we will run to the
|
||||
// location set.
|
||||
// * Set only by "AI_HELP_MY_FRIEND_CONSTANT" at the moment.
|
||||
case AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT:
|
||||
{
|
||||
// We get a location to move to first
|
||||
location lTarget = GetAILocation(AI_MOVE_TO_COMBAT_LOCATION);
|
||||
object oObject = GetAreaFromLocation(lTarget);
|
||||
|
||||
// Check if the location is valid
|
||||
if(GetIsObjectValid(oObject) && GetArea(OBJECT_SELF) == oObject)
|
||||
{
|
||||
// Just move, rapidly, to lTarget.
|
||||
ClearAllActions();
|
||||
|
||||
// Buff up an action
|
||||
ActionCastMoveToCombatSpells();
|
||||
|
||||
// Move (fast) to that location
|
||||
ActionMoveToLocation(lTarget, TRUE);
|
||||
// If we see/hear combat, we'll attack
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get who we should "follow" or move to.
|
||||
oObject = GetAIObject(AI_MOVE_TO_COMBAT_OBJECT);
|
||||
|
||||
if(GetIsObjectValid(oObject))
|
||||
{
|
||||
// Just move, rapidly, to oTarget. It isn't "real" following,
|
||||
// but paced. Means it looks OK. Need to test - but should be OK.
|
||||
ClearAllActions();
|
||||
|
||||
// Buff up an action
|
||||
ActionCastMoveToCombatSpells();
|
||||
|
||||
// Move (fast) to that location
|
||||
ActionMoveToObject(oTarget, TRUE);
|
||||
// If we see/hear combat, we'll attack
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove the special action and return FALSE
|
||||
ResetCurrentAction();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Return false to carry on a normal heartbeat
|
||||
return FALSE;
|
||||
@@ -256,21 +502,103 @@ void ActionCastFleeingSpells()
|
||||
SetAIInteger(AI_HEARTBEAT_FLEE_SPELLS, TRUE);
|
||||
|
||||
// Invisibilities
|
||||
if(FleeingSpellCast(SPELL_IMPROVED_INVISIBILITY)) return;
|
||||
if(FleeingSpellCast(SPELL_INVISIBILITY)) return;
|
||||
if(HeartbeatSpellCast(SPELL_IMPROVED_INVISIBILITY)) return;
|
||||
if(HeartbeatSpellCast(SPELL_INVISIBILITY)) return;
|
||||
|
||||
// Haste
|
||||
if(FleeingSpellCast(SPELL_MASS_HASTE)) return;
|
||||
if(FleeingSpellCast(SPELL_HASTE)) return;
|
||||
if(FleeingSpellCast(SPELL_EXPEDITIOUS_RETREAT)) return;
|
||||
if(HeartbeatSpellCast(SPELL_MASS_HASTE)) return;
|
||||
if(HeartbeatSpellCast(SPELL_HASTE)) return;
|
||||
if(HeartbeatSpellCast(SPELL_EXPEDITIOUS_RETREAT)) return;
|
||||
}
|
||||
|
||||
// Attempt to cast iSpell. TRUE if true.
|
||||
int FleeingSpellCast(int iSpell)
|
||||
// Cast fleeing spells.
|
||||
// - Invisiblity (best)
|
||||
// - Haste/Expeditious Retreat
|
||||
void ActionCastMoveToCombatSpells()
|
||||
{
|
||||
if(GetHasSpell(iSpell))
|
||||
// Timer to stop too many spells at once
|
||||
if(GetLocalTimer(AI_TIMER_MOVE_TO_COMBAT_BUFF)) return;
|
||||
|
||||
// We first will cast a preperation spell before jumping in!
|
||||
// This is used once per minute.
|
||||
SetLocalTimer(AI_TIMER_MOVE_TO_COMBAT_BUFF, 60.0);
|
||||
|
||||
// We possibly cast a few spell first - stoneskin range, see
|
||||
// invisible range, and invisibility range.
|
||||
// Protection things
|
||||
// * Cast 1 spell!
|
||||
if(HeartbeatSpellCast(SPELL_PREMONITION)) return;
|
||||
if(HeartbeatSpellCast(SPELL_GREATER_STONESKIN)) return;
|
||||
if(HeartbeatSpellCast(SPELL_STONESKIN)) return;
|
||||
// Invisibility range
|
||||
if(HeartbeatSpellCast(SPELL_ETHEREALNESS)) return;
|
||||
if(HeartbeatSpellCast(SPELL_IMPROVED_INVISIBILITY)) return;
|
||||
if(HeartbeatSpellCast(SPELL_INVISIBILITY_SPHERE)) return;
|
||||
if(HeartbeatSpellCast(SPELL_INVISIBILITY)) return;
|
||||
// See invisible things
|
||||
if(HeartbeatSpellCast(SPELL_TRUE_SEEING)) return;
|
||||
if(HeartbeatSpellCast(SPELL_SEE_INVISIBILITY)) return;
|
||||
|
||||
// Stealth! Only if we are good at it, of course.
|
||||
|
||||
// Spawn in conditions for it
|
||||
if(!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_HIDING, AI_OTHER_COMBAT_MASTER))
|
||||
{
|
||||
// Need skill or force on
|
||||
if((GetSkillRank(SKILL_HIDE) - 4 >= GetHitDice(OBJECT_SELF)) ||
|
||||
GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER))
|
||||
{
|
||||
// Use hide
|
||||
SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Used in Search(). This apply Trueseeing, See invisibility, or Invisiblity purge
|
||||
// if we have neither of the 3 on us.
|
||||
void SearchSpells()
|
||||
{
|
||||
effect eCheck = GetFirstEffect(OBJECT_SELF);
|
||||
int nEffectType, bBreak;
|
||||
while(GetIsEffectValid(eCheck) && bBreak == FALSE)
|
||||
{
|
||||
nEffectType = GetEffectType(eCheck);
|
||||
if(nEffectType == EFFECT_TYPE_TRUESEEING ||
|
||||
nEffectType == EFFECT_TYPE_SEEINVISIBLE)
|
||||
{
|
||||
bBreak = TRUE;
|
||||
}
|
||||
eCheck = GetNextEffect(OBJECT_SELF);
|
||||
}
|
||||
// We have effects, stop.
|
||||
if(bBreak == TRUE || GetHasSpellEffect(SPELL_INVISIBILITY_PURGE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Else we apply the best spell we have.
|
||||
if(HeartbeatSpellCast(SPELL_TRUE_SEEING)) return;
|
||||
if(HeartbeatSpellCast(SPELL_SEE_INVISIBILITY)) return;
|
||||
if(HeartbeatSpellCast(SPELL_INVISIBILITY_PURGE)) return;
|
||||
}
|
||||
// Attempt to cast nSpell. TRUE if true.
|
||||
int HeartbeatSpellCast(int nSpell)
|
||||
{
|
||||
// 1.4: added check to see if has effect already
|
||||
if(GetHasSpell(nSpell) && !GetHasSpellEffect(nSpell, OBJECT_SELF))
|
||||
{
|
||||
ActionCastSpellAtObject(nSpell, OBJECT_SELF);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Returns TRUE if any of the animation settings are on.
|
||||
int GetHasValidAnimations()
|
||||
{
|
||||
int nCheck = GetLocalInt(OBJECT_SELF, NW_GENERIC_MASTER);
|
||||
if((nCheck & NW_FLAG_AMBIENT_ANIMATIONS) ||
|
||||
(nCheck & NW_FLAG_AMBIENT_ANIMATIONS_AVIAN) ||
|
||||
(nCheck & NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS))
|
||||
{
|
||||
ActionCastSpellAtObject(iSpell, OBJECT_SELF);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [Combat Attack] **************************************
|
||||
Filename: j_inc_npc_attack
|
||||
************************* [Combat Attack] **************************************
|
||||
/*/////////////////////// [Include - NPC (Combat) Attack] //////////////////////
|
||||
Filename: J_INC_NPC_Attack
|
||||
///////////////////////// [Include - NPC (Combat) Attack] //////////////////////
|
||||
What does this do?
|
||||
|
||||
It is a wrapper/include for getting a creature to attack target X, or do
|
||||
@@ -11,17 +11,20 @@
|
||||
|
||||
And it also keeps Combat files SMALL! I uses Execute Script to fire the
|
||||
combat file, not include it here.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - TO DO:
|
||||
- Bugfix a few things (copy/paste errors)
|
||||
- Add example script to use (User defined events)
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Include this in any conversation file or whatever, and mearly read the
|
||||
descriptions of the different functions, and it will do what it says :-)
|
||||
************************* [Arguments] ******************************************
|
||||
Arguments:
|
||||
************************* [Combat Attack] *************************************/
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A
|
||||
///////////////////////// [Include - NPC (Combat) Attack] ////////////////////*/
|
||||
|
||||
// Include the constants for the combat, spawn integers ETC.
|
||||
#include "j_inc_constants"
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
// Hostile amount
|
||||
const int HOSTILE = -100;// Reputation to change to
|
||||
@@ -41,22 +44,22 @@ void DetermineSpeakCombatRoundNotMe(object oTarget, object oAttacker);
|
||||
|
||||
// This is the main wrapper to get an NPC to attack in conversation.
|
||||
// * fDelay - The delay AFTER adjusting reputation, that we attack and shout
|
||||
// * iPlot - The plot flag to set to (Usually FALSE).
|
||||
// * iImmortal - The immortal flag to set to (Usually FALSE).
|
||||
// * bPlot - The plot flag to set US to (Usually FALSE).
|
||||
// * bImmortal - The immortal flag US to set to (Usually FALSE).
|
||||
// Example, how to keep flags already set:
|
||||
// HostileAttackPCSpeaker(0.0, GetPlotFlag(), GetImmortal());
|
||||
// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackPCSpeaker(float fDelay = 0.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE);
|
||||
// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackPCSpeaker(float fDelay = 0.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE);
|
||||
|
||||
// This will make our faction hostile to the target, and attack them.
|
||||
// * oTarget - The target object to attack
|
||||
// * fDelay - The delay AFTER adjusting reputation, that we attack and shout
|
||||
// * iPlot - The plot flag to set to (Usually FALSE).
|
||||
// * iImmortal - The immortal flag to set to (Usually FALSE).
|
||||
// * bPlot - The plot flag to set US to (Usually FALSE).
|
||||
// * bImmortal - The immortal flag US to set to (Usually FALSE).
|
||||
// Example, how to keep flags already set:
|
||||
// HostileAttackObject(oPC, 0.0, GetPlotFlag(), GetImmortal());
|
||||
// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackObject(object oTarget, float fDelay = 0.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE);
|
||||
// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackObject(object oTarget, float fDelay = 0.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE);
|
||||
|
||||
// This will make our faction hostile to the target, and shout.
|
||||
// * oTarget - The target object to shout about.
|
||||
@@ -65,25 +68,25 @@ void HostileAttackObject(object oTarget, float fDelay = 0.0, int iPlot = FALSE,
|
||||
void ShoutAbout(object oTarget);
|
||||
|
||||
// This will make our faction hostile to ALL(!) PC's...in the area or game or range
|
||||
// * iType - TYPE_ALL_PCS (1) is all PC's in the world.
|
||||
// * nType - TYPE_ALL_PCS (1) is all PC's in the world.
|
||||
// - TYPE_ALL_AREA (2) is all PC's in the specific area.
|
||||
// - TYPE_IN_RANGE (3) is all PC's within fRange.
|
||||
// * iPlot - The plot flag to set to (Usually FALSE).
|
||||
// * iImmortal - The immortal flag to set to (Usually FALSE).
|
||||
// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE);
|
||||
// * bPlot - The plot flag to set US to (Usually FALSE).
|
||||
// * bImmortal - The immortal flag US to set to (Usually FALSE).
|
||||
// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackAllPCs(int nType = 1, float fRange = 40.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE);
|
||||
|
||||
// This will thier most damaging weapon, and wait to disarm it.
|
||||
// * fDuration - Delay until the weapon is withdrawn.
|
||||
// * iRanged - if TRUE, it will equip a ranged weapon as a prioritory (EquipRanged call)
|
||||
void EquipWeaponsDuration(float fDuration, int iRanged = FALSE);
|
||||
// * bRanged - if TRUE, it will equip a ranged weapon as a prioritory (EquipRanged call)
|
||||
void EquipWeaponsDuration(float fDuration, int bRanged = FALSE);
|
||||
// Disarms the persons right-hand-weapon
|
||||
void RemoveWeapons();
|
||||
|
||||
// Plays talks like "ATTACK!" and "Group Near Me" etc.
|
||||
// * iLowest, iHighest - the High/Lowest value to use.
|
||||
// * nLowest, nHighest - the High/Lowest value to use.
|
||||
// 0 = ATTACK, 1 = TAUNT, 2-4 = BATTLE(1-3), 5 = ENEMIES, 6 = GROUP, 7 = HELP.
|
||||
void PlaySomeTaunt(int iLowest = 0, int iHighest = 7);
|
||||
void PlaySomeTaunt(int nLowest = 0, int nHighest = 7);
|
||||
|
||||
// Gets all allies of ourselves to attack oTarget
|
||||
// * oTarget - The target to attack.
|
||||
@@ -156,72 +159,75 @@ void DetermineSpeakCombatRoundNotMe(object oTarget, object oAttacker)
|
||||
}
|
||||
}
|
||||
// This is the main wrapper to get an NPC to attack in conversation.
|
||||
// * iPlot - The plot flag to set to (Usually FALSE).
|
||||
// * iImmortal - The immortal flag to set to (Usually FALSE).
|
||||
// * fDelay - The delay AFTER adjusting reputation, that we attack and shout
|
||||
// * bPlot - The plot flag to set US to (Usually FALSE).
|
||||
// * bImmortal - The immortal flag US to set to (Usually FALSE).
|
||||
// Example, how to keep flags already set:
|
||||
// AttackPCSpeaker(GetPlotFlag(), GetImmortal());
|
||||
// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackPCSpeaker(float fDelay = 0.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE)
|
||||
// HostileAttackPCSpeaker(0.0, GetPlotFlag(), GetImmortal());
|
||||
// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackPCSpeaker(float fDelay = 0.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE)
|
||||
{
|
||||
// Get the PC
|
||||
object oPC = GetPCSpeaker();
|
||||
|
||||
// Error checking
|
||||
if(!GetIsObjectValid(oPC) || GetIsDM(oPC)) return;
|
||||
// Change the flags
|
||||
if(GetPlotFlag() != iPlot)
|
||||
SetPlotFlag(OBJECT_SELF, iPlot);
|
||||
if(GetImmortal() != iImmortal)
|
||||
SetImmortal(OBJECT_SELF, iPlot);
|
||||
|
||||
// Change our flags for plot and immortal (usually turns them off)
|
||||
SetPlotFlag(OBJECT_SELF, bPlot);
|
||||
SetImmortal(OBJECT_SELF, bImmortal);
|
||||
|
||||
// We make them hostile to our faction
|
||||
AdjustReputation(oPC, OBJECT_SELF, HOSTILE);
|
||||
|
||||
// Attack them
|
||||
SetLocalObject(OBJECT_SELF, AI_TO_ATTACK, oPC);
|
||||
if(fDelay > 0.0)
|
||||
{
|
||||
// Round start...
|
||||
DelayCommand(fDelay, DetermineSpeakCombatRound(oPC, I_WAS_ATTACKED));
|
||||
if(iAllAllies)
|
||||
DelayCommand(fDelay, AlliesAttack(oPC));
|
||||
DelayCommand(fDelay, DetermineSpeakCombatRound(oPC, AI_SHOUT_I_WAS_ATTACKED));
|
||||
if(bAllAllies) DelayCommand(fDelay, AlliesAttack(oPC));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Round start...
|
||||
DetermineSpeakCombatRound(oPC, I_WAS_ATTACKED);
|
||||
if(iAllAllies) AlliesAttack(oPC);
|
||||
DetermineSpeakCombatRound(oPC, AI_SHOUT_I_WAS_ATTACKED);
|
||||
if(bAllAllies) AlliesAttack(oPC);
|
||||
}
|
||||
}
|
||||
|
||||
// This will make our faction hostile to the target, and attack them.
|
||||
// * oTarget - The target object to attack
|
||||
// * iPlot - The plot flag to set to (Usually FALSE).
|
||||
// * iImmortal - The immortal flag to set to (Usually FALSE).
|
||||
// * fDelay - The delay AFTER adjusting reputation, that we attack and shout
|
||||
// * bPlot - The plot flag to set US to (Usually FALSE).
|
||||
// * bImmortal - The immortal flag US to set to (Usually FALSE).
|
||||
// Example, how to keep flags already set:
|
||||
// AttackObject(oPC, GetPlotFlag(), GetImmortal());
|
||||
// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackObject(object oTarget, float fDelay = 0.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE)
|
||||
// HostileAttackObject(oPC, 0.0, GetPlotFlag(), GetImmortal());
|
||||
// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackObject(object oTarget, float fDelay = 0.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE)
|
||||
{
|
||||
// Error checking
|
||||
if(!GetIsObjectValid(oTarget) || GetIsDM(oTarget)) return;
|
||||
// Change the flags
|
||||
if(GetPlotFlag() != iPlot)
|
||||
SetPlotFlag(OBJECT_SELF, iPlot);
|
||||
if(GetImmortal() != iImmortal)
|
||||
SetImmortal(OBJECT_SELF, iPlot);
|
||||
|
||||
// Change our flags for plot and immortal (usually turns them off)
|
||||
SetPlotFlag(OBJECT_SELF, bPlot);
|
||||
SetImmortal(OBJECT_SELF, bImmortal);
|
||||
|
||||
// We make them hostile to our faction
|
||||
AdjustReputation(oTarget, OBJECT_SELF, HOSTILE);
|
||||
|
||||
// Attack them
|
||||
SetLocalObject(OBJECT_SELF, AI_TO_ATTACK, oTarget);
|
||||
|
||||
if(fDelay > 0.0)
|
||||
{
|
||||
// Round start...
|
||||
DelayCommand(fDelay, DetermineSpeakCombatRound(oTarget, I_WAS_ATTACKED));
|
||||
DelayCommand(fDelay, DetermineSpeakCombatRound(oTarget, AI_SHOUT_I_WAS_ATTACKED));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Round start...
|
||||
DetermineSpeakCombatRound(oTarget, I_WAS_ATTACKED);
|
||||
DetermineSpeakCombatRound(oTarget, AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,23 +239,23 @@ void ShoutAbout(object oTarget)
|
||||
// We make them hostile to our faction
|
||||
AdjustReputation(oTarget, OBJECT_SELF, HOSTILE);
|
||||
// And shout for others to attack
|
||||
AISpeakString(CALL_TO_ARMS);
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
|
||||
// This will make our faction hostile to ALL(!) PC's...in the area or game or range
|
||||
// * iType - TYPE_ALL_PCS (1) is all PC's in the world.
|
||||
// * nType - TYPE_ALL_PCS (1) is all PC's in the world.
|
||||
// - TYPE_ALL_AREA (2) is all PC's in the specific area.
|
||||
// - TYPE_IN_RANGE (3) is all PC's within fRange.
|
||||
// * iPlot - The plot flag to set to (Usually FALSE).
|
||||
// * iImmortal - The immortal flag to set to (Usually FALSE).
|
||||
// * iAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE, int iImmortal = FALSE, int iAllAllies = TRUE)
|
||||
// * bPlot - The plot flag to set US to (Usually FALSE).
|
||||
// * bImmortal - The immortal flag US to set to (Usually FALSE).
|
||||
// * bAllAllies - This will determine combat rounds against the target, that are in 50.0M. False = Don't
|
||||
void HostileAttackAllPCs(int nType = 1, float fRange = 40.0, int bPlot = FALSE, int bImmortal = FALSE, int bAllAllies = TRUE)
|
||||
{
|
||||
object oPC, oToAttack;
|
||||
int iShout, iCnt;
|
||||
int bShout, nCnt;
|
||||
float fNearestEnemy = 10000.0;
|
||||
object oArea = GetArea(OBJECT_SELF);
|
||||
switch(iType)
|
||||
switch(nType)
|
||||
{
|
||||
case TYPE_ALL_PCS:// s all PC's in the world.
|
||||
{
|
||||
@@ -267,7 +273,7 @@ void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE,
|
||||
oToAttack = oPC;
|
||||
}
|
||||
}
|
||||
iShout = TRUE;
|
||||
bShout = TRUE;
|
||||
}
|
||||
oPC = GetNextPC();
|
||||
}
|
||||
@@ -275,8 +281,8 @@ void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE,
|
||||
break;
|
||||
case TYPE_ALL_AREA:// is all PC's in the specific area.
|
||||
{
|
||||
iCnt = 1;
|
||||
oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
|
||||
nCnt = 1;
|
||||
oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, nCnt);
|
||||
while(GetIsObjectValid(oPC))
|
||||
{
|
||||
// Attack it! (if not a DM!)
|
||||
@@ -290,19 +296,18 @@ void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE,
|
||||
oToAttack = oPC;
|
||||
}
|
||||
}
|
||||
iShout = TRUE;
|
||||
bShout = TRUE;
|
||||
}
|
||||
// Next one
|
||||
iCnt++;
|
||||
oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC,
|
||||
OBJECT_SELF, iCnt);
|
||||
nCnt++;
|
||||
oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, nCnt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TYPE_IN_RANGE:// is all PC's within fRange.
|
||||
{
|
||||
iCnt = 1;
|
||||
oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
|
||||
nCnt = 1;
|
||||
oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, nCnt);
|
||||
while(GetIsObjectValid(oPC) && GetDistanceToObject(oPC) <= fRange)
|
||||
{
|
||||
// Attack it! (if not a DM!)
|
||||
@@ -316,12 +321,11 @@ void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE,
|
||||
oToAttack = oPC;
|
||||
}
|
||||
}
|
||||
iShout = TRUE;
|
||||
bShout = TRUE;
|
||||
}
|
||||
// Next one
|
||||
iCnt++;
|
||||
oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC,
|
||||
OBJECT_SELF, iCnt);
|
||||
nCnt++;
|
||||
oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, nCnt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -329,17 +333,22 @@ void HostileAttackAllPCs(int iType = 1, float fRange = 40.0, int iPlot = FALSE,
|
||||
// Attack nearest one (if valid)
|
||||
if(GetIsObjectValid(oToAttack))
|
||||
{
|
||||
// Change our flags for plot and immortal (usually turns them off)
|
||||
SetPlotFlag(OBJECT_SELF, bPlot);
|
||||
SetImmortal(OBJECT_SELF, bImmortal);
|
||||
|
||||
DetermineSpeakCombatRound(oToAttack);
|
||||
if(iAllAllies) AlliesAttack(oToAttack);
|
||||
if(bAllAllies) AlliesAttack(oToAttack);
|
||||
}
|
||||
// Check if we shout
|
||||
if(iShout) AISpeakString(CALL_TO_ARMS);
|
||||
if(bShout) AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
// This will thier most damaging melee weapon, and wait to disarm it.
|
||||
// This will thier most damaging weapon, and wait to disarm it.
|
||||
// * fDuration - Delay until the weapon is withdrawn.
|
||||
void EquipWeaponsDuration(float fDuration, int iRanged = FALSE)
|
||||
// * bRanged - if TRUE, it will equip a ranged weapon as a prioritory (EquipRanged call)
|
||||
void EquipWeaponsDuration(float fDuration, int bRanged = FALSE)
|
||||
{
|
||||
if(iRanged)
|
||||
if(bRanged)
|
||||
{
|
||||
// Equip any most damaging (don't use oVersus, incase it doesn't arm anything)
|
||||
ActionEquipMostDamagingRanged();
|
||||
@@ -376,23 +385,23 @@ void RemoveWeapons()
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Created by : Jasperre
|
||||
//:://///////////////////////////////////////////*/
|
||||
void PlaySomeTaunt(int iLowest, int iHighest)
|
||||
void PlaySomeTaunt(int nLowest, int nHighest)
|
||||
{
|
||||
int iRandom = Random(iHighest) + iLowest;
|
||||
int iVoice = VOICE_CHAT_ATTACK;
|
||||
switch (iRandom)
|
||||
int nRandom = Random(nHighest) + nLowest;
|
||||
int nVoice = VOICE_CHAT_ATTACK;
|
||||
switch (nRandom)
|
||||
{
|
||||
case 0: iVoice = VOICE_CHAT_ATTACK; break;
|
||||
case 1: iVoice = VOICE_CHAT_TAUNT; break;
|
||||
case 2: iVoice = VOICE_CHAT_BATTLECRY1; break;
|
||||
case 3: iVoice = VOICE_CHAT_BATTLECRY2; break;
|
||||
case 4: iVoice = VOICE_CHAT_BATTLECRY3; break;
|
||||
case 5: iVoice = VOICE_CHAT_ENEMIES; break;
|
||||
case 6: iVoice = VOICE_CHAT_GROUP; break;
|
||||
case 7: iVoice = VOICE_CHAT_HELP; break;
|
||||
default: iVoice = VOICE_CHAT_ATTACK; break;
|
||||
case 0: nVoice = VOICE_CHAT_ATTACK; break;
|
||||
case 1: nVoice = VOICE_CHAT_TAUNT; break;
|
||||
case 2: nVoice = VOICE_CHAT_BATTLECRY1; break;
|
||||
case 3: nVoice = VOICE_CHAT_BATTLECRY2; break;
|
||||
case 4: nVoice = VOICE_CHAT_BATTLECRY3; break;
|
||||
case 5: nVoice = VOICE_CHAT_ENEMIES; break;
|
||||
case 6: nVoice = VOICE_CHAT_GROUP; break;
|
||||
case 7: nVoice = VOICE_CHAT_HELP; break;
|
||||
default: nVoice = VOICE_CHAT_ATTACK; break;
|
||||
}
|
||||
PlayVoiceChat(iVoice);
|
||||
PlayVoiceChat(nVoice);
|
||||
}
|
||||
|
||||
// Gets all allies of ourselves to attack oTarget
|
||||
@@ -400,16 +409,16 @@ void PlaySomeTaunt(int iLowest, int iHighest)
|
||||
void AlliesAttack(object oTarget)
|
||||
{
|
||||
if(!GetIsObjectValid(oTarget)) return;
|
||||
int iCnt = 1;
|
||||
object oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, iCnt, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
int nCnt = 1;
|
||||
object oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, nCnt, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
while(GetIsObjectValid(oAlly) && GetDistanceToObject(oAlly) <= 50.0)
|
||||
{
|
||||
// A slightly modified way to determine a combat round.
|
||||
// * oTarget - The target to attack
|
||||
// * oAttacker - The NPC who you want to determine a combat round, on oTarget
|
||||
DetermineSpeakCombatRoundNotMe(oTarget, oAlly);
|
||||
iCnt++;
|
||||
oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, iCnt, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
nCnt++;
|
||||
oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, nCnt, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,4 +438,10 @@ object GetNearestFriendCreature()
|
||||
return GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND);
|
||||
}
|
||||
|
||||
//void main(){}
|
||||
// Debug: To compile this script full, uncomment all of the below.
|
||||
/* - Add two "/"'s at the start of this line
|
||||
void main()
|
||||
{
|
||||
return;
|
||||
}
|
||||
//*/
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [Include - Other AI Functions] ***********************
|
||||
Filename: j_inc_other_ai
|
||||
************************* [Include - Other AI Functions] ***********************
|
||||
/*/////////////////////// [Include - Other AI Functions] ///////////////////////
|
||||
Filename: J_INC_Other_AI
|
||||
///////////////////////// [Include - Other AI Functions] ///////////////////////
|
||||
This contains fuctions and calls for these scripts:
|
||||
nw_c2_default2 - Percieve
|
||||
nw_c2_default3 - On Combat round End (For DetermineCombatRound() only)
|
||||
@@ -9,43 +9,44 @@
|
||||
nw_c2_default6 - Damaged
|
||||
nw_c2_default8 - Disturbed
|
||||
nw_c2_defaultb - Spell cast at
|
||||
Ones that don't use this use different/No includes.
|
||||
|
||||
Ones that don't use this use different or no includes.
|
||||
|
||||
HOPEFULLY it will make them faster, if they don't run combat.
|
||||
|
||||
They use Execute Script to initiate combat. (With the override ones
|
||||
initiating the override version, the normal initiateing the normal).
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added to speed up compilings and gather non-combat, or other workings
|
||||
in one place.
|
||||
************************* [Workings] *******************************************
|
||||
This is included, by #include "J_INC_OTHER_AI" in other AI files.
|
||||
1.4 - TO DO:
|
||||
-
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This is included in other AI files.
|
||||
|
||||
They then use these functions in them scripts.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A
|
||||
************************* Include - Other AI Functions] ***********************/
|
||||
///////////////////////// [Include - Other AI Functions] /////////////////////*/
|
||||
|
||||
// All constants.
|
||||
#include "j_inc_constants"
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
// Responds to it (like makinging the callers attacker thier target)
|
||||
// Responds to it (like makinging the callers attacker thier target)
|
||||
// Called in OnConversation, and thats it. Use "ShouterFriend" To stop repeated GetIsFriend calls.
|
||||
void RespondToShout(object oShouter, int nShoutIndex);
|
||||
// Gets the attacker or attakee of the target, which should be a friend
|
||||
// Gets any possible target which is attacking oShouter (and isn't an ally)
|
||||
// or who oShouter is attacking. oShouter should be a ally.
|
||||
object GetIntruderFromShout(object oShouter);
|
||||
|
||||
// Shouts, or really brings all people in 60.0M(by default) to the "shouter"
|
||||
void ShoutBossShout(object oEnemy);
|
||||
// Checks the target for a specific EFFECT_TYPE constant value
|
||||
// Returns TRUE or FALSE. Used On Damaged for polymorph checking.
|
||||
int GetHasEffect(int nEffectType, object oTarget = OBJECT_SELF);
|
||||
// This sets a morale penalty, to the exsisting one, if there is one.
|
||||
// It will reduce itself after fDuration (or if we die, ETC, it is deleted).
|
||||
// It is deleted at the end of combat as well.
|
||||
void SetMoralePenalty(int iPenalty, float fDuration = 0.0);
|
||||
// Removes iPenalty amount if it can.
|
||||
void RemoveMoralePenalty(int iPenalty);
|
||||
void SetMoralePenalty(int nPenalty, float fDuration = 0.0);
|
||||
// Removes nPenalty amount if it can.
|
||||
void RemoveMoralePenalty(int nPenalty);
|
||||
// At 5+ intelligence, we fire off any dispells at oPlaceables location
|
||||
void SearchDispells(object oPlaceable);
|
||||
|
||||
@@ -66,6 +67,18 @@ void ActionMoveToEnemy(object oEnemy);
|
||||
// - They then run! (Badly)
|
||||
int PerceptionFleeFrom(object oEnemy);
|
||||
|
||||
// This wrappers commonly used code for a "Call to arms" type response.
|
||||
// * We know of no enemy, so we will move to oAlly, who either called to
|
||||
// us, or, well, we know of.
|
||||
// * Calls out AI_SHOUT_CALL_TO_ARMS too.
|
||||
void CallToArmsResponse(object oAlly);
|
||||
// This wrappers commonly used code for a "I was attacked" type response.
|
||||
// * We know there will be an enemy - or should be - and if we find one to attack
|
||||
// (using GetIntruderFromShout()) - we attack it (and call another I was attacked)
|
||||
// else, this will run CallToArmsResponse(oAlly);
|
||||
// * Calls out AI_SHOUT_I_WAS_ATTACKED, or AI_SHOUT_CALL_TO_ARMS too.
|
||||
void IWasAttackedResponse(object oAlly);
|
||||
|
||||
/*::///////////////////////////////////////////////
|
||||
//:: Name: ShoutBossShout
|
||||
//::///////////////////////////////////////////////
|
||||
@@ -74,16 +87,19 @@ int PerceptionFleeFrom(object oEnemy);
|
||||
//:://///////////////////////////////////////////*/
|
||||
void ShoutBossShout(object oEnemy)
|
||||
{
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_BOSS_MONSTER_SHOUT, AI_OTHER_COMBAT_MASTER))
|
||||
// 1.4 - Added a 5 minute cooldown timer for this. Thusly, if the boss lingers,
|
||||
// so will the big shout they do.
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_BOSS_MONSTER_SHOUT, AI_OTHER_COMBAT_MASTER) &&
|
||||
!GetLocalTimer(AI_TIMER_BOSS_SHOUT_COOLDOWN))
|
||||
{
|
||||
// Get the range (and default to 60.0 M)
|
||||
float fRange = IntToFloat(GetBoundriedAIInteger(AI_BOSS_MONSTER_SHOUT_RANGE, i60, 370));
|
||||
float fRange = IntToFloat(GetBoundriedAIInteger(AI_BOSS_MONSTER_SHOUT_RANGE, 60, 370));
|
||||
// We loop through nearest not-seen, not-heard allies and get them
|
||||
// to attack the person.
|
||||
int Cnt = i1;
|
||||
int nCnt = 1;
|
||||
// Not seen, not heard...
|
||||
object oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND,
|
||||
OBJECT_SELF, Cnt, CREATURE_TYPE_IS_ALIVE, TRUE,
|
||||
OBJECT_SELF, nCnt, CREATURE_TYPE_IS_ALIVE, TRUE,
|
||||
CREATURE_TYPE_PERCEPTION, PERCEPTION_NOT_SEEN_AND_NOT_HEARD);
|
||||
// Get who thier target is.
|
||||
object oThierTarget;
|
||||
@@ -103,13 +119,19 @@ void ShoutBossShout(object oEnemy)
|
||||
ExecuteScript(COMBAT_FILE, oAlly);
|
||||
}
|
||||
}
|
||||
Cnt++;
|
||||
nCnt++;
|
||||
oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND,
|
||||
OBJECT_SELF, Cnt, CREATURE_TYPE_IS_ALIVE, TRUE,
|
||||
OBJECT_SELF, nCnt, CREATURE_TYPE_IS_ALIVE, TRUE,
|
||||
CREATURE_TYPE_PERCEPTION, PERCEPTION_NOT_SEEN_AND_NOT_HEARD);
|
||||
}
|
||||
// Remove it :-)
|
||||
DeleteSpawnInCondition(AI_FLAG_OTHER_COMBAT_BOSS_MONSTER_SHOUT, AI_OTHER_COMBAT_MASTER);
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
// Speak a string associated with this action being carried out
|
||||
SpeakArrayString(AI_TALK_ON_LEADER_BOSS_SHOUT);
|
||||
}
|
||||
// Remove it for 5 minutes.
|
||||
SetLocalTimer(AI_TIMER_BOSS_SHOUT_COOLDOWN, 300.0);
|
||||
}
|
||||
}
|
||||
// This MAY make us set a local timer to turn off hiding.
|
||||
@@ -122,7 +144,7 @@ void TurnOffHiding(object oIntruder)
|
||||
(GetObjectSeen(OBJECT_SELF, oIntruder) ||
|
||||
GetObjectHeard(OBJECT_SELF, oIntruder)))
|
||||
{
|
||||
SetLocalTimer(AI_TIMER_TURN_OFF_HIDE, f18);
|
||||
SetLocalTimer(AI_TIMER_TURN_OFF_HIDE, 18.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +158,8 @@ void HideOrClear()
|
||||
GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH) == FALSE)
|
||||
{
|
||||
// Need skill or force on
|
||||
if((GetSkillRank(SKILL_HIDE) - i4 >= GetHitDice(OBJECT_SELF)) ||
|
||||
int nRank = GetSkillRank(SKILL_HIDE);
|
||||
if((nRank - 4 >= GetHitDice(OBJECT_SELF) && nRank >= 7) ||
|
||||
GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_FORCE_HIDING, AI_OTHER_COMBAT_MASTER))
|
||||
{
|
||||
// Use hide
|
||||
@@ -173,12 +196,17 @@ void HideOrClear()
|
||||
I_WAS_ATTACKED = 1;
|
||||
|
||||
If not in combat, attack the attackee of the shouter. Basically the best
|
||||
way to get people to come and help us.
|
||||
way to get people to come and help us, if we know of an attacker!
|
||||
* Call this after we call DetermineCombatRound() to make sure that any
|
||||
responses know of the attackers. It doesn't matter in actual fact, but
|
||||
useful anyway.
|
||||
|
||||
CALL_TO_ARMS = 3;
|
||||
|
||||
If not in combat, determine combat round. By default, it should check any
|
||||
allies it can see/hear for thier targets and help them too.
|
||||
* Better if we do not know of a target (and thusly our allies wouldn't know
|
||||
of them as well) so the allies will move to us.
|
||||
|
||||
HELP_MY_FRIEND = 4;
|
||||
|
||||
@@ -208,179 +236,254 @@ void HideOrClear()
|
||||
//::///////////////////////////////////////////////
|
||||
// Modified almost completely: Jasperre
|
||||
//:://///////////////////////////////////////////*/
|
||||
// Gets the attacker or attakee of the target, which should be a friend
|
||||
// Gets any possible target which is attacking oShouter (and isn't an ally)
|
||||
// or who oShouter is attacking. oShouter should be a ally.
|
||||
object GetIntruderFromShout(object oShouter)
|
||||
{
|
||||
object oIntruder = GetAttackTarget(oShouter);
|
||||
if(!GetIsObjectValid(oIntruder) ||
|
||||
GetIgnoreNoFriend(oIntruder))
|
||||
// First, get who they specifically want to attack (IE: Input target the shout
|
||||
// is usually for)
|
||||
object oIntruder = GetLocalObject(oShouter, AI_OBJECT + AI_ATTACK_SPECIFIC_OBJECT);
|
||||
if(GetIgnoreNoFriend(oIntruder) || (!GetObjectSeen(oShouter) && !GetObjectHeard(oShouter)))
|
||||
{
|
||||
oIntruder = GetLastHostileActor(oShouter);
|
||||
if(GetIgnoreNoFriend(oIntruder))
|
||||
// Or, we look for the last melee target (which, at least, will be set)
|
||||
oIntruder = GetLocalObject(oShouter, AI_OBJECT + AI_LAST_MELEE_TARGET);
|
||||
if(GetIgnoreNoFriend(oIntruder) || (!GetObjectSeen(oShouter) && !GetObjectHeard(oShouter)))
|
||||
{
|
||||
return OBJECT_INVALID;
|
||||
// Current actual attack target of the shouter
|
||||
oIntruder = GetAttackTarget(oShouter);
|
||||
if(GetIgnoreNoFriend(oIntruder) || (!GetObjectSeen(oShouter) && !GetObjectHeard(oShouter)))
|
||||
{
|
||||
// Last hostile actor of the shouter
|
||||
oIntruder = GetLastHostileActor(oShouter);
|
||||
if(GetIgnoreNoFriend(oIntruder) || (!GetObjectSeen(oShouter) && !GetObjectHeard(oShouter)))
|
||||
{
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return oIntruder;
|
||||
}
|
||||
|
||||
// Responds to it (like makinging the callers attacker thier target)
|
||||
// Called in OnConversation, and thats it. Use "ShouterFriend" To stop repeated GetIsFriend calls.
|
||||
void RespondToShout(object oShouter, int nShoutIndex)
|
||||
{
|
||||
// We use oIntruder to set who to attack.
|
||||
object oIntruder;
|
||||
// Ones we don't care about if we are in combat...
|
||||
if(nShoutIndex == i6) // "Attack specific object"
|
||||
// Check nShoutIndex against known constants
|
||||
switch(nShoutIndex)
|
||||
{
|
||||
// If a leader, we set it as a local object, nothing more
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oShouter))
|
||||
// Note: Not checked in sequential order (especially as they are constants).
|
||||
// Instead, it is "Ones which if we are in combat, we still check" first.
|
||||
|
||||
// Attack a specific object which the leader shouted about.
|
||||
case AI_SHOUT_LEADER_ATTACK_TARGET_CONSTANT:
|
||||
{
|
||||
oIntruder = GetLocalObject(oShouter, AI_ATTACK_SPECIFIC_OBJECT);
|
||||
if(GetObjectSeen(oIntruder))
|
||||
// If a leader, we set it as a local object, nothing more
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oShouter))
|
||||
{
|
||||
// Set local object to use in next DetermineCombatRound.
|
||||
// We do not interrupt current acition (EG: Life saving stoneskins!) to re-direct.
|
||||
SetAIObject(AI_ATTACK_SPECIFIC_OBJECT, oIntruder);
|
||||
// 6 second delay.
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6);
|
||||
// 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput)
|
||||
DebugActionSpeakByInt(70, oShouter, nShoutIndex);
|
||||
|
||||
oIntruder = GetLocalObject(oShouter, AI_ATTACK_SPECIFIC_OBJECT);
|
||||
if(GetObjectSeen(oIntruder))
|
||||
{
|
||||
// Set local object to use in next DetermineCombatRound.
|
||||
// We do not interrupt current acition (EG: Life saving stoneskins!) to re-direct.
|
||||
SetAIObject(AI_ATTACK_SPECIFIC_OBJECT, oIntruder);
|
||||
// 6 second delay.
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if(nShoutIndex == i5)// "leader flee now"
|
||||
{
|
||||
// If a leader, we set it as a local object, nothing more
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oShouter))
|
||||
break;
|
||||
// Leader flee now - mass retreat to those who hear it.
|
||||
case AI_SHOUT_LEADER_FLEE_NOW_CONSTANT:
|
||||
{
|
||||
oIntruder = GetLocalObject(oShouter, AI_FLEE_TO);
|
||||
// RUN! If intruder set is over 5.0M or no valid intruder
|
||||
ClearAllActions();
|
||||
// If a leader, we set it as a local object, nothing more
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_GROUP_LEADER, AI_OTHER_COMBAT_MASTER, oShouter))
|
||||
{
|
||||
// Get who we are going to run too
|
||||
oIntruder = GetLocalObject(oShouter, AI_FLEE_TO);
|
||||
|
||||
// RUN! If intruder set is over 5.0M or no valid intruder
|
||||
ClearAllActions();
|
||||
|
||||
// 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput)
|
||||
DebugActionSpeakByInt(70, oShouter, nShoutIndex);
|
||||
|
||||
// Set to run
|
||||
SetCurrentAction(AI_SPECIAL_ACTIONS_FLEE);
|
||||
// Turn on fleeing visual effect
|
||||
ApplyFleeingVisual();
|
||||
|
||||
// Ignore talk for 12 seconds
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 12.0);
|
||||
|
||||
// If valid, we run to the intruder
|
||||
if(GetIsObjectValid(oIntruder))
|
||||
{
|
||||
SetAIObject(AI_FLEE_TO, oIntruder);
|
||||
ActionMoveToObject(oIntruder);
|
||||
}
|
||||
else // Else, we will just follow our leader!
|
||||
{
|
||||
SetAIObject(AI_FLEE_TO, oShouter);
|
||||
ActionForceFollowObject(oShouter, 3.0);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
// All others (IE: We need to not be in combat for these)
|
||||
// Anything that requires "DetermineCombatRound()" is here.
|
||||
|
||||
// If the shout is number 8, it is "I was opened" and so can only be a
|
||||
// placeable or door.
|
||||
case AI_SHOUT_I_WAS_OPENED_CONSTANT:
|
||||
{
|
||||
// If we are already attacking, we ignore this shout.
|
||||
if(CannotPerformCombatRound()) return;
|
||||
|
||||
// We need somewhat complexe here - to get thier opener.
|
||||
int nType = GetObjectType(oShouter);
|
||||
// Check object type. If not a placeable nor door - stop script.
|
||||
if(nType == OBJECT_TYPE_PLACEABLE ||
|
||||
nType == OBJECT_TYPE_DOOR)
|
||||
{
|
||||
// 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput)
|
||||
DebugActionSpeakByInt(70, oShouter, nShoutIndex);
|
||||
|
||||
// Now, we assign the placeable/door to set thier opener.
|
||||
// We do this by just executing a script that does it.
|
||||
ExecuteScript(FILE_SET_OPENER, oShouter);
|
||||
// We can immediantly get this would-be attacker!
|
||||
oIntruder = GetLocalObject(oShouter, AI_PLACEABLE_LAST_OPENED_BY);
|
||||
if(GetIsObjectValid(oIntruder))
|
||||
{
|
||||
// Attack
|
||||
ClearAllActions();
|
||||
DetermineCombatRound(oShouter);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move to the object who shouted in detect mode
|
||||
SetActionMode(OBJECT_SELF, ACTION_MODE_DETECT, TRUE);
|
||||
ActionMoveToObject(oShouter, TRUE);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
// Call to arms requires nothing special. It is only called if
|
||||
// There is no target the shouter has to attack specifically, rather then
|
||||
// "I_WAS_ATTACKED" which would have.
|
||||
case AI_SHOUT_CALL_TO_ARMS_CONSTANT:
|
||||
{
|
||||
// If we are already attacking, we ignore this shout.
|
||||
if(CannotPerformCombatRound()) return;
|
||||
|
||||
// Ignore for 6 seconds
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0);
|
||||
|
||||
// 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput)
|
||||
DebugActionSpeakByInt(70, oShouter, nShoutIndex);
|
||||
SetCurrentAction(AI_SPECIAL_ACTIONS_FLEE);
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f12);
|
||||
if(GetIsObjectValid(oIntruder))
|
||||
{
|
||||
SetAIObject(AI_FLEE_TO, oIntruder);
|
||||
ActionMoveToObject(oIntruder);
|
||||
}
|
||||
else // Else, we will just follow our leader!
|
||||
{
|
||||
SetAIObject(AI_FLEE_TO, oShouter);
|
||||
ActionForceFollowObject(oShouter, f3);
|
||||
}
|
||||
|
||||
// do standard Call to Arms response - IE: Move to oShouter
|
||||
CallToArmsResponse(oShouter);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// If the shout is number 8, it is "I was opened" and so can only be a
|
||||
// placeable or door.
|
||||
else if(nShoutIndex == i8)// "I was opened"
|
||||
{
|
||||
// We need somewhat complexe here - to get thier opener.
|
||||
int nType = GetObjectType(oShouter);
|
||||
// Check object type. If not a placeable nor door - stop script.
|
||||
if(nType == OBJECT_TYPE_PLACEABLE ||
|
||||
nType == OBJECT_TYPE_DOOR)
|
||||
{
|
||||
// Now, we assign the placeable/door to set thier opener.
|
||||
// - Need to check it works.
|
||||
AssignCommand(oShouter, SetLocalObject(oShouter, PLACEABLE_LAST_OPENED_BY, GetLastOpenedBy()));
|
||||
oIntruder = GetLocalObject(oShouter, PLACEABLE_LAST_OPENED_BY);
|
||||
if(GetIsObjectValid(oIntruder))
|
||||
{
|
||||
// Attack
|
||||
ClearAllActions();
|
||||
DetermineCombatRound(oShouter);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Else, we must not be in combat for the rest
|
||||
else if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Call to arms requires nothing special
|
||||
if(nShoutIndex == i3)// "Call to arms"
|
||||
{
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6);
|
||||
// 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput)
|
||||
DebugActionSpeakByInt(70, oShouter, nShoutIndex);
|
||||
DetermineCombatRound();
|
||||
}
|
||||
// Ones we can GetIntruderFromShout(oShouter);
|
||||
if(nShoutIndex == i1 || // "I was attacked"
|
||||
nShoutIndex == i4 || // "Help my friend"
|
||||
nShoutIndex == i7) // "I was killed"
|
||||
{
|
||||
// Am not already fighting, and we don't ignore the intruder
|
||||
oIntruder = GetIntruderFromShout(oShouter);
|
||||
if(!GetIsObjectValid(oIntruder))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(nShoutIndex == i1 ||
|
||||
nShoutIndex == i7)
|
||||
{
|
||||
// Morale penalty if they were killed
|
||||
if(nShoutIndex == i7)
|
||||
{
|
||||
SetMoralePenalty((GetHitDice(oShouter)/i4), f18);
|
||||
}
|
||||
// Get intruder
|
||||
// 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput)
|
||||
DebugActionSpeakByInt(70, oShouter, nShoutIndex);
|
||||
if(GetObjectSeen(oIntruder))
|
||||
{
|
||||
// Stop, and attack, if we can see them!
|
||||
ClearAllActions();
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f9);
|
||||
DetermineCombatRound(oIntruder);
|
||||
DelayCommand(f2, AISpeakString(I_WAS_ATTACKED));
|
||||
}
|
||||
else // Else the enemy is not seen
|
||||
{
|
||||
// If I can see neither the shouter nor the enemy
|
||||
// stop what I am doing, and move to the attacker.
|
||||
// - 1.3 change. They move to the attackers location (IE directed by ally)
|
||||
ClearAllActions();
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6);
|
||||
// This will move to oIntruder if nothing else
|
||||
DetermineCombatRound(oIntruder);
|
||||
// Shout to other allies, after a second.
|
||||
DelayCommand(f2, AISpeakString(HELP_MY_FRIEND));
|
||||
}
|
||||
}
|
||||
else if(nShoutIndex == i4)// "Help my friend"
|
||||
break;
|
||||
// "Help my friend" is when a runner is running off (sorta fleeing) to
|
||||
// get help. This will move to the location set on them to reinforce.
|
||||
case AI_SHOUT_HELP_MY_FRIEND_CONSTANT:
|
||||
{
|
||||
// If we are already attacking, we ignore this shout.
|
||||
if(CannotPerformCombatRound()) return;
|
||||
|
||||
// Ignore things for 6 seconds
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0);
|
||||
|
||||
// We move to where the runner/shouter wants us.
|
||||
location lMoveTo = GetLocalLocation(oShouter, AI_HELP_MY_FRIEND_LOCATION);
|
||||
location lMoveTo = GetLocalLocation(oShouter, AI_LOCATION + AI_HELP_MY_FRIEND_LOCATION);
|
||||
|
||||
// 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput)
|
||||
DebugActionSpeakByInt(70, oShouter, nShoutIndex);
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6);
|
||||
|
||||
// If the location is valid
|
||||
if(GetIsObjectValid(GetAreaFromLocation(lMoveTo)))
|
||||
{
|
||||
// New special action, but one that is overrided by combat
|
||||
SetCurrentAction(AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT);
|
||||
SetAIObject(AI_MOVE_TO_COMBAT_OBJECT, oShouter);
|
||||
SetAILocation(AI_MOVE_TO_COMBAT_LOCATION, lMoveTo);
|
||||
|
||||
// Move to the location of the fight, attack.
|
||||
ClearAllActions();
|
||||
// Move to the fights location
|
||||
ActionMoveToLocation(lMoveTo, TRUE);
|
||||
ActionDoCommand(DetermineCombatRound());
|
||||
// When we see someone fighting, we'll DCR
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we do not know of the friend attacker, we will follow them
|
||||
// Else, if we do not know of the friends attackers, or the location
|
||||
// they are at, we will follow them without casting any preperation
|
||||
// spells.
|
||||
ClearAllActions();
|
||||
SetSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER);
|
||||
ActionForceFollowObject(oShouter, f3);
|
||||
ActionDoCommand(DetermineCombatRound());
|
||||
ActionForceFollowObject(oShouter, 3.0);
|
||||
// When we see an enemy, we'll attack!
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
// "I was attacked" is called when a creature is hurt or sees an enemy,
|
||||
// and starts to attack them. This means they know who the enemy is -
|
||||
// and thusly we can get it from them (Ususally GetLastHostileActor()
|
||||
// "I was killed" is the same, but applies a morale penalty too
|
||||
case AI_SHOUT_I_WAS_ATTACKED_CONSTANT:
|
||||
case AI_SHOUT_I_WAS_KILLED_CONSTANT:
|
||||
{
|
||||
// If it was "I was killed", we apply a short morale penatly
|
||||
// Penalty is "Hit dice / 4 + 1" (so always 1 minimum) for 18 seconds.
|
||||
if(nShoutIndex == AI_SHOUT_I_WAS_KILLED_CONSTANT)
|
||||
{
|
||||
SetMoralePenalty(GetHitDice(oShouter)/4 + 1, 18.0);
|
||||
}
|
||||
|
||||
// If we are already attacking, we ignore this shout.
|
||||
if(CannotPerformCombatRound()) return;
|
||||
|
||||
// 70. "[Shout] Reacting To Shout. [ShoutNo.] " + IntToString(iInput) + " [Shouter] " + GetName(oInput)
|
||||
DebugActionSpeakByInt(70, oShouter, nShoutIndex);
|
||||
|
||||
// Ignore for 6 seconds
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0);
|
||||
|
||||
// Respond to oShouter's request for help - find thier target, and
|
||||
// attack!
|
||||
IWasAttackedResponse(oShouter);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// At 5+ intelligence, we fire off any dispells at oPlaceables location
|
||||
void SearchDispells(object oPlaceable)
|
||||
{
|
||||
// No dispelling at low intelligence.
|
||||
if(GetBoundriedAIInteger(AI_INTELLIGENCE) < i5) return;
|
||||
if(GetBoundriedAIInteger(AI_INTELLIGENCE) < 5) return;
|
||||
location lPlace = GetLocation(oPlaceable);
|
||||
// Move closer if not seen.
|
||||
if(!GetObjectSeen(oPlaceable))
|
||||
{
|
||||
// Move nearer - 6 M is out of the dispell range
|
||||
ActionMoveToObject(oPlaceable, TRUE, f6);
|
||||
ActionMoveToObject(oPlaceable, TRUE, 6.0);
|
||||
}
|
||||
// Dispell if we have any - at the location of oPlaceable.
|
||||
if(GetHasSpell(SPELL_LESSER_DISPEL))
|
||||
@@ -401,41 +504,22 @@ void SearchDispells(object oPlaceable)
|
||||
}
|
||||
}
|
||||
|
||||
// Get Has Effect
|
||||
// Checks to see if the target has a given
|
||||
// effect, usually from a spell. Really useful this is.
|
||||
int GetHasEffect(int nEffectType, object oTarget = OBJECT_SELF)
|
||||
{
|
||||
effect eCheck = GetFirstEffect(oTarget);
|
||||
while(GetIsEffectValid(eCheck))
|
||||
{
|
||||
if(GetEffectType(eCheck) == nEffectType)
|
||||
{
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
eCheck = GetNextEffect(oTarget);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// This sets a morale penalty, to the exsisting one, if there is one.
|
||||
// It will reduce itself (by the penalty) after fDuration (or if we die, ETC, it is deleted).
|
||||
// It is deleted at the end of combat as well.
|
||||
void SetMoralePenalty(int iPenalty, float fDuration = 0.0)
|
||||
void SetMoralePenalty(int nPenalty, float fDuration = 0.0)
|
||||
{
|
||||
int iOriginal = GetAIInteger(AI_MORALE_PENALTY);
|
||||
int iNew = iOriginal + iPenalty;
|
||||
SetAIInteger(AI_MORALE_PENALTY, iNew);
|
||||
DelayCommand(fDuration, RemoveMoralePenalty(iPenalty));
|
||||
int nNewPenalty = GetAIInteger(AI_MORALE_PENALTY) + nPenalty;
|
||||
SetAIInteger(AI_MORALE_PENALTY, nNewPenalty);
|
||||
DelayCommand(fDuration, RemoveMoralePenalty(nPenalty));
|
||||
}
|
||||
void RemoveMoralePenalty(int iPenalty)
|
||||
// Removes nPenalty amount if it can.
|
||||
void RemoveMoralePenalty(int nPenalty)
|
||||
{
|
||||
int iOriginal = GetAIInteger(AI_MORALE_PENALTY);
|
||||
int iNew = iOriginal - iPenalty;
|
||||
if(iNew > 0 && !GetIsDead(OBJECT_SELF))
|
||||
int nNewPenalty = GetAIInteger(AI_MORALE_PENALTY) - nPenalty;
|
||||
if(nNewPenalty > 0 && !GetIsDead(OBJECT_SELF))
|
||||
{
|
||||
SetAIInteger(AI_MORALE_PENALTY, iNew);
|
||||
SetAIInteger(AI_MORALE_PENALTY, nNewPenalty);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -478,10 +562,10 @@ int PerceptionFleeFrom(object oEnemy)
|
||||
// Valid run from target
|
||||
if(!GetIsObjectValid(oRunTarget))
|
||||
{
|
||||
oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
if(!GetIsObjectValid(oRunTarget))
|
||||
{
|
||||
oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, i1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
oRunTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
if(!GetIsObjectValid(oRunTarget))
|
||||
{
|
||||
oRunTarget = GetLastHostileActor();
|
||||
@@ -495,12 +579,140 @@ int PerceptionFleeFrom(object oEnemy)
|
||||
}
|
||||
// Run from enemy
|
||||
ClearAllActions();
|
||||
ActionMoveAwayFromObject(oRunTarget, TRUE, f50);
|
||||
ActionMoveAwayFromObject(oRunTarget, TRUE, 50.0);
|
||||
return TRUE;
|
||||
}
|
||||
// 0 or more morale.
|
||||
return FALSE;
|
||||
}
|
||||
// This wrappers commonly used code for a "Call to arms" type response.
|
||||
// * We know of no enemy, so we will move to oAlly, who either called to
|
||||
// us, or, well, we know of.
|
||||
// * Calls out AI_SHOUT_CALL_TO_ARMS too.
|
||||
void CallToArmsResponse(object oAlly)
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
// If we are over 2 meters away from oShouter, we move to them using
|
||||
// the special action
|
||||
if(GetDistanceToObject(oAlly) > 2.0 || !GetObjectSeen(oAlly))
|
||||
{
|
||||
// New special action, but one that is overrided by combat
|
||||
location lAlly = GetLocation(oAlly);
|
||||
SetCurrentAction(AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT);
|
||||
SetAIObject(AI_MOVE_TO_COMBAT_OBJECT, oAlly);
|
||||
SetAILocation(AI_MOVE_TO_COMBAT_LOCATION, lAlly);
|
||||
|
||||
// Move to the location of the fight, attack.
|
||||
ClearAllActions();
|
||||
// Move to the fights location
|
||||
ActionMoveToLocation(lAlly, TRUE);
|
||||
// When we see someone fighting, we'll DCR
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Determine it anyway - we will search around oShouter
|
||||
// if nothing is found...but we are near to the shouter
|
||||
DetermineCombatRound(oAlly);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// This wrappers commonly used code for a "I was attacked" type response.
|
||||
// * We know there will be an enemy - or should be - and if we find one to attack
|
||||
// (using GetIntruderFromShout()) - we attack it (and call another I was attacked)
|
||||
// else, this will run CallToArmsResponse(oAlly);
|
||||
// * Calls out AI_SHOUT_I_WAS_ATTACKED, or AI_SHOUT_CALL_TO_ARMS too.
|
||||
void IWasAttackedResponse(object oAlly)
|
||||
{
|
||||
// Get the indruder. This is either who oShouter is currently attacking,
|
||||
// or the last attacker of them.
|
||||
object oIntruder = GetIntruderFromShout(oAlly);
|
||||
|
||||
// If valid, of course attack!
|
||||
if(GetIsObjectValid(oIntruder))
|
||||
{
|
||||
// 1.4 Note:
|
||||
// * It used to check "Are they seen". Basically, this is redudant
|
||||
// with the checks used in DetermineCombatRound(). It will do the
|
||||
// searching using oIntruder whatever.
|
||||
|
||||
// Stop, and attack
|
||||
ClearAllActions();
|
||||
DetermineCombatRound(oIntruder);
|
||||
|
||||
// Shout I was attacked - we've set our intruder now
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
return;
|
||||
}
|
||||
// If invalid, we act as if it was "Call to arms" type thing.
|
||||
// Call to arms is better to use normally, of course.
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
// We see if they are attacking anything:
|
||||
oIntruder = GetAttackTarget(oAlly);
|
||||
if(!GetIsObjectValid(oIntruder))
|
||||
{
|
||||
oIntruder = GetLocalObject(oAlly, AI_OBJECT + AI_LAST_MELEE_TARGET);
|
||||
}
|
||||
|
||||
// If valid, we will move to a point bisecting the intruder and oAlly, or
|
||||
// move to oAlly. Should get interrupted once we see the attack target.
|
||||
// * NEED TO TEST
|
||||
if(GetIsObjectValid(oIntruder))
|
||||
{
|
||||
// New special action, but one that is overrided by combat
|
||||
vector vTarget = GetPosition(oIntruder);
|
||||
vector vSource = GetPosition(OBJECT_SELF);
|
||||
vector vDirection = vTarget - vSource;
|
||||
float fDistance = VectorMagnitude(vDirection) / 2.0;
|
||||
vector vPoint = VectorNormalize(vDirection) * fDistance + vSource;
|
||||
location lTarget = Location(GetArea(OBJECT_SELF), vPoint, DIRECTION_NORTH);
|
||||
|
||||
SetCurrentAction(AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT);
|
||||
SetAIObject(AI_MOVE_TO_COMBAT_OBJECT, oAlly);
|
||||
SetAILocation(AI_MOVE_TO_COMBAT_LOCATION, lTarget);
|
||||
|
||||
// Move to the location of the fight, attack.
|
||||
ClearAllActions();
|
||||
// Move to the fights location
|
||||
ActionMoveToLocation(lTarget, TRUE);
|
||||
// When we see someone fighting, we'll DCR
|
||||
return;
|
||||
}
|
||||
// If we are over 2 meters away from oShouter, we move to them using
|
||||
// the special action
|
||||
else if(GetDistanceToObject(oAlly) > 2.0 || !GetObjectSeen(oAlly))
|
||||
{
|
||||
// New special action, but one that is overrided by combat
|
||||
location lAlly = GetLocation(oAlly);
|
||||
SetCurrentAction(AI_SPECIAL_ACTIONS_MOVE_TO_COMBAT);
|
||||
SetAIObject(AI_MOVE_TO_COMBAT_OBJECT, oAlly);
|
||||
SetAILocation(AI_MOVE_TO_COMBAT_LOCATION, lAlly);
|
||||
|
||||
// Move to the location of the fight, attack.
|
||||
ClearAllActions();
|
||||
// Move to the fights location
|
||||
ActionMoveToLocation(lAlly, TRUE);
|
||||
// When we see someone fighting, we'll DCR
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Determine it anyway - we will search around oShouter
|
||||
// if nothing is found...but we are near to the shouter
|
||||
DetermineCombatRound(oAlly);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Debug: To compile this script full, uncomment all of the below.
|
||||
/* - Add two "/"'s at the start of this line
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [Set Effects Include] ********************************
|
||||
Filename:
|
||||
************************* [Set Effects] ****************************************
|
||||
/*/////////////////////// [Include - Set Effects] //////////////////////////////
|
||||
Filename: J_INC_SetEffects
|
||||
///////////////////////// [Include - Set Effects] //////////////////////////////
|
||||
This can be executed on a PC or NPC, and sets what thier current effects
|
||||
are - the hostile ones.
|
||||
|
||||
@@ -9,22 +9,28 @@
|
||||
|
||||
It is meant to be more efficient then doing countless checks against other
|
||||
NPCs and PCs for what effects they already have on them.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Changed so fear and stun was seperate.
|
||||
Uncommandable still is now for any uncommandable effects.
|
||||
|
||||
- TO DO
|
||||
- Make the ability decrease into "light" "major" and so on, about 4
|
||||
ratings, each set as more decreases are present.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
ExecuteScript - might not work faster. If so, it is easy to add into the
|
||||
generic AI and have oTarget to set to.
|
||||
|
||||
It searches the code and sets 3 custom integers, but only once (so not
|
||||
during the loop)
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: N/A
|
||||
************************* [Set Effects] ***************************************/
|
||||
///////////////////////// [Include - Set Effects] ////////////////////////////*/
|
||||
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
// List (use Global to not conflict with the nwscript.nss!)
|
||||
const int GlobalEffectUncommandable = 0x00000001;// Stun. Sleep. Fear. Turning.
|
||||
const int GlobalEffectUncommandable = 0x00000001;// Stun. Sleep. Fear. Turning. Paralsis. Petrify.
|
||||
const int GlobalEffectSilenced = 0x00000002;// Eeek!
|
||||
const int GlobalEffectSlowed = 0x00000004;// Stop with haste.
|
||||
const int GlobalEffectUltravision = 0x00000008;
|
||||
@@ -35,7 +41,7 @@ const int GlobalEffectInvisible = 0x00000080;
|
||||
const int GlobalEffectDeaf = 0x00000100;// Ack!
|
||||
const int GlobalEffectHaste = 0x00000200;
|
||||
const int GlobalEffectPolymorph = 0x00000400;// Only attack
|
||||
const int GlobalEffectBlindness = 0x00000800;// Oh no!
|
||||
const int GlobalEffectBlindness = 0x00000800;// Oh no! Cannot see others to cast spells.
|
||||
const int GlobalEffectDisease = 0x00001000;
|
||||
const int GlobalEffectPoison = 0x00002000;
|
||||
const int GlobalEffectCurse = 0x00004000;
|
||||
@@ -47,13 +53,15 @@ const int GlobalEffectDazed = 0x00080000;// Special: 1.30
|
||||
const int GlobalEffectEthereal = 0x00100000;
|
||||
const int GlobalEffectPetrify = 0x00200000;
|
||||
const int GlobalEffectParalyze = 0x00400000;// Divided from Uncommandable for healing of
|
||||
//const int GlobalEffectAbilityDecrease = 0x00080000;// Ohh! Tingly!
|
||||
const int GlobalEffectSpellFailure = 0x00800000;// Makes sure spells are not cast under high failure.
|
||||
const int GlobalEffectDamageShield = 0x01000000;// All damage shields
|
||||
const int GlobalEffectFear = 0x02000000;// 1.4. Remove fear + G.Rest. Removes.
|
||||
const int GlobalEffectStun = 0x04000000;// 1.4. G.Rest. Removes.
|
||||
//int GlobalEffectAbilityDecrease = 0; // In combat include
|
||||
|
||||
// These are Globals for spell effects, to not csat them on us again, and to
|
||||
// speed things up...
|
||||
// These are *good* spells. This effect is only set up on us.
|
||||
const int GlobalHasStoneSkinProtections = 0x00000001;
|
||||
const int GlobalHasElementalProtections = 0x00000002;
|
||||
const int GlobalHasVisageProtections = 0x00000004;
|
||||
@@ -80,7 +88,7 @@ const int GlobalHasRegenerateSpell = 0x00400000;
|
||||
const int GlobalHasOwlsWisdomSpell = 0x00800000;
|
||||
const int GlobalHasSpellResistanceSpell = 0x01000000;
|
||||
const int GlobalHasSpellWarCrySpell = 0x02000000;
|
||||
//const int GlobalHasElementalShieldSpell = 0x04000000;
|
||||
//const int GlobalHasElementalShieldSpell = 0x04000000;// Is general effect
|
||||
const int GlobalHasDomainSpells = 0x08000000;
|
||||
const int GlobalHasDeflectionACSpell = 0x10000000;
|
||||
const int GlobalHasNaturalACSpell = 0x20000000;
|
||||
@@ -94,154 +102,173 @@ const int GlobalHasWeaponHelpSpell = 0x80000000;
|
||||
int TempEffectHex, TempSpellHex;
|
||||
|
||||
// Sets up an effects thing to that
|
||||
void AI_SetWeHaveEffect(int iEffectHex);
|
||||
void AI_SetTargetHasEffect(int nEffectHex);
|
||||
// Sets we have spell iSpellHex's effects.
|
||||
void AI_SetWeHaveSpellsEffect(int iSpellHex);
|
||||
void AI_SetWeHaveSpellsEffect(int nSpellHex);
|
||||
// Sets up effects on oTarget
|
||||
void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF);
|
||||
|
||||
|
||||
// Simple return TRUE if it matches hex.
|
||||
// - Effects tested on oTarget
|
||||
int AI_GetAIHaveEffect(int iEffectHex, object oTarget = OBJECT_SELF);
|
||||
int AI_GetAIHaveEffect(int nEffectHex, object oTarget = OBJECT_SELF);
|
||||
// Simple return TRUE if it matches hex.
|
||||
// - Uses oTarget
|
||||
int AI_GetAIHaveSpellsEffect(int iSpellHex, object oTarget = OBJECT_SELF);
|
||||
// * Can only be used on ourself.
|
||||
int AI_GetAIHaveSpellsEffect(int nSpellHex);
|
||||
|
||||
// Sets up an effects thing to that
|
||||
void AI_SetWeHaveEffect(int iEffectHex)
|
||||
void AI_SetTargetHasEffect(int nEffectHex)
|
||||
{
|
||||
TempEffectHex = TempEffectHex | iEffectHex;
|
||||
TempEffectHex = TempEffectHex | nEffectHex;
|
||||
}
|
||||
// Sets we have spell iSpellHex's effects.
|
||||
void AI_SetWeHaveSpellsEffect(int iSpellHex)
|
||||
void AI_SetWeHaveSpellsEffect(int nSpellHex)
|
||||
{
|
||||
TempSpellHex = TempSpellHex | iSpellHex;
|
||||
TempSpellHex = TempSpellHex | nSpellHex;
|
||||
}
|
||||
|
||||
// Simple return TRUE if it matches hex.
|
||||
// - Effects tested on oTarget
|
||||
int AI_GetAIHaveEffect(int iEffectHex, object oTarget = OBJECT_SELF)
|
||||
int AI_GetAIHaveEffect(int nEffectHex, object oTarget = OBJECT_SELF)
|
||||
{
|
||||
return (GetLocalInt(oTarget, AI_EFFECT_HEX) & iEffectHex);
|
||||
return (GetLocalInt(oTarget, AI_EFFECT_HEX) & nEffectHex);
|
||||
|
||||
}
|
||||
// Simple return TRUE if it matches hex.
|
||||
// - Uses oTarget
|
||||
int AI_GetAIHaveSpellsEffect(int iSpellHex, object oTarget = OBJECT_SELF)
|
||||
// * Can only be used on ourself.
|
||||
int AI_GetAIHaveSpellsEffect(int nSpellHex)
|
||||
{
|
||||
return (GetLocalInt(oTarget, AI_SPELL_HEX) & iSpellHex);
|
||||
return (GetLocalInt(OBJECT_SELF, AI_SPELL_HEX) & nSpellHex);
|
||||
}
|
||||
|
||||
|
||||
// Sets up effects on oTarget
|
||||
void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF)
|
||||
{
|
||||
TempEffectHex = FALSE;
|
||||
TempSpellHex = FALSE;
|
||||
// Checks our effects once.
|
||||
effect eCheck = GetFirstEffect(oTarget);
|
||||
int iEffect, iEffectAbilityDecrease, iSpellID;
|
||||
int nEffect, nEffectAbilityDecrease, nSpellID;
|
||||
// EFFECTS:
|
||||
// For ALL targets (that we will use), we set up effects on a system of Hexes.
|
||||
// like spawn in things. Replaces GetHasSpellEffect, except genralising -
|
||||
// IE we will NOT cast more than one of the stoneskin type things at once.
|
||||
while(GetIsEffectValid(eCheck))
|
||||
{
|
||||
iEffect = GetEffectType(eCheck);
|
||||
switch(iEffect)
|
||||
nEffect = GetEffectType(eCheck);
|
||||
switch(nEffect)
|
||||
{
|
||||
case EFFECT_TYPE_INVALIDEFFECT:
|
||||
case EFFECT_TYPE_VISUALEFFECT:
|
||||
// Don't check these for spell values.
|
||||
break;
|
||||
case EFFECT_TYPE_PARALYZE:
|
||||
AI_SetWeHaveEffect(GlobalEffectParalyze);
|
||||
case EFFECT_TYPE_PARALYZE: // Also makes you uncommandable
|
||||
{
|
||||
AI_SetTargetHasEffect(GlobalEffectParalyze);
|
||||
AI_SetTargetHasEffect(GlobalEffectUncommandable);
|
||||
}
|
||||
break;
|
||||
case EFFECT_TYPE_STUNNED:
|
||||
case EFFECT_TYPE_FRIGHTENED:
|
||||
case EFFECT_TYPE_STUNNED: // Also makes you uncommandable
|
||||
{
|
||||
AI_SetTargetHasEffect(GlobalEffectStun);
|
||||
AI_SetTargetHasEffect(GlobalEffectUncommandable);
|
||||
}
|
||||
break;
|
||||
case EFFECT_TYPE_FRIGHTENED: // Also makes you uncommandable
|
||||
{
|
||||
AI_SetTargetHasEffect(GlobalEffectFear);
|
||||
AI_SetTargetHasEffect(GlobalEffectUncommandable);
|
||||
}
|
||||
break;
|
||||
// * Cannot remove these, but make you unable to move.
|
||||
case EFFECT_TYPE_SLEEP:
|
||||
case EFFECT_TYPE_TURNED:
|
||||
case EFFECT_TYPE_DISAPPEARAPPEAR:// Added for dragon flying
|
||||
AI_SetWeHaveEffect(GlobalEffectUncommandable);
|
||||
case EFFECT_TYPE_CONFUSED:// 1.4 added. wasn't in before
|
||||
AI_SetTargetHasEffect(GlobalEffectUncommandable);
|
||||
break;
|
||||
case EFFECT_TYPE_DAZED:
|
||||
AI_SetWeHaveEffect(GlobalEffectDazed);
|
||||
AI_SetTargetHasEffect(GlobalEffectDazed);
|
||||
break;
|
||||
case EFFECT_TYPE_SILENCE:
|
||||
AI_SetWeHaveEffect(GlobalEffectSilenced);
|
||||
AI_SetTargetHasEffect(GlobalEffectSilenced);
|
||||
break;
|
||||
case EFFECT_TYPE_SLOW:
|
||||
AI_SetWeHaveEffect(GlobalEffectSlowed);
|
||||
AI_SetTargetHasEffect(GlobalEffectSlowed);
|
||||
break;
|
||||
case EFFECT_TYPE_ULTRAVISION:
|
||||
AI_SetWeHaveEffect(GlobalEffectUltravision);
|
||||
AI_SetTargetHasEffect(GlobalEffectUltravision);
|
||||
break;
|
||||
case EFFECT_TYPE_SEEINVISIBLE:
|
||||
AI_SetWeHaveEffect(GlobalEffectSeeInvisible);
|
||||
AI_SetTargetHasEffect(GlobalEffectSeeInvisible);
|
||||
break;
|
||||
// Caused by Beholder things mainly, but this stops any spell being
|
||||
// cast, not just, for example, arcane spells cast in armor.
|
||||
case EFFECT_TYPE_SPELL_FAILURE:
|
||||
AI_SetWeHaveEffect(GlobalEffectSpellFailure);
|
||||
AI_SetTargetHasEffect(GlobalEffectSpellFailure);
|
||||
break;
|
||||
// Penetrates darkness.
|
||||
case EFFECT_TYPE_TRUESEEING:
|
||||
AI_SetWeHaveEffect(GlobalEffectTrueSeeing);
|
||||
AI_SetTargetHasEffect(GlobalEffectTrueSeeing);
|
||||
break;
|
||||
// Timestop - IE don't cast same spell twice.
|
||||
case EFFECT_TYPE_TIMESTOP:
|
||||
AI_SetWeHaveEffect(GlobalEffectTimestop);
|
||||
AI_SetTargetHasEffect(GlobalEffectTimestop);
|
||||
break;
|
||||
// Invisibility/Improved (although improved only uses normal in the spell)
|
||||
// Sneak attack/whatever :-)
|
||||
// - include the spell EFFECT_TYPE_ETHEREAL.
|
||||
case EFFECT_TYPE_INVISIBILITY:
|
||||
case EFFECT_TYPE_IMPROVEDINVISIBILITY:
|
||||
AI_SetWeHaveEffect(GlobalEffectInvisible);
|
||||
AI_SetTargetHasEffect(GlobalEffectInvisible);
|
||||
break;
|
||||
// Deaf - spell failing of 20%, but still cast.
|
||||
case EFFECT_TYPE_DEAF:
|
||||
AI_SetWeHaveEffect(GlobalEffectDeaf);
|
||||
AI_SetTargetHasEffect(GlobalEffectDeaf);
|
||||
break;
|
||||
// Special invis.
|
||||
case EFFECT_TYPE_ETHEREAL:
|
||||
AI_SetWeHaveEffect(GlobalEffectEthereal);
|
||||
AI_SetTargetHasEffect(GlobalEffectEthereal);
|
||||
break;
|
||||
// Haste - so don't cast haste again and whatever.
|
||||
case EFFECT_TYPE_HASTE:
|
||||
AI_SetWeHaveEffect(GlobalEffectHaste);
|
||||
AI_SetTargetHasEffect(GlobalEffectHaste);
|
||||
break;
|
||||
// Haste - so don't cast haste again and whatever.
|
||||
case EFFECT_TYPE_POLYMORPH:
|
||||
AI_SetWeHaveEffect(GlobalEffectPolymorph);
|
||||
AI_SetTargetHasEffect(GlobalEffectPolymorph);
|
||||
break;
|
||||
// Blindness - oh no, can't see, only hear!
|
||||
case EFFECT_TYPE_BLINDNESS:
|
||||
AI_SetWeHaveEffect(GlobalEffectBlindness);
|
||||
AI_SetTargetHasEffect(GlobalEffectBlindness);
|
||||
break;
|
||||
// Damage shield = Elemental shield, wounding whispers, Death armor, mestals
|
||||
// sheth and so on.
|
||||
case EFFECT_TYPE_ELEMENTALSHIELD:
|
||||
AI_SetWeHaveEffect(GlobalEffectDamageShield);
|
||||
AI_SetTargetHasEffect(GlobalEffectDamageShield);
|
||||
break;
|
||||
// Things we may want to remove VIA cirtain spells, we set here - may as well.
|
||||
// Same setting as any other.
|
||||
// IF we can remove it (not confusion ETC of course) then we set it.
|
||||
case EFFECT_TYPE_DISEASE:
|
||||
AI_SetWeHaveEffect(GlobalEffectDisease);
|
||||
AI_SetTargetHasEffect(GlobalEffectDisease);
|
||||
break;
|
||||
case EFFECT_TYPE_POISON:
|
||||
AI_SetWeHaveEffect(GlobalEffectPoison);
|
||||
AI_SetTargetHasEffect(GlobalEffectPoison);
|
||||
break;
|
||||
// SoU Petrify
|
||||
// Note: Also makes them uncommandable
|
||||
case EFFECT_TYPE_PETRIFY:
|
||||
AI_SetWeHaveEffect(GlobalEffectPetrify);
|
||||
{
|
||||
AI_SetTargetHasEffect(GlobalEffectPetrify);
|
||||
AI_SetTargetHasEffect(GlobalEffectUncommandable);
|
||||
}
|
||||
break;
|
||||
case EFFECT_TYPE_CURSE:
|
||||
AI_SetWeHaveEffect(GlobalEffectCurse);
|
||||
AI_SetTargetHasEffect(GlobalEffectCurse);
|
||||
break;
|
||||
case EFFECT_TYPE_NEGATIVELEVEL:
|
||||
AI_SetWeHaveEffect(GlobalEffectNegativeLevel);
|
||||
AI_SetTargetHasEffect(GlobalEffectNegativeLevel);
|
||||
break;
|
||||
case EFFECT_TYPE_ABILITY_DECREASE:
|
||||
case EFFECT_TYPE_AC_DECREASE:
|
||||
@@ -252,24 +279,25 @@ void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF)
|
||||
case EFFECT_TYPE_SPELL_RESISTANCE_DECREASE:
|
||||
case EFFECT_TYPE_SKILL_DECREASE:
|
||||
// Special - we add one to this, to determine when to use restoration
|
||||
iEffectAbilityDecrease++;
|
||||
nEffectAbilityDecrease++;
|
||||
break;
|
||||
case EFFECT_TYPE_ENTANGLE:
|
||||
AI_SetWeHaveEffect(GlobalEffectEntangle);
|
||||
AI_SetTargetHasEffect(GlobalEffectEntangle);
|
||||
break;
|
||||
case EFFECT_TYPE_MOVEMENT_SPEED_DECREASE:
|
||||
AI_SetWeHaveEffect(GlobalEffectMovementSpeedDecrease);
|
||||
AI_SetTargetHasEffect(GlobalEffectMovementSpeedDecrease);
|
||||
break;
|
||||
case EFFECT_TYPE_DARKNESS:
|
||||
AI_SetWeHaveEffect(GlobalEffectDarkness);
|
||||
AI_SetTargetHasEffect(GlobalEffectDarkness);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
// Check spells we have on...so we don't cast over them!
|
||||
iSpellID = GetEffectSpellId(eCheck);
|
||||
if(iSpellID != iM1)
|
||||
// Check spells *we* (1.4 change: now checks OBJECT_SELF)
|
||||
// have on...so we don't cast over them!
|
||||
nSpellID = GetEffectSpellId(eCheck);
|
||||
if(nSpellID != -1 && oTarget == OBJECT_SELF)
|
||||
{
|
||||
switch(iSpellID)
|
||||
switch(nSpellID)
|
||||
{
|
||||
// All weapon things are on one variable. We cast the best.
|
||||
case SPELL_MAGIC_WEAPON:
|
||||
@@ -338,7 +366,7 @@ void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF)
|
||||
break;
|
||||
case SPELL_CATS_GRACE:
|
||||
case SPELL_GREATER_CATS_GRACE:
|
||||
case AI_SPELL_HARPER_CATS_GRACE: // Harper
|
||||
case AI_SPELLABILITY_HARPER_CATS_GRACE: // Harper
|
||||
AI_SetWeHaveSpellsEffect(GlobalHasCatsGraceSpell);
|
||||
break;
|
||||
case SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE:
|
||||
@@ -361,7 +389,7 @@ void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF)
|
||||
break;
|
||||
case SPELL_EAGLE_SPLEDOR:
|
||||
case SPELL_GREATER_EAGLE_SPLENDOR:
|
||||
case AI_SPELL_HARPER_EAGLE_SPLEDOR: // Harper
|
||||
case AI_SPELLABILITY_HARPER_EAGLE_SPLEDOR: // Harper
|
||||
AI_SetWeHaveSpellsEffect(GlobalHasEaglesSpledorSpell);
|
||||
break;
|
||||
case SPELL_ENDURANCE:
|
||||
@@ -436,9 +464,13 @@ void AI_SetEffectsOnTarget(object oTarget = OBJECT_SELF)
|
||||
}
|
||||
DeleteLocalInt(oTarget, AI_ABILITY_DECREASE);
|
||||
DeleteLocalInt(oTarget, AI_EFFECT_HEX);
|
||||
DeleteLocalInt(oTarget, AI_SPELL_HEX);
|
||||
// Special - only we set spell hexs on ourselves.
|
||||
if(oTarget == OBJECT_SELF)
|
||||
{
|
||||
DeleteLocalInt(oTarget, AI_SPELL_HEX);
|
||||
SetLocalInt(oTarget, AI_SPELL_HEX, TempSpellHex);
|
||||
}
|
||||
// Set final ones from temp integers
|
||||
SetLocalInt(oTarget, AI_ABILITY_DECREASE, iEffectAbilityDecrease);
|
||||
SetLocalInt(oTarget, AI_ABILITY_DECREASE, nEffectAbilityDecrease);
|
||||
SetLocalInt(oTarget, AI_EFFECT_HEX, TempEffectHex);
|
||||
SetLocalInt(oTarget, AI_SPELL_HEX, TempSpellHex);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ int StartingConditional()
|
||||
object oPC = GetPCSpeaker();
|
||||
|
||||
int nInt;
|
||||
nInt=GetLocalInt(oPC, "NW_JOURNAL_ENTRYmarthek);
|
||||
nInt = GetLocalInt(oPC, "NW_JOURNAL_ENTRYmarthek");
|
||||
|
||||
if (nInt >= 1)
|
||||
return TRUE;
|
||||
|
@@ -7,14 +7,13 @@ http://nwvault.ign.com/View.php?view=Other.Detail&id=4683&id=625 */
|
||||
//Put this on action taken in the conversation editor
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
object oItem;
|
||||
oItem = GetItemPossessedBy(oPC, "ScrollofEtherealJaunt");
|
||||
|
||||
if (GetIsObjectValid(oItem))
|
||||
DestroyObject(oItem);
|
||||
|
||||
object oPC = GetPCSpeaker();
|
||||
|
||||
object oTarget;
|
||||
location lTarget;
|
||||
oTarget = GetWaypointByTag("menak1");
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [On Heartbeat] ***************************************
|
||||
Filename: nw_c2_default1 or j_ai_onheartbeat
|
||||
************************* [On Heartbeat] ***************************************
|
||||
/*/////////////////////// [On Heartbeat] ///////////////////////////////////////
|
||||
Filename: nw_c2_default1 or J_AI_OnHeartbeat
|
||||
///////////////////////// [On Heartbeat] ///////////////////////////////////////
|
||||
Removed stupid stuff, special behaviour, sleep.
|
||||
|
||||
Also, note please, I removed waypoints and day/night posting from this.
|
||||
@@ -24,21 +24,22 @@
|
||||
execute script.
|
||||
|
||||
-Working- Best possible, fast compile.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added more "buffs" to fast buff.
|
||||
- Fixed animations (they both WORK and looping ones do loop right!)
|
||||
- Loot behaviour!
|
||||
- Randomly moving nearer a PC in 25M if set.
|
||||
- Removed silly day/night optional setting. Anything we can remove, is a good idea.
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Removed AI level setting. Not good to use, I mistakenly added it.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This fires off every 6 seconds (with PCs in the area, or AI_LEVEL_HIGH without)
|
||||
and therefore is intensive.
|
||||
|
||||
It fires of ExecutesScript things for the different parts - saves CPU stuff
|
||||
if the bits are not used.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: Basically, none. Nothing activates this script. Fires every 6 seconds.
|
||||
************************* [On Heartbeat] **************************************/
|
||||
///////////////////////// [On Heartbeat] /////////////////////////////////////*/
|
||||
|
||||
// - This includes J_Inc_Constants
|
||||
#include "J_INC_HEARTBEAT"
|
||||
@@ -52,10 +53,8 @@ void main()
|
||||
// - Includes door bashing stop heartbeat
|
||||
if(PerformSpecialAction()) return;
|
||||
|
||||
// Pre-heartbeat-event
|
||||
if(FireUserEvent(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, EVENT_HEARTBEAT_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_HEARTBEAT_PRE_EVENT)) return;
|
||||
// Pre-heartbeat-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, EVENT_HEARTBEAT_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff() || GetSpawnInCondition(AI_FLAG_OTHER_LAG_IGNORE_HEARTBEAT, AI_OTHER_MASTER)) return;
|
||||
@@ -63,29 +62,6 @@ void main()
|
||||
// Define the enemy and player to use.
|
||||
object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
|
||||
object oPlayer = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
|
||||
int iTempInt;
|
||||
|
||||
// AI level (re)setting
|
||||
if(!GetIsInCombat() && !GetIsObjectValid(GetAttackTarget()) &&
|
||||
(GetIsObjectValid(oEnemy) && GetDistanceToObject(oEnemy) <= f50 ||
|
||||
GetIsObjectValid(oPlayer) && GetDistanceToObject(oPlayer) <= f50))
|
||||
{
|
||||
// AI setting, normally higher then normal.
|
||||
iTempInt = GetAIConstant(LAG_AI_LEVEL_YES_PC_OR_ENEMY_50M);
|
||||
if(iTempInt > iM1 && GetAILevel() != iTempInt)
|
||||
{
|
||||
SetAILevel(OBJECT_SELF, iTempInt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// AI setting, normally higher then normal.
|
||||
iTempInt = GetAIConstant(LAG_AI_LEVEL_NO_PC_OR_ENEMY_50M);
|
||||
if(iTempInt > iM1 && GetAILevel() != iTempInt)
|
||||
{
|
||||
SetAILevel(OBJECT_SELF, iTempInt);
|
||||
}
|
||||
}
|
||||
|
||||
// We can skip to the end if we are in combat, or something...
|
||||
if(!JumpOutOfHeartBeat() && // We don't stop due to effects.
|
||||
@@ -95,7 +71,7 @@ void main()
|
||||
{
|
||||
// Fast buffing...if we have the spawn in condition...
|
||||
if(GetSpawnInCondition(AI_FLAG_COMBAT_FLAG_FAST_BUFF_ENEMY, AI_COMBAT_MASTER) &&
|
||||
GetIsObjectValid(oEnemy) && GetDistanceToObject(oEnemy) <= f40)
|
||||
GetIsObjectValid(oEnemy) && GetDistanceToObject(oEnemy) <= 40.0)
|
||||
{
|
||||
// ...we may do an advanced buff. If we cannot see/hear oEnemy, but oEnemy
|
||||
// is within 40M, we cast many defensive spells instantly...
|
||||
@@ -116,21 +92,20 @@ void main()
|
||||
// We must have animations set, and not be "paused", so doing a
|
||||
// longer looping one
|
||||
// - Need a valid player.
|
||||
if(GetIsObjectValid(oPlayer))
|
||||
if(GetIsObjectValid(oPlayer) && !IsInConversation(OBJECT_SELF))
|
||||
{
|
||||
// Do we have any animations to speak of?
|
||||
// If we have a nearby PC, not in conversation, we do animations.
|
||||
if(!IsInConversation(OBJECT_SELF) &&
|
||||
GetAIInteger(AI_VALID_ANIMATIONS))
|
||||
{
|
||||
ExecuteScript(FILE_HEARTBEAT_ANIMATIONS, OBJECT_SELF);
|
||||
}
|
||||
// We may search for PC enemies :-) move closer to PC's
|
||||
else if(GetSpawnInCondition(AI_FLAG_OTHER_SEARCH_IF_ENEMIES_NEAR, AI_OTHER_MASTER) &&
|
||||
!GetLocalTimer(AI_TIMER_SEARCHING) && d4() == i1)
|
||||
// We may search for PC enemies, 25% chance to move closer to PC's
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_SEARCH_IF_ENEMIES_NEAR, AI_OTHER_MASTER) &&
|
||||
!GetLocalTimer(AI_TIMER_SEARCHING) && d4() == 1)
|
||||
{
|
||||
ExecuteScript(FILE_HEARTBEAT_WALK_TO_PC, OBJECT_SELF);
|
||||
}
|
||||
// Else, Do we have any animations to speak of?
|
||||
// If we have a nearby PC, we do animations.
|
||||
else if(GetHasValidAnimations())
|
||||
{
|
||||
ExecuteScript(FILE_HEARTBEAT_ANIMATIONS, OBJECT_SELF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [On Percieve] ****************************************
|
||||
Filename: j_ai_onpercieve or nw_c2_default2
|
||||
************************* [On Percieve] ****************************************
|
||||
/*/////////////////////// [On Percieve] ////////////////////////////////////////
|
||||
Filename: J_AI_OnPercieve or nw_c2_default2
|
||||
///////////////////////// [On Percieve] ////////////////////////////////////////
|
||||
If the target is an enemy, attack
|
||||
Will determine combat round on that person, is an enemy, basically.
|
||||
Includes shouting for a big radius - if the spawn in condition is set to this.
|
||||
@@ -8,37 +8,43 @@
|
||||
NOTE: Debug strings in this file will be uncommented for speed by default.
|
||||
- It is one of the most intensive scripts as it runs so often.
|
||||
- Attempted to optimise as much as possible.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - We include j_inc_other_ai to initiate combat (or go into combat again)
|
||||
- j_inc_other_ai holds all other needed functions/integers ETC.
|
||||
- Turn off hide things.
|
||||
- Added "Only attack if attacked"
|
||||
- Removed special conversation things. Almost no one uses them, and the taunt system is easier.
|
||||
- Should now search around if they move to a dead body, and only once they get there.
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - TO DO:
|
||||
|
||||
1. Perception needs checking - attacking outside perception ranges!
|
||||
2. Vanishing targets, etc. test, improve.
|
||||
3. Problems with dispelling invisibility. Maybe either do change the line to create placable, or, of course, cast at location (dispells cannot be metamagiked or whatever) Source
|
||||
4. No Effect Type Ethereal. Source
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
It fires:
|
||||
|
||||
- When a creature enters it perception range (Set in creature properties) and
|
||||
is seen or heard.
|
||||
* Tests show (and in general) it fires HEARD first, then immediantly SEEN if,
|
||||
of course, they are visible. Odd really, but true.
|
||||
- When a creature uses invisiblity/leaves the area in the creatures perception
|
||||
range
|
||||
- When a creature appears suddenly, already in the perception range (not
|
||||
the other way round, normally)
|
||||
- When a creature moves out of the creatures perception range, and therefore
|
||||
becomes unseen.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetLastPerceived, GetLastPerceptionSeen, GetLastPerceptionHeard,
|
||||
GetLastPerceptionVanished, GetLastPerceptionInaudible.
|
||||
************************* [On Percieve] ***************************************/
|
||||
///////////////////////// [On Percieve] //////////////////////////////////////*/
|
||||
|
||||
#include "j_inc_other_ai"
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Percieve pre event.
|
||||
if(FireUserEvent(AI_FLAG_UDE_PERCIEVE_PRE_EVENT, EVENT_PERCIEVE_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_PERCIEVE_PRE_EVENT)) return;
|
||||
// Pre-percieve-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_PERCIEVE_PRE_EVENT, EVENT_PERCIEVE_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
@@ -47,8 +53,21 @@ void main()
|
||||
// - We declare OUTSIDE if's JUST IN CASE!
|
||||
object oPerceived = GetLastPerceived();
|
||||
object oAttackTarget = GetAttackTarget();
|
||||
// 1.4: Very rarely is our attack target valid, so we will set it to
|
||||
// what we would have melee attacked when DCR was called.
|
||||
if(GetIgnoreNoFriend(oAttackTarget) || oAttackTarget == OBJECT_SELF)
|
||||
{
|
||||
oAttackTarget = GetAIObject(AI_LAST_MELEE_TARGET);
|
||||
}
|
||||
int bSeen = GetLastPerceptionSeen();
|
||||
int bHeard = GetLastPerceptionHeard();
|
||||
int bVanished = GetLastPerceptionVanished();
|
||||
int bInaudiable = GetLastPerceptionInaudible();
|
||||
|
||||
// Debug
|
||||
DebugActionSpeak("*** PER ***: " + GetName(oPerceived) + "| SEEN: " + IntToString(bSeen) +
|
||||
"| HEARD: " + IntToString(bHeard) + "| VANISHED: " + IntToString(bVanished) +
|
||||
"| INAUDIABLE: " + IntToString(bInaudiable));
|
||||
|
||||
// Need to be valid and not ignorable.
|
||||
if(GetIsObjectValid(oPerceived) &&
|
||||
@@ -58,31 +77,35 @@ void main()
|
||||
// First, easy enemy checks.
|
||||
if(GetIsEnemy(oPerceived) && !GetFactionEqual(oPerceived))
|
||||
{
|
||||
DebugActionSpeak("*** PER *** ENEMY");
|
||||
|
||||
// Turn of hiding, a timer to activate Hiding in the main file. This is
|
||||
// done in each of the events, with the opposition checking seen/heard.
|
||||
TurnOffHiding(oPerceived);
|
||||
|
||||
// Well, are we both inaudible and vanished?
|
||||
// * the GetLastPerception should only say what specific event has fired!
|
||||
if(GetLastPerceptionInaudible() || GetLastPerceptionVanished())
|
||||
if(bVanished || bInaudiable)
|
||||
{
|
||||
DebugActionSpeak("*** PER *** VANISHED OR INAUDIBLE");
|
||||
// If they just became invisible because of the spell
|
||||
// invisiblity, or improved invisiblity...we set a local object.
|
||||
// - Beta: Added in ethereal as well.
|
||||
if(GetHasEffect(EFFECT_TYPE_INVISIBILITY, oPerceived) ||
|
||||
GetHasEffect(EFFECT_TYPE_ETHEREAL, oPerceived) ||
|
||||
GetHasEffect(EFFECT_TYPE_SANCTUARY, oPerceived) ||
|
||||
GetStealthMode(oPerceived) == STEALTH_MODE_ACTIVATED)
|
||||
{
|
||||
// Set object, AND the location they went invisible!
|
||||
SetAIObject(AI_LAST_TO_GO_INVISIBLE, oPerceived);
|
||||
// We also set thier location for AOE dispelling - same name
|
||||
SetLocalLocation(OBJECT_SELF, AI_LAST_TO_GO_INVISIBLE, GetLocation(oPerceived));
|
||||
SetAILocation(AI_LAST_TO_GO_INVISIBLE, GetLocation(oPerceived));
|
||||
}
|
||||
|
||||
// If they were our target, follow! >:-D
|
||||
// - Optional, on spawn option, for following through areas.
|
||||
if(oAttackTarget == oPerceived)
|
||||
{
|
||||
DebugActionSpeak("*** PER *** VANISHED OR INAUDIBLE AND IS CURRENT TARGET");
|
||||
// This means they have exited the area! follow!
|
||||
if(GetArea(oPerceived) != GetArea(OBJECT_SELF))
|
||||
{
|
||||
@@ -94,7 +117,10 @@ void main()
|
||||
}
|
||||
// - Added check for not casting a spell. If we are, we finnish
|
||||
// (EG: AOE spell) and automatically carry on.
|
||||
else if(GetCurrentAction() != ACTION_CASTSPELL)
|
||||
// 1.4: If we are using a targetted spell, we do cancle our
|
||||
// spellcasting if it is them.
|
||||
else if(GetCurrentAction() != ACTION_CASTSPELL ||
|
||||
GetAttackTarget() == oPerceived)
|
||||
{
|
||||
ClearAllActions();
|
||||
// 52: "[Perception] Enemy Vanished (Same area) Retargeting/Searching [Percieved] " + GetName(oPerceived)
|
||||
@@ -111,76 +137,79 @@ void main()
|
||||
if(bSeen && GetCurrentAction() != ACTION_CASTSPELL &&
|
||||
(oAttackTarget == oPerceived || !GetObjectSeen(oAttackTarget)))
|
||||
{
|
||||
AISpeakString(I_WAS_ATTACKED);
|
||||
// 53: "[Perception] Enemy seen, and was old enemy/cannot see current. Re-evaluating (no spell) [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(53, oPerceived);
|
||||
DetermineCombatRound(oPerceived);
|
||||
|
||||
// Shout to allies to attack oPerceived
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
// Else We check if we are already attacking.
|
||||
else if(!CannotPerformCombatRound() &&
|
||||
!GetSpawnInCondition(AI_FLAG_OTHER_ONLY_ATTACK_IF_ATTACKED, AI_OTHER_MASTER))
|
||||
{
|
||||
// Special shout, d1000 though!
|
||||
SpeakArrayString(AI_TALK_ON_PERCIEVE_ENEMY, TRUE);
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
// Special shout, d1000 though!
|
||||
SpeakArrayString(AI_TALK_ON_PERCIEVE_ENEMY, TRUE);
|
||||
}
|
||||
|
||||
// Stop stuff because of facing point - New enemy
|
||||
HideOrClear();
|
||||
|
||||
// Face the person (this helps stops sneak attacks if we then
|
||||
// cast something on ourselves, ETC).
|
||||
SetFacingPoint(GetPosition(oPerceived));
|
||||
|
||||
// Get all allies in 60M to come to thier aid. Talkvolume silent
|
||||
// shout does not seem to work well.
|
||||
// - void function. Checks for the spawn int. in it.
|
||||
// - Turns it off in it too
|
||||
// - Turns it off in it too (5 minutes - 1.4)
|
||||
// - Variable range On Spawn
|
||||
ShoutBossShout(oPerceived);
|
||||
|
||||
// Warn others
|
||||
AISpeakString(I_WAS_ATTACKED);
|
||||
// 54: "[Perception] Enemy Seen. Not in combat, attacking. [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(54, oPerceived);
|
||||
// Note: added ActionDoCommand, so that SetFacingPoint is not
|
||||
// interrupted.
|
||||
ActionDoCommand(DetermineCombatRound(oPerceived));
|
||||
|
||||
// 1.4 change: SetFacingPoint(GetPosition(oPerceived));
|
||||
// Is now part of DetermineCombatRound().
|
||||
// * This means other events will work similarily.
|
||||
DetermineCombatRound(oPerceived);
|
||||
|
||||
// Warn others
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Else, they are an equal faction, or not an enemy (or both)
|
||||
else
|
||||
{
|
||||
// If they are dead, say we saw something on waypoints, we charge in
|
||||
// to investigate.
|
||||
// If they are dead, or fighting, eg: we saw something on
|
||||
// waypoints, we charge in to investigate.
|
||||
// * Higher intelligence will buff somewhat as well!
|
||||
if(GetIsDead(oPerceived) && (bSeen || bHeard))
|
||||
if((GetIsDead(oPerceived) || GetIsInCombat(oPerceived)) &&
|
||||
(bSeen || bHeard))
|
||||
{
|
||||
// Warn others
|
||||
AISpeakString(I_WAS_ATTACKED);
|
||||
if(GetIsDead(oPerceived))
|
||||
{
|
||||
// 55: "[Perception] Percieved Dead Friend! Moving into investigate [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(55, oPerceived);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 56: "[Perception] Percieved Alive Fighting Friend! Moving to and attacking. [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(56, oPerceived);
|
||||
}
|
||||
// Check if we can attack
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Hide or clear actions
|
||||
HideOrClear();
|
||||
// 55: "[Perception] Percieved Dead Friend! Moving and Searching [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(55, oPerceived);
|
||||
ActionMoveToLocation(GetLocation(oPerceived), TRUE);
|
||||
ActionDoCommand(DetermineCombatRound());
|
||||
|
||||
// If we were called to arms, react
|
||||
CallToArmsResponse(oPerceived);
|
||||
}
|
||||
}
|
||||
else if(GetIsInCombat(oPerceived) && (bSeen || bHeard))
|
||||
{
|
||||
// Warn others
|
||||
AISpeakString(I_WAS_ATTACKED);
|
||||
// Only if we can attack.
|
||||
if(!CannotPerformCombatRound())
|
||||
else
|
||||
{
|
||||
// Hide or clear actions
|
||||
HideOrClear();
|
||||
// 56: "[Perception] Percieved Alive Fighting Friend! Moving to and attacking. [Percieved] " + GetName(oPerceived)
|
||||
DebugActionSpeakByInt(56, oPerceived);
|
||||
ActionMoveToLocation(GetLocation(oPerceived), TRUE);
|
||||
ActionDoCommand(DetermineCombatRound());
|
||||
// Warn others even if we don't, or cannot, attack
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,28 +1,27 @@
|
||||
/************************ [On Combat Round End] ********************************
|
||||
Filename: nw_c2_default3 or j_ai_oncombatrou
|
||||
************************* [On Combat Round End] ********************************
|
||||
/*/////////////////////// [On Combat Round End] ////////////////////////////////
|
||||
Filename: nw_c2_default3 or J_AI_OnCombatrou
|
||||
///////////////////////// [On Combat Round End] ////////////////////////////////
|
||||
This is run every 3 or 6 seconds, if the creature is in combat. It is
|
||||
executed only in combat automatically.
|
||||
|
||||
It runs what the AI should do, bascially.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Executes same script as the other parts of the AI to cuase a new action
|
||||
************************* [Workings] *******************************************
|
||||
1.4 -
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Calls the combat AI file using the J_INC_OTHER_AI include function,
|
||||
DetermineCombatRound.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetAttackTarget, GetLastHostileActor, GetAttemptedAttackTarget,
|
||||
GetAttemptedSpellTarget (Or these are useful at least!)
|
||||
************************* [On Combat Round End] *******************************/
|
||||
///////////////////////// [On Combat Round End] //////////////////////////////*/
|
||||
|
||||
#include "j_inc_other_ai"
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-combat-round-event
|
||||
if(FireUserEvent(AI_FLAG_UDE_END_COMBAT_ROUND_PRE_EVENT, EVENT_END_COMBAT_ROUND_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_END_COMBAT_ROUND_PRE_EVENT)) return;
|
||||
// Pre-combat-round-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_END_COMBAT_ROUND_PRE_EVENT, EVENT_END_COMBAT_ROUND_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
@@ -1,16 +1,17 @@
|
||||
/************************ [On Conversation] ************************************
|
||||
Filename: j_ai_onconversat or nw_c2_default4
|
||||
************************* [On Conversation] ************************************
|
||||
/*/////////////////////// [On Conversation] ////////////////////////////////////
|
||||
Filename: J_AI_OnConversat or nw_c2_default4
|
||||
///////////////////////// [On Conversation] ////////////////////////////////////
|
||||
OnConversation/ Listen to shouts.
|
||||
Documented, and checked. -Working-
|
||||
|
||||
Added spawn in condition - Never clear actions when talking.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added in conversation thing - IE we can set speakstrings, no need for conversation file.
|
||||
- Sorted more shouts out.
|
||||
- Should work right, and not cause too many actions (as we ignore
|
||||
shouts for normally 12 or so seconds before letting them affect us again).
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Deafness incorpreated.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Uses RespondToShout to react to allies' shouts, and just attacks any enemy
|
||||
who speaks, or at least moves to them. (OK, dumb if they are invisible, but
|
||||
oh well, they shouldn't talk so loud!)
|
||||
@@ -18,19 +19,21 @@
|
||||
Remember, whispers are never heard if too far away, speakstrings don't go
|
||||
through walls, and shouts are always heard (so we don't go off to anyone
|
||||
not in our area, remember)
|
||||
************************* [Arguments] ******************************************
|
||||
|
||||
Deafness causes us to never hear battle, so unless we see the target speaking
|
||||
we do not react. Doesn't apply to normal conversations - although if we cannot
|
||||
talk (also restricted by deafness) then so be it.
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetListenPatternNumber, GetLastSpeaker, TestStringAgainstPattern,
|
||||
GetMatchedSubstring
|
||||
************************* [On Conversation] ***********************************/
|
||||
///////////////////////// [On Conversation] //////////////////////////////////*/
|
||||
|
||||
#include "j_inc_other_ai"
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-heartbeat-event
|
||||
if(FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_PRE_EVENT, EVENT_ON_DIALOGUE_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_ON_DIALOGUE_PRE_EVENT)) return;
|
||||
// Pre-conversation-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_ON_DIALOGUE_PRE_EVENT, EVENT_ON_DIALOGUE_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
@@ -38,17 +41,16 @@ void main()
|
||||
// Declarations
|
||||
int nMatch = GetListenPatternNumber();
|
||||
object oShouter = GetLastSpeaker();
|
||||
string sSpoken = GetMatchedSubstring(i0);
|
||||
string sSpoken = GetMatchedSubstring(0);
|
||||
|
||||
// We can ignore everything under special cases - EG no valid shouter,
|
||||
// we are fleeing, its us, or we are not in the same area.
|
||||
// - We break out of the script if this happens.
|
||||
if(!GetIsObjectValid(oShouter) || /* Must be a valid speaker! */
|
||||
!GetCommandable() || /* Commandable */
|
||||
oShouter == OBJECT_SELF || /* Not us! */
|
||||
GetIsPerformingSpecialAction() || /* Not fleeing */
|
||||
GetIgnore(oShouter) || /* Not ignoring the shouter */
|
||||
GetArea(oShouter) != GetArea(OBJECT_SELF))/* Same area (Stops "SHOUT" getting NPCs */
|
||||
GetArea(oShouter) != GetArea(OBJECT_SELF))/* Same area (Stops loud yellow shouts getting NPCs) */
|
||||
{
|
||||
// Fire End of Dialogue event
|
||||
FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_EVENT, EVENT_ON_DIALOGUE_EVENT);
|
||||
@@ -56,44 +58,51 @@ void main()
|
||||
}
|
||||
|
||||
// Conversation if not a shout.
|
||||
if(nMatch == iM1)
|
||||
if(nMatch == -1)
|
||||
{
|
||||
// Make sure it is a PC and we are not fighting.
|
||||
if(!GetIsFighting() && (GetIsPC(oShouter) || GetIsDMPossessed(oShouter)))
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
// If we have something random (or not) to say instead of
|
||||
// the conversation, we will say that.
|
||||
if(GetLocalInt(OBJECT_SELF, ARRAY_SIZE + AI_TALK_ON_CONVERSATION))
|
||||
// Make sure it is a PC and we are not fighting.
|
||||
if(!GetIsFighting() && (GetIsPC(oShouter) || GetIsDMPossessed(oShouter)))
|
||||
{
|
||||
ClearAllActions();// Stop
|
||||
SetFacingPoint(GetPosition(oShouter));// Face
|
||||
SpeakArrayString(AI_TALK_ON_CONVERSATION);// Speak string
|
||||
PlayAnimation(ANIMATION_LOOPING_TALK_NORMAL, f1, f3);// "Talk", then resume potitions.
|
||||
ActionDoCommand(ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF));
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are set to NOT clear all actions, we won't.
|
||||
if(!GetSpawnInCondition(AI_FLAG_OTHER_NO_CLEAR_ACTIONS_BEFORE_CONVERSATION, AI_OTHER_MASTER))
|
||||
// If we have something random (or not) to say instead of
|
||||
// the conversation, we will say that.
|
||||
if(GetLocalInt(OBJECT_SELF, ARRAY_SIZE + AI_TALK_ON_CONVERSATION))
|
||||
{
|
||||
ClearAllActions();
|
||||
ClearAllActions();// Stop
|
||||
SetFacingPoint(GetPosition(oShouter));// Face
|
||||
SpeakArrayString(AI_TALK_ON_CONVERSATION);// Speak string
|
||||
PlayAnimation(ANIMATION_LOOPING_TALK_NORMAL, 1.0, 3.0);// "Talk", then resume potitions.
|
||||
ActionDoCommand(ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF));
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we are set to NOT clear all actions, we won't.
|
||||
if(!GetSpawnInCondition(AI_FLAG_OTHER_NO_CLEAR_ACTIONS_BEFORE_CONVERSATION, AI_OTHER_MASTER))
|
||||
{
|
||||
ClearAllActions();
|
||||
}
|
||||
BeginConversation();
|
||||
}
|
||||
BeginConversation();
|
||||
}
|
||||
}
|
||||
}
|
||||
// If it is a valid shout...and a valid shouter.
|
||||
// - Not a DM. Not ignoring shouting. Not a Debug String.
|
||||
else if(!GetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID) && // Not listening (IE heard already)
|
||||
!GetIsDM(oShouter) && FindSubString(sSpoken, "[Debug]") == iM1)
|
||||
else if(!GetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID) &&// Not listening (IE heard already)
|
||||
!GetIsDM(oShouter) && FindSubString(sSpoken, "[Debug]") == -1 &&
|
||||
// 1.4 - Deafness (or they are seen) check, for fun.
|
||||
(!GetHasEffect(EFFECT_TYPE_DEAF) || GetObjectSeen(oShouter)))
|
||||
{
|
||||
if(GetIsFriend(oShouter) || GetFactionEqual(oShouter))
|
||||
{
|
||||
// If they are a friend, not a PC, and a valid number, react.
|
||||
// In the actual RespondToShout call, we do check to see if we bother.
|
||||
// - Is PC - or is...master?
|
||||
// - Shouts of 1 or over only.
|
||||
if(nMatch >= i1 && !GetIsPC(oShouter) && !GetIsPC(GetMaster(oShouter)))
|
||||
// - Shouts which are not negative, and not AI_ANYTHING_SAID_CONSTANT.
|
||||
if(nMatch >= 0 && nMatch != AI_SHOUT_ANYTHING_SAID_CONSTANT &&
|
||||
!GetIsPC(oShouter) && !GetIsPC(GetMaster(oShouter)))
|
||||
{
|
||||
// Respond to the shout
|
||||
RespondToShout(oShouter, nMatch);
|
||||
@@ -104,31 +113,27 @@ void main()
|
||||
GetIsInCombat(oShouter) &&
|
||||
GetObjectType(oShouter) == OBJECT_TYPE_CREATURE)
|
||||
{
|
||||
// Only use attack target.
|
||||
object oIntruder = GetIntruderFromShout(oShouter);
|
||||
// Valid, and not a friend if a PC speaker
|
||||
if(GetIsObjectValid(oIntruder) &&
|
||||
!GetFactionEqual(oIntruder) &&
|
||||
!GetIsFriend(oIntruder))
|
||||
{
|
||||
// 57: "[Shout] Friend (may be PC) in combat. Attacking! [Friend] " + GetName(oShouter)
|
||||
DebugActionSpeakByInt(57, oShouter);
|
||||
DetermineCombatRound(oIntruder);
|
||||
}
|
||||
// 57: "[Shout] Friend (may be PC) in combat. Attacking! [Friend] " + GetName(oShouter)
|
||||
DebugActionSpeakByInt(57, oShouter);
|
||||
|
||||
// Respond to oShouter
|
||||
IWasAttackedResponse(oShouter);
|
||||
}
|
||||
}
|
||||
else if(GetIsEnemy(oShouter) && GetObjectType(oShouter) == OBJECT_TYPE_CREATURE)
|
||||
{
|
||||
// If we hear anything said by an enemy, and are not fighting, attack them!
|
||||
if(!CannotPerformCombatRound())
|
||||
// the negatives are associate shouts, 0+ are my shouts. 0 is anything
|
||||
// the negatives are associate shouts, Normally (!)
|
||||
// 0+ are my shouts. 0 is anything
|
||||
{
|
||||
// We make sure it isn't an emote (set by default)
|
||||
if(nMatch == i0 && GetSpawnInCondition(AI_FLAG_OTHER_DONT_RESPOND_TO_EMOTES, AI_OTHER_MASTER))
|
||||
if(nMatch == AI_SHOUT_ANYTHING_SAID_CONSTANT &&
|
||||
GetSpawnInCondition(AI_FLAG_OTHER_DONT_RESPOND_TO_EMOTES, AI_OTHER_MASTER))
|
||||
{
|
||||
// Jump out if its an emote - "*Nods*"
|
||||
if(GetStringLeft(sSpoken, i1) == EMOTE_STAR &&
|
||||
GetStringRight(sSpoken, i1) == EMOTE_STAR)
|
||||
if(GetStringLeft(sSpoken, 1) == EMOTE_STAR &&
|
||||
GetStringRight(sSpoken, 1) == EMOTE_STAR)
|
||||
{
|
||||
// Fire End of Dialogue event
|
||||
FireUserEvent(AI_FLAG_UDE_ON_DIALOGUE_EVENT, EVENT_ON_DIALOGUE_EVENT);
|
||||
@@ -137,11 +142,16 @@ void main()
|
||||
}
|
||||
// 58: "[Shout] Responding to shout [Enemy] " + GetName(oShouter) + " Who has spoken!"
|
||||
DebugActionSpeakByInt(58, oShouter);
|
||||
|
||||
// Short non-respond
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, f6);
|
||||
SetLocalTimer(AI_TIMER_SHOUT_IGNORE_ANYTHING_SAID, 6.0);
|
||||
|
||||
// Attack the enemy!
|
||||
ClearAllActions();
|
||||
DetermineCombatRound(oShouter);
|
||||
|
||||
// Shout to allies to attack the shouter
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,26 +1,25 @@
|
||||
/************************ [On Phisical Attacked] *******************************
|
||||
Filename: j_ai_onphiattack or nw_c2_default5
|
||||
************************* [On Phisical Attacked] *******************************
|
||||
/*/////////////////////// [On Phisical Attacked] ///////////////////////////////
|
||||
Filename: J_AI_OnPhiAttack or nw_c2_default5
|
||||
///////////////////////// [On Phisical Attacked] ///////////////////////////////
|
||||
On Attacked
|
||||
No checking for fleeing or warnings.
|
||||
Very boring really!
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added hiding things
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Missing Silent Shouts have been added.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Got some simple Knockdown timer, so that we use heal sooner if we keep getting
|
||||
a creature who is attempting to knock us down.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetLastAttacker, GetLastWeaponUsed, GetLastAttackMode, GetLastAttackType
|
||||
************************* [On Phisical Attacked] ******************************/
|
||||
///////////////////////// [On Phisical Attacked] /////////////////////////////*/
|
||||
|
||||
#include "j_inc_other_ai"
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-attacked-event
|
||||
if(FireUserEvent(AI_FLAG_UDE_ATTACK_PRE_EVENT, EVENT_ATTACK_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_ATTACK_PRE_EVENT)) return;
|
||||
// Pre-attacked-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_ATTACK_PRE_EVENT, EVENT_ATTACK_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
@@ -28,11 +27,11 @@ void main()
|
||||
// Set up objects.
|
||||
object oAttacker = GetLastAttacker();
|
||||
object oWeapon = GetLastWeaponUsed(oAttacker);
|
||||
int iMode = GetLastAttackMode(oAttacker); // Currently unused
|
||||
int iAttackType = GetLastAttackType(oAttacker);
|
||||
//int nMode = GetLastAttackMode(oAttacker); // Currently unused
|
||||
int nAttackType = GetLastAttackType(oAttacker);
|
||||
|
||||
if(GetIsObjectValid(oAttacker) && !GetFactionEqual(oAttacker) &&
|
||||
!GetIsDM(oAttacker) && !GetIgnore(oAttacker))
|
||||
// Check if they are valid, a DM, we are ignoring them, they are dead now, or invalid
|
||||
if(!GetIgnoreNoFriend(oAttacker))
|
||||
{
|
||||
// Adjust automatically if set.
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER))
|
||||
@@ -42,23 +41,28 @@ void main()
|
||||
AdjustReputation(oAttacker, OBJECT_SELF, -100);
|
||||
}
|
||||
}
|
||||
|
||||
// If we were attacked by knockdown, for a timer of X seconds, we make
|
||||
// sure we attempt healing at a higher level.
|
||||
if(!GetLocalTimer(AI_TIMER_KNOCKDOWN) &&
|
||||
(iAttackType == SPECIAL_ATTACK_IMPROVED_KNOCKDOWN ||
|
||||
iAttackType == SPECIAL_ATTACK_KNOCKDOWN) &&
|
||||
(nAttackType == SPECIAL_ATTACK_IMPROVED_KNOCKDOWN ||
|
||||
nAttackType == SPECIAL_ATTACK_KNOCKDOWN) &&
|
||||
!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_KNOCKDOWN) &&
|
||||
GetBaseAttackBonus(oAttacker) + i20 >= GetAC(OBJECT_SELF))
|
||||
GetBaseAttackBonus(oAttacker) + 20 >= GetAC(OBJECT_SELF))
|
||||
{
|
||||
SetLocalTimer(AI_TIMER_KNOCKDOWN, f30);
|
||||
SetLocalTimer(AI_TIMER_KNOCKDOWN, 30.0);
|
||||
}
|
||||
|
||||
// Set last hostile attacker.
|
||||
// Set last hostile, valid attacker (Used in the On Damaged event)
|
||||
SetAIObject(AI_STORED_LAST_ATTACKER, oAttacker);
|
||||
|
||||
// Speak the phisically attacked string, if applicable.
|
||||
// Speak the damaged string, if applicable.
|
||||
SpeakArrayString(AI_TALK_ON_PHISICALLY_ATTACKED);
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
// Speak the phisically attacked string, if applicable.
|
||||
// Speak the damaged string, if applicable.
|
||||
SpeakArrayString(AI_TALK_ON_PHISICALLY_ATTACKED);
|
||||
}
|
||||
|
||||
// Turn of hiding, a timer to activate Hiding in the main file. This is
|
||||
// done in each of the events, with the opposition checking seen/heard.
|
||||
@@ -79,19 +83,52 @@ void main()
|
||||
// If we are not fighting, and they are in the area, attack. Else, determine anyway.
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Must be in our area to go after now.
|
||||
if(GetArea(oAttacker) == GetArea(OBJECT_SELF))
|
||||
{
|
||||
// 59: "[Phisically Attacked] Attacking back. [Attacker(enemy)] " + GetName(oAttacker)
|
||||
DebugActionSpeakByInt(59, oAttacker);
|
||||
|
||||
// Attack the attacker
|
||||
DetermineCombatRound(oAttacker);
|
||||
|
||||
// Shout to allies to attack the enemy who attacked me
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
// 60: "[Phisically Attacked] Not same area. [Attacker(enemy)] " + GetName(oAttacker)
|
||||
DebugActionSpeakByInt(60, oAttacker);
|
||||
DetermineCombatRound();// May find another hostile to attack...
|
||||
|
||||
// May find another hostile to attack...
|
||||
DetermineCombatRound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
// Else, invalid, DM, ally, etc...must be prepared at least (could be
|
||||
// they are charmed or something!)
|
||||
else
|
||||
{
|
||||
// If we are not fighting, prepare for battle. Something bad must have
|
||||
// happened.
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Respond to oAttacker as if they shouted for help.
|
||||
IWasAttackedResponse(oAttacker);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
|
||||
// Fire End of Attacked event
|
||||
|
@@ -1,53 +1,61 @@
|
||||
/************************ [On Damaged] *****************************************
|
||||
Filename: nw_c2_default6 or j_ai_ondamaged
|
||||
************************* [On Damaged] *****************************************
|
||||
/*/////////////////////// [On Damaged] /////////////////////////////////////////
|
||||
Filename: nw_c2_default6 or J_AI_OnDamaged
|
||||
///////////////////////// [On Damaged] /////////////////////////////////////////
|
||||
We attack any damager if same area (and not already fighting
|
||||
then search for enemies (defaults to searching if there are no enemies left).
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - If we have a damager, not equal faction, and not a DM...
|
||||
- We set Max Elemental damage.
|
||||
- Sets the highest damager and amount (if the new damager is seen/heard)
|
||||
- Polymorph improved a little
|
||||
- Hide check
|
||||
- Morale penalty (if set)
|
||||
************************* [Workings] *******************************************
|
||||
GetDamageDealtByType() will not work with proper phisical attacks - a workaround
|
||||
is GetTotalDamageDealt() - All GetDamageDealtByType(). This means it will
|
||||
get everything not applied with EffectDamage() which normally fires this
|
||||
script.
|
||||
************************* [Arguments] ******************************************
|
||||
1.4 - Elemental damage fixed with bugfixed introduced in later patches.
|
||||
- Moved things around, more documentation, a little more ordered.
|
||||
- Added the missing silent shout strings to get allies to attack.
|
||||
- Damaged taunting will not happen if we are dead.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Now with fixes, we can correctly set physical damage done (and elemental
|
||||
damage).
|
||||
|
||||
Otherwise, this acts like a hositile spell, or a normal attack or pickpocket
|
||||
attempt would - and attack the damn person who dares damage us!
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetTotalDamageDealt, GetLastDamager, GetCurrentHitPoints (and max),
|
||||
GetDamageDealtByType (must be done seperatly for each, doesn't count melee damage)
|
||||
************************* [On Damaged] ****************************************/
|
||||
///////////////////////// [On Damaged] ///////////////////////////////////////*/
|
||||
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
#include "j_inc_other_ai"
|
||||
void main()
|
||||
{
|
||||
// Pre-damaged-event
|
||||
if(FireUserEvent(AI_FLAG_UDE_DAMAGED_PRE_EVENT, EVENT_DAMAGED_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_DAMAGED_PRE_EVENT)) return;
|
||||
// Pre-damaged-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_DAMAGED_PRE_EVENT, EVENT_DAMAGED_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
// Define Objects/Integers.
|
||||
int iDamage = GetTotalDamageDealt();
|
||||
int nDamage = GetTotalDamageDealt();
|
||||
object oDamager = GetLastDamager();
|
||||
// Check to see if we will polymorph.
|
||||
int iPolymorph = GetAIConstant(AI_POLYMORPH_INTO);
|
||||
int nPolymorph = GetAIConstant(AI_POLYMORPH_INTO);
|
||||
|
||||
// Total up the physical damage
|
||||
|
||||
// Polymorph check.
|
||||
if(iPolymorph >= i0)
|
||||
if(nPolymorph >= 0)
|
||||
{
|
||||
if(!GetHasEffect(EFFECT_TYPE_POLYMORPH))// We won't polymorph if already so
|
||||
// We won't polymorph if already so
|
||||
if(!GetHasEffect(EFFECT_TYPE_POLYMORPH))
|
||||
{
|
||||
effect eShape = SupernaturalEffect(EffectPolymorph(iPolymorph));
|
||||
// Polymorph into the requested shape. Cannot be dispelled.
|
||||
effect eShape = SupernaturalEffect(EffectPolymorph(nPolymorph));
|
||||
effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD);
|
||||
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eShape, OBJECT_SELF));
|
||||
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF));
|
||||
}
|
||||
SetAIConstant(AI_POLYMORPH_INTO, -1);// We set it to invalid (sets to 0).
|
||||
DeleteAIConstant(AI_POLYMORPH_INTO);// We set it to invalid (sets to 0).
|
||||
}
|
||||
// First, we check AOE spells...
|
||||
if(GetObjectType(oDamager) == OBJECT_TYPE_AREA_OF_EFFECT)
|
||||
@@ -55,15 +63,16 @@ void main()
|
||||
// Set the damage done by it (the last damage)
|
||||
// Set to the tag of the AOE, prefixed AI style to be sure.
|
||||
// - Note, doesn't matter about things like
|
||||
if(iDamage > i1)
|
||||
if(nDamage > 0)
|
||||
{
|
||||
// Set it to object to string, which we will delete later anywho.
|
||||
SetAIInteger(ObjectToString(oDamager), iDamage);
|
||||
SetAIInteger(ObjectToString(oDamager), nDamage);
|
||||
}
|
||||
}
|
||||
// Hostile attacker...
|
||||
else if(GetIsObjectValid(oDamager) && !GetFactionEqual(oDamager) &&
|
||||
!GetIsDM(oDamager)&& !GetIgnore(oDamager))
|
||||
// Hostile attacker...but it doesn't matter (at the moment) if they even
|
||||
// did damage.
|
||||
// * GetIgnoreNoFriend() wrappers DM, Validity, Faction Equal and Dead checks in one
|
||||
else if(!GetIgnoreNoFriend(oDamager))
|
||||
{
|
||||
// Adjust automatically if set. (and not an AOE)
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER))
|
||||
@@ -73,80 +82,101 @@ void main()
|
||||
AdjustReputation(oDamager, OBJECT_SELF, -100);
|
||||
}
|
||||
}
|
||||
// Set the max elemental damage done, for better use of elemental protections.
|
||||
// This is set for the most damage...so it could be 1 (for a +1 fire weapon, any
|
||||
// number of hits) or over 50 (good fireball).
|
||||
// Need to have protection single (IE including elemental ones) ready.
|
||||
if(GetSpawnInCondition(AI_VALID_TALENT_BENEFICIAL_PROTECTION_SINGLE, AI_VALID_SPELLS))
|
||||
{
|
||||
// Please make sure | works! By Blind Io!
|
||||
int iDamageDone = GetDamageDealtByType(DAMAGE_TYPE_ACID |
|
||||
DAMAGE_TYPE_COLD | DAMAGE_TYPE_ELECTRICAL |
|
||||
DAMAGE_TYPE_FIRE | DAMAGE_TYPE_SONIC);
|
||||
if(iDamageDone > GetAIInteger(MAX_ELEMENTAL_DAMAGE))
|
||||
{
|
||||
SetAIInteger(MAX_ELEMENTAL_DAMAGE, iDamageDone);
|
||||
}
|
||||
// Set the last damage done, may set to 0 of course :-P
|
||||
SetAIInteger(LAST_ELEMENTAL_DAMAGE, iDamageDone);
|
||||
}
|
||||
|
||||
// Turn of hiding, a timer to activate Hiding in the main file. This is
|
||||
// done in each of the events, with the opposition checking seen/heard.
|
||||
TurnOffHiding(oDamager);
|
||||
|
||||
// Speak the damaged string, if applicable.
|
||||
SpeakArrayString(AI_TALK_ON_DAMAGED);
|
||||
|
||||
// Morale: We may get a penalty if it does more than a cirtain amount of HP damage.
|
||||
// Other: We set highest damager and amount.
|
||||
if(iDamage > i0)
|
||||
// Did they do damage to use? (IE: No DR) Some things are inapproprate
|
||||
// to check if no damage was actually done.
|
||||
if(nDamage > 0)
|
||||
{
|
||||
if(!GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER))
|
||||
// Speak the damaged string, if applicable.
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
int iToDamage = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_FOR_MORALE_PENALTY, GetMaxHitPoints()/i6, GetMaxHitPoints(), i1);
|
||||
int iPenalty = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_PENALTY, i6, i50, i1);
|
||||
if(iDamage > iToDamage)
|
||||
{
|
||||
// 61: "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(iPenalty)
|
||||
DebugActionSpeakByInt(61, OBJECT_INVALID, iPenalty);
|
||||
// Apply penalty
|
||||
SetMoralePenalty(iPenalty, 300.0);
|
||||
}
|
||||
SpeakArrayString(AI_TALK_ON_DAMAGED);
|
||||
}
|
||||
// 1.4 note: These two variables are currently *unused* apart from
|
||||
// healing. When healing a being (even another NPC) they are checked
|
||||
// for massive damage. Can not bother to set the highest damager for now.
|
||||
// NEW:
|
||||
int nHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT);
|
||||
if(nDamage >= nHighestDamage)
|
||||
{
|
||||
SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, nDamage);
|
||||
}
|
||||
|
||||
/* OLD:
|
||||
|
||||
// Get the previous highest damager, and highest damage amount
|
||||
object oHighestDamager = GetAIObject(AI_HIGHEST_DAMAGER);
|
||||
int iHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT);
|
||||
// If the original was not valid...or not seen/heard, we delete it whatever.
|
||||
if(!GetIsObjectValid(oHighestDamager) ||
|
||||
int nHighestDamage = GetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT);
|
||||
// Set the highest damager, if they are seen or heard, and have done loads.
|
||||
if((GetObjectSeen(oDamager) || GetObjectHeard(oDamager)) &&
|
||||
nDamage >= nHighestDamage || !GetIsObjectValid(oHighestDamager))
|
||||
{
|
||||
SetAIObject(AI_HIGHEST_DAMAGER, oDamager);
|
||||
SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, nDamage);
|
||||
}
|
||||
// Else, if the original was not valid...or not seen/heard, we
|
||||
// delete it so we don't bother to use it later.
|
||||
else if(!GetIsObjectValid(oHighestDamager) ||
|
||||
(!GetObjectSeen(oHighestDamager) && !GetObjectHeard(oHighestDamager)))
|
||||
{
|
||||
DeleteAIObject(AI_HIGHEST_DAMAGER);
|
||||
DeleteAIInteger(AI_HIGHEST_DAMAGE_AMOUNT);
|
||||
}
|
||||
// Set the highest damager.
|
||||
if((GetObjectSeen(oDamager) || GetObjectHeard(oDamager)) &&
|
||||
iDamage >= iHighestDamage)
|
||||
{
|
||||
SetAIObject(AI_HIGHEST_DAMAGER, oDamager);
|
||||
SetAIInteger(AI_HIGHEST_DAMAGE_AMOUNT, iDamage);
|
||||
}
|
||||
// Phisical damage - only sets if the last damager is the last attacker.
|
||||
*/
|
||||
|
||||
// Get all the physical damage. Elemental damage is then nDamage minus
|
||||
// the physical damage.
|
||||
int nPhysical = GetDamageDealtByType(DAMAGE_TYPE_BASE_WEAPON |
|
||||
DAMAGE_TYPE_BLUDGEONING |
|
||||
DAMAGE_TYPE_PIERCING |
|
||||
DAMAGE_TYPE_SLASHING);
|
||||
// If they are all -1, then we make nPhysical 0.
|
||||
if(nPhysical <= -1) nPhysical = 0;
|
||||
|
||||
// Physical damage - only sets if the last damager is the last attacker.
|
||||
if(GetAIObject(AI_STORED_LAST_ATTACKER) == oDamager)
|
||||
{
|
||||
int iHighestPhisicalDamage = GetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT);
|
||||
int iPhisicalDamage = iDamage -
|
||||
// This relies upon the bug that these damage types only return damage
|
||||
// from EffectDamage, and melee damage is any that remains. Wish it was
|
||||
// fixed though...
|
||||
GetDamageDealtByType(DAMAGE_TYPE_ACID | DAMAGE_TYPE_BLUDGEONING |
|
||||
DAMAGE_TYPE_COLD | DAMAGE_TYPE_DIVINE |
|
||||
DAMAGE_TYPE_ELECTRICAL | DAMAGE_TYPE_FIRE |
|
||||
DAMAGE_TYPE_MAGICAL | DAMAGE_TYPE_NEGATIVE |
|
||||
DAMAGE_TYPE_PIERCING | DAMAGE_TYPE_POSITIVE |
|
||||
DAMAGE_TYPE_SLASHING | DAMAGE_TYPE_SONIC);
|
||||
if(iHighestPhisicalDamage < iPhisicalDamage)
|
||||
// Get the previous highest damage and test it
|
||||
if(nPhysical > GetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT))
|
||||
{
|
||||
SetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT, iPhisicalDamage);
|
||||
// If higher, and was a melee/ranged attacker, set it.
|
||||
// This does include other additional physical damage - EG:
|
||||
// weapon property: Bonus Damage.
|
||||
SetAIInteger(AI_HIGHEST_PHISICAL_DAMAGE_AMOUNT, nPhysical);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the max elemental damage done, for better use of elemental
|
||||
// protections. This is set for the most damage...so it could be
|
||||
// 1 (for a +1 fire weapon, any number of hits) or over 50 (good
|
||||
// fireball/flame storm etc.)
|
||||
int nElemental = nDamage - nPhysical;
|
||||
if(nElemental > GetAIInteger(MAX_ELEMENTAL_DAMAGE))
|
||||
{
|
||||
SetAIInteger(MAX_ELEMENTAL_DAMAGE, nElemental);
|
||||
}
|
||||
// Set the last damage done, may set to 0 of course :-P
|
||||
// * This is only set if they did damage us at all, however.
|
||||
SetAIInteger(LAST_ELEMENTAL_DAMAGE, nElemental);
|
||||
|
||||
// Morale: We may get a penalty if it does more than a cirtain amount of HP damage.
|
||||
// Other: We set highest damager and amount.
|
||||
if(!GetSpawnInCondition(AI_FLAG_FLEEING_FEARLESS, AI_TARGETING_FLEE_MASTER))
|
||||
{
|
||||
// Get penalty and how much damage at once needs to be done
|
||||
int nPenalty = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_PENALTY, 6, 50, 1);
|
||||
int nToDamage = GetBoundriedAIInteger(AI_DAMAGE_AT_ONCE_FOR_MORALE_PENALTY, GetMaxHitPoints()/6, GetMaxHitPoints(), 1);
|
||||
if(nDamage > nToDamage)
|
||||
{
|
||||
// 61: "[Damaged] Morale Penalty for 600 seconds [Penalty]" + IntToString(iPenalty)
|
||||
DebugActionSpeakByInt(61, OBJECT_INVALID, nPenalty);
|
||||
// Apply penalty
|
||||
SetMoralePenalty(nPenalty, 300.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,27 +185,53 @@ void main()
|
||||
{
|
||||
// 62: "[Damaged] Not in combat: DCR [Damager]" + GetName(oDamager)
|
||||
DebugActionSpeakByInt(62, oDamager);
|
||||
|
||||
// Check if they are in the same area. Can be a left AOE spell.
|
||||
// Don't attack purposly across area's.
|
||||
if(GetArea(oDamager) == GetArea(OBJECT_SELF))
|
||||
{
|
||||
// Shout to allies to attack the enemy who attacked me
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
|
||||
DetermineCombatRound(oDamager);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
DetermineCombatRound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
else // Else it is friendly, or invalid damager
|
||||
// Else it is friendly, or invalid damager
|
||||
else
|
||||
{
|
||||
// Still will react - eg: A left AOE spell (which might mean a battle
|
||||
// just happened)
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Shout to allies to attack generally. No target to specifically attack,
|
||||
// as it is an ally.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
// 63: [Damaged] Not in combat: DCR. Ally hit us. [Damager(Ally?)]" + GetName(oDamager)
|
||||
DebugActionSpeakByInt(63, oDamager);
|
||||
DetermineCombatRound();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
// User defined event - for normally immoral creatures.
|
||||
if(GetCurrentHitPoints() == i1)
|
||||
if(GetCurrentHitPoints() == 1)
|
||||
{
|
||||
// Fire the immortal damaged at 1 HP event.
|
||||
FireUserEvent(AI_FLAG_UDE_DAMAGED_AT_1_HP, EVENT_DAMAGED_AT_1_HP);
|
||||
|
@@ -1,38 +1,37 @@
|
||||
/************************ [On Death] *******************************************
|
||||
Filename: j_ai_ondeath or nw_c2_default7
|
||||
************************* [On Death] *******************************************
|
||||
/*/////////////////////// [On Death] ///////////////////////////////////////////
|
||||
Filename: J_AI_OnDeath or nw_c2_default7
|
||||
///////////////////////// [On Death] ///////////////////////////////////////////
|
||||
Speeded up no end, when compiling, with seperate Include.
|
||||
Cleans up all un-droppable items, all ints and all local things when destroyed.
|
||||
|
||||
Check down near the bottom for a good place to add XP or corpse lines ;-)
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added in Turn of corpses toggle
|
||||
- Added in appropriate space for XP awards, marked with ideas (effect death)
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Removed the redudnant notes on the "You have gained 0 experience" message
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
You can edit this for experience, there is a seperate section for it.
|
||||
|
||||
It will use DeathCheck to execute a cleanup-and-destroy script, that removes
|
||||
any coprse, named "j_ai_destroyself".
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetLastKiller.
|
||||
************************* [On Death] ******************************************/
|
||||
///////////////////////// [On Death] /////////////////////////////////////////*/
|
||||
|
||||
// We only require the constants/debug file. We have 1 function, not worth another include.
|
||||
#include "j_inc_constants"
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
// We need a wrapper. If the amount of deaths, got in this, is not equal to iDeaths,
|
||||
// we don't execute the script, else we do. :-P
|
||||
void DeathCheck(int iDeaths);
|
||||
void DeathCheck(int nDeaths);
|
||||
|
||||
void main()
|
||||
{
|
||||
// If we are set to, don't fire this script at all
|
||||
if(GetAIInteger(I_AM_TOTALLY_DEAD)) return;
|
||||
|
||||
// Pre-death-event
|
||||
if(FireUserEvent(AI_FLAG_UDE_DEATH_PRE_EVENT, EVENT_DEATH_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_DEATH_PRE_EVENT)) return;
|
||||
// Pre-death-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_DEATH_PRE_EVENT, EVENT_DEATH_PRE_EVENT)) return;
|
||||
|
||||
// Note: No AI on/off check here.
|
||||
|
||||
@@ -50,7 +49,7 @@ void main()
|
||||
if(!GetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH))
|
||||
{
|
||||
// Don't apply effect death to self more then once per 2 seconds.
|
||||
SetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH, f2);
|
||||
SetLocalTimer(AI_TIMER_DEATH_EFFECT_DEATH, 2.0);
|
||||
// This should make the last killer us.
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), OBJECT_SELF);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(GetMaxHitPoints()), OBJECT_SELF);
|
||||
@@ -61,50 +60,47 @@ void main()
|
||||
// Set have died once, stops giving out mulitple amounts of XP.
|
||||
SetAIInteger(WE_HAVE_DIED_ONCE, TRUE);
|
||||
|
||||
/************************ [Experience] *****************************************
|
||||
THIS is the place for it, below this comment. To reward XP, you might want
|
||||
to first apply EffectDeath to ourselves (uncomment the example lines) which
|
||||
will remove the "You recieved 0 Experience" if you have normal XP at 0, as
|
||||
the On Death event is before the reward, and therefore now our last killer
|
||||
will be outselves. It will not cause any errors, oKiller is already set.
|
||||
/*/////////////////////// [Experience] /////////////////////////////////////////
|
||||
THIS is the place for it, below this comment.
|
||||
|
||||
Anything else, I leave to you. GetFirstFactionMember (and next), GiveXPToCreature,
|
||||
GetXP, SetXP, GetChallengeRating all are really useful.
|
||||
It is useful to use GetFirstFactionMember (and Next), GiveXPToCreature,
|
||||
GetXP, SetXP, GetChallengeRating (of self) all are really useful.
|
||||
|
||||
Bug note: GetFirstFactionMember/Next with the PC parameter means either ONLY PC
|
||||
************************* [Experience] ****************************************/
|
||||
// Do XP things (Use object "oKiller").
|
||||
Bug note: GetFirstFactionMember/Next with the PC parameter means either ONLY PC,
|
||||
and so NPC henchmen, unless FALSE is used, will not be even recognised.
|
||||
///////////////////////// [Experience] ///////////////////////////////////////*/
|
||||
// Do XP things (Use object "oKiller" for who killed us).
|
||||
|
||||
|
||||
|
||||
/************************ [Experience] ****************************************/
|
||||
/*/////////////////////// [Experience] ///////////////////////////////////////*/
|
||||
}
|
||||
|
||||
// Note: Here we do a simple way of checking how many times we have died.
|
||||
// Nothing special. Debugging most useful aspect.
|
||||
int iDeathCounterNew = GetAIInteger(AMOUNT_OF_DEATHS);
|
||||
iDeathCounterNew++;
|
||||
SetAIInteger(AMOUNT_OF_DEATHS, iDeathCounterNew);
|
||||
int nDeathCounterNew = GetAIInteger(AMOUNT_OF_DEATHS);
|
||||
nDeathCounterNew++;
|
||||
SetAIInteger(AMOUNT_OF_DEATHS, nDeathCounterNew);
|
||||
|
||||
// Here is the last time (in game seconds) we died. It is used in the executed script
|
||||
// to make sure we don't prematurly remove areselves.
|
||||
|
||||
// We may want some sort of visual effect - like implosion or something, to fire.
|
||||
int iDeathEffect = GetAIConstant(AI_DEATH_VISUAL_EFFECT);
|
||||
int nDeathEffect = GetAIConstant(AI_DEATH_VISUAL_EFFECT);
|
||||
|
||||
// Valid constants from 0 and up. Apply to our location (not to us, who will go!)
|
||||
if(iDeathEffect >= i0)
|
||||
if(nDeathEffect >= 0)
|
||||
{
|
||||
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(iDeathEffect), GetLocation(OBJECT_SELF));
|
||||
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(nDeathEffect), GetLocation(OBJECT_SELF));
|
||||
}
|
||||
// Default Commoner alignment changing. (If the commoner is not evil!)
|
||||
if(GetLevelByClass(CLASS_TYPE_COMMONER) > i0 &&
|
||||
if(GetLevelByClass(CLASS_TYPE_COMMONER) > 0 &&
|
||||
GetAlignmentGoodEvil(OBJECT_SELF) != ALIGNMENT_EVIL &&
|
||||
!GetSpawnInCondition(AI_FLAG_OTHER_NO_COMMONER_ALIGNMENT_CHANGE, AI_OTHER_MASTER))
|
||||
{
|
||||
if(GetIsPC(oKiller))
|
||||
{
|
||||
AdjustAlignment(oKiller, ALIGNMENT_EVIL, i5);
|
||||
AdjustAlignment(oKiller, ALIGNMENT_EVIL, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -113,29 +109,31 @@ void main()
|
||||
object oMaster = GetMaster(oKiller);
|
||||
if(GetIsObjectValid(oMaster) && GetIsPC(oMaster))
|
||||
{
|
||||
AdjustAlignment(oMaster, ALIGNMENT_EVIL, i5);
|
||||
AdjustAlignment(oMaster, ALIGNMENT_EVIL, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Always shout when we are killed. Reactions - Morale penalty, and attack the killer.
|
||||
AISpeakString(I_WAS_KILLED);
|
||||
// Always shout when we are killed. Reactions - Morale penalty, and
|
||||
// attack the killer.
|
||||
AISpeakString(AI_SHOUT_I_WAS_KILLED);
|
||||
|
||||
// Speaks the set death speak, like "AGGGGGGGGGGGGGGGGGGG!! NOOOO!" for instance :-)
|
||||
// Note for 1.4: No need for "CanSpeak()" for this, of course.
|
||||
SpeakArrayString(AI_TALK_ON_DEATH);
|
||||
|
||||
// First check - do we use "destroyable corpses" or not? (default, yes)
|
||||
if(!GetSpawnInCondition(AI_FLAG_OTHER_TURN_OFF_CORPSES, AI_OTHER_MASTER))
|
||||
{
|
||||
// We will actually dissapear after 30.0 seconds if not raised.
|
||||
int iTime = GetAIInteger(AI_CORPSE_DESTROY_TIME);
|
||||
if(iTime == i0) // Error checking
|
||||
int nTime = GetAIInteger(AI_CORPSE_DESTROY_TIME);
|
||||
if(nTime == 0) // Error checking
|
||||
{
|
||||
iTime = i1;
|
||||
nTime = 30;
|
||||
}
|
||||
// 64: "[Death] Checking corpse status in " + IntToString(iTime) + " [Killer] " + GetName(oKiller) + " [Times Died Now] " + IntToString(iDeathCounterNew)
|
||||
DebugActionSpeakByInt(64, oKiller, iTime, IntToString(iDeathCounterNew));
|
||||
// 64: "[Death] Checking corpse status in " + IntToString(nTime) + " [Killer] " + GetName(oKiller) + " [Times Died Now] " + IntToString(nDeathCounterNew)
|
||||
DebugActionSpeakByInt(64, oKiller, nTime, IntToString(nDeathCounterNew));
|
||||
// Delay check
|
||||
DelayCommand(IntToFloat(iTime), DeathCheck(iDeathCounterNew));
|
||||
DelayCommand(IntToFloat(nTime), DeathCheck(nDeathCounterNew));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -155,10 +153,10 @@ void main()
|
||||
|
||||
// We need a wrapper. If the amount of deaths, got in this, is not equal to iDeaths,
|
||||
// we don't execute the script, else we do. :-P
|
||||
void DeathCheck(int iDeaths)
|
||||
void DeathCheck(int nDeaths)
|
||||
{
|
||||
// Do the deaths imputted equal the amount we have suffered?
|
||||
if(GetAIInteger(AMOUNT_OF_DEATHS) == iDeaths)
|
||||
if(GetAIInteger(AMOUNT_OF_DEATHS) == nDeaths)
|
||||
{
|
||||
// - This now includes a check for Bioware's lootable functions and using them.
|
||||
ExecuteScript(FILE_DEATH_CLEANUP, OBJECT_SELF);
|
||||
|
@@ -1,72 +1,83 @@
|
||||
/************************ [On Disturbed] ***************************************
|
||||
Filename: j_ai_ondisturbed or nw_c2_default8
|
||||
************************* [On Disturbed] ***************************************
|
||||
/*/////////////////////// [On Disturbed] ///////////////////////////////////////
|
||||
Filename: J_AI_OnDisturbed or nw_c2_default8
|
||||
///////////////////////// [On Disturbed] ///////////////////////////////////////
|
||||
This will attack pickpockets, and inventory disturbers. Note: Stupidly, Bioware
|
||||
made this only affect the creature by stealing. Still, oh well :-(
|
||||
|
||||
This means that the only event which fires it is pickpocketing.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Changed why we determine combat round
|
||||
- Any change in inventory will trigger appropriate SetWeapons again.
|
||||
- Added turn of hide things.
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Cleaned up a bit. Removed unused declared variable.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Only fired by stealing, great. Oh well, it will attack any disturber anyway.
|
||||
|
||||
It *might* not be fired if the natural spot check to notice a theft doesn't
|
||||
work. No idea personally.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetInventoryDisturbItem, GetLastDisturbed,
|
||||
GetInventoryDisturbType (I think it is always be stolen :-( ).
|
||||
************************* [On Disturbed] **************************************/
|
||||
///////////////////////// [On Disturbed] /////////////////////////////////////*/
|
||||
|
||||
#include "j_inc_other_ai"
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-disturbed-event
|
||||
if(FireUserEvent(AI_FLAG_UDE_DISTURBED_PRE_EVENT, EVENT_DISTURBED_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_DISTURBED_PRE_EVENT)) return;
|
||||
// Pre-disturbed-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_DISTURBED_PRE_EVENT, EVENT_DISTURBED_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
// We will set weapons if it is a weapon.
|
||||
object oItem = GetInventoryDisturbItem();
|
||||
int nBase = GetBaseItemType(oItem);
|
||||
// Declare major variables
|
||||
object oDisturber = GetLastDisturbed();
|
||||
int iType = GetInventoryDisturbType();
|
||||
string Middle;
|
||||
object oItem = GetInventoryDisturbItem();
|
||||
int nType = GetInventoryDisturbType();
|
||||
int nBase = GetBaseItemType(oItem);
|
||||
|
||||
// We will reset weapons if it is a weapon.
|
||||
// Reset weapons, or specifically healers kits.
|
||||
if(GetIsObjectValid(oItem))
|
||||
{
|
||||
// Kits
|
||||
if(nBase == BASE_ITEM_HEALERSKIT)
|
||||
{
|
||||
SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, i2);
|
||||
SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, 2);
|
||||
ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF);
|
||||
}
|
||||
else // Think it is a weapon. Saves time :-)
|
||||
{
|
||||
SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, i1);
|
||||
SetLocalInt(OBJECT_SELF, AI_WEAPONSETTING_SETWEAPONS, 1);
|
||||
ExecuteScript(FILE_RE_SET_WEAPONS, OBJECT_SELF);
|
||||
}
|
||||
}
|
||||
// Fight! Or search!
|
||||
if(GetIsObjectValid(oDisturber) && !GetIsDM(oDisturber) && !GetFactionEqual(oDisturber) &&
|
||||
(iType == INVENTORY_DISTURB_TYPE_STOLEN || GetIsEnemy(oDisturber)))
|
||||
if(!GetIgnoreNoFriend(oDisturber) &&
|
||||
(nType == INVENTORY_DISTURB_TYPE_STOLEN || GetIsEnemy(oDisturber)))
|
||||
{
|
||||
// Turn of hiding, a timer to activate Hiding in the main file. This is
|
||||
// done in each of the events, with the opposition checking seen/heard.
|
||||
TurnOffHiding(oDisturber);
|
||||
|
||||
// Can we attack?
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
AISpeakString(CALL_TO_ARMS);
|
||||
// Someone specific to attack
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
|
||||
// One debug speak. We always do one.
|
||||
// 65: "[Disturbed] (pickpocket) Attacking Enemy Distrube [Disturber] " + GetName(oTarget) + " [Type] " + IntToString(iType)
|
||||
DebugActionSpeakByInt(65, oDisturber, iType);
|
||||
DebugActionSpeakByInt(65, oDisturber, nType);
|
||||
|
||||
// Attack the disturber
|
||||
DetermineCombatRound(oDisturber);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get allies interested.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
}
|
||||
|
||||
// Fire End-heartbeat-UDE
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [On Spawn] *******************************************
|
||||
Filename: j_ai_onspawn or nw_c2_default9
|
||||
************************* [On Spawn] *******************************************
|
||||
/*/////////////////////// [On Spawn] ///////////////////////////////////////////
|
||||
Filename: J_AI_OnSpawn or nw_c2_default9
|
||||
///////////////////////// [On Spawn] ///////////////////////////////////////////
|
||||
This file contains options that will determine some AI behaviour, and a lot
|
||||
of toggles for turning things on/off. A big read, but might be worthwhile.
|
||||
|
||||
@@ -28,18 +28,28 @@
|
||||
- Targeting is imporant :-D
|
||||
- If you delete this script, there is a template for the On Spawn file
|
||||
in the zip it came in, for use in the "scripttemplate" directory.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
Note: I have removed:
|
||||
- Default "Teleporting" and exit/return (this seemed bugged anyway, or useless)
|
||||
- Spawn in animation. This can be, of course, re-added.
|
||||
- Day/night posting. This is uneeded, with a changed walk waypoints that does it automatically.
|
||||
|
||||
Changes from 1.0-1.2:
|
||||
- All constants names are changed, I am afraid.
|
||||
- Added Set/Delete/GetAIInteger/Constant/Object. This makes sure that the AI
|
||||
doesn't ever interfere with other things - it pre-fixes all stored things
|
||||
with AI_INTEGER_ (and so on)
|
||||
************************* [Workings] *******************************************
|
||||
1.0-1.2 - Used short amount of spawn options.
|
||||
1.3 - All constants names are changed, I am afraid.
|
||||
- Added Set/Delete/GetAIInteger/Constant/Object. This makes sure that the AI
|
||||
doesn't ever interfere with other things - it pre-fixes all stored things
|
||||
with AI_INTEGER_ (and so on)
|
||||
1.4 - TO DO: Clear up some old non-working ones
|
||||
- Added in User Defined part of the script, an auto-turn-off-spells for
|
||||
Ranger and Paladin classes. Need to test - perhaps 1.64 fixed it?
|
||||
|
||||
|
||||
Spawn options changed:
|
||||
- Removed AI level settings (can still be done manually)
|
||||
- Added optional (and off by default) fear-visual for fleeing
|
||||
|
||||
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Note: You can do without all the comments (it may be that you don't want
|
||||
the extra KB it adds or something, although it does not at all slow down a module)
|
||||
so as long as you have these at the end:
|
||||
@@ -50,9 +60,9 @@
|
||||
Oh, and the include file (Below, "j_inc_spawnin") must be at the top like
|
||||
here. Also recommended is the AI_INTELLIGENCE and AI_MORALE being set (if
|
||||
not using custom AI).
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetIsEncounterCreature
|
||||
************************* [On Spawn] ******************************************/
|
||||
///////////////////////// [On Spawn] /////////////////////////////////////////*/
|
||||
|
||||
// Treasure Includes - See end of spawn for uncomment options.
|
||||
|
||||
@@ -65,7 +75,7 @@
|
||||
// - This will spawn treasure based on chests placed in the module. See "x0_i0_treasure" for more information.
|
||||
|
||||
// This is required for all spawn in options!
|
||||
#include "j_inc_spawnin"
|
||||
#include "J_INC_SPAWNIN"
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -116,13 +126,13 @@ void main()
|
||||
// - Remember, uncommenting one will just ignore it (so will never check target's
|
||||
// AC without TARGETING_AC on)
|
||||
|
||||
AI_SetAITargetingValues(TARGETING_MANTALS, TARGET_LOWER, i1, i12);
|
||||
AI_SetAITargetingValues(TARGETING_MANTALS, TARGET_LOWER, 1, 12);
|
||||
// Spell mantals are checked only for the spell target. Either Absense of or got any.
|
||||
AI_SetAITargetingValues(TARGETING_RANGE, TARGET_HIGHER, i2, i9);
|
||||
AI_SetAITargetingValues(TARGETING_RANGE, TARGET_HIGHER, 2, 9);
|
||||
// Range - very imporant! Basis for all ranged/spell attacks.
|
||||
AI_SetAITargetingValues(TARGETING_AC, TARGET_LOWER, i2, i6);
|
||||
AI_SetAITargetingValues(TARGETING_AC, TARGET_LOWER, 2, 6);
|
||||
// AC is used for all phisical attacks. Lower targets lower (By default).
|
||||
AI_SetAITargetingValues(TARGETING_SAVES, TARGET_LOWER, i2, i4);
|
||||
AI_SetAITargetingValues(TARGETING_SAVES, TARGET_LOWER, 2, 4);
|
||||
// Used for spell attacks. Saves are sorta a AC versus spells.
|
||||
|
||||
// Phisical protections. Used by spells, ranged and melee.
|
||||
@@ -131,22 +141,22 @@ void main()
|
||||
if(GetBaseAttackBonus(OBJECT_SELF) > ((GetHitDice(OBJECT_SELF)/2) + 1))
|
||||
{
|
||||
// Fighter/Clerics (It is over a mages BAB + 1 (IE 0.5 BAB/Level) target lower
|
||||
AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_LOWER, i2, i6);
|
||||
AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_LOWER, 2, 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mages target higher (so dispel/elemental attack those who fighters
|
||||
// cannot hit as much). (the lowest BAB, under half our hit dice in BAB)
|
||||
AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_HIGHER, i1, i5);
|
||||
AI_SetAITargetingValues(TARGETING_PHISICALS, TARGET_HIGHER, 1, 5);
|
||||
}
|
||||
// Base attack bonus. Used for spells and phisical attacks. Checked with GetBaseAttackBonus.
|
||||
AI_SetAITargetingValues(TARGETING_BAB, TARGET_LOWER, i1, i4);
|
||||
AI_SetAITargetingValues(TARGETING_BAB, TARGET_LOWER, 1, 4);
|
||||
// Hit dice - how powerful in levels the enemy is. Used for all checks.
|
||||
AI_SetAITargetingValues(TARGETING_HITDICE, TARGET_LOWER, i1, i3);
|
||||
AI_SetAITargetingValues(TARGETING_HITDICE, TARGET_LOWER, 1, 3);
|
||||
|
||||
//AI_SetAITargetingValues(TARGETING_HP_PERCENT, TARGET_LOWER, i1, i3);
|
||||
//AI_SetAITargetingValues(TARGETING_HP_CURRENT, TARGET_LOWER, i1, i3);
|
||||
//AI_SetAITargetingValues(TARGETING_HP_MAXIMUM, TARGET_LOWER, i1, i3);
|
||||
//AI_SetAITargetingValues(TARGETING_HP_PERCENT, TARGET_LOWER, 1, 3);
|
||||
//AI_SetAITargetingValues(TARGETING_HP_CURRENT, TARGET_LOWER, 1, 3);
|
||||
//AI_SetAITargetingValues(TARGETING_HP_MAXIMUM, TARGET_LOWER, 1, 3);
|
||||
// The HP's are the last thing to choose a target with.
|
||||
/************************ [Targeting] *****************************************/
|
||||
|
||||
@@ -185,6 +195,9 @@ void main()
|
||||
// They will flee to the nearest object of the tag below, if set.
|
||||
//SetLocalString(OBJECT_SELF, AI_FLEE_OBJECT, "BOSS_TAG_OR_WHATEVER");
|
||||
// This needs setting if the above is to work.
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_FLEEING_USE_VISUAL_EFFECT, AI_TARGETING_FLEE_MASTER);
|
||||
// If this is on, we play a visual effect while we flee.
|
||||
/************************ [Fleeing] *******************************************/
|
||||
|
||||
/************************ [Combat - Fighters] **********************************
|
||||
@@ -456,15 +469,6 @@ void main()
|
||||
//SetSpawnInCondition(AI_FLAG_OTHER_LAG_TARGET_NEAREST_ENEMY, AI_OTHER_MASTER);
|
||||
// Ignores targeting settings. VERY good for lag/bad AI. Attacks nearest seen enemy.
|
||||
|
||||
/*** AI Level setting - Do not use AI_LEVEL_DEFAULT at all. ***/
|
||||
|
||||
//SetAIConstant(LAG_AI_LEVEL_NO_PC_OR_ENEMY_50M, AI_LEVEL_VERY_LOW);
|
||||
// Changes to this AI setting if there is no enemy or PC in 50M.
|
||||
//SetAIConstant(LAG_AI_LEVEL_YES_PC_OR_ENEMY_50M, AI_LEVEL_LOW);
|
||||
// Changes to this AI setting if there IS an enemy or PC in 50M.
|
||||
//SetAIConstant(LAG_AI_LEVEL_COMBAT, AI_LEVEL_NORMAL);
|
||||
// This OVERRIDES others. Only used when a creature is put into combat.
|
||||
|
||||
/************************ [Other - Behaviour/Generic] *************************/
|
||||
|
||||
/************************ [User Defined and Shouts] ****************************
|
||||
@@ -475,6 +479,10 @@ void main()
|
||||
(User Defined Event = UDE)
|
||||
************************* [User Defined and Shouts] ***************************/
|
||||
|
||||
// This is REQUIRED if we use any Pre-events. If not there, it will default
|
||||
// to the default User Defined Event script for the default AI.
|
||||
SetCustomUDEFileName("k_ai_onuserdef");
|
||||
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_HEARTBEAT_EVENT, AI_UDE_MASTER); // UDE 1001
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_HEARTBEAT_PRE_EVENT, AI_UDE_MASTER); // UDE 1021
|
||||
//SetSpawnInCondition(AI_FLAG_UDE_PERCIEVE_EVENT, AI_UDE_MASTER); // UDE 1002
|
||||
@@ -549,6 +557,9 @@ void main()
|
||||
// This will be said when the leader, if this creature, sends a runner.
|
||||
//AI_SetSpawnInSpeakValue(AI_TALK_ON_LEADER_ATTACK_TARGET, "Help attack this target!");
|
||||
// When the leader thinks target X should be attacked, it will say this.
|
||||
//AI_SetSpawnInSpeakValue(AI_TALK_ON_LEADER_BOSS_SHOUT, "Come my minions! To battle!");
|
||||
// This will be said when the leader, if this creature, sees an enemy and uses his "Boss Monster Shout", if turned on.
|
||||
|
||||
|
||||
/************************ [User Defined and Shouts] ***************************/
|
||||
|
||||
@@ -616,10 +627,18 @@ void main()
|
||||
SetBaseAttackBonus(nNumber);
|
||||
}
|
||||
|
||||
// If we are a ranger or paladin class, do not cast spells. This can be
|
||||
// manually removed if wished. To get the spells they have working correctly,
|
||||
// remove this, and use Monster Abilties instead of thier normal class spells.
|
||||
// if(GetLevelByClass(CLASS_TYPE_RANGER) >= 1 || GetLevelByClass(CLASS_TYPE_PALADIN) >= 1)
|
||||
// {
|
||||
// SetSpawnInCondition(AI_FLAG_OTHER_LAG_NO_SPELLS, AI_OTHER_MASTER);
|
||||
// }
|
||||
|
||||
/************************ [User] **********************************************/
|
||||
|
||||
// Note: You shouldn't really remove this, even if they have no waypoints.
|
||||
DelayCommand(f2, SpawnWalkWayPoints());
|
||||
DelayCommand(2.0, SpawnWalkWayPoints());
|
||||
// Delayed walk waypoints, as to not upset instant combat spawning.
|
||||
// This will also check if to change to day/night posts during the walking, no heartbeats.
|
||||
}
|
||||
|
@@ -1,35 +1,43 @@
|
||||
/************************ [On Rested] ******************************************
|
||||
Filename: j_ai_onrest or nw_c2_defaulta
|
||||
************************* [On Rested] ******************************************
|
||||
/*/////////////////////// [On Rested] //////////////////////////////////////////
|
||||
Filename: J_AI_OnRest or nw_c2_defaulta
|
||||
///////////////////////// [On Rested] //////////////////////////////////////////
|
||||
This will play the sitting animation for 6 seconds, just something for resting.
|
||||
Also, walks waypoints (as resting would stop this) :-) and signals event (if so be)
|
||||
Feel free to edit.
|
||||
|
||||
It does have the spell trigger information resetting, however. This can
|
||||
only be removed if they have no spell triggers, although it is hardly worth it.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added sitting.
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Will be editing this down. No need to reset anything on rest, for a
|
||||
better working AI.
|
||||
IDEA: Change so that we will work through all spells/feats in order.
|
||||
If, at cirtain levels, we do not have any spells to cast from that
|
||||
level (set in a global stored integer in the general AI) we ignore all
|
||||
spells in that level. Same for each talent category (no need to use
|
||||
talents for them in the spawn script).
|
||||
|
||||
If not in combat (EG: In heartbeat) we reset the integers saying "don't
|
||||
bother checking those spells" to false.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This fires once, at the END of resting.
|
||||
|
||||
If ClearAllActions is added, the resting is actually stopped, or so it seems.
|
||||
|
||||
It doesn't fire more then once.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: None, it seems.
|
||||
************************* [On Rested] *****************************************/
|
||||
///////////////////////// [On Rested] ////////////////////////////////////////*/
|
||||
|
||||
#include "j_inc_constants"
|
||||
#include "J_INC_CONSTANTS"
|
||||
|
||||
// Resets all spell triggers used for sString
|
||||
void LoopResetTriggers(string sString, object oTrigger);
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-heartbeat-event
|
||||
if(FireUserEvent(AI_FLAG_UDE_RESTED_PRE_EVENT, EVENT_RESTED_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_RESTED_PRE_EVENT)) return;
|
||||
// Pre-rest-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_RESTED_PRE_EVENT, EVENT_RESTED_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
@@ -49,8 +57,8 @@ void main()
|
||||
LoopResetTriggers(SPELLTRIGGER_START_OF_COMBAT, oTrigger);
|
||||
}
|
||||
// Some sitting for a few seconds.
|
||||
ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS, f1, f6);
|
||||
DelayCommand(f9, ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF));
|
||||
ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS, 1.0, 6.0);
|
||||
DelayCommand(9.0, ExecuteScript(FILE_WALK_WAYPOINTS, OBJECT_SELF));
|
||||
|
||||
// Fire End-heartbeat-UDE
|
||||
FireUserEvent(AI_FLAG_UDE_RESTED_EVENT, EVENT_RESTED_EVENT);
|
||||
@@ -59,18 +67,18 @@ void main()
|
||||
// Resets all spell triggers used for sString
|
||||
void LoopResetTriggers(string sString, object oTrigger)
|
||||
{
|
||||
int iCnt, iBreak, iUsed;
|
||||
for(iCnt = i1; iBreak != TRUE; iCnt++)
|
||||
int nCnt, bBreak, bUsed;
|
||||
for(nCnt = 1; bBreak != TRUE; nCnt++)
|
||||
{
|
||||
// Check max for this setting
|
||||
iUsed = GetLocalInt(oTrigger, sString + USED);
|
||||
if(iUsed)
|
||||
bUsed = GetLocalInt(oTrigger, sString + USED);
|
||||
if(bUsed)
|
||||
{
|
||||
DeleteLocalInt(oTrigger, sString + USED);
|
||||
}
|
||||
else
|
||||
{
|
||||
iBreak = TRUE;
|
||||
bBreak = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,29 +1,30 @@
|
||||
/************************ [On Spell Cast At] ***********************************
|
||||
/*/////////////////////// [On Spell Cast At] ///////////////////////////////////
|
||||
Filename: j_ai_onspellcast or nw_c2_defaultb
|
||||
************************* [On Spell Cast At] ***********************************
|
||||
///////////////////////// [On Spell Cast At] ///////////////////////////////////
|
||||
What does this do? Well...
|
||||
- Any AOE spell effects are set in a timer, so we can react to them right
|
||||
- Reacts to hostile casters, or allies in combat
|
||||
|
||||
And the normal attack :-)
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added special AOE checks.
|
||||
- Hide checks.
|
||||
************************* [Workings] *******************************************
|
||||
1.4 - Added more silent shouts. Edited the formatting. Moved a few things around.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
This is fired when EventSpellCastAt(object oCaster, int nSpell, int bHarmful=TRUE)
|
||||
is signaled on the creature.
|
||||
|
||||
GetLastSpellCaster() = oCaster (Door, Placeable, Creature who cast it)
|
||||
GetLastSpell() = nSpell (The spell cast at us)
|
||||
GetLastSpellHarmful()= bHarmful (If it is harmful!)
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetLastSpellCaster, GetLastSpellHarmful GetLastSpell()
|
||||
************************* [On Spell Cast At] **********************************/
|
||||
///////////////////////// [On Spell Cast At] /////////////////////////////////*/
|
||||
|
||||
#include "j_inc_other_ai"
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
// Sets a local timer if the spell is an AOE one
|
||||
void SetAOESpell(int iSpellCast, object oCaster);
|
||||
void SetAOESpell(int nSpellCast, object oCaster);
|
||||
// Gets the nearest AOE cast by oCaster, of sTag.
|
||||
object GetNearestAOECastBy(string sTag, object oCaster);
|
||||
// Gets the amount of protections we have - IE globes
|
||||
@@ -31,67 +32,49 @@ int GetOurSpellLevelImmunity();
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-heartbeat-event
|
||||
if(FireUserEvent(AI_FLAG_UDE_SPELL_CAST_AT_PRE_EVENT, EVENT_SPELL_CAST_AT_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_SPELL_CAST_AT_PRE_EVENT)) return;
|
||||
// Pre-spell cast at-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_SPELL_CAST_AT_PRE_EVENT, EVENT_SPELL_CAST_AT_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
|
||||
object oCaster = GetLastSpellCaster();
|
||||
int iHarmful = GetLastSpellHarmful();
|
||||
int iSpellCast = GetLastSpell();
|
||||
int bHarmful = GetLastSpellHarmful();
|
||||
int nSpellCast = GetLastSpell();
|
||||
object oAttackerOfCaster;
|
||||
|
||||
// If harmful, we set the spell to a timer, if an AOE one.
|
||||
if(iHarmful && GetIsObjectValid(oCaster))
|
||||
if(bHarmful && GetIsObjectValid(oCaster))
|
||||
{
|
||||
// Might set AOE spell to cast.
|
||||
SetAOESpell(iSpellCast, oCaster);
|
||||
SetAOESpell(nSpellCast, oCaster);
|
||||
}
|
||||
// If not a creature, probably an AOE or trap.
|
||||
if(GetObjectType(oCaster) != OBJECT_TYPE_CREATURE)
|
||||
{
|
||||
// 67: "[Spell] Caster isn't a creature! May look for target [Caster] " + GetName(oCaster)
|
||||
DebugActionSpeakByInt(67, oCaster);
|
||||
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
// Attack anyone else around
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// Determine Combat Round
|
||||
DetermineCombatRound();
|
||||
}
|
||||
}
|
||||
else if(GetIsObjectValid(oCaster) && !GetIsDM(oCaster) &&
|
||||
!GetIgnore(oCaster) && oCaster != OBJECT_SELF && !GetIsDead(oCaster))
|
||||
// If a friend, or dead, or a DM, or invalid, or self, we ignore them.
|
||||
else if(!GetIgnoreNoFriend(oCaster) && oCaster != OBJECT_SELF)
|
||||
{
|
||||
// 1.3 changes here:
|
||||
// - We do NOT need to know if it is hostile or not, except if it is hostile
|
||||
// and they are not our faction! We do, however, use iHarmful for speakstrings.
|
||||
if(!GetFactionEqual(oCaster))
|
||||
{
|
||||
// If harmful, we attack anyone! (and if is enemy)
|
||||
if(iHarmful || GetIsEnemy(oCaster))
|
||||
{
|
||||
if(iHarmful)
|
||||
{
|
||||
// Hostile spell speaksting, if set.
|
||||
SpeakArrayString(AI_TALK_ON_HOSTILE_SPELL_CAST_AT);
|
||||
}
|
||||
// Turn of hiding check
|
||||
TurnOffHiding(oCaster);
|
||||
// Attack
|
||||
AISpeakString(I_WAS_ATTACKED);
|
||||
// We attack
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// 68: "[Spell:Enemy/Hostile] Not in combat. Attacking: [Caster] " + GetName(oCaster)
|
||||
DebugActionSpeakByInt(68, oCaster);
|
||||
DetermineCombatRound(oCaster);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Else, faction is equal, we normally ignore, and only move to attack.
|
||||
else
|
||||
// and they are not our faction! We do, however, use bHarmful for speakstrings.
|
||||
|
||||
// If harmful, we attack anyone! (and if is enemy)
|
||||
// 1.4: Faction equal check in GetIgnoreNoFriend()
|
||||
if(bHarmful || GetIsEnemy(oCaster))
|
||||
{
|
||||
// Spawn in condition hostile thingy
|
||||
if(GetSpawnInCondition(AI_FLAG_OTHER_CHANGE_FACTIONS_TO_HOSTILE_ON_ATTACK, AI_OTHER_MASTER))
|
||||
@@ -101,43 +84,74 @@ void main()
|
||||
AdjustReputation(oCaster, OBJECT_SELF, -100);
|
||||
}
|
||||
}
|
||||
// We move to the person, if they are attacking something we cannot see...
|
||||
AISpeakString(CALL_TO_ARMS);
|
||||
|
||||
// Not in combat
|
||||
if(bHarmful)
|
||||
{
|
||||
// * Don't speak when dead. 1.4 change (an obvious one to make)
|
||||
if(CanSpeak())
|
||||
{
|
||||
// Hostile spell speaksting, if set.
|
||||
SpeakArrayString(AI_TALK_ON_HOSTILE_SPELL_CAST_AT);
|
||||
}
|
||||
}
|
||||
|
||||
// Turn of hiding check
|
||||
TurnOffHiding(oCaster);
|
||||
|
||||
// We attack
|
||||
if(!CannotPerformCombatRound())
|
||||
{
|
||||
// 69: "[Spell] (ally). Not in combat. May Attack/Move [Caster] " + GetName(oCaster)
|
||||
DebugActionSpeakByInt(69, oCaster);
|
||||
ClearAllActions();
|
||||
// Check thier target. Might not be valid (IE AOE spell at location)
|
||||
oAttackerOfCaster = GetAttackTarget(oCaster);
|
||||
// - Faster then DetermineCombatRound(); and looping targets until
|
||||
// we get this ally, and get this attacker! :-)
|
||||
if(GetIsObjectValid(oAttackerOfCaster))
|
||||
// 68: "[Spell:Enemy/Hostile] Not in combat. Attacking: [Caster] " + GetName(oCaster)
|
||||
DebugActionSpeakByInt(68, oCaster);
|
||||
DetermineCombatRound(oCaster);
|
||||
}
|
||||
|
||||
// Shout to allies to attack the enemy who attacked me, got via. Last Hostile Actor.
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
}
|
||||
// Else, was neutral perhaps. Don't attack them anyway.
|
||||
else
|
||||
{
|
||||
// 69: "[Spell] (ally). Not in combat. May Attack/Move [Caster] " + GetName(oCaster)
|
||||
DebugActionSpeakByInt(69, oCaster);
|
||||
|
||||
// Set special action to investigate - as if this event was triggered
|
||||
// by I_WAS_ATTACKED.
|
||||
|
||||
// If we are already attacking, we do not move
|
||||
if(CannotPerformCombatRound())
|
||||
{
|
||||
// Shout to allies to attack, or be prepared.
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We react as if the caster, a neutral, called for help ala
|
||||
// I_WAS_ATTACKED (they might not have, might just be
|
||||
// preperation for something), but normally, this is a neutral
|
||||
// casting a spell. Do not respond to PC's.
|
||||
if(!GetIsPC(oCaster))
|
||||
{
|
||||
// Move to the attack target, and wait for a proper on
|
||||
// perception event (as we are not currently in combat)
|
||||
ActionMoveToObject(oCaster, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move to the caster otherwise
|
||||
ActionMoveToObject(oCaster, TRUE);
|
||||
IWasAttackedResponse(oCaster);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If they are not a faction equal, and valid, we help them.
|
||||
else if(GetIsObjectValid(oCaster) && GetFactionEqual(oCaster))
|
||||
{
|
||||
IWasAttackedResponse(oCaster);
|
||||
}
|
||||
// Fire End-spell cast at-UDE
|
||||
FireUserEvent(AI_FLAG_UDE_SPELL_CAST_AT_EVENT, EVENT_SPELL_CAST_AT_EVENT);
|
||||
}
|
||||
|
||||
// Sets a local timer if the spell is an AOE one
|
||||
void SetAOESpell(int iSpellCast, object oCaster)
|
||||
void SetAOESpell(int nSpellCast, object oCaster)
|
||||
{
|
||||
// Check it is one we can check
|
||||
int iImmuneLevel = GetOurSpellLevelImmunity();
|
||||
switch(iSpellCast)
|
||||
int bStop = TRUE;
|
||||
switch(nSpellCast)
|
||||
{
|
||||
case SPELL_ACID_FOG:
|
||||
case SPELL_MIND_FOG:
|
||||
@@ -159,81 +173,82 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
case SPELL_VINE_MINE_HAMPER_MOVEMENT:
|
||||
case SPELL_VINE_MINE_ENTANGLE:
|
||||
{
|
||||
// Pass though, unless we are totally immune.
|
||||
if(iImmuneLevel >= i9)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Any other spell
|
||||
default:
|
||||
{
|
||||
return;
|
||||
bStop = FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Check immune level
|
||||
int nImmuneLevel = GetOurSpellLevelImmunity();
|
||||
if(nImmuneLevel >= 9)
|
||||
{
|
||||
bStop = TRUE;
|
||||
}
|
||||
// Check
|
||||
if(bStop == TRUE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// We do use intelligence here...
|
||||
int iAIInt = GetBoundriedAIInteger(AI_INTELLIGENCE);
|
||||
int iIgnoreSaves;
|
||||
int iIgnoreImmunities;
|
||||
int nAIInt = GetBoundriedAIInteger(AI_INTELLIGENCE);
|
||||
int bIgnoreSaves;
|
||||
int bIgnoreImmunities;
|
||||
object oAOE;
|
||||
|
||||
// If it is low, we ignore all things that we could ignore with it...
|
||||
if(iAIInt <= i3)
|
||||
if(nAIInt <= 3)
|
||||
{
|
||||
iIgnoreSaves = TRUE;
|
||||
iIgnoreImmunities = TRUE;
|
||||
bIgnoreSaves = TRUE;
|
||||
bIgnoreImmunities = TRUE;
|
||||
}
|
||||
// Average ignores saves
|
||||
else if(iAIInt <= i7)
|
||||
else if(nAIInt <= 7)
|
||||
{
|
||||
iIgnoreSaves = TRUE;
|
||||
iIgnoreImmunities = FALSE;
|
||||
bIgnoreSaves = TRUE;
|
||||
bIgnoreImmunities = FALSE;
|
||||
}
|
||||
// Else, we do both.
|
||||
else
|
||||
{
|
||||
iIgnoreSaves = FALSE;
|
||||
iIgnoreImmunities = FALSE;
|
||||
bIgnoreSaves = FALSE;
|
||||
bIgnoreImmunities = FALSE;
|
||||
}
|
||||
|
||||
int SetAOE = FALSE;// TRUE means set to timer
|
||||
int iSaveDC = i11;
|
||||
int bSetAOE = FALSE;// TRUE means set to timer
|
||||
int nSaveDC = 11;
|
||||
|
||||
// Get the caster DC, the most out of WIS, INT or CHA...
|
||||
int iInt = GetAbilityModifier(ABILITY_INTELLIGENCE, oCaster);
|
||||
int iWis = GetAbilityModifier(ABILITY_WISDOM, oCaster);
|
||||
int iCha = GetAbilityModifier(ABILITY_CHARISMA, oCaster);
|
||||
int nInt = GetAbilityModifier(ABILITY_INTELLIGENCE, oCaster);
|
||||
int nWis = GetAbilityModifier(ABILITY_WISDOM, oCaster);
|
||||
int nCha = GetAbilityModifier(ABILITY_CHARISMA, oCaster);
|
||||
|
||||
if(iInt > iWis && iInt > iCha)
|
||||
if(nInt > nWis && nInt > nCha)
|
||||
{
|
||||
iSaveDC += iInt;
|
||||
nSaveDC += nInt;
|
||||
}
|
||||
else if(iWis > iCha)
|
||||
else if(nWis > nCha)
|
||||
{
|
||||
iSaveDC += iWis;
|
||||
nSaveDC += nWis;
|
||||
}
|
||||
else
|
||||
{
|
||||
iSaveDC += iCha;
|
||||
nSaveDC += nCha;
|
||||
}
|
||||
// Note:
|
||||
// - No reaction type/friendly checks. Signal Event is only fired if the
|
||||
// spell WILL pierce any PvP/Friendly/Area settings
|
||||
|
||||
// We check immunities here, please note...
|
||||
switch(iSpellCast)
|
||||
switch(nSpellCast)
|
||||
{
|
||||
// First: IS GetIsReactionTypeHostile ones.
|
||||
case SPELL_EVARDS_BLACK_TENTACLES:
|
||||
// Fortitude save, but if we are immune to the hits, its impossible to hurt us
|
||||
{
|
||||
// If save immune OR AC immune, we ignore this.
|
||||
if(i25 >= GetAC(OBJECT_SELF) && iImmuneLevel < i4 &&
|
||||
((GetFortitudeSavingThrow(OBJECT_SELF) < iSaveDC + i2) || iIgnoreSaves))
|
||||
if(25 >= GetAC(OBJECT_SELF) && nImmuneLevel < 4 &&
|
||||
((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 2) || bIgnoreSaves))
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
bSetAOE = TRUE;
|
||||
// Nearest string of tag
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_EVARDS_BLACK_TENTACLES, oCaster);
|
||||
}
|
||||
@@ -243,11 +258,11 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
// d4 damage. LOTS of speed loss.
|
||||
// Reflex save, or immunity, would stop the speed
|
||||
{
|
||||
if(iImmuneLevel < i3 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MOVEMENT_SPEED_DECREASE) || iIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < iSaveDC + i5) || iIgnoreSaves))
|
||||
if(nImmuneLevel < 3 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MOVEMENT_SPEED_DECREASE) || bIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 5) || bIgnoreSaves))
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
bSetAOE = TRUE;
|
||||
// Both use ENTANGLE AOE's
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_ENTANGLE, oCaster);
|
||||
}
|
||||
@@ -256,12 +271,12 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
case SPELL_ENTANGLE:
|
||||
case SPELL_VINE_MINE_ENTANGLE:
|
||||
{
|
||||
if(iImmuneLevel < i1 &&
|
||||
(!GetHasFeat(FEAT_WOODLAND_STRIDE) || iIgnoreImmunities) &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || iIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < iSaveDC + i4) || iIgnoreSaves))
|
||||
if(nImmuneLevel < 1 &&
|
||||
(!GetHasFeat(FEAT_WOODLAND_STRIDE) || bIgnoreImmunities) &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || bIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 4) || bIgnoreSaves))
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
bSetAOE = TRUE;
|
||||
// Both use ENTANGLE AOE's
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_ENTANGLE, oCaster);
|
||||
}
|
||||
@@ -269,12 +284,12 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
break;
|
||||
case SPELL_WEB:
|
||||
{
|
||||
if(iImmuneLevel < i1 &&
|
||||
(!GetHasFeat(FEAT_WOODLAND_STRIDE) || iIgnoreImmunities) &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || iIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < iSaveDC + i4) || iIgnoreSaves))
|
||||
if(nImmuneLevel < 1 &&
|
||||
(!GetHasFeat(FEAT_WOODLAND_STRIDE) || bIgnoreImmunities) &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_ENTANGLE) || bIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 4) || bIgnoreSaves))
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
bSetAOE = TRUE;
|
||||
// Web AOE
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_WEB, oCaster);
|
||||
}
|
||||
@@ -283,12 +298,12 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
// Fort save
|
||||
case SPELL_STINKING_CLOUD:
|
||||
{
|
||||
if(iImmuneLevel < i3 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_POISON) || iIgnoreImmunities) &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_DAZED) || iIgnoreImmunities) &&
|
||||
((GetFortitudeSavingThrow(OBJECT_SELF) < iSaveDC + i6) || iIgnoreSaves))
|
||||
if(nImmuneLevel < 3 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_POISON) || bIgnoreImmunities) &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_DAZED) || bIgnoreImmunities) &&
|
||||
((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 6) || bIgnoreSaves))
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
bSetAOE = TRUE;
|
||||
// Stinking cloud persistant AOE.
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGSTINK, oCaster);
|
||||
}
|
||||
@@ -297,10 +312,10 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
// Fort save
|
||||
case SPELL_CLOUD_OF_BEWILDERMENT:
|
||||
{
|
||||
if(iImmuneLevel < i2 &&
|
||||
((GetFortitudeSavingThrow(OBJECT_SELF) < iSaveDC + i7) || iIgnoreSaves))
|
||||
if(nImmuneLevel < 2 &&
|
||||
((GetFortitudeSavingThrow(OBJECT_SELF) < nSaveDC + 7) || bIgnoreSaves))
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
bSetAOE = TRUE;
|
||||
// Bewilderment cloud persistant AOE.
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGBEWILDERMENT, oCaster);
|
||||
}
|
||||
@@ -309,11 +324,11 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
// Special: Mind save is the effect.
|
||||
case SPELL_STONEHOLD:
|
||||
{
|
||||
if(iImmuneLevel < i6 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MIND_SPELLS) || iIgnoreImmunities) &&
|
||||
((GetWillSavingThrow(OBJECT_SELF) < iSaveDC + i7) || iIgnoreSaves))
|
||||
if(nImmuneLevel < 6 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_MIND_SPELLS) || bIgnoreImmunities) &&
|
||||
((GetWillSavingThrow(OBJECT_SELF) < nSaveDC + 7) || bIgnoreSaves))
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
bSetAOE = TRUE;
|
||||
// Stonehold persistant AOE.
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_STONEHOLD, oCaster);
|
||||
}
|
||||
@@ -322,11 +337,11 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
// Special: EFFECT_TYPE_SAVING_THROW_DECREASE is the effect.
|
||||
case SPELL_MIND_FOG:
|
||||
{
|
||||
if(iImmuneLevel < i5 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_SAVING_THROW_DECREASE) || iIgnoreImmunities) &&
|
||||
((GetWillSavingThrow(OBJECT_SELF) < iSaveDC + i6) || iIgnoreSaves))
|
||||
if(nImmuneLevel < 5 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_SAVING_THROW_DECREASE) || bIgnoreImmunities) &&
|
||||
((GetWillSavingThrow(OBJECT_SELF) < nSaveDC + 6) || bIgnoreSaves))
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
bSetAOE = TRUE;
|
||||
// Mind fog
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGMIND, oCaster);
|
||||
}
|
||||
@@ -335,12 +350,12 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
// Special: Feats, knockdown
|
||||
case SPELL_GREASE:
|
||||
{
|
||||
if(iImmuneLevel < i1 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_KNOCKDOWN) || iIgnoreImmunities) &&
|
||||
(!GetHasFeat(FEAT_WOODLAND_STRIDE, OBJECT_SELF) || iIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < iSaveDC + i2) || iIgnoreSaves))
|
||||
if(nImmuneLevel < 1 &&
|
||||
(!GetIsImmune(OBJECT_SELF, IMMUNITY_TYPE_KNOCKDOWN) || bIgnoreImmunities) &&
|
||||
(!GetHasFeat(FEAT_WOODLAND_STRIDE, OBJECT_SELF) || bIgnoreImmunities) &&
|
||||
((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 2) || bIgnoreSaves))
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
bSetAOE = TRUE;
|
||||
// Grease
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_GREASE, oCaster);
|
||||
}
|
||||
@@ -351,23 +366,23 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
case SPELL_INCENDIARY_CLOUD:// reflex
|
||||
case SPELL_WALL_OF_FIRE:// Reflex
|
||||
{
|
||||
if(iImmuneLevel < i6 &&
|
||||
(((GetReflexSavingThrow(OBJECT_SELF) < iSaveDC + i6) &&
|
||||
if(nImmuneLevel < 6 &&
|
||||
(((GetReflexSavingThrow(OBJECT_SELF) < nSaveDC + 6) &&
|
||||
!GetHasFeat(FEAT_IMPROVED_EVASION) &&
|
||||
!GetHasFeat(FEAT_EVASION)) || iIgnoreSaves))
|
||||
!GetHasFeat(FEAT_EVASION)) || bIgnoreSaves))
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
if(iSpellCast == SPELL_BLADE_BARRIER)
|
||||
bSetAOE = TRUE;
|
||||
if(nSpellCast == SPELL_BLADE_BARRIER)
|
||||
{
|
||||
// BB
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_WALLBLADE, oCaster);
|
||||
}
|
||||
else if(iSpellCast == SPELL_INCENDIARY_CLOUD)
|
||||
else if(nSpellCast == SPELL_INCENDIARY_CLOUD)
|
||||
{
|
||||
// Fog of fire
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGFIRE, oCaster);
|
||||
}
|
||||
else if(iSpellCast == SPELL_WALL_OF_FIRE)
|
||||
else if(nSpellCast == SPELL_WALL_OF_FIRE)
|
||||
{
|
||||
// Wall of fire
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_WALLFIRE, oCaster);
|
||||
@@ -379,20 +394,20 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
case SPELL_CLOUDKILL:// No save!
|
||||
case SPELL_CREEPING_DOOM: // No save!
|
||||
{
|
||||
if(iImmuneLevel < i6)
|
||||
if(nImmuneLevel < 6)
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
if(iSpellCast == SPELL_ACID_FOG)
|
||||
bSetAOE = TRUE;
|
||||
if(nSpellCast == SPELL_ACID_FOG)
|
||||
{
|
||||
// Acid fog
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGACID, oCaster);
|
||||
}
|
||||
else if(iSpellCast == SPELL_CLOUDKILL)
|
||||
else if(nSpellCast == SPELL_CLOUDKILL)
|
||||
{
|
||||
// Cloud Kill
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_FOGKILL, oCaster);
|
||||
}
|
||||
else if(iSpellCast == SPELL_CREEPING_DOOM)
|
||||
else if(nSpellCast == SPELL_CREEPING_DOOM)
|
||||
{
|
||||
// Creeping doom
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_CREEPING_DOOM, oCaster);
|
||||
@@ -402,28 +417,28 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
// Storm - because the AI likes it, we stay in it if it is ours :-)
|
||||
case SPELL_STORM_OF_VENGEANCE: // Reflex partial. No check, always damages.
|
||||
{
|
||||
if(oCaster != OBJECT_SELF && iImmuneLevel < i9)
|
||||
if(oCaster != OBJECT_SELF && nImmuneLevel < 9)
|
||||
{
|
||||
SetAOE = TRUE;
|
||||
bSetAOE = TRUE;
|
||||
// Storm of vengance
|
||||
oAOE = GetNearestAOECastBy(AI_AOE_PER_STORM, oCaster);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(SetAOE)
|
||||
if(bSetAOE)
|
||||
{
|
||||
if(!GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(iSpellCast)))
|
||||
if(!GetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast)))
|
||||
{
|
||||
SetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(iSpellCast), f18);
|
||||
SetLocalTimer(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast), 18.0);
|
||||
// Set nearest AOE
|
||||
if(GetIsObjectValid(oAOE))
|
||||
{
|
||||
// Set nearest AOE of this spell to the local
|
||||
object oNearest = GetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(iSpellCast));
|
||||
object oNearest = GetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast));
|
||||
if(GetDistanceToObject(oAOE) < GetDistanceToObject(oNearest) ||
|
||||
!GetIsObjectValid(oNearest))
|
||||
{
|
||||
SetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(iSpellCast), oAOE);
|
||||
SetAIObject(AI_TIMER_AOE_SPELL_EVENT + IntToString(nSpellCast), oAOE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,8 +447,8 @@ void SetAOESpell(int iSpellCast, object oCaster)
|
||||
// Gets the nearest AOE cast by oCaster, of sTag.
|
||||
object GetNearestAOECastBy(string sTag, object oCaster)
|
||||
{
|
||||
int iCnt = i1;
|
||||
object oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, iCnt);
|
||||
int nCnt = 1;
|
||||
object oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, nCnt);
|
||||
object oReturn = OBJECT_INVALID;
|
||||
// Loop
|
||||
while(GetIsObjectValid(oAOE) && !GetIsObjectValid(oReturn))
|
||||
@@ -443,8 +458,8 @@ object GetNearestAOECastBy(string sTag, object oCaster)
|
||||
{
|
||||
oReturn = oAOE;
|
||||
}
|
||||
iCnt++;
|
||||
oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, iCnt);
|
||||
nCnt++;
|
||||
oAOE = GetNearestObjectByTag(sTag, OBJECT_SELF, nCnt);
|
||||
}
|
||||
return oReturn;
|
||||
}
|
||||
@@ -452,27 +467,27 @@ object GetNearestAOECastBy(string sTag, object oCaster)
|
||||
// Gets the amount of protections we have - IE globes
|
||||
int GetOurSpellLevelImmunity()
|
||||
{
|
||||
int iNatural = GetLocalInt(OBJECT_SELF, AI_SPELL_IMMUNE_LEVEL);
|
||||
int nNatural = GetLocalInt(OBJECT_SELF, AI_SPELL_IMMUNE_LEVEL);
|
||||
// Stop here, if natural is over 4
|
||||
if(iNatural > i4) return iNatural;
|
||||
if(nNatural > 4) return nNatural;
|
||||
|
||||
// Big globe affects 4 or lower spells
|
||||
if(GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, OBJECT_SELF) || iNatural >= i4)
|
||||
return i4;
|
||||
if(GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY, OBJECT_SELF) || nNatural >= 4)
|
||||
return 4;
|
||||
// Minor globe is 3 or under
|
||||
if(GetHasSpellEffect(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, OBJECT_SELF) ||
|
||||
// Shadow con version
|
||||
GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MINOR_GLOBE, OBJECT_SELF) ||
|
||||
iNatural >= i3)
|
||||
return i3;
|
||||
nNatural >= 3)
|
||||
return 3;
|
||||
// 2 and under is ethereal visage.
|
||||
if(GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, OBJECT_SELF) || iNatural >= i2)
|
||||
return i2;
|
||||
if(GetHasSpellEffect(SPELL_ETHEREAL_VISAGE, OBJECT_SELF) || nNatural >= 2)
|
||||
return 2;
|
||||
// Ghostly Visarge affects 1 or 0 level spells, and any spell immunity.
|
||||
if(GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, OBJECT_SELF) || iNatural >= i1 ||
|
||||
if(GetHasSpellEffect(SPELL_GHOSTLY_VISAGE, OBJECT_SELF) || nNatural >= 1 ||
|
||||
// Or shadow con version.
|
||||
GetHasSpellEffect(SPELL_GREATER_SHADOW_CONJURATION_MIRROR_IMAGE, OBJECT_SELF))
|
||||
return i1;
|
||||
// Return iNatural, which is 0-9
|
||||
return 1;
|
||||
// Return nNatural, which is 0-9
|
||||
return FALSE;
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/************************ [On User Defined] ************************************
|
||||
Filename: j_ai_onuserdef or nw_c2_defaultd
|
||||
************************* [Workings] *******************************************
|
||||
This is NOT needed, but I have, because of new Pre-events, added it to the
|
||||
files for completeness and documentation.
|
||||
/*/////////////////////// [On User Defined] ////////////////////////////////////
|
||||
Filename: J_AI_OnUserDef or nw_c2_defaultd
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
1.4 Adds proper Pre-event functionality. Use this to make sure you keep the
|
||||
AI working, but making small additions using this event.
|
||||
|
||||
Can be deleted to save space if you want :-)
|
||||
|
||||
@@ -47,23 +47,29 @@
|
||||
|
||||
You can delete sections you don't need, and is recommended as long as you know
|
||||
how to use User Defined events.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.3 - Added in with some documentation
|
||||
************************* [Arguments] ******************************************
|
||||
1.4 - Changed Pre-events. Now, it uses Execute Script. Will need to set
|
||||
a special string on the creature to now what script to fire.
|
||||
- It means they work correctly, however!
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: Dependant on event. See seperate event scripts.
|
||||
************************* [On User Defined] ***********************************/
|
||||
///////////////////////// [On User Defined] //////////////////////////////////*/
|
||||
|
||||
// This contains a lot of useful things.
|
||||
// - Combat starting
|
||||
// - Constant values
|
||||
// - Get/Set spawn in values.
|
||||
#include "j_inc_other_ai"
|
||||
#include "J_INC_OTHER_AI"
|
||||
// This contains some useful things to get NPC's to attack and so on.
|
||||
#include "j_inc_npc_attack"
|
||||
#include "J_INC_NPC_ATTACK"
|
||||
|
||||
/************************ [UDE Values] *****************************************
|
||||
These are uneeded, but here for reference. Use the constants in the file
|
||||
"j_inc_constants" like "EVENT_HEARTBEAT_PRE_EVENT" which is classed as 1021.
|
||||
* The normal death event might not fire before the creature has vanished.
|
||||
Use the Pre-event (but with no stopping the death event) if you want a special
|
||||
death event to happen.
|
||||
|
||||
Name Normal-End event - Pre-Event
|
||||
Heartbeat Event 1001 1021
|
||||
@@ -84,9 +90,11 @@
|
||||
void main()
|
||||
{
|
||||
// Get the user defined number.
|
||||
int iEvent = GetUserDefinedEventNumber();
|
||||
// * NOTE: YOU MUST USE AI_GetUDENumber(), not GetUserDefinedEventNumber()!
|
||||
int nEvent = AI_GetUDENumber();
|
||||
|
||||
// Events.
|
||||
switch(iEvent)
|
||||
switch(nEvent)
|
||||
{
|
||||
// Event Heartbeat
|
||||
// Arguments: Basically, none. Nothing activates this script. Fires every 6 seconds.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/************************ [On Blocked] *****************************************
|
||||
Filename: j_ai_onblocked or nw_c2_defaulte
|
||||
************************* [On Blocked] *****************************************
|
||||
/*/////////////////////// [On Blocked] /////////////////////////////////////////
|
||||
Filename: J_AI_OnBlocked or nw_c2_defaulte
|
||||
///////////////////////// [On Blocked] /////////////////////////////////////////
|
||||
Added in user defined constant - won't open any doors.
|
||||
0 = Default (even if not set) opens as appropriate
|
||||
1 = Always bashes the door.
|
||||
@@ -16,14 +16,20 @@
|
||||
|
||||
Note: This also fires for blocking via. creatures. It is optimised, and
|
||||
works by re-targeting and doing a few small things to do with blocking.
|
||||
************************* [History] ********************************************
|
||||
///////////////////////// [History] ////////////////////////////////////////////
|
||||
1.0 - Opens with Knock. Unlocks door. Ignores trapped doors.
|
||||
1.3 - Debug messages.
|
||||
- New events, even if the change of using them is small!
|
||||
- No ClearAllactions so any previous movings will carry on once the door is gone.
|
||||
- Removed debug messages
|
||||
1.3 - Added Creature reaction code
|
||||
************************* [Workings] *******************************************
|
||||
- Added Creature reaction code
|
||||
1.4 - Need to add a "hands" check (done on spawn, to set a setting to not
|
||||
open doors at all, IE: We do NOT have hands, do not open doors), so
|
||||
its a little more realistic "out of the box"
|
||||
- Fixed an instance of GetObjectSeen being repeated.
|
||||
- Fixed the variable AI_DOOR_INTELLIGENCE not being got via GetAIInteger().
|
||||
- Removed unneeded else statement.
|
||||
///////////////////////// [Workings] ///////////////////////////////////////////
|
||||
Uses simple code to deal with a door in the best way possible.
|
||||
|
||||
Uses DoDoorAction, which is added to the top of an action queue and doesn't,
|
||||
@@ -31,10 +37,10 @@
|
||||
is like this)
|
||||
|
||||
Creatures are reacted by with ClearAllActions usually.
|
||||
************************* [Arguments] ******************************************
|
||||
///////////////////////// [Arguments] //////////////////////////////////////////
|
||||
Arguments: GetBlockingDoor, GetIsDoorActionPossible, GetLocked, GetLockKeyRequired
|
||||
GetLockKeyTag, GetLockUnlockDC, GetPlotFlag, DoDoorAction
|
||||
************************* [On Blocked] ****************************************/
|
||||
///////////////////////// [On Blocked] ///////////////////////////////////////*/
|
||||
|
||||
#include "J_INC_OTHER_AI"
|
||||
|
||||
@@ -45,10 +51,8 @@ int RangedAttack(object oTarget = OBJECT_INVALID);
|
||||
|
||||
void main()
|
||||
{
|
||||
// Pre-blocked-event
|
||||
if(FireUserEvent(AI_FLAG_UDE_ON_BLOCKED_PRE_EVENT, EVENT_ON_BLOCKED_PRE_EVENT))
|
||||
// We may exit if it fires
|
||||
if(ExitFromUDE(EVENT_ON_BLOCKED_PRE_EVENT)) return;
|
||||
// Pre-on blocked-event. Returns TRUE if we interrupt this script call.
|
||||
if(FirePreUserEvent(AI_FLAG_UDE_ON_BLOCKED_PRE_EVENT, EVENT_ON_BLOCKED_PRE_EVENT)) return;
|
||||
|
||||
// AI status check. Is the AI on?
|
||||
if(GetAIOff()) return;
|
||||
@@ -74,19 +78,20 @@ void main()
|
||||
if(GetLocalTimer(AI_TIMER_BLOCKED)) return;
|
||||
|
||||
// Set the timer for 1 second
|
||||
SetLocalTimer(AI_TIMER_BLOCKED, f1);
|
||||
SetLocalTimer(AI_TIMER_BLOCKED, 1.0);
|
||||
|
||||
// Is it an enemy?
|
||||
if(GetIsEnemy(oBlocker))
|
||||
{
|
||||
// Check if seen or heard
|
||||
if(GetObjectSeen(oBlocker) || GetObjectSeen(oBlocker))
|
||||
if(GetObjectSeen(oBlocker) || GetObjectHeard(oBlocker))
|
||||
{
|
||||
// Enemy :-) We can re-target (as know of thier presence), using
|
||||
// them as a target.
|
||||
// - This overrides even casting a spell - basically, as we should
|
||||
// be moving, this will re-cast it at someone or something in range
|
||||
SetAIObject(AI_ATTACK_SPECIFIC_OBJECT, oBlocker);
|
||||
|
||||
// Check if we can do combat - if we cannot, we can re-do combat
|
||||
// next time
|
||||
if(!GetIsBusyWithAction())
|
||||
@@ -106,6 +111,9 @@ void main()
|
||||
{
|
||||
SetAIObject(AI_LAST_TO_GO_INVISIBLE, oBlocker);
|
||||
}
|
||||
// Shout to allies
|
||||
AISpeakString(AI_SHOUT_CALL_TO_ARMS);
|
||||
|
||||
// Check if we can do combat
|
||||
if(!GetIsBusyWithAction())
|
||||
{
|
||||
@@ -125,42 +133,62 @@ void main()
|
||||
|
||||
// Were we attacking in combat?
|
||||
object oPrevious = GetAttackTarget();
|
||||
|
||||
// Check action
|
||||
if(GetCurrentAction() == ACTION_ATTACKOBJECT)
|
||||
{
|
||||
// Action attack, normally means melee attack. If we can, we
|
||||
// attack our previous target if seen, ELSE we will re-initate
|
||||
// combat.
|
||||
AISpeakString(I_WAS_ATTACKED);
|
||||
// This gets set to FALSE if we can cutthrough attack,
|
||||
// or whatever.
|
||||
|
||||
int bPreviousAttackFailed = FALSE;
|
||||
// Check if we can see our previous target
|
||||
if(GetObjectSeen(oPrevious) ||
|
||||
(GetObjectHeard(oPrevious) && LineOfSightObject(OBJECT_SELF, oPrevious)))
|
||||
{
|
||||
// We can! see if we can re-attack with ranged weapon, else
|
||||
// doesn't matter we can see them
|
||||
if(RangedAttack(oPrevious)) return;
|
||||
bPreviousAttackFailed = RangedAttack(oPrevious);
|
||||
}
|
||||
else
|
||||
// We have not stopped the script - so determine combat
|
||||
// round against nearest seen or heard enemy!
|
||||
if(RangedAttack()) return;
|
||||
// Else normal round to try and get a new target
|
||||
ClearAllActions();
|
||||
DetermineCombatRound();
|
||||
|
||||
// If we havn't added an action yet...
|
||||
if(bPreviousAttackFailed == FALSE)
|
||||
{
|
||||
// We have not stopped the script - so determine combat
|
||||
// round against nearest seen or heard enemy!
|
||||
if(!RangedAttack())
|
||||
{
|
||||
// Else normal round to try and get a new target
|
||||
ClearAllActions();
|
||||
DetermineCombatRound();
|
||||
}
|
||||
}
|
||||
// Action attack, normally means melee attack. If we can, we
|
||||
// attack our previous target if seen, ELSE we will re-initate
|
||||
// combat.
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
|
||||
// Fire the On blocked event as normal
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
else // if(iAction == ACTION_CASTSPELL and others)
|
||||
else // if(nAction == ACTION_CASTSPELL and others)
|
||||
{
|
||||
// Reinitate combat
|
||||
// Reinitate combat, but don't attack oPrevious
|
||||
ClearAllActions();
|
||||
DetermineCombatRound();
|
||||
|
||||
// Action attack, normally means melee attack. If we can, we
|
||||
// attack our previous target if seen, ELSE we will re-initate
|
||||
// combat.
|
||||
AISpeakString(AI_SHOUT_I_WAS_ATTACKED);
|
||||
|
||||
// Fire the On blocked event as normal
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Placeable - Not sure it can be returned, however, we can add it to the
|
||||
// type if/else check.
|
||||
// Placeable - Currently not returned, however, added just in case!
|
||||
else if(nBlockerType == OBJECT_TYPE_PLACEABLE)
|
||||
{
|
||||
// Check for plot, and therefore attack it to bring it down.
|
||||
@@ -171,26 +199,29 @@ void main()
|
||||
{
|
||||
// Do placeable action
|
||||
DoPlaceableObjectAction(oBlocker, PLACEABLE_ACTION_BASH);
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Door behaviour
|
||||
else if(nBlockerType == OBJECT_TYPE_DOOR)
|
||||
{
|
||||
int iDoorIntelligence = GetLocalInt(OBJECT_SELF, AI_DOOR_INTELLIGENCE);
|
||||
int iInt = GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE);
|
||||
if(iDoorIntelligence == i1)// 1 = Always bashes the doors, plot, locked or anything.
|
||||
int nDoorIntelligence = GetAIInteger(AI_DOOR_INTELLIGENCE);
|
||||
int nInt = GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE);
|
||||
if(nDoorIntelligence == 1)// 1 = Always bashes the doors, plot, locked or anything.
|
||||
{
|
||||
DoDoorAction(oBlocker, DOOR_ACTION_BASH);
|
||||
// We re-initiate combat.
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
else if(iDoorIntelligence == i2)// 2 = Never open anything, bashing or not.
|
||||
else if(nDoorIntelligence == 2)// 2 = Never open anything, bashing or not.
|
||||
{
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
else if(iDoorIntelligence == i3)// 3 = Never tries anything against plot doors.
|
||||
else if(nDoorIntelligence == 3)// 3 = Never tries anything against plot doors.
|
||||
{
|
||||
if(GetPlotFlag(oBlocker))
|
||||
{
|
||||
@@ -198,10 +229,10 @@ void main()
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(iInt >= i5)
|
||||
if(nInt >= 5)
|
||||
{
|
||||
// Need some intelligence :-)
|
||||
if(iInt >= i7)
|
||||
if(nInt >= 7)
|
||||
{
|
||||
// Right, first, we may...shock...open it!!!
|
||||
// Checks Key, lock, trap and if the action is possible.
|
||||
@@ -221,17 +252,17 @@ void main()
|
||||
!GetSpawnInCondition(AI_FLAG_OTHER_COMBAT_NO_OPENING_LOCKED_DOORS, AI_OTHER_COMBAT_MASTER) &&
|
||||
!GetLockKeyRequired(oBlocker) && GetHasSkill(SKILL_OPEN_LOCK) &&
|
||||
GetIsDoorActionPossible(oBlocker, DOOR_ACTION_UNLOCK) && !GetIsTrapped(oBlocker) &&
|
||||
(GetSkillRank(SKILL_OPEN_LOCK) >= (GetLockLockDC(oBlocker) - i20)))
|
||||
(GetSkillRank(SKILL_OPEN_LOCK) >= (GetLockLockDC(oBlocker) - 20)))
|
||||
{
|
||||
DoDoorAction(oBlocker, DOOR_ACTION_UNLOCK);
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
// Specilist thing - knock
|
||||
if(iInt >= i10)
|
||||
if(nInt >= 10)
|
||||
{
|
||||
if((GetIsDoorActionPossible(oBlocker, DOOR_ACTION_KNOCK)) &&
|
||||
GetLockUnlockDC(oBlocker) <= i25 &&
|
||||
GetLockUnlockDC(oBlocker) <= 25 &&
|
||||
!GetLockKeyRequired(oBlocker) && GetHasSpell(SPELL_KNOCK))
|
||||
{
|
||||
DoDoorAction(oBlocker, DOOR_ACTION_KNOCK);
|
||||
@@ -239,16 +270,16 @@ void main()
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If Our Int is over 5, we will bash after everything else.
|
||||
if(GetIsDoorActionPossible(oBlocker, DOOR_ACTION_BASH) && !GetPlotFlag(oBlocker))
|
||||
}
|
||||
// If Our Int is over 5, we will bash after everything else.
|
||||
if(GetIsDoorActionPossible(oBlocker, DOOR_ACTION_BASH) && !GetPlotFlag(oBlocker))
|
||||
{
|
||||
if(GetAttackTarget() != oBlocker)
|
||||
{
|
||||
if(GetAttackTarget() != oBlocker)
|
||||
{
|
||||
DoDoorAction(oBlocker, DOOR_ACTION_BASH);
|
||||
}
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
DoDoorAction(oBlocker, DOOR_ACTION_BASH);
|
||||
}
|
||||
FireBlockedEvent();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,11 +315,13 @@ int RangedAttack(object oTarget)
|
||||
// Ranged weapon attack against oTarget
|
||||
// doesn't matter we can see them
|
||||
object oRanged = GetAIObject(AI_WEAPON_RANGED);
|
||||
int iAmmo = GetAIInteger(AI_WEAPON_RANGED_AMMOSLOT);
|
||||
int nAmmo = GetAIInteger(AI_WEAPON_RANGED_AMMOSLOT);
|
||||
|
||||
// Check ammo and validness
|
||||
if(GetIsObjectValid(oRanged) && (iAmmo == INVENTORY_SLOT_RIGHTHAND ||
|
||||
GetIsObjectValid(GetItemInSlot(iAmmo))))
|
||||
if(GetIsObjectValid(oRanged) && (nAmmo == INVENTORY_SLOT_RIGHTHAND ||
|
||||
GetIsObjectValid(GetItemInSlot(nAmmo))))
|
||||
{
|
||||
// Attack with it
|
||||
ClearAllActions();
|
||||
ActionEquipItem(oRanged, INVENTORY_SLOT_RIGHTHAND);
|
||||
ActionAttack(oRangedTarget);
|
||||
|
@@ -29,7 +29,7 @@ void main()
|
||||
// These MUST be called! the AI might fail to work correctly if they don't fire!
|
||||
|
||||
// Note: You shouldn't really remove this. Also performs hiding ETC.
|
||||
DelayCommand(f2, SpawnWalkWayPoints());
|
||||
DelayCommand(2.0f, SpawnWalkWayPoints());
|
||||
// Delayed walk waypoints, as to not upset instant combat spawning.
|
||||
// This will also check if to change to day/night posts during the walking, no heartbeats.
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@ void main()
|
||||
}
|
||||
|
||||
// Note: You shouldn't really remove this. Also performs hiding ETC.
|
||||
DelayCommand(f2, SpawnWalkWayPoints());
|
||||
DelayCommand(2.0f, SpawnWalkWayPoints());
|
||||
// Delayed walk waypoints, as to not upset instant combat spawning.
|
||||
// This will also check if to change to day/night posts during the walking, no heartbeats.
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ void main()
|
||||
// These MUST be called! the AI might fail to work correctly if they don't fire!
|
||||
|
||||
// Note: You shouldn't really remove this. Also performs hiding ETC.
|
||||
DelayCommand(f2, SpawnWalkWayPoints());
|
||||
DelayCommand(2.0f, SpawnWalkWayPoints());
|
||||
// Delayed walk waypoints, as to not upset instant combat spawning.
|
||||
// This will also check if to change to day/night posts during the walking, no heartbeats.
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ void main()
|
||||
|
||||
int nUser = GetUserDefinedEventNumber();
|
||||
int nChange = GetLocalInt(OBJECT_SELF,"NW_LYCANTHROPE");
|
||||
effect eShape = EffectPolymorph(POLYMORPH_TYPE_RAKSHASA); //Use one of the polymorph constants here (WERE_RAT, WERE_WOLF or WERE_CAT)
|
||||
effect eShape = EffectPolymorph(88); //Use one of the polymorph constants here (WERE_RAT, WERE_WOLF or WERE_CAT)
|
||||
effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD);
|
||||
if(nUser == 1005 && nChange == 0)
|
||||
{
|
||||
|
@@ -54,3 +54,4 @@ void main()
|
||||
|
||||
effect eStatue = EffectPetrify();
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eStatue, OBJECT_SELF);
|
||||
}
|
@@ -11,17 +11,10 @@
|
||||
//:: Created On: September 2003
|
||||
//:://////////////////////////////////////////////
|
||||
#include "x2_inc_ws_smith"
|
||||
//#include "x2_inc_cutscene"
|
||||
|
||||
|
||||
|
||||
//void StartCutscene(object oPC);
|
||||
//void StartCutscene2(object oPC);
|
||||
void CopyUpgradeItem(object oItem, object oPC);
|
||||
void MakeNewWeapon(object oPC);
|
||||
|
||||
//int nCutsceneNumber = 114;
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
@@ -33,273 +26,8 @@ void main()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//ActionPauseConversation();
|
||||
|
||||
//if(GetTag(GetArea(oPC)) != "HellbreathTavern")
|
||||
{
|
||||
//Only show the cutscene once
|
||||
//if (GetLocalInt(oPC, "X2_Chapter2SmithCut") == 1)
|
||||
//{
|
||||
// MakeNewWeapon(oPC);
|
||||
// return;
|
||||
// }
|
||||
// SetLocalInt(oPC, "X2_Chapter2SmithCut", 1);
|
||||
// DelayCommand(0.7, StartCutscene(oPC));
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
//Only show the cutscene once
|
||||
//if (GetLocalInt(oPC, "X2_Chapter3SmithCut") == 1)
|
||||
//{
|
||||
//MakeNewWeapon(oPC);
|
||||
//return;
|
||||
//}
|
||||
// SetLocalInt(oPC, "X2_Chapter3SmithCut", 1);
|
||||
// DelayCommand(0.7, StartCutscene2(oPC));
|
||||
//}
|
||||
|
||||
//Set Cutscene 114 as active for all future calls to Cut_ commands
|
||||
//CutSetActiveCutscene(nCutsceneNumber, CUT_DELAY_TYPE_CONSTANT);
|
||||
|
||||
//AssignCommand(oPC, ClearAllActions());
|
||||
//Fade PCs to black
|
||||
//BlackScreen(oPC);
|
||||
//CutSetActiveCutsceneForObject(oPC, nCutsceneNumber, TRUE);
|
||||
//CutDisableAbort(nCutsceneNumber);
|
||||
|
||||
//CutSetCutsceneMode(0.5, oPC, TRUE, TRUE, TRUE, TRUE); // pc invis - keep and freeze associates
|
||||
|
||||
//CutFadeFromBlack(1.5, oPC, FADE_SPEED_MEDIUM, FALSE);
|
||||
|
||||
|
||||
//}
|
||||
|
||||
//void StartCutscene(object oPC)
|
||||
//{
|
||||
|
||||
//Change the Music
|
||||
//object oArea = GetArea(oPC);
|
||||
//MusicBattlePlay(oArea);
|
||||
// Cutscene actors and objects.
|
||||
// Invisible creature "takes" item
|
||||
|
||||
//location lLoc = GetLocation(GetNearestObjectByTag("SpawnHere"));
|
||||
//object oHelper = CreateObject(OBJECT_TYPE_CREATURE, "x2_helper", lLoc);
|
||||
//object oSmith = OBJECT_SELF;
|
||||
//object oForge = GetNearestObjectByTag("x2_magic_forge");
|
||||
|
||||
//CutSetActiveCutsceneForObject(oHelper, nCutsceneNumber);
|
||||
//CutSetActiveCutsceneForObject(oSmith, nCutsceneNumber);
|
||||
//CutSetActiveCutsceneForObject(oForge, nCutsceneNumber);
|
||||
|
||||
//CutApplyEffectToObject2(0.0, DURATION_TYPE_PERMANENT, EffectCutsceneGhost(), oHelper);
|
||||
//Locations
|
||||
//location lForge = GetLocation(GetNearestObjectByTag("X2_Forge"));
|
||||
|
||||
//Camera waypoints
|
||||
//object oCamera1 = GetNearestObjectByTag("wp_cut114_camera1");
|
||||
//location lCamera1 = GetLocation(GetNearestObjectByTag("wp_cut114_camera1"));
|
||||
//location lCamera2 = GetLocation(GetNearestObjectByTag("wp_cut114_camera2"));
|
||||
|
||||
//Make a copy of the PC to move about
|
||||
//location lStart = GetLocation(oPC);
|
||||
//object oCopy = CutCreatePCCopy(oPC, lStart, "Cut114PCCopy");
|
||||
//ChangeToStandardFaction(oCopy, STANDARD_FACTION_COMMONER);
|
||||
//CutSetActiveCutsceneForObject(oCopy, nCutsceneNumber);
|
||||
|
||||
// Camera movements (includes moving the PC as the camera.
|
||||
//////////////////////////////////////////////////////////
|
||||
//CutJumpToObject(0.0, oPC, oCamera1, TRUE);
|
||||
//CutSetCamera(0.0, oPC, CAMERA_MODE_TOP_DOWN, 90.0, 10.0, 75.0,
|
||||
// CAMERA_TRANSITION_TYPE_SNAP);
|
||||
//CutSetCamera(0.2, oPC, CAMERA_MODE_TOP_DOWN, 150.0, 13.0, 50.0,
|
||||
//CAMERA_TRANSITION_TYPE_SLOW);
|
||||
|
||||
//CutActionMoveToLocation(0.2, oPC, lCamera2, FALSE, FALSE);
|
||||
// Smith chants
|
||||
//CutPlayAnimation(0.7, oSmith, ANIMATION_LOOPING_MEDITATE, 6.0, FALSE);
|
||||
// CutPlaySound(0.5, oSmith, "al_mg_chntmagic1", FALSE);
|
||||
|
||||
|
||||
// * Make creature invisible and non bumpable
|
||||
// effect eInvis = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY);
|
||||
// ApplyEffectToObject(DURATION_TYPE_PERMANENT, eInvis, oHelper);
|
||||
//effect eNoBump = EffectCutsceneGhost();
|
||||
//CutApplyEffectToObject2(0.0, DURATION_TYPE_PERMANENT, eNoBump, oHelper);
|
||||
|
||||
//object oItem = GetRightHandWeapon(oCopy);
|
||||
// object oItem2 = GetRightHandWeapon(oPC);
|
||||
|
||||
// SpeakString("OLD " + GetName(oItem));
|
||||
// object oNewItem = CopyItem(oItem, oHelper, TRUE);
|
||||
// SpeakString("NEW " + GetName(oNewItem));
|
||||
|
||||
//AssignCommand(oPC, ActionUnequipItem(oItem)); // * unequip the item
|
||||
//object oNewItem = CopyItem(oItem, oCopy, TRUE);
|
||||
|
||||
// DelayCommand(2.0, AssignCommand(oCopy, ActionGiveItem(oNewItem, oHelper)));
|
||||
|
||||
//DestroyObject(oItem, 2.0);
|
||||
//DestroyObject(oItem2, 2.0);
|
||||
//CutClearAllActions(1.5, oHelper, FALSE);
|
||||
//CutActionEquipItem(2.4, oHelper, oNewItem, INVENTORY_SLOT_RIGHTHAND);
|
||||
|
||||
// Runs up to forge
|
||||
|
||||
//CutActionMoveToLocation(3.0, oHelper, lForge, FALSE, FALSE);
|
||||
|
||||
// * Need visual effects to hide the sword moving from you to the object
|
||||
// Light up Forge
|
||||
// effect eStrike = EffectVisualEffect(VFX_FNF_STRIKE_HOLY);
|
||||
//effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_BUMP);
|
||||
//effect eLink = EffectLinkEffects(eStrike, eShake);
|
||||
//CutApplyEffectToObject2(5.0, DURATION_TYPE_INSTANT, eLink, oForge);
|
||||
//CutPlayAnimation(5.0, oForge, ANIMATION_PLACEABLE_ACTIVATE, 5.0, FALSE);
|
||||
|
||||
// effect eRing = EffectVisualEffect(VFX_DUR_ELEMENTAL_SHIELD);
|
||||
// CutApplyEffectToObject(6.1, DURATION_TYPE_TEMPORARY, VFX_DUR_ELEMENTAL_SHIELD, oHelper, 0.7);
|
||||
|
||||
// Item is enhanced
|
||||
//DelayCommand(6.0, wsEnhanceItem(oHelper, oPC));
|
||||
|
||||
//Copy the upgraded item into the PCs inventory
|
||||
//DelayCommand(7.0, CopyUpgradeItem(oNewItem, oPC));
|
||||
|
||||
//CutPlayAnimation(6.0, oHelper, ANIMATION_FIREFORGET_VICTORY2, 3.0, FALSE);
|
||||
|
||||
// Weapon Given back to player
|
||||
//CutClearAllActions(7.5, oHelper, FALSE, FALSE);
|
||||
//CutActionMoveToObject(8.0, oHelper, oCopy, TRUE);
|
||||
// DelayCommand(9.7, AssignCommand(oHelper, ActionGiveItem(oNewItem, oCopy)));
|
||||
//DelayCommand(11.0, AssignCommand(oCopy, ActionEquipItem(oNewItem, INVENTORY_SLOT_RIGHTHAND)));
|
||||
//CutPlayAnimation(12.0, oCopy, ANIMATION_FIREFORGET_VICTORY2, 2.0);
|
||||
// End Cutscene
|
||||
|
||||
//CutFadeOutAndIn(13.0, oPC);
|
||||
|
||||
|
||||
//Clean up actors...
|
||||
//CutDestroyObject(14.3, oHelper);
|
||||
|
||||
//CutDisableCutscene(nCutsceneNumber, 14.5, 14.5, RESTORE_TYPE_COPY);
|
||||
|
||||
// * Resume conversation - Cleanup
|
||||
|
||||
//DelayCommand(15.5, ActionResumeConversation());
|
||||
|
||||
}
|
||||
|
||||
//void StartCutscene2(object oPC)
|
||||
{
|
||||
//Change the Music
|
||||
//object oArea = GetArea(oPC);
|
||||
//MusicBattlePlay(oArea);
|
||||
// Cutscene actors and objects.
|
||||
// Invisible creature "takes" item
|
||||
|
||||
//location lLoc = GetLocation(GetNearestObjectByTag("SpawnHere"));
|
||||
//object oHelper = CreateObject(OBJECT_TYPE_CREATURE, "x2_helper", lLoc);
|
||||
//object oSmith = OBJECT_SELF;
|
||||
//object oForge = GetNearestObjectByTag("x2_magic_forge");
|
||||
|
||||
//CutSetActiveCutsceneForObject(oHelper, nCutsceneNumber);
|
||||
//CutSetActiveCutsceneForObject(oSmith, nCutsceneNumber);
|
||||
//CutSetActiveCutsceneForObject(oForge, nCutsceneNumber);
|
||||
//Locations
|
||||
// location lForge = GetLocation(GetNearestObjectByTag("X2_Forge"));
|
||||
|
||||
//Camera waypoints
|
||||
//object oCamera1 = GetNearestObjectByTag("wp_cut114_camera1");
|
||||
// location lCamera1 = GetLocation(GetNearestObjectByTag("wp_cut114_camera1"));
|
||||
//location lCamera2 = GetLocation(GetNearestObjectByTag("wp_cut114_camera2"));
|
||||
|
||||
//Make a copy of the PC to move about
|
||||
//location lStart = GetLocation(GetNearestObjectByTag("hx_smith_wp", oPC));
|
||||
//object oCopy = CutCreatePCCopy(oPC, lStart, "Cut114PCCopy");
|
||||
//ChangeToStandardFaction(oCopy, STANDARD_FACTION_COMMONER);
|
||||
//CutSetActiveCutsceneForObject(oCopy, nCutsceneNumber);
|
||||
|
||||
// Camera movements (includes moving the PC as the camera.
|
||||
//////////////////////////////////////////////////////////
|
||||
//CutJumpToObject(0.0, oPC, oCamera1, TRUE);
|
||||
//CutSetCamera(0.0, oPC, CAMERA_MODE_TOP_DOWN, 40.0, 6.0, 80.0,
|
||||
// CAMERA_TRANSITION_TYPE_SNAP);
|
||||
// CutSetCamera(0.2, oPC, CAMERA_MODE_TOP_DOWN, 40.0, 3.0, 80.0,
|
||||
// CAMERA_TRANSITION_TYPE_VERY_SLOW);
|
||||
// Smith chants
|
||||
//CutPlayAnimation(0.7, oSmith, ANIMATION_LOOPING_MEDITATE, 6.0, FALSE);
|
||||
//CutPlaySound(0.5, oSmith, "al_mg_chntmagic1", FALSE);
|
||||
|
||||
|
||||
// * Make creature invisible and non bumpable
|
||||
// effect eInvis = EffectVisualEffect(VFX_DUR_CUTSCENE_INVISIBILITY);
|
||||
// ApplyEffectToObject(DURATION_TYPE_PERMANENT, eInvis, oHelper);
|
||||
//effect eNoBump = EffectCutsceneGhost();
|
||||
// CutApplyEffectToObject2(0.0, DURATION_TYPE_PERMANENT, eNoBump, oHelper);
|
||||
|
||||
// object oItem = GetRightHandWeapon(oCopy);
|
||||
// object oItem2 = GetRightHandWeapon(oPC);
|
||||
|
||||
// SpeakString("OLD " + GetName(oItem));
|
||||
// object oNewItem = CopyItem(oItem, oHelper, TRUE);
|
||||
// SpeakString("NEW " + GetName(oNewItem));
|
||||
|
||||
//AssignCommand(oPC, ActionUnequipItem(oItem)); // * unequip the item
|
||||
//object oNewItem = CopyItem(oItem, oCopy, TRUE);
|
||||
|
||||
//
|
||||
//DelayCommand(2.0, AssignCommand(oCopy, ActionGiveItem(oNewItem, oHelper)));
|
||||
|
||||
// DestroyObject(oItem, 2.0);
|
||||
// DestroyObject(oItem2, 2.0);
|
||||
//CutClearAllActions(1.5, oHelper, FALSE);
|
||||
//CutActionEquipItem(2.4, oHelper, oNewItem, INVENTORY_SLOT_RIGHTHAND);
|
||||
|
||||
// Runs up to forge
|
||||
|
||||
//CutActionMoveToLocation(3.0, oHelper, lForge, FALSE, FALSE);
|
||||
|
||||
// * Need visual effects to hide the sword moving from you to the object
|
||||
// Light up Forge
|
||||
//effect eStrike = EffectVisualEffect(VFX_FNF_STRIKE_HOLY);
|
||||
//effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_BUMP);
|
||||
//effect eLink = EffectLinkEffects(eStrike, eShake);
|
||||
//CutApplyEffectToObject2(5.0, DURATION_TYPE_INSTANT, eLink, oForge);
|
||||
//CutPlayAnimation(5.0, oForge, ANIMATION_PLACEABLE_ACTIVATE, 5.0, FALSE);
|
||||
|
||||
//effect eRing = EffectVisualEffect(VFX_DUR_ELEMENTAL_SHIELD);
|
||||
//CutApplyEffectToObject(6.1, DURATION_TYPE_TEMPORARY, VFX_DUR_ELEMENTAL_SHIELD, oHelper, 0.7);
|
||||
|
||||
// Item is enhanced
|
||||
// DelayCommand(6.0, wsEnhanceItem(oHelper, oPC));
|
||||
|
||||
//Copy the upgraded item into the PCs inventory
|
||||
//DelayCommand(7.0, CopyUpgradeItem(oNewItem, oPC));
|
||||
|
||||
//CutPlayAnimation(6.0, oHelper, ANIMATION_FIREFORGET_VICTORY2, 3.0, FALSE);
|
||||
|
||||
// Weapon Given back to player
|
||||
//CutClearAllActions(7.5, oHelper, FALSE, FALSE);
|
||||
//CutActionMoveToObject(8.0, oHelper, oCopy, TRUE);
|
||||
//DelayCommand(9.7, AssignCommand(oHelper, ActionGiveItem(oNewItem, oCopy)));
|
||||
//DelayCommand(11.0, AssignCommand(oCopy, ActionEquipItem(oNewItem, INVENTORY_SLOT_RIGHTHAND)));
|
||||
// CutPlayAnimation(12.0, oCopy, ANIMATION_FIREFORGET_VICTORY2, 2.0);
|
||||
// End Cutscene
|
||||
|
||||
//CutFadeOutAndIn(13.0, oPC);
|
||||
|
||||
|
||||
//Clean up actors...
|
||||
//CutDestroyObject(14.3, oHelper);
|
||||
|
||||
//CutDisableCutscene(nCutsceneNumber, 14.5, 14.5, RESTORE_TYPE_COPY);
|
||||
|
||||
// * Resume conversation - Cleanup
|
||||
|
||||
// DelayCommand(15.5, ActionResumeConversation());
|
||||
//}
|
||||
|
||||
void CopyUpgradeItem(object oItem, object oPC)
|
||||
{
|
||||
object oNewItem = CopyItem(oItem, oPC, TRUE);
|
||||
|
Reference in New Issue
Block a user