///
// Template file v5.12 (07/27/01)
////////////////////////////////////////////////////////////////////////
// File: war.wdl "Modified by the Mad Dog on
10/1/01"
// WDL prefabs for hostile entities
////////////////////////////////////////////////////////////////////////
// Mod Date: 05/18/01 DCP
// Fixed
"double shots" (the cause of robot1's self hits)
//
// Mod Date: 06/05/01 DCP
// attack_approach(), avoid_walls():
Replaced TO_ANGLE with vec_to_angle()
//
// Mod Date: 06/21/01 DCP
// Replaced
SYNONYMs with pointers
//
// Mod: 07/19/01 MWS
// state_wait(): Use specified
cowardice value instead of universal 30.
// Use
specified alertness instead of universal 1000.
// Also
now skips the player scan entirely if alertness is zero.
//
// attack_fire(): MY_ANGLE used in
shooting at player now varies by a random
// amount
between -MY._I_ACCURACY to +MY._I_ACCURACY
//
// Mod Date: 7/26/01 MWS
// attack_transitions(): Made
"escape" branch test for MY._I_COWARDICE
// instead
of default 30.
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
//DEFINE WAR_CHAT_ON; //
display 'thought' actions for the AIs
IFDEF WAR_CHAT_ON;
STRING
war_wait_str,"Waiting...";
STRING
war_attack_str,"Attacking!!!";
STRING
war_hunt_str,"Searching...";
STRING
war_escape_str,"Retreat!!!";
STRING
war_dead_str,"I have been undone!";
ENDIF;
//////////////////////////////////////////////////////////////////////
// WAR.WDL - fighting behaviour
///////////////////////////////////////////////////////////////////////
IFNDEF WAR_DEFS;
DEFINE
ACTOR_EXPLO,<explo+7.pcx>;
DEFINE
ACTOR_EXPLO_FRAMES,7;
ENDIF;
///////////////////////////////////////////////////////////////////////
var freeze_actors = 0; //
1,2 for testing purposes
///////////////////////////////////////////////////////////////
///Add different attack gun sounds for a killer bot (enemy)
////////////
SOUND bigax,<pickax.wav>; // replace with your sounds
sound gunmy,<snd1.wav>; //ex. "sound
NAME,<name.wav>;"
///////////////////////////////////////////////////////////////////////
DEFINE _STATE_WAIT,1;
DEFINE _STATE_ATTACK,2;
DEFINE _STATE_ESCAPE,3;
DEFINE _STATE_DIE,4;
DEFINE _STATE_FREEZE,5; // 05/15/01 DCP: Changed from 4->5
DEFINE _STATE_HUNT,6;
////////////////////////////////////////////////
// For different enemy gun sounds and or sword
////////
DEFINE MELEE,1; //
assign this in enemy action script example
DEFINE RANGED,2; // "my._attackmode = Melee;
DEFINE MYGUN,3; //
the gun sounds for these are controlled
//
in "function attack_fire"
DEFINE _ATTACKMODE,SKILL48;//attackmode definition for enemy
gun sound
// End of my different gun sounds
//////////////////////////////////////////////
DEFINE _MUZZLE_VERT,SKILL32;
DEFINE _I_ACCURACY,SKILL33; // 07/19/01 MWS: Added
DEFINE _I_COWARDICE,SKILL34; // 07/19/01 MWS: Added
DEFINE _I_ALERTNESS,SKILL35; // 07/19/01 MWS: Added
// DEFINE USER INPUT SKILLs
// These skill will be inputted from WED and work with
entities that use the actions:
//
"player_walk_fight" and "actor_walk_fight"
DEFINE _WALKSWIM_DIST,
SKILL1; // Walk Distance . Swim
Distance
DEFINE _RUNCRAWL_DIST,
SKILL2; // Run Distance . Crawl
Distance
DEFINE _STANDJUMP_TIME,
SKILL3; // Stand Time . Jump Time
DEFINE _ATTACKDUCK_TIME,
SKILL4; // Attack Time . Duck Time
DEFINE _RUNTHRESHOLD,
SKILL14; // Run Threshold
//DEFINE _FORCE,
SKILL5; // Force
//DEFINE _BANKING,
SKILL6; // Banking
amount (player only)
//DEFINE _HITMODE,
SKILL6; // Hitmode (actor only)
//DEFINE _MOVEMODE,
SKILL7; // Starting movemode
//DEFINE _FIREMODE,
SKILL8; // Firemode
//DEFINE _HEALTH,
SKILL9; // Heath
//DEFINE _ARMOR,
SKILL10; // Armor
DEFINE _ALERTNESS,
SKILL11; // Alertness
DEFINE _ACCURACY,
SKILL12; // Accuracy
DEFINE _COWARDICE,
SKILL13; // Cowardice
DEFINE _MUZZLEATTACH,
SKILL15; // Muzzle vertex .
Attach vertex
///////////////////////////////////////////////////////////////////////
entity* test_actor; //
test actor entity pointer. Used in robot_test
entity* ent_marker; //
marker entity, used in hunting
STRING robot_attack_str,
"attack"; // attack
frame names used by robot
ACTION robot_test
{
IFNDEF test;
remove(ME);
return;
ENDIF;
test_actor
= ME;
MY._WALKFRAMES
= 8.030;
MY._RUNFRAMES
= 4.050;
MY._ATTACKFRAMES
= 6;
MY._DIEFRAMES
= 1;
MY._FORCE =
2;
MY._FIREMODE
= DAMAGE_SHOOT+FIRE_PARTICLE+HIT_FLASH+0.05;
MY._HITMODE
= HIT_GIB;//HIT_EXPLO;
MY._WALKSOUND
= _SOUND_ROBOT;
drop_shadow();
anim_init();
actor_fight();
}
// Desc: Action for robot #1
// Init values and call actor_fight
ACTION robot1
{
MY._FORCE =
0.7;
MY._FIREMODE
= DAMAGE_EXPLODE+FIRE_BALL+HIT_EXPLO+BULLET_SMOKETRAIL+0.20;
MY._HITMODE
= 0;
MY._WALKSOUND
= _SOUND_ROBOT;
anim_init();
drop_shadow(); // attach shadow to robot
actor_fight();
// if(MY.FLAG4
== ON) { CALL patrol; }
}
// Desc: Action for robot #2
// Init values and call actor_fight
ACTION robot2
{
MY._FORCE =
2;
MY._FIREMODE
= DAMAGE_SHOOT+FIRE_PARTICLE+HIT_FLASH+0.05;
MY._HITMODE
= HIT_GIB;//HIT_EXPLO;
MY._WALKSOUND
= _SOUND_ROBOT;
anim_init();
drop_shadow();
// attach shadow to robot
actor_fight();
// if(MY.FLAG4
== ON) { patrol(); }
create(<arrow.pcx>,MY.POS,_ROBOT_TEST_WATCHER); // used to activate watcher drone
}
// Desc: Action for robot #3
// Init values and call actor_fight
//
// NOTE: robot #3 removes itself from the game!
ACTION robot3
{
remove(ME);
return;
MY._FORCE =
0.7;
MY._FIREMODE
= DAMAGE_EXPLODE+FIRE_BALL+HIT_EXPLO+BULLET_SMOKETRAIL+0.20;
anim_init();
drop_shadow();
actor_fight();
// if(MY.FLAG4
== ON) { patrol(); }
}
// Desc: Debugging utility, watches a ROBOT and sets flags
using its values
//
entity* ent_test_watcher; // marker entity, used in hunting
function _ROBOT_TEST_WATCHER()
{
MY.PASSABLE
= ON;
// MY.INVISIBLE
= ON;
MY.ENTITY1
= YOU;
WHILE(MY.ENTITY1
!= 0)
{
ent_test_watcher = MY.ENTITY1;
// tst_value_1
= ent_test_watcher._STATE;
wait(1);
}
// tst_value_1 = -1;
remove(ME);
}
///////////////////////////////////////////////////////////////////////
// Desc: the wait state
//
// Mod: 07/19/01 MWS
// Use specified cowardice value
instead of universal 30.
// Use specified alertness instead of
universal 1000.
// Also now skips the player scan
entirely if alertness is zero.
function state_wait()
{
IFDEF WAR_CHAT_ON;
msg.STRING = war_wait_str;
show_message();
ENDIF;
// init
values here for backwards compatibility
if(MY._I_COWARDICE
== 0)
{
MY._I_COWARDICE = 30; } // use default cowardice
if(MY._I_ALERTNESS
== 0)
{
MY._I_ALERTNESS = 1000; } //
use default alertness
MY._STATE =
_STATE_WAIT;
while(MY._STATE
== _STATE_WAIT)
{
if(MY._HEALTH <= 0) // no health? Die
{
EXCLUSIVE_ENTITY;
wait(1);
state_die();
return;
}
// Note: changed, negative cowardice
means never retreat
if(MY._HEALTH <=
MY._I_COWARDICE && MY._I_COWARDICE >= 0) // low health? Escape
{
EXCLUSIVE_ENTITY;
wait(1);
state_escape();
return;
}
if (MY._I_ALERTNESS > 0) // dont be alert if negative
alertness
{
// scan for the player coming near
temp.PAN = 180;
temp.TILT = 180;
temp.Z = MY._I_ALERTNESS;
indicator = _WATCH;
scan(MY.POS,MY.ANGLE,temp);
// if the player has been
detected...
if(MY._SIGNAL == _DETECTED)
{
MY._SIGNAL
= 0;
state_attack(); // ATTACK!
return;
}
}
force = 0; // no force from this actor
actor_move(); // react to outside forces (gravity, etc) even while
waiting
waitt(1);
}
}
// Desc: The attack state
//
function state_attack()
{
MY._STATE =
_STATE_ATTACK;
IFDEF WAR_CHAT_ON;
msg.STRING = war_attack_str;
show_message();
ENDIF;
MY._MOVEMODE
= _MODE_ATTACK; // stop patrolling etc.
attack_transitions(); // branch to other states depending on
values
// fire and
close distance
while(MY._STATE
== _STATE_ATTACK)
{
// fire two or three times
MY._COUNTER = 1; // MY._COUNTER = 1.5 + RANDOM(1);
//
check to see if player is shootable,
if((attack_fire())
== -1)
{
// cannot see player
EXCLUSIVE_ENTITY;
wait(1);
state_hunt();
return;
}
while(MY._COUNTER > 0) {
waitt(1); } // don't continue
until attack_fire is finished
//
walk towards player for one to three seconds
MY._COUNTER = 16 + RANDOM(32);
attack_approach();
while(MY._COUNTER > 0) {
waitt(1); } // don't continue until attack_approach is finished
}
}
// Desc: Use internal and external values to branch to other
states
//
// Mod Date: 7/26/01 MWS
// Made
"escape" branch test for MY._I_COWARDICE instead of default 30
function attack_transitions()
{
while(MY._STATE
== _STATE_ATTACK)
{
if(MY._HEALTH <= 0) // goto die state
{
EXCLUSIVE_ENTITY;
wait(1);
state_die();
return;
}
if(MY._HEALTH <=
MY._I_COWARDICE && MY._I_COWARDICE >= 0) // low health? Escape
{
EXCLUSIVE_ENTITY;
wait(1);
state_escape();
return;
}
if(freeze_actors > 0) // goto freeze state
{
EXCLUSIVE_ENTITY;
wait(1);
state_freeze();
return;
}
wait(1);
}
}
// Desc:
attack the player:
// -turn
towards player
// -check
if entity can see the player
// -play
fire animation
// -fire
shot
//
// Mod Date: 05/18/01 DCP
// Fixed
"double shots" (the cause of robot1's self hits)
//
// Mod Date: 07/19/01 MWS
// MY_ANGLE
used in shooting at player now varies by a random
// amount
between -MY._I_ACCURACY to +MY._I_ACCURACY
//
// Mod Date: 08/22/01 DCP
// Added "Advanced" Animation
for firing
///////////////////////////////////////////////////
/////////////////////////////////////////
//
function attack_fire()
{
while((MY._STATE
== _STATE_ATTACK) && (MY._COUNTER > 0))
{
// turn towards player
temp.X = player.X - MY.X;
temp.Y = player.Y - MY.Y;
temp.Z = player.Z - MY.Z;
vec_to_angle(MY_ANGLE,temp);
force = MY._FORCE * 2;
actor_turn();
// watch out if player visible. If
yes, then shoot at him
indicator = _WATCH;
//SHOOT MY.POS,player.POS;
trace_mode = IGNORE_ME +
IGNORE_PASSABLE + IGNORE_PASSENTS;
trace(MY.POS,player.POS);
if((RESULT > 0) && (YOU
== player)) // spotted him!
{
// fire at player
// 1) PLAY ATTACK ANIMATION
// check for *ADVANCED ANIMATION*
(frame names and entity tick/dist values)
if(int(MY._WALKFRAMES) < 0)
{
//
reset entity's animation time to zero
MY._ANIMDIST
= 0;
while(MY._ANIMDIST
< 50)
{
// if you have more than one attacking animation, here's
where you would test for it...
// calculate a percentage out of the animation time
MY._ANIMDIST +=
100*(TIME /
(INT(((-MY._ADVANIM_TICK)&MASK_ANIM_ATTACK_TICKS)>>10)));
// set the frame from the percentage
ent_frame(robot_attack_str,MY._ANIMDIST);
wait(1);
}
}
else
{
//
decide whether it's a frame number (old) or frame name (new) animation
if(frc(MY._WALKFRAMES)
> 0)// OLD STYLE ATTACK ANIMATION
{
// play attack animation
MY.FRAME = 1 + MY._WALKFRAMES + MY._RUNFRAMES + 1; // set frame to start
MY.NEXT_FRAME = 0; //
inbetween to the real next frame
while(MY.FRAME > 1 + MY._WALKFRAMES + MY._RUNFRAMES +
MY._ATTACKFRAMES)
{
wait(1);
MY.FRAME += 0.4 * TIME;
}
MY.FRAME
= 1 + MY._WALKFRAMES + MY._RUNFRAMES + 1;
// end at start frame
}//
END OLD STYLE ATTACK ANIMATION
else
// new animation format
(frc(MY._WALKFRAMES) == 0)
{
// reset entity's animation time to zero
MY._ANIMDIST = 0;
while(MY._ANIMDIST < 50)
{
wait(1);
// calculate a percentage out of the
animation time
MY._ANIMDIST
+= 8.0 * TIME; // attack in ~1 second
// set
the frame from the percentage
// -old-
SET_FRAME ME,robot_attack_str,MY._ANIMDIST;
ent_frame(robot_attack_str,MY._ANIMDIST);
}
}//
END NEW STYLE ATTACK ANIMATION
} // END NOT ADVANCED
// 2) fire shot
damage = frc(MY._FIREMODE) * 100;
fire_mode = MY._FIREMODE;
if((fire_mode & MODE_DAMAGE) ==
DAMAGE_SHOOT)
{
shot_speed.X
= 500;
}
else
{
shot_speed.X
= 100;
}
shot_speed.Y = 0;
shot_speed.Z = 0;
MY_ANGLE.PAN = MY.PAN; // TILT is already set from TO_ANGLE
// Add in a random amount according
to MY._I_ACCURACY
if (MY._I_ACCURACY != 0)
{
MY_ANGLE.PAN += random(MY._I_ACCURACY*2) -
MY._I_ACCURACY;
MY_ANGLE.TILT += random(MY._I_ACCURACY*2)
- MY._I_ACCURACY;
}
vec_rotate(shot_speed,MY_ANGLE);
// now shot_speed points ahead
// check to see if the model is
using a muzzle vertice
/////////////////////////////////////////////////////////////////
if(MY._MUZZLE_VERT == 0)
{
//
default gun muzzle
vec_set(gun_muzzle.X,MY.X);
}
else
{
ent_vertex(gun_muzzle.X,MY._MUZZLE_VERT);
}
///////////////////////////////////////////////////////////////
///////////////////// Add the new play entsound here /////////////////
///////////////////////////////////////////////////////////////
IF(MY._ATTACKMODE ==
MELEE)
{
play_entsound(ME,bigax,150); // change these sounds to your
}
IF(MY._ATTACKMODE
== RANGED) // own gun sound..
(Me,YOUR SOUND,150);
{
play_entsound(ME,gun_wham,150);
}
IF(MY._ATTACKMODE
== MYGUN)
{
play_entsound(ME,gunmy,150);
}
gun_shot();
//MY._COUNTER -= 1;// don't use this
//if(frc(MY._WALKFRAMES) == 0)//
don't use this
{
/////////////////////////////////////////////////////////////
// check for *ADVANCED ANIMATION* (frame names and entity
tick/dist values)
if(int(MY._WALKFRAMES) < 0)
{
//
set entity's animation to halfway
MY._ANIMDIST
= 50;
while(MY._ANIMDIST
< 100)
{
// if you have more than one attacking animation, here's
where you would test for it...
// calculate a percentage out of the animation time
MY._ANIMDIST +=
100 * (TIME /
(INT(((-MY._ADVANIM_TICK)&MASK_ANIM_ATTACK_TICKS)>>10)));
// set the frame from the percentage
ent_frame(robot_attack_str,MY._ANIMDIST);
wait(1);
}
}
else
{
if(frc(MY._WALKFRAMES)
== 0)
{
// play the second half of the animation
while(MY._ANIMDIST
< 100)
{
wait(1);
// calculate a percentage out of the
animation time
MY._ANIMDIST
+= 8.0 * TIME; // attack in ~1 second
// set
the frame from the percentage
// -old-
SET_FRAME ME,robot_attack_str,MY._ANIMDIST;
ent_frame(robot_attack_str,MY._ANIMDIST);
}
}//
END NEW STYLE ATTACK ANIMATION
}
}// END if((RESULT > 0)
&& (YOU == player))
else
{
MY._COUNTER = 0;
return(-1); // can not see player
}
waitt(2); // space shots appart (so they don't hit each other!
MY._COUNTER -= 1;
}//
END while((MY._STATE == _STATE_ATTACK)
&& (MY._COUNTER > 0))
}
// Desc: approach the player with random deviation
// do not approach any closer then 50
units
//
// Note: only
rotates by PANning
//
// Calls:
actor_turn()
// actor_move()
//
// Mod Date: 06/05/01 DCP
// Replaced TO_ANGLE with
vec_to_angle()
function attack_approach()
{
//
calculate a direction to walk into
temp.X =
player.X - MY.X;
temp.Y =
player.Y - MY.Y;
temp.Z = 0;
//--- TO_ANGLE
MY_ANGLE,temp;
vec_to_angle(MY_ANGLE,temp);
// ADD
random deviation angle
MY._TARGET_PAN
= MY_ANGLE.PAN - 15 + RANDOM(30);
while((MY._STATE
== _STATE_ATTACK) && (MY._COUNTER > 0))
{
// turn
towards player
MY_ANGLE.PAN = MY._TARGET_PAN;
MY_ANGLE.TILT = 0;
MY_ANGLE.ROLL = 0;
force = MY._FORCE * 2;
actor_turn();
// walk towards him if not too close
temp = (player.X - MY.X)*(player.X -
MY.X)+(player.Y - MY.Y)*(player.Y - MY.Y);
if(temp > 10000) // 100^2
{
force = MY._FORCE;
MY._MOVEMODE = _MODE_WALKING;
actor_move();
}
wait(1);
MY._COUNTER -= TIME;
}
}
// low on health => try to run away
function state_escape()
{
IFDEF WAR_CHAT_ON;
msg.STRING = war_escape_str;
show_message();
ENDIF;
MY._STATE =
_STATE_ESCAPE;
while(MY._STATE
== _STATE_ESCAPE)
{
if(MY._HEALTH <= 0)
{
EXCLUSIVE_ENTITY;
wait(1);
state_die();
return;
}
// turn away from player
temp.X = MY.X - player.X;
temp.Y = MY.Y - player.Y;
temp.Z = MY.Z - player.Z;
vec_to_angle(MY_ANGLE,temp);
force = MY._FORCE * 6;
actor_turn();
force = MY._FORCE * 4;
MY._MOVEMODE = _MODE_WALKING;
actor_move();
wait(1);
}
}
// Desc: Die:
// -stop
moving
// -stop
scanning and shooting
// -null
out my.event
// -play
death animation
// -become
passable
//
//
// Mod Date:
08/22/01 DCP
// Use advanced animation for death
(twice attack ticks).
// Notes: Uses
entity's _AMIMDIST value as a 'percent death' value (0 start, 100 end)
function state_die()
{
IFDEF WAR_CHAT_ON;
msg.STRING = war_dead_str;
show_message();
ENDIF;
MY._MOVEMODE
= 0; //
don't move anymore
MY._STATE =
_STATE_DIE;
MY.ENABLE_SCAN
= OFF; // get deaf and blind
MY.ENABLE_SHOOT
= OFF;
MY.EVENT =
NULL; // and don't react anymore
// check if
we have a marker...
if(MY.ENTITY1
!= 0)
{
// if so, remove it.
remove(MY.ENTITY1);
}
// check
for *ADVANCED ANIMATION* (frame names and entity tick/dist values)
if(int(MY._WALKFRAMES)
< 0)
{
// reset entity's animation time to
zero
MY._ANIMDIST = 0;
while(MY._ANIMDIST < 100)
{
// if you have more than one
attacking animation, here's where you would test for it...
// calculate a percentage out of the
animation time
MY._ANIMDIST += 100*(TIME /
(INT(((-MY._ADVANIM_TICK)&MASK_ANIM_ATTACK_TICKS)>>9))); //
(x>>10) * 2
// set the frame from the percentage
ent_frame(anim_death_str,MY._ANIMDIST);
wait(1);
}
}
else
{
// decide whether it's a frame
number (old) or frame name (new) animation
if(frc(MY._WALKFRAMES) > 0)// OLD
STYLE ATTACK ANIMATION
{
MY.FRAME = 1 + MY._WALKFRAMES + MY._RUNFRAMES +
MY._ATTACKFRAMES + 1;
MY.NEXT_FRAME = 0; // inbetween to the real next frame
while(MY.FRAME <= (1 +
MY._WALKFRAMES + MY._RUNFRAMES + MY._ATTACKFRAMES + MY._DIEFRAMES))
{
wait(1);
MY.FRAME
+= 0.7 * TIME;
}
}// END OLD STYLE Death ANIMATION
else // new animation format (frc(MY._WALKFRAMES) == 0)
{
// reset entity's animation time to
zero
MY._ANIMDIST = 0;
while(MY._ANIMDIST < 100)
{
wait(1);
//
calculate a percentage out of the animation time
MY._ANIMDIST
+= 5.0 * TIME; // death in ~1.25
seconds
//
set the frame from the percentage
//
-old- SET_FRAME ME,anim_death_str,MY._ANIMDIST;
ent_frame(anim_death_str,MY._ANIMDIST);
}
}// END NEW STYLE ATTACK ANIMATION
} // END
NOT ADVANCED
// If
entity explodes after death
if((ME !=
player) && ((MY._HITMODE & MODE_HIT) == HIT_EXPLO))//(MY._HITMODE
& HIT_EXPLO))
{
morph(ACTOR_EXPLO,ME);
MY._DIEFRAMES
= ACTOR_EXPLO_FRAMES;
actor_explode(); // ends with the removal of this entity
return;
}
// If entity 'gibs' after death
if((ME !=
player) && ((MY._HITMODE & MODE_HIT) == HIT_GIB))//(MY._HITMODE
& HIT_GIB))
{
_gib(25); // use new "gib" function
actor_explode(); // ends with the removal of this entity
return;
}
MY.PASSABLE
= ON; // body remains
}
// Desc: used to "tag" the last know target
location
// "CREATE
<arrow.pcx>, MY.POS, _last_know_target_loc;"
function _last_know_target_loc()
{
YOUR.ENTITY1
= ME;
MY.INVISIBLE
= ON;
MY.PASSABLE
= ON;
}
// Desc: move to the entity1 location
function hunt_approach()
{
ent_marker
= MY.ENTITY1;
//
calculate a direction to walk into
temp.X =
ent_marker.X - MY.X;
temp.Y =
ent_marker.Y - MY.Y;
temp.Z =
ent_marker.Z - MY.Z;
vec_to_angle(MY_ANGLE,temp);
MY._TARGET_PAN
= MY_ANGLE.PAN;
// turn towards
target
MY_ANGLE.PAN
= MY._TARGET_PAN;
MY_ANGLE.TILT
= 0;
MY_ANGLE.ROLL
= 0;
force =
MY._FORCE * 2;
actor_turn();
if(avoid_walls()
== 1) // avoid hitting walls
{
force = MY._FORCE * 4;
actor_turn();
}
temp =
(ent_marker.X - MY.X)*(ent_marker.X - MY.X)+(ent_marker.Y - MY.Y)*(ent_marker.Y
- MY.Y);
// walk
towards target only if not too close
if(temp
< 100) // 10^2
{
remove(MY.ENTITY1); // remove marker
EXCLUSIVE_ENTITY;
wait(1);
state_wait(); // branch to wait mode
return;
}
// walk
towards ent_marker
force =
MY._FORCE;
MY._MOVEMODE
= _MODE_WALKING;
actor_move();
}
// Desc: avoid hitting walls
//
// Return: 1 if to close to a wall, o otherwise
function avoid_walls()
{
// shoot a
line between the entity and the target point
SHOOT
MY.POS, ent_marker.POS;
IF((YOU !=
ent_marker) && (RESULT < 50)) //
too close to a wall...
{
// angle away from the wall.
temp.X = (TARGET.X + (100 *
NORMAL.X)) - MY.X;
temp.Y = (TARGET.Y + (100 *
NORMAL.Y)) - MY.Y;
temp.Z = MY.Z;
vec_to_angle(MY_ANGLE,temp);
RETURN(1);
}
RETURN(0);
}
// Desc: follow a wall until you reach a corner
//
// NOTE: to-do (pathfind.wdl?)
function follow_wall()
{
RETURN(0);
}
// Desc: Use internal and external values to branch to other
states
//
// Mod Date: 7/26/01 MWS
// Escape
branch tests for MY._I_COWARDICE instead of constant 30
function hunt_transitions()
{
while(MY._STATE
== _STATE_HUNT)
{
// Check heath
IF(MY._HEALTH <= 0) // goto die state
{
EXCLUSIVE_ENTITY;
wait(1);
state_die();
return;
}
if(MY._HEALTH <=
MY._I_COWARDICE && MY._I_COWARDICE >= 0) // low health? Escape
{
EXCLUSIVE_ENTITY;
wait(1);
state_escape();
return;
}
//
scan for the player coming near
temp.PAN = 180;
temp.TILT = 180;
temp.Z = MY._I_ALERTNESS;
indicator = _WATCH;
SCAN MY.POS,MY.ANGLE,temp;
// if the player has been
detected...
if(MY._SIGNAL == _DETECTED)
{
MY._SIGNAL = 0;
remove(MY.ENTITY1);
EXCLUSIVE_ENTITY;
wait(1);
state_attack(); // ATTACK!
return;
}
// Check debug
IF(freeze_actors > 0) // goto freeze state
{
EXCLUSIVE_ENTITY;
wait(1);
state_freeze();
return;
}
waitt(1);
}
}
// Desc: if you lose your target, move towards its last know
location while
// scanning.
function state_hunt()
{
MY._STATE =
_STATE_HUNT;
IFDEF WAR_CHAT_ON;
msg.STRING = war_hunt_str;
show_message();
ENDIF;
// create a
"marker" at the last known player location
create(<arrow.pcx>,
PLAYER.POS, _last_know_target_loc);
MY._MOVEMODE
= _MODE_WALKING; // stop patrolling etc.
hunt_transitions(); // branch to other states depending on
values
while(MY._STATE
== _STATE_HUNT)
{
// approach the marker
hunt_approach();
wait(1);
}
}
// Desc: freeze in place
function state_freeze()
{
MY._STATE =
_STATE_FREEZE;
MY._MOVEMODE
= _MODE_STILL; // stop patrolling
etc.
while(MY._STATE
== _STATE_FREEZE)
{
if(freeze_actors > 1)
{
MY.PASSABLE = ON;
}
if(freeze_actors == 0)
{
state_wait();
return;
}
wait(1);
}
}
////////////////////////////////////////////////////////////////////////
// Desc: take damage and detect player
//
// Mod: 02/06/01 DCP
// Added wait before shoot command to
remove 'Dangerous instruction error'
// Replaced SHOOT with trace()
//
// Mod: 05/05/01 DCP
// Modified damage from ranged
explosion (replaced ABS with MAX)
function fight_event()
{
if((EVENT_TYPE
== EVENT_SCAN && indicator == _EXPLODE)
|| (EVENT_TYPE == EVENT_SHOOT
&& indicator == _GUNFIRE))
{
MY._SIGNAL = _DETECTED; // by shooting, player gives away
his position
if (indicator == _EXPLODE)
{ //
reduce damage according to distance
damage *= max(0,(range -
RESULT))/range;
}
if(MY._ARMOR <= 0)
{
MY._HEALTH -= damage;
}
else
{
MY._ARMOR -= damage;
}
return;
}
if(EVENT_TYPE
== EVENT_DETECT && YOU == player)
{
wait(1); //fix for dangerous instruction
indicator = _WATCH;
//--- SHOOT MY.POS,YOUR.POS; // can player be seen from here?
trace_mode = IGNORE_ME + IGNORE_PASSABLE
+ ACTIVATE_SHOOT;
RESULT = trace(MY.POS,YOUR.POS); //
if entity YOU was visible from MY position, its SHOOT event was triggered
if((RESULT > 0) && (YOU
== player)) // yes
{
MY._SIGNAL = _DETECTED;
}
return;
}
}
// Desc: init actor for fighting and branch to the wait
state
function actor_fight()
{
// if(MY._ARMOR
== 0) { MY._ARMOR = 100; }
if(MY._HEALTH
== 0) { MY._HEALTH = 100; } //
default health
if(MY._FORCE
== 0) { MY._FORCE = 1; } //
default force
// Allow
player to pass thru actor if frozen
if(freeze_actors
> 1) { MY.PASSABLE = ON; }