///

// 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; }