retarded bots(oh noes new problemz)
Posted: Thu Jul 12, 2007 11:05 pm
hello, since my other bots have....problems per say i modded genericmissile monster so it is awesome. when i changed my allies to that script they pwned the old buggy script enemies
BUT!!!!!! when i changed the enemies to that script, the enemies attacked and destroyed my allies and they did nothing! plus my allies were just going to their path with messed up anims! the run anim would sometimes freeze! noooooooooooo
Ally script
enemy script
{
BUT!!!!!! when i changed the enemies to that script, the enemies attacked and destroyed my allies and they did nothing! plus my allies were just going to their path with messed up anims! the run anim would sometimes freeze! noooooooooooo
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 [50] // 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 [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
// 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, RUNSPEED, 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[ ()
{
KILLERX = self.enemy_X;
KILLERY = self.enemy_Y;
KILLERZ = self.enemy_Z;
KILLER = self.target_name;
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[ ()
{
self.ThinkTime = 0.1;
if(self.health<=0)
{
drop();
HighLevel("Death"); // dead
return 0;
}
if(EnemyExist(DAMAGEATTRIBUTE) < 3)
{
HighLevel("LostTarget"); // enemy is gone or dead
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 + 1000; // set delay well ahead so it is ignored
}
if(self.animate_at_end = true)
{
if(attack_delay < self.time)
{
self.think = "shoot_start"; // go back to missile attack
SetHoldAtEnd(false);
self.ThinkTime = 0.1;
}
}
} ]
// 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);
}
} ]
// 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;
} ]
}
{
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 [enemy] // hostile to this group
HEALTHATTRIBUTE [enemy_health] // name of health attribute
HEALTH [50] // 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
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 [bad_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
// 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", "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, RUNSPEED, 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[ ()
{
KILLERX = self.enemy_X;
KILLERY = self.enemy_Y;
KILLERZ = self.enemy_Z;
KILLER = self.target_name;
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[ ()
{
self.ThinkTime = 0.1;
if(self.health<=0)
{
drop();
HighLevel("Death"); // dead
return 0;
}
if(EnemyExist(DAMAGEATTRIBUTE) < 3)
{
HighLevel("LostTarget"); // enemy is gone or dead
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 + 1000; // set delay well ahead so it is ignored
}
if(self.animate_at_end = true)
{
if(attack_delay < self.time)
{
self.think = "shoot_start"; // go back to missile attack
SetHoldAtEnd(false);
self.ThinkTime = 0.1;
}
}
} ]
// 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,"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);
}
} ]
// 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;
} ]
}