My alllies wont die :O
Posted: Mon Aug 13, 2007 4:35 pm
well the title pratically sums it up. my allies WILL get hurt, blood spurts out unrealistically and they lose more blood than the human body has................but they just wont die <_<. the enemies they make short work of but my allies wont die at all.
Ally script
Enemy SCript
Ally script
Code: Select all
{
// Allied Bot Script
// Made from Generic missile monster
GROUP [Allies] // name of monster group
BOXWIDTH [40] // width and depth of bounding box
HOSTILEPLAYER [false] // hostile to player
HOSTILEDIFFERENT [true] // hostile to different Pawn group
HOSTILESAME [false] // hostile to same Pawn group
HOSTILETOGROUP [enemy] // hostile to this group
HEALTHATTRIBUTE [playerhealth] // name of health attribute
HEALTH [25] // initial amount of health
SIGHTDIST [3000] // max distance monster can see at idle
ALERTSIGHTDIST [3000] // max distance monster can see when alert
FOV [180] // field of view in degrees
YAWSPEED [120] // speed of rotation in deg/sec
DAMAGEATTRIBUTE [enemy_health] // attribute damaged by attack
ALERTTRIGGER [AlertG] // name of alert trigger
SCALE [1.4] // amount to scale actor by
SPAWNPOINT [spawn_good] // spawnpoint no 1
SPAWNPOINT2 [spawn_good2] // spawnpoint no 2
FIRSTPOINT [null]
STAND [idle] // idle animation
TURNL [idle] // turn left animation
TURNR [idle] // turn right animation
PAIN [pain] // pain animations
PAIN1 [pain]
PAIN2 [pain]
PAIN3 [pain]
PAINPERCENT [0] // percentage of time pain is shown
DIE [die] // dying animations
DIE1 [die2]
DIE2 [die]
DIE3 [die2]
DIEHOLD [5] // time corpse still appears
DIEFADE [10] // fadeout time of corpse
KILLERX [0] // X pos of enemy before death
KILLERY [0] // Y pos of enemy before death
KILLERZ [0] // Z pos of enemy before death
KILLER [null] // name o killer
RUN [run] // running animation
RUNSPEED [300] // average run speed
RUNSOUND [breath.wav]
WALK [walk] // walking animation
WALKSPEED [200] // average walk speed
WEAPON1 [M16_bot]
WEAP1MAG [30]
WEAPON2 [FAMAS_bot]
WEAP2MAG [25]
WEAPON3 [AWP_BOT] // Sniper Weapon
WEAP3MAG [10]
WEAPON4 [MP7_BOT]
WEAP4MAG [40]
WEAPON5 [ump_bot]
WEAP5MAG [25]
CURRENTWEAPAMMO [0]
ATTACKRANGE [3000]
SIGHTRANGE [3400]
RELOADTIME [2]
CLIPSIZE [0]
BULLET [bad_shell]
FIREBONE [BIP01]
WEAPON [0]
MISSILEATTACK [shoot] // missile attacking animation
SHOOTUP [shoot1]
SHOOTDOWN [shoot2]
STRAFE [strafe] // strafeing animation
RELOAD [reload] // reload animation
SNIPERRANGE [5000] // distance for sniper rifle
MISSILERANGE [3400] // max distance to start missile attack
PROJECTILE [rifle_shell] // projectile name
FIREBONE [BIP01 R HAND] // projectile launch bone
OFFSETX [0] // launch offsets
OFFSETY [0]
OFFSETZ [0]
ATTACKDELAY [1] // time between shots
FIREDELAY [0.8] // delay after animation starts before projectile launch
SKILL [0] // skill level 1 to 10
LOSTTIME [15] // time to search for enemy before giving up
POINTRADIUS [20] // radius from point when considered there
INSIDEKOTH [false] // trigger koth
// local variables - do not change
RUNFUNC [monster_run_start] // monster run to attack function
MISSILEFUNC [monster_missile_start] // monster missile function
LOSTFUNC [monster_lost_target_start] // monster lost target function
AS_NONE [0]
AS_MISSILE [2]
AS_STRAIGHT [3]
attack_delay [0]
lost_time [0]
back_up [false]
back_time [0]
left_time [0]
back_flag [false]
fire_delay [0]
skill_time [0]
attack_state [0]
lastorder [null]
lastanim [null]
killed [false]
// spawn pawn and do setup work
Spawn[ ()
{
Console(true);
BoxWidth(BOXWIDTH); // set bounding box width/depth
Scale(SCALE); // scale actor
AttributeOrder(HEALTHATTRIBUTE, HEALTH, "Death"); // give monster health
HostilePlayer(HOSTILEPLAYER); // set who monster is hostile to
HostileSame(HOSTILESAME);
HostileDifferent(HOSTILEDIFFERENT);
TargetGroup(HOSTILETOGROUP);
AvoidOrder("Avoidance");
switch(random(1,5)) // lets bot choose between 5 weapons
{
case 1
{
SetWeapon("M16_bot");
WEAPON = 1; // Weapon Number. Used in Attack cmds.
CURRENTWEAPAMMO = WEAP1MAG + 0;
}
case 2
{
SetWeapon("FAMAS_bot");
WEAPON = 2; // Weapon Number. Used in Attack cmds.
CURRENTWEAPAMMO = WEAP2MAG + 0;
}
case 3
{
SetWeapon("AWP_BOT"); // Sets Sniping Weapon
WEAPON = 3; // Weapon Number. Used in Attack cmds.
CURRENTWEAPAMMO = WEAP3MAG + 0;
}
case 4
{
SetWeapon("MP7_BOT");
WEAPON = 4; // Weapon Number. Used in Attack cmds.
CURRENTWEAPAMMO = WEAP4MAG + 0;
}
case 5
{
SetWeapon("ump_bot");
WEAPON = 5; // Weapon Number. Used in Attack cmds.
CURRENTWEAPAMMO = WEAP5MAG + 0;
}
}
CLIPSIZE = CURRENTWEAPAMMO + 0;
FIRSTPOINT = self.point_name;
SetFOV(FOV); // set field of view
SetGroup(GROUP); // assign a group to belong to
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // seen a target to chase
AddPainOrder("IdlePain", 100); // show pain and trigger alert
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
NewOrder("Patrol");
} ]
DieSpawn[ ()
{
Console(true);
BoxWidth(BOXWIDTH); // set bounding box width/depth
HostilePlayer(HOSTILEPLAYER); // set who monster is hostile to
HostileSame(HOSTILESAME);
HostileDifferent(HOSTILEDIFFERENT);
TargetGroup(HOSTILETOGROUP);
AvoidOrder("Avoidance");
CURRENTWEAPAMMO = CLIPSIZE + 0;
NewPoint(FIRSTPOINT);
SetFOV(FOV); // set field of view
SetGroup(GROUP); // assign a group to belong to
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // seen a target to chase
AddPainOrder("IdlePain", 100); // show pain and trigger alert
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
if(random(1,10) < 6)
{
NewOrder("Patrol");
}
else
{
FindPointOrder("Patrol");
}
} ]
Patrol[ ()
{
RotateMoveToPoint(RUN, YAWSPEED, RUNSPEED*SCALE, false, RUNSOUND);
MoveToPoint(RUN, RUNSPEED*SCALE, RUNSOUND);
FindTargetOrder(4000, "FoundTarget", "enemy_health" );
AvoidOrder("Avoidance");
AddPainOrder("IdlePain", 100);
NextPoint();
RestartOrder();
} ]
Avoidance[ ()
{
if(random(1,10) < 5)
{
MoveForward(RUN, RUNSPEED, 100, RUNSOUND); // Runs forward
MoveRight(RUN, RUNSPEED, 100, RUNSOUND );
Jump(RUN, 50, true, RUNSOUND );
AddTimerOrder(1, 10, "CheckForPoints" );
}
else
{
MoveForward(RUN, RUNSPEED, 100, RUNSOUND); // Run forward
MoveLeft(RUN, RUNSPEED, 100, RUNSOUND );
AddTimerOrder(1, 10, "CheckForPoints" );
}
Return();
} ]
CheckForPoints[ ()
{
if(self.point_vis)
{
NewOrder("Patrol");
}
else
{
FindPointOrder("Patrol");
}
} ]
// show pain at idle then trigger to alert
IdlePain[ ()
{
switch(random(1,4)) // chose between 4 animations
{
case 1
{
PlayAnimation(PAIN, true, "");
}
case 2
{
PlayAnimation(PAIN1, true, "");
}
case 3
{
PlayAnimation(PAIN2, true, "");
}
case 4
{
PlayAnimation(PAIN3, true, "");
}
}
NewOrder("FoundTarget");
} ]
// start shifting from idle to alert
IdleToAlert[ ()
{
FindTargetOrder(ALERTSIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // increase viewing distance
AddPainOrder("AlertPain", PAINPERCENT); // show pain
AddTimerOrder(1, 10, "AlertToIdle"); // go to idle after 10 secs
SetEventState(ALERTTRIGGER, false); // turn off alert trigger
NewOrder("Patrol");
} ]
// look around at alert looking for enemy
Alert[ ()
{
FindTargetOrder(ALERTSIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);
PlayAnimation(STAND, true, "");
if(random(1,10)>3) // turn around once in awhile
{
if(random(1,10)>5)
{
Rotate(TURNL, 102, 0, 90, 0, "");
Rotate(TURNL, 102, 0, 90, 0, "");
Rotate(TURNL, 102, 0, 90, 0, "");
Rotate(TURNL, 102, 0, 90, 0, "");
}
else
{
Rotate(TURNR, 108, 0, -90, 0, "");
Rotate(TURNR, 108, 0, -90, 0, "");
Rotate(TURNR, 108, 0, -90, 0, "");
Rotate(TURNR, 108, 0, -90, 0, "");
}
}
RestartOrder();
} ]
// show pain at alert
AlertPain[ ()
{
switch(random(1,4)) // play on of 4 animations
{
case 1
{
AddExplosion("blood",FIREBONE,0,0,0);
PlayAnimation(PAIN, true, "");
}
case 2
{
AddExplosion("blood2",FIREBONE,0,0,0);
PlayAnimation(PAIN1, true, "");
}
case 3
{
AddExplosion("blood",FIREBONE,0,0,0);
AddExplosion("blood2",FIREBONE,0,0,0);
PlayAnimation(PAIN2, true, "");
}
case 4
{
AddExplosion("blood",FIREBONE,0,0,0);
AddExplosion("blood2",FIREBONE,0,50,0);
PlayAnimation(PAIN3, true, "");
}
}
Return();
} ]
// timed out at alert so go to idle
AlertToIdle[ ()
{
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // decrease viewing distance
AddPainOrder("IdlePain", 100); // show pain
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
NewOrder("Patrol");
} ]
// found a target to attack
FoundTarget[ ()
{
DelTimerOrder(1); // get rid of alert timer
LowLevel(RUNFUNC); // attack functions are low level
} ]
// lost target while attacking so go back to idle again
LostTarget[ ()
{
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // seen a target to chase
AddPainOrder("IdlePain", 100); // show pain and trigger alert
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
NewOrder("Patrol");
} ]
// you died
Death[ ()
{
killed = true;
AddExplosion("blood",FIREBONE,0,0,0);
AddExplosion("blood2",FIREBONE,0,50,0);
if(random(1,10) < 6)
{
AnimateStop(DIE,DIEHOLD, "speak/imdieing.wav");
}
else
{
AnimateStop(DIE1,DIEHOLD, "die.wav");
}
ModifyAttribute("terr", 1, "Player");
if(random(1,10) < 6)
{
TeleportToPoint(SPAWNPOINT,0,0,0);
}
else
{
TeleportToPoint(SPAWNPOINT2,0,0,0);
}
SetAttribute(HEALTHATTRIBUTE,HEALTH);
NewOrder("DieSpawn");
} ]
// Low level attack routines
// Start of run to attack
monster_run_start[ ()
{
Animate(RUN); // play run animation
self.ThinkTime = 0; // start thinking on next frame
self.think = "monster_run"; // go to run attack routine
self.ideal_yaw = enemy_yaw; // set direction to run
self.yaw_speed = YAWSPEED; // set rotation speed
back_up = false; // initialize obsticle avoidance
attack_state = AS_NONE; // not attacking yet
} ]
// run to enemy to attack
monster_run[ ()
{
if(self.health<=0)
{
drop();
HighLevel("Death"); // dead
return 0;
}
if(EnemyExist(DAMAGEATTRIBUTE) < 3)
{
HighLevel("LostTarget"); // enemy is gone or dead
return 0;
}
if(self.enemy_range < ATTACKRANGE)
{
self.think = "monster_missile_start";
return 0;
}
if(enemy_vis = false)
{
self.think = LOSTFUNC; // lost sight of enemy
lost_time = time + LOSTTIME;
return 0;
}
if(CURRENTWEAPAMMO < 1)
{
Animate(RELOAD);
self.think = "run_reload";
}
if(random(1,10) < 2)
{
PlaySound("speak/wehavehostiles.wav",1000);
}
ai_run(random(RUNSPEED-2,RUNSPEED+2)); // run toward enemy
} ]
run_reload[ ()
{
ai_face();
SetHoldAtEnd(true);
if(self.animate_at_end)
{
CURRENTWEAPAMMO = CLIPSIZE + 0;
self.think = "monster_run";
}
} ]
// start of lost sight of enemy routine
monster_lost_target_start[ ()
{
Animate(RUN); // play run animation
self.ThinkTime = 0; // start thinking on next frame
self.think = "monster_lost_target";
} ]
// go to last known location of enemy
monster_lost_target[ ()
{
self.ThinkTime = 0.1;
if(lost_time<time)
{
HighLevel("LostTarget"); // timed out while looking
return 0;
}
if(self.health<=0)
{
drop();
HighLevel("Death"); // died
return 0;
}
if(self.in_pain = true and (random(1,10) < 1))
{
if(random(1,10) < 2)
{
AddExplosion("blood",FIREBONE,0,0,0);
AddExplosion("blood2",FIREBONE,0,50,0);
PlaySound("speak/backup.wav", 1000);
}
}
if(EnemyExist(DAMAGEATTRIBUTE) < 3)
{
HighLevel("LostTarget"); // enemy died or was removed
return 0;
}
if(CURRENTWEAPAMMO < 1)
{
Animate(RELOAD);
self.think = "lost_reload";
}
if(enemy_vis = true)
{
if(random(1,10)>5)
{
PlaySound("speak/attack.wav", 1000);
}
else
{
PlaySound("speak/wehavehostiles.wav", 1000);
}
self.think = "monster_run_start"; // seen again so run to attack
self.ThinkTime = 0;
return 0;
}
if(enemy_range>POINTRADIUS) // get close to last known location
{
walk_movetogoal(random(RUNSPEED-2,RUNSPEED+2));
}
else
{
HighLevel("LostTarget"); // can't find at last known location
return 0;
}
} ]
// Reload the weapon
lost_reload[ ()
{
ai_face();
SetHoldAtEnd(true);
if(self.animate_at_end)
{
CURRENTWEAPAMMO = CLIPSIZE + 0;
self.think = "monster_lost_target_start";
}
} ]
// start of missile attack
monster_missile_start[ ()
{
if(WEAPON = 3)
{
Animate(MISSILEATTACK); // play missile attack animation
SetHoldAtEnd(true);
self.ThinkTime = 0;
self.think = "sniper_shoot";
fire_delay = time + FIREDELAY; // set firing delay
UpdateTarget(); // update target location
skill_time = time + (SKILL*0.1); // calculate next update time
attack_delay = time + ATTACKDELAY; // delay until next shot
}
else
{
Animate(MISSILEATTACK); // play missile attack animation
SetHoldAtEnd(true);
self.ThinkTime = 0;
self.think = "monster_missile";
fire_delay = time + FIREDELAY; // set firing delay
UpdateTarget(); // update target location
skill_time = time + (SKILL*0.1); // calculate next update time
attack_delay = time + ATTACKDELAY; // delay until next shot
}
} ]
sniper_shoot[ ()
{
self.ThinkTime = 0.1;
if(self.health<=0)
{
SetHoldAtEnd(false);
drop();
HighLevel("Death"); // dead
return 0;
}
exist = EnemyExist(DAMAGEATTRIBUTE);
if(exist < 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead and gone
return 0;
}
if(exist = 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead but body remains
return 0;
}
if(self.enemy_vis = false)
{
self.think = LOSTFUNC; // lost sight of enemy
lost_time = self.time + LOSTTIME;
SetHoldAtEnd(false);
return 0;
}
if(CURRENTWEAPAMMO < 1)
{
Animate(RELOAD);
self.think = "shoot_reload";
}
if(self.enemy_range>SNIPERRANGE)
{
self.think = RUNFUNC; // too far away so run toward
SetHoldAtEnd(false);
return 0;
}
if(skill_time<self.time) // update according to skill level
{
UpdateTarget(); // update target location
skill_time = self.time + (SKILL*0.1);
ai_face(); // face enemy while attacking
}
if(fire_delay<self.time) // delay after animation starts before firing
{
FireProjectile("sniper_shell", FIREBONE, OFFSETX, OFFSETY, OFFSETZ, DAMAGEATTRIBUTE);
CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
PlaySound("good.wav", 500);
SetHoldAtEnd(false);
fire_delay = self.time + 1; // set delay well ahead so it is ignored
}
} ]
// attack target with projectile
monster_missile[ ()
{
self.ThinkTime = 0.2;
debug(CURRENTWEAPAMMO);
if(self.health<=0)
{
drop();
SetHoldAtEnd(false);
HighLevel("Death"); // dead
return 0;
}
if(self.in_pain = true and (random(1,10) < 1))
{
if(random(1,10) < 2)
{
AddExplosion("blood",FIREBONE,0,0,0);
AddExplosion("blood2",FIREBONE,0,50,0);
}
}
exist = EnemyExist(DAMAGEATTRIBUTE);
if(exist < 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead and gone
return 0;
}
if(exist = 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead but body remains
return 0;
}
if(enemy_vis = false)
{
self.think = LOSTFUNC; // lost sight of enemy
lost_time = time + LOSTTIME;
SetHoldAtEnd(false);
return 0;
}
if(enemy_range>MISSILERANGE)
{
self.think = RUNFUNC; // too far away so run toward
SetHoldAtEnd(false);
return 0;
}
if(skill_time < time) // update according to skill level
{
UpdateTarget(); // update target location
skill_time = time + (SKILL*0.1);
ai_face(); // face enemy while attacking
}
if(enemy_range<MISSILERANGE) // delay after animation starts before firing
{
UpdateTarget(); // update target location
Animate(MISSILEATTACK);
CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
SetTargetPoint(random(-20,20),1000*sin(-self.enemy_pitch) + random(-20,20) + 20,1000*cos(self.enemy_pitch) + random(-20,20));
FireProjectile(PROJECTILE,"BIP01",0,0,0,"enemy_health");
AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
PlaySound("good.wav");
}
if(self.enemy_Y > Integer(self.current_Y + 100))
{
UpdateTarget(); // update target location
Animate(SHOOTUP);
CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
FireProjectile("bad_shell", "BIP 01", 0, 0, 25, "enemy_health");
AddExplosion("Muzzleflash2","BIP 01 R HAND",0,0,0);
PlaySound("good.wav", 500);
SetHoldAtEnd(false);
}
if(self.enemy_Y < Integer(self.current_Y - 100))
{
UpdateTarget(); // update target location
Animate(SHOOTDOWN);
CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
FireProjectile(PROJECTILE, FIREBONE, OFFSETX, OFFSETY, OFFSETZ, "enemy_health");
AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
PlaySound("good.wav", 500);
SetHoldAtEnd(false);
}
if(CURRENTWEAPAMMO < 1)
{
Animate(RELOAD);
self.think = "shoot_reload";
}
if(random(1,10) <2)
{
Animate(STRAFE);
if(random(1,10) < 6)
{
ForceLeft(30);
return 0;
}
else
{
ForceRight(30);
return 0;
}
}
if(fire_delay<time) // delay after animation starts before firing
{
if(random(1,10) < 5)
{
Animate(STRAFE);
ForceRight(10);
return 0;
}
else
{
Animate(STRAFE);
ForceLeft(10);
return 0;
}
UpdateTarget(); // update target location
Animate(MISSILEATTACK);
CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
SetTargetPoint(random(-20,20),1000*sin(-self.enemy_pitch) + random(-20,20) + 20,1000*cos(self.enemy_pitch) + random(-20,20));
FireProjectile(PROJECTILE,"BIP01",0,0,0,"enemy_health");
AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
PlaySound("good.wav");
}
if(self.animate_at_end = true)
{
if(attack_delay < time)
{
self.think = "monster_missile_start"; // go back to missile attack
SetHoldAtEnd(false);
self.ThinkTime = 0.1;
}
}
} ]
// Reload the weapon
shoot_reload[ ()
{
ai_face();
SetHoldAtEnd(true);
if(self.animate_at_end)
{
CURRENTWEAPAMMO = CLIPSIZE + 0;
self.think = "monster_missile_start";
}
} ]
// Drop that gun soldier
drop[ ()
{
if(WEAPON = 1)
{
SetPosition("m16", self.current_X, self.current_Y, self.current_Z);
}
if(WEAPON = 2)
{
SetPosition("famas", self.current_X, self.current_Y, self.current_Z);
}
if(WEAPON = 3)
{
SetPosition("awp", self.current_X, self.current_Y, self.current_Z);
}
if(WEAPON = 4)
{
SetPosition("mp7", self.current_X, self.current_Y, self.current_Z);
}
if(WEAPON = 5)
{
SetPosition("ump", self.current_X, self.current_Y, self.current_Z);
}
} ]
// If the bot is in side the koth area
insidekoth[ ()
{
if(GetDistanceTo("hill") < 1000)
{
INSIDEKOTH = true;
HighLevel("Camp");
return 0;
}
} ]
Camp[ ()
{
if(INSIDEKOTH = true)
{
FindTargetOrder(SIGHTRANGE, "FoundTarget", DAMAGEATTRIBUTE);
if(random(1,10) < 3)
{
Rotate(TURNL, random(1,180), 0, random(1,90), 0, "");
}
}
else
{
NewOrder("Patrol");
}
} ]
// basic AI routines
// run toward enemy and see if you are ready to attack
ai_run[ (dist)
{
if (attack_state = AS_MISSILE) // do missile attack
{
ai_run_missile();
return 0;
}
if (CheckAnyAttack()) // check if you can start the actual attack
{
return 0;
}
walk_movetogoal(dist); // else move toward the enemy
} ]
// missile attack setup
ai_run_missile[ ()
{
ai_face();
if(FacingIdeal()) // got close enough
{
self.think = MISSILEFUNC; // start missile attack
attack_state = AS_STRAIGHT;
UpdateTarget();
skill_time = time + (SKILL*0.1);
}
} ]
// face enemy
ai_face[ ()
{
self.ideal_yaw = enemy_yaw;
ChangeYaw(); // rotate to face enemy
} ]
// use walkmove to naviagte to enemy
walk_movetogoal[ (dist)
{
if(IsFalling = true)
{
return 0; // don't move while falling
}
if(back_up = false)
{
ai_face(); // turn to face enemy
if(FacingIdeal())
{
if(walkmove(self.current_yaw, dist) = true)
{
return 0; // can move in current direction
}
else
{
if(random(1,10)<3) // backup and move sideways
{
back_up = true;
back_time = time + 0.5;
back_flag = false;
return 0;
}
else
{
ForceUp(30); // jump up, forward and to side
ForceForward(30);
if(random(1,10)<6)
{
ForceRight(30);
}
else
{
ForceLeft(30);
}
}
}
}
}
else
{
if(back_flag = false) // go backward 1/2 sec
{
if(back_time > time)
{
walkmove((self.current_yaw-(180*0.0174532925199433)), dist);
return 0;
}
else
{
back_time = time + 0.5;
back_flag = true;
}
}
if(back_time > time) // go sideways 1/2 sec
{
walkmove((self.current_yaw-(90*0.0174532925199433)), dist);
return 0;
}
back_up = false;
}
} ]
// check if nearly facing enemy
FacingIdeal[ ()
{
selfangle = self.current_yaw/0.0174532925199433; // your direction in degrees
idealangle = self.ideal_yaw/0.0174532925199433; // his direction in degrees
delta = selfangle - idealangle; // difference in directions
if (delta > -20 and delta < 20) // within 20 degrees is close enough
{
return true;
}
return false;
} ]
// check if ready to do actual attacking
CheckAnyAttack[ ()
{
if(attack_delay>time)
{
return false;
}
if(enemy_range<MISSILERANGE) // inside missile range
{
attack_state = AS_MISSILE; // do a missile attack
return true;
}
return false;
} ]
}
Enemy SCript
Code: Select all
{
// Enemy Bot Script
// Made from Generic missile monster
GROUP [enemy] // name of monster group
BOXWIDTH [40] // width and depth of bounding box
HOSTILEPLAYER [true] // hostile to player
HOSTILEDIFFERENT [true] // hostile to different Pawn group
HOSTILESAME [false] // hostile to same Pawn group
HOSTILETOGROUP [guy] // hostile to this group
HEALTHATTRIBUTE [enemy_health] // name of health attribute
HEALTH [100] // initial amount of health
SIGHTDIST [500] // max distance monster can see at idle
ALERTSIGHTDIST [600] // max distance monster can see when alert
FOV [180] // field of view in degrees
YAWSPEED [120] // speed of rotation in deg/sec
DAMAGEATTRIBUTE [playerhealth] // attribute damaged by attack
ALERTTRIGGER [AlertG] // name of alert trigger
SCALE [1.4] // amount to scale actor by
SPAWNPOINT [spawn_enemy] // spawnpoint no 1
SPAWNPOINT2 [spawn_enemy2] // spawnpoint no 2
FIRSTPOINT [null]
STAND [idle] // idle animation
TURNL [idle] // turn left animation
TURNR [idle] // turn right animation
PAINPERCENT [0] // percentage of time pain is shown
DIE [die] // dying animations
DIE1 [die2]
DIE2 [die]
DIE3 [die2]
DIEHOLD [5] // time corpse still appears
DIEFADE [10] // fadeout time of corpse
KILLERX [0] // X pos of enemy before death
KILLERY [0] // Y pos of enemy before death
KILLERZ [0] // Z pos of enemy before death
KILLER [null] // name o killer
RUN [run] // running animation
RUNSPEED [300] // average run speed
RUNSOUND [breath.wav]
WALK [walk] // walking animation
WALKSPEED [200] // average walk speed
WEAPON1 [ak_bot]
WEAP1MAG [30]
WEAPON2 [galil_bot]
WEAP2MAG [30]
WEAPON3 [AWP_BOT] // Sniper Weapon
WEAP3MAG [10]
WEAPON4 [pp19_BOT]
WEAP4MAG [45]
WEAPON5 [ump_bot]
WEAP5MAG [25]
CURRENTWEAPAMMO [0]
ATTACKRANGE [3000]
SIGHTRANGE [3400]
RELOADTIME [2]
CLIPSIZE [0]
BULLET [bad_shell]
FIREBONE [BIP01]
WEAPON [0]
MISSILEATTACK [shoot] // missile attacking animation
SHOOTUP [shoot1]
SHOOTDOWN [shoot2]
STRAFE [strafe] // strafeing animation
RELOAD [reload] // reload animation
SNIPERRANGE [5000] // distance for sniper rifle
MISSILERANGE [3400] // max distance to start missile attack
PROJECTILE [rifle_shell] // projectile name
FIREBONE [BIP01 R HAND] // projectile launch bone
OFFSETX [0] // launch offsets
OFFSETY [0]
OFFSETZ [0]
ATTACKDELAY [1] // time between shots
FIREDELAY [0.8] // delay after animation starts before projectile launch
SKILL [0] // skill level 1 to 10
LOSTTIME [15] // time to search for enemy before giving up
POINTRADIUS [20] // radius from point when considered there
INSIDEKOTH [false] // trigger koth
// local variables - do not change
RUNFUNC [monster_run_start] // monster run to attack function
MISSILEFUNC [monster_missile_start] // monster missile function
LOSTFUNC [monster_lost_target_start] // monster lost target function
AS_NONE [0]
AS_MISSILE [2]
AS_STRAIGHT [3]
attack_delay [0]
lost_time [0]
back_up [false]
back_time [0]
left_time [0]
back_flag [false]
fire_delay [0]
skill_time [0]
attack_state [0]
lastorder [null]
lastanim [null]
killed [false]
// spawn pawn and do setup work
Spawn[ ()
{
Console(true);
BoxWidth(BOXWIDTH); // set bounding box width/depth
Scale(SCALE); // scale actor
AttributeOrder(HEALTHATTRIBUTE, HEALTH, "Death"); // give monster health
HostilePlayer(HOSTILEPLAYER); // set who monster is hostile to
HostileSame(HOSTILESAME);
HostileDifferent(HOSTILEDIFFERENT);
TargetGroup(HOSTILETOGROUP);
AvoidOrder("Avoidance");
switch(random(1,5)) // lets bot choose between 5 weapons
{
case 1
{
SetWeapon("ak_bot");
WEAPON = 1; // Weapon Number. Used in Attack cmds.
CURRENTWEAPAMMO = WEAP1MAG + 0;
}
case 2
{
SetWeapon("galil_bot");
WEAPON = 2; // Weapon Number. Used in Attack cmds.
CURRENTWEAPAMMO = WEAP2MAG + 0;
}
case 3
{
SetWeapon("AWP_bot"); // Sets Sniping Weapon
WEAPON = 3; // Weapon Number. Used in Attack cmds.
CURRENTWEAPAMMO = WEAP3MAG + 0;
}
case 4
{
SetWeapon("pp19_bot");
WEAPON = 4; // Weapon Number. Used in Attack cmds.
CURRENTWEAPAMMO = WEAP4MAG + 0;
}
case 5
{
SetWeapon("ump_bot");
WEAPON = 5; // Weapon Number. Used in Attack cmds.
CURRENTWEAPAMMO = WEAP5MAG + 0;
}
}
CLIPSIZE = CURRENTWEAPAMMO + 0;
FIRSTPOINT = self.point_name;
SetFOV(FOV); // set field of view
SetGroup(GROUP); // assign a group to belong to
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // seen a target to chase
AddPainOrder("IdlePain", 100); // show pain and trigger alert
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
NewOrder("Patrol");
} ]
DieSpawn[ ()
{
Console(true);
BoxWidth(BOXWIDTH); // set bounding box width/depth
HostilePlayer(HOSTILEPLAYER); // set who monster is hostile to
HostileSame(HOSTILESAME);
HostileDifferent(HOSTILEDIFFERENT);
TargetGroup(HOSTILETOGROUP);
AvoidOrder("Avoidance");
CURRENTWEAPAMMO = CLIPSIZE + 0;
NewPoint(FIRSTPOINT);
SetFOV(FOV); // set field of view
SetGroup(GROUP); // assign a group to belong to
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // seen a target to chase
AddPainOrder("IdlePain", 100); // show pain and trigger alert
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
if(random(1,10) < 6)
{
NewOrder("Patrol");
}
else
{
FindPointOrder("Patrol");
}
} ]
Patrol[ ()
{
RotateMoveToPoint(RUN, YAWSPEED, RUNSPEED*SCALE, false, RUNSOUND);
MoveToPoint(RUN, RUNSPEED*SCALE, RUNSOUND);
FindTargetOrder(4000, "FoundTarget", "playerhealth" );
AvoidOrder("Avoidance");
AddPainOrder("IdlePain", 100);
NextPoint();
RestartOrder();
} ]
Avoidance[ ()
{
if(random(1,10) < 5)
{
MoveForward(RUN, RUNSPEED, 100, RUNSOUND); // Runs forward
MoveRight(RUN, RUNSPEED, 100, RUNSOUND );
Jump(RUN, 50, true, RUNSOUND );
AddTimerOrder(1, 10, "CheckForPoints" );
}
else
{
MoveForward(RUN, RUNSPEED, 100, RUNSOUND); // Run forward
MoveLeft(RUN, RUNSPEED, 100, RUNSOUND );
AddTimerOrder(1, 10, "CheckForPoints" );
}
Return();
} ]
CheckForPoints[ ()
{
if(self.point_vis)
{
NewOrder("Patrol");
}
else
{
FindPointOrder("Patrol");
}
} ]
// show pain at idle then trigger to alert
IdlePain[ ()
{
NewOrder("FoundTarget");
} ]
// start shifting from idle to alert
IdleToAlert[ ()
{
FindTargetOrder(ALERTSIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // increase viewing distance
AddPainOrder("AlertPain", PAINPERCENT); // show pain
AddTimerOrder(1, 10, "AlertToIdle"); // go to idle after 10 secs
SetEventState(ALERTTRIGGER, false); // turn off alert trigger
NewOrder("Patrol");
} ]
// look around at alert looking for enemy
Alert[ ()
{
FindTargetOrder(ALERTSIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE);
PlayAnimation(STAND, true, "");
if(random(1,10)>3) // turn around once in awhile
{
if(random(1,10)>5)
{
Rotate(TURNL, 102, 0, 90, 0, "");
Rotate(TURNL, 102, 0, 90, 0, "");
Rotate(TURNL, 102, 0, 90, 0, "");
Rotate(TURNL, 102, 0, 90, 0, "");
}
else
{
Rotate(TURNR, 108, 0, -90, 0, "");
Rotate(TURNR, 108, 0, -90, 0, "");
Rotate(TURNR, 108, 0, -90, 0, "");
Rotate(TURNR, 108, 0, -90, 0, "");
}
}
RestartOrder();
} ]
// show pain at alert
AlertPain[ ()
{
switch(random(1,4)) // play on of 4 animations
{
case 1
{
AddExplosion("blood",FIREBONE,0,0,0);
PlayAnimation(PAIN, true, "");
}
case 2
{
AddExplosion("blood2",FIREBONE,0,0,0);
PlayAnimation(PAIN1, true, "");
}
case 3
{
AddExplosion("blood",FIREBONE,0,0,0);
AddExplosion("blood2",FIREBONE,0,0,0);
PlayAnimation(PAIN2, true, "");
}
case 4
{
AddExplosion("blood",FIREBONE,0,0,0);
AddExplosion("blood2",FIREBONE,0,50,0);
PlayAnimation(PAIN3, true, "");
}
}
Return();
} ]
// timed out at alert so go to idle
AlertToIdle[ ()
{
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // decrease viewing distance
AddPainOrder("IdlePain", 100); // show pain
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
NewOrder("Patrol");
} ]
// found a target to attack
FoundTarget[ ()
{
DelTimerOrder(1); // get rid of alert timer
LowLevel(RUNFUNC); // attack functions are low level
} ]
// lost target while attacking so go back to idle again
LostTarget[ ()
{
FindTargetOrder(SIGHTDIST, "FoundTarget", DAMAGEATTRIBUTE); // seen a target to chase
AddPainOrder("IdlePain", 100); // show pain and trigger alert
AddTriggerOrder("IdleToAlert", ALERTTRIGGER, 0); // go to alert when triggered
NewOrder("Patrol");
} ]
// you died
Death[ ()
{
killed = true;
AddExplosion("blood",FIREBONE,0,0,0);
AddExplosion("blood2",FIREBONE,0,50,0);
if(random(1,10) < 6)
{
AnimateStop(DIE,DIEHOLD, "speak/imdieing.wav");
}
else
{
AnimateStop(DIE1,DIEHOLD, "die.wav");
}
ModifyAttribute("usmc", 1, "Player");
if(random(1,10) < 6)
{
TeleportToPoint(SPAWNPOINT,0,0,0);
}
else
{
TeleportToPoint(SPAWNPOINT2,0,0,0);
}
SetAttribute(HEALTHATTRIBUTE,HEALTH);
NewOrder("DieSpawn");
} ]
// Low level attack routines
// Start of run to attack
monster_run_start[ ()
{
Animate(RUN); // play run animation
self.ThinkTime = 0; // start thinking on next frame
self.think = "monster_run"; // go to run attack routine
self.ideal_yaw = enemy_yaw; // set direction to run
self.yaw_speed = YAWSPEED; // set rotation speed
back_up = false; // initialize obsticle avoidance
attack_state = AS_NONE; // not attacking yet
} ]
// run to enemy to attack
monster_run[ ()
{
if(self.health<=0)
{
drop();
HighLevel("Death"); // dead
return 0;
}
if(EnemyExist(DAMAGEATTRIBUTE) < 3)
{
HighLevel("LostTarget"); // enemy is gone or dead
return 0;
}
if(self.enemy_range < SHOOTRANGE)
{
self.think = "monster_missile_start";
return 0;
}
if(enemy_vis = false)
{
self.think = LOSTFUNC; // lost sight of enemy
lost_time = time + LOSTTIME;
return 0;
}
if(CURRENTWEAPAMMO < 1)
{
Animate(RELOAD);
self.think = "run_reload";
}
if(random(1,10) < 2)
{
PlaySound("speak/wehavehostiles.wav",1000);
}
ai_run(random(RUNSPEED-2,RUNSPEED+2)); // run toward enemy
} ]
run_reload[ ()
{
ai_face();
SetHoldAtEnd(true);
if(self.animate_at_end)
{
CURRENTWEAPAMMO = CLIPSIZE + 0;
self.think = "monster_run";
}
} ]
// start of lost sight of enemy routine
monster_lost_target_start[ ()
{
Animate(RUN); // play run animation
self.ThinkTime = 0; // start thinking on next frame
self.think = "monster_lost_target";
} ]
// go to last known location of enemy
monster_lost_target[ ()
{
self.ThinkTime = 0.1;
if(lost_time<time)
{
HighLevel("LostTarget"); // timed out while looking
return 0;
}
if(self.health<=0)
{
drop();
HighLevel("Death"); // died
return 0;
}
if(self.in_pain = true and (random(1,10) < 1))
{
if(random(1,10) < 2)
{
AddExplosion("blood",FIREBONE,0,0,0);
AddExplosion("blood2",FIREBONE,0,50,0);
PlaySound("speak/backup.wav", 1000);
}
}
if(EnemyExist(DAMAGEATTRIBUTE) < 3)
{
HighLevel("LostTarget"); // enemy died or was removed
return 0;
}
if(CURRENTWEAPAMMO < 1)
{
Animate(RELOAD);
self.think = "lost_reload";
}
if(enemy_vis = true)
{
if(random(1,10)>5)
{
PlaySound("speak/attack.wav", 1000);
}
else
{
PlaySound("speak/wehavehostiles.wav", 1000);
}
self.think = "monster_run_start"; // seen again so run to attack
self.ThinkTime = 0;
return 0;
}
if(enemy_range>POINTRADIUS) // get close to last known location
{
walk_movetogoal(random(RUNSPEED-2,RUNSPEED+2));
}
else
{
HighLevel("LostTarget"); // can't find at last known location
return 0;
}
} ]
// Reload the weapon
lost_reload[ ()
{
ai_face();
SetHoldAtEnd(true);
if(self.animate_at_end)
{
CURRENTWEAPAMMO = CLIPSIZE + 0;
self.think = "monster_lost_target_start";
}
} ]
// start of missile attack
monster_missile_start[ ()
{
if(WEAPON = 3)
{
Animate(MISSILEATTACK); // play missile attack animation
SetHoldAtEnd(true);
self.ThinkTime = 0;
self.think = "sniper_shoot";
fire_delay = time + FIREDELAY; // set firing delay
UpdateTarget(); // update target location
skill_time = time + (SKILL*0.1); // calculate next update time
attack_delay = time + ATTACKDELAY; // delay until next shot
}
else
{
Animate(MISSILEATTACK); // play missile attack animation
SetHoldAtEnd(true);
self.ThinkTime = 0;
self.think = "monster_missile";
fire_delay = time + FIREDELAY; // set firing delay
UpdateTarget(); // update target location
skill_time = time + (SKILL*0.1); // calculate next update time
attack_delay = time + ATTACKDELAY; // delay until next shot
}
} ]
sniper_shoot[ ()
{
self.ThinkTime = 0.1;
if(self.health<=0)
{
SetHoldAtEnd(false);
drop();
HighLevel("Death"); // dead
return 0;
}
exist = EnemyExist(DAMAGEATTRIBUTE);
if(exist < 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead and gone
return 0;
}
if(exist = 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead but body remains
return 0;
}
if(self.enemy_vis = false)
{
self.think = LOSTFUNC; // lost sight of enemy
lost_time = self.time + LOSTTIME;
SetHoldAtEnd(false);
return 0;
}
if(CURRENTWEAPAMMO < 1)
{
Animate(RELOAD);
self.think = "shoot_reload";
}
if(self.enemy_range>SNIPERRANGE)
{
self.think = RUNFUNC; // too far away so run toward
SetHoldAtEnd(false);
return 0;
}
if(skill_time<self.time) // update according to skill level
{
UpdateTarget(); // update target location
skill_time = self.time + (SKILL*0.1);
ai_face(); // face enemy while attacking
}
if(fire_delay<self.time) // delay after animation starts before firing
{
FireProjectile("sniper_shell", FIREBONE, OFFSETX, OFFSETY, OFFSETZ, DAMAGEATTRIBUTE);
CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
PlaySound("good.wav", 500);
SetHoldAtEnd(false);
fire_delay = self.time + 1; // set delay well ahead so it is ignored
}
} ]
// attack target with projectile
monster_missile[ ()
{
self.ThinkTime = 0.2;
debug(CURRENTWEAPAMMO);
if(self.health<=0)
{
drop();
SetHoldAtEnd(false);
HighLevel("Death"); // dead
return 0;
}
if(self.in_pain = true and (random(1,10) < 1))
{
if(random(1,10) < 2)
{
AddExplosion("blood",FIREBONE,0,0,0);
AddExplosion("blood2",FIREBONE,0,50,0);
}
}
exist = EnemyExist(DAMAGEATTRIBUTE);
if(exist < 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead and gone
return 0;
}
if(exist = 2)
{
SetHoldAtEnd(false);
HighLevel("LostTarget"); // enemy is dead but body remains
return 0;
}
if(enemy_vis = false)
{
self.think = LOSTFUNC; // lost sight of enemy
lost_time = time + LOSTTIME;
SetHoldAtEnd(false);
return 0;
}
if(enemy_range>MISSILERANGE)
{
self.think = RUNFUNC; // too far away so run toward
SetHoldAtEnd(false);
return 0;
}
if(skill_time < time) // update according to skill level
{
UpdateTarget(); // update target location
skill_time = time + (SKILL*0.1);
ai_face(); // face enemy while attacking
}
if(enemy_range<MISSILERANGE) // delay after animation starts before firing
{
UpdateTarget(); // update target location
Animate(MISSILEATTACK);
CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
SetTargetPoint(random(-10,10),1000*sin(-self.enemy_pitch) + random(-10,10) + 20,1000*cos(self.enemy_pitch) + random(-20,20));
FireProjectile(PROJECTILE,"BIP01",0,0,0,"playerhealth");
AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
PlaySound("good.wav");
}
if(self.enemy_Y > Integer(self.current_Y + 100))
{
UpdateTarget(); // update target location
Animate(SHOOTUP);
CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
FireProjectile("bad_shell", "BIP 01", 0, 0, 25, "playerhealth");
AddExplosion("Muzzleflash2","BIP 01 R HAND",0,0,0);
PlaySound("good.wav", 500);
SetHoldAtEnd(false);
}
if(self.enemy_Y < Integer(self.current_Y - 100))
{
UpdateTarget(); // update target location
Animate(SHOOTDOWN);
CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
FireProjectile(PROJECTILE, FIREBONE, OFFSETX, OFFSETY, OFFSETZ, "playerhealth");
AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
PlaySound("good.wav", 500);
SetHoldAtEnd(false);
}
if(CURRENTWEAPAMMO < 1)
{
Animate(RELOAD);
self.think = "shoot_reload";
}
if(random(1,10) <2)
{
Animate(STRAFE);
if(random(1,10) < 6)
{
ForceLeft(30);
return 0;
}
else
{
ForceRight(30);
return 0;
}
}
if(fire_delay<time) // delay after animation starts before firing
{
if(random(1,10) < 5)
{
Animate(STRAFE);
ForceRight(10);
return 0;
}
else
{
Animate(STRAFE);
ForceLeft(10);
return 0;
}
UpdateTarget(); // update target location
Animate(MISSILEATTACK);
CURRENTWEAPAMMO = CURRENTWEAPAMMO - 1;
SetTargetPoint(random(-20,20),1000*sin(-self.enemy_pitch) + random(-20,20) + 20,1000*cos(self.enemy_pitch) + random(-20,20));
FireProjectile(PROJECTILE,"BIP01",0,0,0,"playerhealth");
AddExplosion("Muzzleflash2","BIP01 R HAND",0,0,0);
PlaySound("good.wav");
}
if(self.animate_at_end = true)
{
if(attack_delay < time)
{
self.think = "monster_missile_start"; // go back to missile attack
SetHoldAtEnd(false);
self.ThinkTime = 0.1;
}
}
} ]
// Reload the weapon
shoot_reload[ ()
{
ai_face();
SetHoldAtEnd(true);
if(self.animate_at_end)
{
CURRENTWEAPAMMO = CLIPSIZE + 0;
self.think = "monster_missile_start";
}
} ]
// Drop that gun soldier
drop[ ()
{
if(WEAPON = 1)
{
SetPosition("m16", self.current_X, self.current_Y, self.current_Z);
}
if(WEAPON = 2)
{
SetPosition("famas", self.current_X, self.current_Y, self.current_Z);
}
if(WEAPON = 3)
{
SetPosition("awp", self.current_X, self.current_Y, self.current_Z);
}
if(WEAPON = 4)
{
SetPosition("mp7", self.current_X, self.current_Y, self.current_Z);
}
if(WEAPON = 5)
{
SetPosition("ump", self.current_X, self.current_Y, self.current_Z);
}
} ]
// If the bot is in side the koth area
insidekoth[ ()
{
if(GetDistanceTo("hill") < 1000)
{
INSIDEKOTH = true;
HighLevel("Camp");
return 0;
}
} ]
Camp[ ()
{
if(INSIDEKOTH = true)
{
FindTargetOrder(SIGHTRANGE, "FoundTarget", DAMAGEATTRIBUTE);
if(random(1,10) < 3)
{
Rotate(TURNL, random(1,180), 0, random(1,90), 0, "");
}
}
else
{
NewOrder("Patrol");
}
} ]
// basic AI routines
// run toward enemy and see if you are ready to attack
ai_run[ (dist)
{
if (attack_state = AS_MISSILE) // do missile attack
{
ai_run_missile();
return 0;
}
if (CheckAnyAttack()) // check if you can start the actual attack
{
return 0;
}
walk_movetogoal(dist); // else move toward the enemy
} ]
// missile attack setup
ai_run_missile[ ()
{
ai_face();
if(FacingIdeal()) // got close enough
{
self.think = MISSILEFUNC; // start missile attack
attack_state = AS_STRAIGHT;
UpdateTarget();
skill_time = time + (SKILL*0.1);
}
} ]
// face enemy
ai_face[ ()
{
self.ideal_yaw = enemy_yaw;
ChangeYaw(); // rotate to face enemy
} ]
// use walkmove to naviagte to enemy
walk_movetogoal[ (dist)
{
if(IsFalling = true)
{
return 0; // don't move while falling
}
if(back_up = false)
{
ai_face(); // turn to face enemy
if(FacingIdeal())
{
if(walkmove(self.current_yaw, dist) = true)
{
return 0; // can move in current direction
}
else
{
if(random(1,10)<3) // backup and move sideways
{
back_up = true;
back_time = time + 0.5;
back_flag = false;
return 0;
}
else
{
ForceUp(30); // jump up, forward and to side
ForceForward(30);
if(random(1,10)<6)
{
ForceRight(30);
}
else
{
ForceLeft(30);
}
}
}
}
}
else
{
if(back_flag = false) // go backward 1/2 sec
{
if(back_time > time)
{
walkmove((self.current_yaw-(180*0.0174532925199433)), dist);
return 0;
}
else
{
back_time = time + 0.5;
back_flag = true;
}
}
if(back_time > time) // go sideways 1/2 sec
{
walkmove((self.current_yaw-(90*0.0174532925199433)), dist);
return 0;
}
back_up = false;
}
} ]
// check if nearly facing enemy
FacingIdeal[ ()
{
selfangle = self.current_yaw/0.0174532925199433; // your direction in degrees
idealangle = self.ideal_yaw/0.0174532925199433; // his direction in degrees
delta = selfangle - idealangle; // difference in directions
if (delta > -20 and delta < 20) // within 20 degrees is close enough
{
return true;
}
return false;
} ]
// check if ready to do actual attacking
CheckAnyAttack[ ()
{
if(attack_delay>time)
{
return false;
}
if(enemy_range<MISSILERANGE) // inside missile range
{
attack_state = AS_MISSILE; // do a missile attack
return true;
}
return false;
} ]
}