//:://////////////////////////////////////////////////
//:: Default OnSpawn Handler
//:: NW_C2_Default9.nss
//:: Copyright © 2001 Bioware Corp.
//:://////////////////////////////////////////////////
/*
Default OnSpawn handler with NWN Enhanced revisions.
This script has been heavily modified to take advantage of the increased
functionality offered by using variables to modify creature behavior and
call custom OnUserDefined events. Using this system there is no need to
write a custom OnSpawn event script for creatures whose behavior the
Builder wishes to modify.
These switches are more fully explained in the NWN Enhanced Builder's
Guide.
These switches can be used to customize creature behavior in three main
ways:
- Set a variable on a creature to activate certain common desired
behaviors from the moment when it spawns in.
- Set a variable on a creature that signals it to fire user defined
events that you can then handle with a custom OnUserDefined event
handler script.
- Add new code _at the end_ to alter a creature's initial behavior
in a more customized way.
*/
//:://////////////////////////////////////////////////
//:: Copyright © 2002 Floodgate Entertainment
//:: Created By: Naomi Novik
//:: Created On: 12/11/2002
//:://////////////////////////////////////////////////
//:: Updated: 8/20/03 Georg Zoeller - Added check for variables to activate OnSpawn conditions without changing the spawnscript
//:: Updated: 4/30/08 Pstemarie - Converted the default system to use variables set on the creature for ALL behavior states - added switches as necessary.
//:: Updated: 1/31/10 Pstemarie - Eliminated redundant comments and streamlined coding.
//:: Updated: 1/31/10 Pstemarie - Added switches for defining creature behavior (carnivore, herbivore, or omnivore) using variables set on the creature.
//:: Updated: 6/10/10 Pstemarie - Streamlined code
//:://////////////////////////////////////////////////
#include "nw_i0_generic"
#include "x0_i0_anims"
#include "x0_i0_treasure"
#include "x2_inc_switches"
//------------------------------------------------------------------------------
// CONSTANTS
//------------------------------------------------------------------------------
// CREATURE AI OVERRIDES
const string CREATURE_VAR_SPECIAL_CONVERSATION = "X4_SPECIAL_CONVERSATION";
const string CREATURE_VAR_SPECIAL_COMBAT_CONVERSATION = "X4_SPECIAL_COMBAT_CONVERSATION";
const string CREATURE_VAR_AI_ASSIST_ALLIES = "X4_L_ASSIST_ALLIES";
const string CREATURE_VAR_AI_SHOUT_WARNING = "X4_L_SHOUT_WARNING";
const string CREATURE_VAR_AI_DAY_NIGHT_POST = "X4_L_DAY_NIGHT_POST";
const string CREATURE_VAR_USE_SPAWN_APPEAR_ANIM = "X4_L_SPAWN_USE_APPEAR_ANIM";
// AMBIENT ANIMATION CONDITIONS - Can only be used with Ambient Animations
const string CREATURE_VAR_USE_AMBIENT_CIVILIZED = "X2_L_USE_AMBIENT_CIVILIZED";
const string CREATURE_VAR_USE_AMBIENT_CONSTANT = "X2_L_USE_AMBIENT_CONSTANT";
const string CREATURE_VAR_USE_AMBIENT_CHATTER = "X2_L_USE_AMBIENT_CHATTER";
const string CREATURE_VAR_USE_AMBIENT_CLOSE = "X2_L_USE_AMBIENT_MOBILE_CLOSE";
// SPECIAL COMBAT TACTICS - Use only one at a time
const string CREATURE_VAR_AI_COMBAT_RANGED = "X2_L_AI_COMBAT_RANGED";
const string CREATURE_VAR_AI_COMBAT_DEFENSE = "X2_L_AI_COMBAT_DEFENSE";
const string CREATURE_VAR_AI_COMBAT_AMBUSH = "X2_L_AI_COMBAT_AMBUSH";
const string CREATURE_VAR_AI_COMBAT_COWARD = "X2_L_AI_COMBAT_COWARD";
// SPECIAL ESCAPE TACTICS - Use only one at a time
const string CREATURE_VAR_AI_ESCAPE_RETURN = "X2_L_AI_ESCAPE_RETURN";
const string CREATURE_VAR_AI_ESCAPE_LEAVE = "X2_L_AI_ESCAPE_LEAVE";
const string CREATURE_VAR_AI_TELEPORT_LEAVE = "X2_L_AI_TELEPORT_LEAVE";
const string CREATURE_VAR_AI_TELEPORT_RETURN = "X2_L_AI_TELEPORT_RETURN";
// USER DEFINED EVENTS - fires the OnSpawn user defined event
const string CREATURE_VAR_UD_HEARTBEAT = "X2_L_SPAWN_UD_HEARTBEAT";
const string CREATURE_VAR_UD_PERCIEVE = "X2_L_SPAWN_UD_PERCIEVE";
const string CREATURE_VAR_UD_END_COMBAT = "X2_L_SPAWN_UD_END_COMBAT";
const string CREATURE_VAR_UD_DIALOG = "X2_L_SPAWN_UD_DIALOG";
const string CREATURE_VAR_UD_ATTACK = "X2_L_SPAWN_UD_ATTACK";
const string CREATURE_VAR_UD_DAMAGED = "X2_L_SPAWN_UD_DAMAGED";
const string CREATURE_VAR_UD_DEATH = "X2_L_SPAWN_UD_DEATH";
const string CREATURE_VAR_UD_DISTURBED = "X2_L_SPAWN_UD_DISTURBED";
const string CREATURE_VAR_UD_SPELL_CAST_AT = "X2_L_SPAWN_UD_SPELLCAST";
// SPECIAL BEHAVIOR STATES
const string CREATURE_VAR_BS_CARNIVORE = "X2_L_BS_CARNIVORE";
const string CREATURE_VAR_BS_HERBIVORE = "X2_L_BS_HERBIVORE";
const string CREATURE_VAR_BS_OMNIVORE = "X2_L_BS_OMNIVORE";
//------------------------------------------------------------------------------
void main()
{
// ***** Spawn-In Conditions ***** //
//--------------------------------------------------------------------------
// * Speak a one-liner greeting from creature's conversation file upon
// * perceiving the player. Put [NW_D2_GenCheck] in the "Text Seen When"
// * field of the greeting in the conversation file. Do not attach any
// * player responses.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_SPECIAL_CONVERSATION) == TRUE)
{
SetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION);
}
//--------------------------------------------------------------------------
// * Same as above, but for hostile creatures say a line before attacking.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_SPECIAL_COMBAT_CONVERSATION) == TRUE)
{
SetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVERSATION);
}
//--------------------------------------------------------------------------
// * Make a creature attack when its allies call for help.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_ASSIST_ALLIES) == TRUE)
{
SetSpawnInCondition(NW_FLAG_SHOUT_ATTACK_MY_TARGET);
}
//--------------------------------------------------------------------------
// * Enable stealth mode, great for ambushes.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_SPAWN_STEALTH) == TRUE)
{
SetSpawnInCondition(NW_FLAG_STEALTH);
}
//--------------------------------------------------------------------------
// * Enter search mode, great for guards, etc.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_SPAWN_SEARCH) == TRUE)
{
SetSpawnInCondition(NW_FLAG_SEARCH);
}
//--------------------------------------------------------------------------
// * Shout a warning to non enemies before attacking.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_SHOUT_WARNING) == TRUE)
{
SetSpawnInCondition(NW_FLAG_SET_WARNINGS);
}
//--------------------------------------------------------------------------
// * Separate the NPC's waypoints into day & night. See the comments on
// * WalkWayPoints() for use.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_DAY_NIGHT_POST) == TRUE)
{
SetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING);
}
//--------------------------------------------------------------------------
// * Creature appears using the "EffectAppear" animation instead of fading
// * in, *IF* SetListeningPatterns() is called.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_SPAWN_APPEAR_ANIM) == TRUE)
{
SetSpawnInCondition(NW_FLAG_APPEAR_SPAWN_IN_ANIMATION);
}
//--------------------------------------------------------------------------
// Enable immobile ambient animations.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_SPAWN_AMBIENT_IMMOBILE) == TRUE)
{
SetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS);
}
//--------------------------------------------------------------------------
// Enable mobile ambient animations.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_SPAWN_AMBIENT) == TRUE)
{
SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS);
}
// **** Animation Conditions **** //
// * These are extra conditions you can put on creatures with ambient
// * animations.
//--------------------------------------------------------------------------
// * Civilized creatures interact with placeables in their area that have
// * the tag "NW_INTERACTIVE" and "talk" to each other.
// *
// * Humanoid races are civilized by default, so only set this flag for
// * races that you want to behave the same way.
// *
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_AMBIENT_CIVILIZED) == TRUE)
{
SetAnimationCondition(NW_ANIM_FLAG_IS_CIVILIZED);
}
//--------------------------------------------------------------------------
// * Creature will constantly be acting. Otherwise, creatures will onlystart
// * performing their ambient animations when they first perceive a player,
// * and they will stop when the player moves away.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_AMBIENT_CONSTANT) == TRUE)
{
SetAnimationCondition(NW_ANIM_FLAG_CONSTANT);
}
//--------------------------------------------------------------------------
// * Civilized creatures with this flag set will randomly use a few
// * voicechats. Avoid putting this on multiple creatures that are using the
// * same voiceset.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_AMBIENT_CHATTER) == TRUE)
{
SetAnimationCondition(NW_ANIM_FLAG_CHATTER);
}
//--------------------------------------------------------------------------
// * Creatures with _immobile_ ambient animations become _mobile_ at close
// * range. They will never leave their immediate area, but will move around
// * in it, frequently returning to their starting point.
// *
// * Note, creatures spawned inside interior areas that contain a waypoint
// * with one of the tags "NW_HOME", "NW_TAVERN", "NW_SHOP" automatically
// * have this condition set.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_USE_AMBIENT_CLOSE) == TRUE)
{
SetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE);
}
// **** Special Combat Tactics *****//
// * These are special flags that can be set on creatures to make them follow
// * certain specialized combat tactics.
// *
// * NOTE: ONLY ONE OF THESE SHOULD BE SET ON A SINGLE CREATURE.
//--------------------------------------------------------------------------
// * Ranged attacker - attempts to stay at ranged distance from its target.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_COMBAT_RANGED) == TRUE)
{
SetCombatCondition(X0_COMBAT_FLAG_RANGED);
}
//--------------------------------------------------------------------------
// * Defensive attacker - uses defensive combat feats and parry.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_COMBAT_DEFENSE) == TRUE)
{
SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE);
}
//--------------------------------------------------------------------------
// * Ambusher - go into _stealth_ mode and attack, then run away and try
// * to go into _stealth_ mode again before attacking anew.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_COMBAT_AMBUSH) == TRUE)
{
SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER);
}
//--------------------------------------------------------------------------
// * Cowardly - attempts to flee attackers.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_COMBAT_COWARD) == TRUE)
{
SetCombatCondition(X0_COMBAT_FLAG_COWARDLY);
}
// **** Escape Commands ***** //
// * NOTE: ONLY ONE OF THE FOLLOWING SHOULD EVER BE SET AT ONE TIME.
// * NOTE2: Not clear that these actually work. -- NN
//--------------------------------------------------------------------------
// * Flee to a way point and return a short time later.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_ESCAPE_RETURN) == TRUE)
{
SetSpawnInCondition(NW_FLAG_ESCAPE_RETURN);
}
//--------------------------------------------------------------------------
// * Flee to a way point and do not return.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_ESCAPE_LEAVE) == TRUE)
{
SetSpawnInCondition(NW_FLAG_ESCAPE_LEAVE);
}
//--------------------------------------------------------------------------
// * Teleport to safety and do not return.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_TELEPORT_LEAVE) == TRUE)
{
SetSpawnInCondition(NW_FLAG_TELEPORT_LEAVE);
}
//--------------------------------------------------------------------------
// * Teleport to safety and return a short time later.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_AI_TELEPORT_RETURN) == TRUE)
{
SetSpawnInCondition(NW_FLAG_TELEPORT_RETURN);
}
// **** Special Behavior States *****//
// * These are special flags that can be set on creatures to make them follow
// * certain specialized behavior patterns.
// *
// * NOTE: ONLY ONE OF THESE CAN BE SET ON A CREATURE AT THE SAME TIME.
//--------------------------------------------------------------------------
// * Always attack regardless of faction.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_BS_CARNIVORE) == TRUE)
{
SetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL);
SetBehaviorState(NW_FLAG_BEHAVIOR_CARNIVORE);
}
//--------------------------------------------------------------------------
// * Flee from any creature that closes within 7m if they are not friends,
// * Rangers, or Druids.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_BS_HERBIVORE) == TRUE)
{
SetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL);
SetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE);
}
//--------------------------------------------------------------------------
// * Attack creatures that close within 5m and are not friends, Rangers, or
// * Druids.
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_BS_OMNIVORE) == TRUE)
{
SetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL);
SetBehaviorState(NW_FLAG_BEHAVIOR_OMNIVORE);
}
// ***** CUSTOM USER DEFINED EVENTS ***** /
/*
Setting one of these integer variables to TRUE on a creature will
cause it to fire the designated user defined event.
- X2_L_SPAWN_UD_HEARTBEAT
- X2_L_SPAWN_UD_PERCIEVE
- X2_L_SPAWN_UD_END_COMBAT
- X2_L_SPAWN_UD_DIALOG
- X2_L_SPAWN_UD_ATTACK
- X2_L_SPAWN_UD_DAMAGED
- X2_L_SPAWN_UD_DEATH
- X2_L_SPAWN_UD_DISTURBED
A creature may have multiple user defined events. Furthermore, as
the name implies, user defined events must be coded by the Builder
in the creature's OnUserDefined event script.
*/
//--------------------------------------------------------------------------
// * Fire User Defined Event 1001 in the OnHeartbeat
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_UD_HEARTBEAT) == TRUE)
{
SetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT);
}
//--------------------------------------------------------------------------
// * Fire User Defined Event 1002
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_UD_PERCIEVE) == TRUE)
{
SetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT);
}
//--------------------------------------------------------------------------
// * Fire User Defined Event 1005
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_UD_ATTACK) == TRUE)
{
SetSpawnInCondition(NW_FLAG_ATTACK_EVENT);
}
//--------------------------------------------------------------------------
// * Fire User Defined Event 1006
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_UD_DAMAGED) == TRUE)
{
SetSpawnInCondition(NW_FLAG_DAMAGED_EVENT);
}
//--------------------------------------------------------------------------
// * Fire User Defined Event 1008
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_UD_DISTURBED) == TRUE)
{
SetSpawnInCondition(NW_FLAG_DISTURBED_EVENT);
}
//--------------------------------------------------------------------------
// * Fire User Defined Event 1003
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_UD_END_COMBAT) == TRUE)
{
SetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT);
}
//--------------------------------------------------------------------------
// * Fire User Defined Event 1004
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_UD_DIALOG) == TRUE)
{
SetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT);
}
//--------------------------------------------------------------------------
// * Fire User Defined Event 1007 - Reliability is questionable
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_UD_DEATH) == TRUE)
{
SetSpawnInCondition(NW_FLAG_DEATH_EVENT);
}
//--------------------------------------------------------------------------
// * Fire User Defined Event 1011
//--------------------------------------------------------------------------
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_UD_SPELL_CAST_AT) == TRUE)
{
SetSpawnInCondition(NW_FLAG_SPELL_CAST_AT_EVENT);
}
// ***** DEFAULT GENERIC BEHAVIOR (DO NOT TOUCH) ***** //
// * Goes through and sets up which shouts the NPC will listen to.
// *
SetListeningPatterns();
// * Walk among a set of waypoints.
// * 1. Find waypoints with the tag "WP_" + NPC TAG + "_##" and walk
// * among them in order.
// * 2. If the tag of the Way Point is "POST_" + NPC TAG, stay there
// * and return to it after combat.
//
// * Optional Parameters:
// * void WalkWayPoints(int nRun = FALSE, float fPause = 1.0)
//
// * If "NW_FLAG_DAY_NIGHT_POSTING" is set above, you can also
// * create waypoints with the tags "WN_" + NPC Tag + "_##"
// * and those will be walked at night. (The standard waypoints
// * will be walked during the day.)
// * The night "posting" waypoint tag is simply "NIGHT_" + NPC tag.
WalkWayPoints();
//* Create a small amount of treasure on the creature
if ((GetLocalInt(GetModule(), "X2_L_NOTREASURE") == FALSE) &&
(GetLocalInt(OBJECT_SELF, "X2_L_NOTREASURE") == FALSE) )
{
CTG_GenerateNPCTreasure(TREASURE_TYPE_MONSTER, OBJECT_SELF);
}
// ***** ADD ANY SPECIAL ON-SPAWN CODE HERE ***** //
// * If Incorporeal, apply changes
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_IS_INCORPOREAL) == TRUE)
{
effect eConceal = EffectConcealment(50, MISS_CHANCE_TYPE_NORMAL);
eConceal = ExtraordinaryEffect(eConceal);
effect eGhost = EffectCutsceneGhost();
eGhost = ExtraordinaryEffect(eGhost);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eConceal, OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, OBJECT_SELF);
}
// * Give the create a random name.
// * If you create a script named x3_name_gen in your module, you can
// * set the value of the variable X3_S_RANDOM_NAME on OBJECT_SELF inside
// * the script to override the creature's default name.
if (GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_RANDOMIZE_NAME) == TRUE)
{
ExecuteScript("x3_name_gen",OBJECT_SELF);
string sName = GetLocalString(OBJECT_SELF,"X3_S_RANDOM_NAME");
if ( sName == "" )
{
sName = RandomName();
}
SetName(OBJECT_SELF,sName);
}
}