progress :)

This commit is contained in:
Bill Currie 2003-07-23 22:44:15 +00:00
parent f0845d2710
commit d186408279
6 changed files with 431 additions and 433 deletions

View file

@ -44,6 +44,8 @@ this notice in its entirety.
#include "libfrikbot.h"
float stagger_think;
@implementation Bot (AI)
/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@ -54,21 +56,21 @@ checks to see if an entity is on the bot's stack
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
float(entity scot) target_onstack =
-(integer)target_onstack:(entity)scot
{
if (scot == NIL)
return FALSE;
else if (self.target1 == scot)
else if (targets[0] == scot)
return 1;
else if (self.target2 == scot)
else if (targets[1] == scot)
return 2;
else if (self.target3 == scot)
else if (targets[2] == scot)
return 3;
else if (self.target4 == scot)
else if (targets[3] == scot)
return 4;
else
return FALSE;
};
}
/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@ -80,19 +82,19 @@ LIFO stack, this will be the bot's new target1
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
void(entity ent) target_add =
-(void)target_add:(entity)e
{
if (ent == NIL)
if (e == NIL)
return;
if (target_onstack (ent))
if ([self target_onstack:e])
return;
self.target4 = self.target3;
self.target3 = self.target2;
self.target2 = self.target1;
self.target1 = ent;
self.search_time = time + 5;
};
targets[3] = targets[2];
targets[2] = targets[1];
targets[1] = targets[0];
targets[0] = e;
ent.search_time = time + 5;
}
/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@ -107,31 +109,31 @@ is gone too.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
void(entity ent) target_drop =
-(void)target_drop:(entity)e
{
switch (target_onstack (ent)) {
switch ([self target_onstack:e]) {
case 1:
self.target1 = self.target2;
self.target2 = self.target3;
self.target3 = self.target4;
self.target4 = NIL;
targets[0] = targets[1];
targets[1] = targets[2];
targets[2] = targets[3];
targets[3] = NIL;
break;
case 2:
self.target1 = self.target3;
self.target2 = self.target4;
self.target3 = self.target4 = NIL;
targets[0] = targets[2];
targets[1] = targets[3];
targets[2] = targets[3] = NIL;
break;
case 3:
self.target1 = self.target4;
self.target2 = self.target3 = self.target4 = NIL;
targets[0] = targets[3];
targets[1] = targets[2] = targets[3] = NIL;
break;
case 4:
self.target1 = self.target2 = self.target3 = self.target4 = NIL;
targets[0] = targets[1] = targets[2] = targets[3] = NIL;
default:
break;
}
self.search_time = time + 5;
};
ent.search_time = time + 5;
}
/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@ -142,37 +144,37 @@ Bot has lost its target.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
void(entity targ, float success) bot_lost =
-(void)lost:(entity)targ :(integer)success
{
if (!targ)
return;
target_drop(targ);
[self target_drop:targ];
if (targ.classname == "waypoint")
targ.b_sound &= ~(ClientBitFlag (self.b_clientno));
targ.b_sound &= ~(ClientBitFlag (b_clientno));
// find a new route
if (!success) {
self.target1 = self.target2 = self.target3 = self.target4 = NIL;
self.last_way = FindWayPoint (self.current_way);
targets[0] = targets[1] = targets[2] = targets[3] = NIL;
last_way = FindWayPoint (current_way);
ClearMyRoute ();
self.b_aiflags = 0;
b_aiflags = 0;
} else {
if (targ.classname == "item_artifact_invisibility")
if (self.items & 524288)
if (ent.items & 524288)
bot_start_topic (3);
if (targ.flags & FL_ITEM) {
if (!targ.model)
targ._last = NIL;
else
targ._last = self;
targ._last = ent;
}
}
if (targ.classname != "player")
targ.search_time = time + 5;
};
}
/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@ -184,11 +186,11 @@ removed.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
void(entity targ) bot_check_lost =
-(void)check_lost:(entity)targ
{
local vector dist;
dist = realorigin (targ) - self.origin;
dist = realorigin (targ) - ent.origin;
dist_z = 0;
if (targ == NIL)
@ -196,83 +198,83 @@ void(entity targ) bot_check_lost =
// waypoints and items are lost if you get close enough to them
if (targ.flags & FL_ITEM) {
if (vlen (targ.origin - self.origin) < 32)
bot_lost (targ, TRUE);
if (vlen (targ.origin - ent.origin) < 32)
[self lost:targ :TRUE];
else if (!targ.model)
bot_lost (targ, TRUE);
[self lost:targ :TRUE];
} else if (targ.classname == "waypoint") {
if (!(self.b_aiflags & (AI_SNIPER | AI_AMBUSH))) {
if (self.b_aiflags & AI_RIDE_TRAIN) {
if (vlen (targ.origin - self.origin) < 48)
bot_lost (targ, TRUE);
} else if (self.b_aiflags & AI_PRECISION) {
if (vlen (targ.origin - self.origin) < 24)
bot_lost (targ, TRUE);
} else if (vlen (targ.origin - self.origin) < 32)
bot_lost (targ, TRUE);
if (!(b_aiflags & (AI_SNIPER | AI_AMBUSH))) {
if (b_aiflags & AI_RIDE_TRAIN) {
if (vlen (targ.origin - ent.origin) < 48)
[self lost:targ :TRUE];
} else if (b_aiflags & AI_PRECISION) {
if (vlen (targ.origin - ent.origin) < 24)
[self lost:targ :TRUE];
} else if (vlen (targ.origin - ent.origin) < 32)
[self lost:targ :TRUE];
}
} else if (targ.classname == "temp_waypoint") {
if (vlen (targ.origin - self.origin) < 32)
bot_lost (targ, TRUE);
if (vlen (targ.origin - ent.origin) < 32)
[self lost:targ :TRUE];
} else if (targ.classname == "player") {
if (targ.health <= 0)
bot_lost (targ, TRUE);
else if ((coop) || (teamplay && targ.team == self.team)) {
[self lost:targ :TRUE];
else if ((coop) || (teamplay && targ.team == ent.team)) {
if (targ.target1.classname == "player") {
if (!targ.target1.ishuman)
bot_lost (targ, TRUE);
[self lost:targ :TRUE];
} else if (targ.teleport_time > time) {
// try not to telefrag teammates
self.keys &= 960;
} else if (vlen (targ.origin - self.origin) < 128) {
if (vlen (targ.origin - self.origin) < 48)
frik_walkmove (self.origin - targ.origin);
keys &= 960;
} else if (vlen (targ.origin - ent.origin) < 128) {
if (vlen (targ.origin - ent.origin) < 48)
[self walkmove: ent.origin - targ.origin];
else {
self.keys &= 960;
keys &= 960;
bot_start_topic (4);
}
self.search_time = time + 5; // never time out
ent.search_time = time + 5; // never time out
} else if (!fisible(targ))
bot_lost (targ, FALSE);
[self lost:targ :FALSE];
} else if (waypoint_mode > WM_LOADED) {
if (vlen (targ.origin - self.origin) < 128) {
bot_lost (targ, TRUE);
if (vlen (targ.origin - ent.origin) < 128) {
[self lost:targ :TRUE];
}
}
} else if (targ.classname == "func_button") {
// buttons are lost of their frame changes
if (targ.frame) {
bot_lost (targ, TRUE);
if (self.enemy == targ)
self.enemy = NIL;
// if (self.target1)
// bot_get_path (self.target1, TRUE);
[self lost:targ :TRUE];
if (ent.enemy == targ)
ent.enemy = NIL;
// if (target[0])
// bot_get_path (target[0], TRUE);
}
} else if ((targ.movetype == MOVETYPE_NONE) && (targ.solid == SOLID_TRIGGER)) {
// trigger_multiple style triggers are lost if their thinktime changes
if (targ.nextthink >= time) {
bot_lost (targ, TRUE);
// if (self.target1)
// bot_get_path (self.target1, TRUE);
[self lost:targ :TRUE];
// if (target[0])
// bot_get_path (target[0], TRUE);
}
}
// lose any target way above the bot's head
// FIXME: if the bot can fly in your mod..
if ((targ.origin_z - self.origin_z) > 64) {
dist = targ.origin - self.origin;
if ((targ.origin_z - ent.origin_z) > 64) {
dist = targ.origin - ent.origin;
dist_z = 0;
if (vlen (dist) < 32)
if (self.flags & FL_ONGROUND)
if (!frik_recognize_plat (FALSE))
bot_lost (targ, FALSE);
if (ent.flags & FL_ONGROUND)
if (![self recognize_plat:FALSE])
[self lost:targ :FALSE];
} else if (targ.classname == "train") {
if (frik_recognize_plat (FALSE))
bot_lost (targ, TRUE);
if ([self recognize_plat:FALSE])
[self lost:targ :TRUE];
}
// targets are lost if the bot's search time has expired
if (time > self.search_time)
bot_lost (targ, FALSE);
};
if (time > ent.search_time)
[self lost:targ :FALSE];
}
/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@ -284,7 +286,7 @@ based b_aiflags.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
void() bot_handle_ai =
-(void)handle_ai
{
local entity newt;
local vector v;
@ -294,121 +296,112 @@ void() bot_handle_ai =
// wait is used by the ai to stop the bot until his search time expires / or route changes
if (self.b_aiflags & AI_WAIT)
self.keys &= 960;
if (b_aiflags & AI_WAIT)
keys &= 960;
if (self.b_aiflags & AI_DOORFLAG) {
if (b_aiflags & AI_DOORFLAG) {
// was on a door when spawned
b_temp3 = self;
self = self.last_way;
// if there is nothing there now
if (!frik_recognize_plat (FALSE)) {
newt = FindThing ("door"); // this is likely the door responsible (crossfingers)
self = b_temp3;
if (![ent.@this recognize_plat:FALSE]) {
newt = FindThing (ent, "door"); // this is likely the door responsible (crossfingers)
if (self.b_aiflags & AI_DOOR_NO_OPEN) {
if (b_aiflags & AI_DOOR_NO_OPEN) {
if (newt.nextthink)
self.keys &= 960; // wait until it closes
keys &= 960; // wait until it closes
else {
bot_lost (self.last_way, FALSE);
[self lost:last_way :FALSE];
}
} else {
if (newt.targetname) {
newt = find (NIL, target, newt.targetname);
if (newt.health > 0) {
self.enemy = newt;
bot_weapon_switch (1);
ent.enemy = newt;
[self weapon_switch:1];
} else {
// target_drop (self.last_way);
target_add (newt);
// target_drop (last_way);
[self target_add:newt];
// bot_get_path (newt, TRUE);
}
}
self.b_aiflags &= ~AI_DOORFLAG;
b_aiflags &= ~AI_DOORFLAG;
}
} else
self = b_temp3;
}
}
if (self.b_aiflags & AI_JUMP) {
if (self.flags & FL_ONGROUND) {
bot_jump ();
self.b_aiflags &= ~AI_JUMP;
if (b_aiflags & AI_JUMP) {
if (ent.flags & FL_ONGROUND) {
[self jump];
b_aiflags &= ~AI_JUMP;
}
} else if (self.b_aiflags & AI_SUPER_JUMP) {
if (self.weapon != 32)
self.impulse = 7;
else if (self.flags & FL_ONGROUND) {
self.b_aiflags &= ~AI_SUPER_JUMP;
if (bot_can_rj (self)) {
bot_jump ();
self.v_angle_x = self.b_angle_x = 80;
self.button0 = TRUE;
} else if (b_aiflags & AI_SUPER_JUMP) {
if (ent.weapon != 32)
ent.impulse = 7;
else if (ent.flags & FL_ONGROUND) {
b_aiflags &= ~AI_SUPER_JUMP;
if ([self can_rj]) {
[self jump];
v_angle.x = b_angle.x = 80;
ent.button0 = TRUE;
} else
bot_lost (self.target1, FALSE);
[self lost: targets[0] :FALSE];
}
}
if (self.b_aiflags & AI_SURFACE) {
if (self.waterlevel > 2) {
self.keys = KEY_MOVEUP;
self.button2 = TRUE; // swim!
if (b_aiflags & AI_SURFACE) {
if (ent.waterlevel > 2) {
keys = KEY_MOVEUP;
ent.button2 = TRUE; // swim!
} else
self.b_aiflags &= ~AI_SURFACE;
b_aiflags &= ~AI_SURFACE;
}
if (self.b_aiflags & AI_RIDE_TRAIN) {
if (b_aiflags & AI_RIDE_TRAIN) {
// simple, but effective
// this can probably be used for a lot of different
// things, not just trains (door elevators come to mind)
b_temp3 = self;
self = self.last_way;
if (!frik_recognize_plat(FALSE)) {
if (![ent.@this recognize_plat:FALSE]) {
// if there is nothing there now
self = b_temp3;
self.keys &= 960;
keys &= 960;
} else {
self = b_temp3;
if (frik_recognize_plat (FALSE)) {
v = realorigin (trace_ent) + trace_ent.origin - self.origin;
if ([self recognize_plat:FALSE]) {
v = realorigin (trace_ent) + trace_ent.origin - ent.origin;
v_z = 0;
if (vlen (v) < 24)
self.keys &= 960;
keys &= 960;
else {
self.b_aiflags |= AI_PRECISION;
self.keys = frik_KeysForDir (v);
b_aiflags |= AI_PRECISION;
keys = [self keysForDir:v];
}
}
}
}
if (self.b_aiflags & AI_PLAT_BOTTOM) {
newt = FindThing ("plat");
if (b_aiflags & AI_PLAT_BOTTOM) {
newt = FindThing (ent, "plat");
if (newt.state != 1) {
v = self.origin - realorigin (newt);
v = ent.origin - realorigin (newt);
v_z = 0;
if (vlen (v) > 96)
self.keys &= 960;
keys &= 960;
else
frik_walkmove (v);
[self walkmove:v];
} else
self.b_aiflags &= ~AI_PLAT_BOTTOM;
b_aiflags &= ~AI_PLAT_BOTTOM;
}
if (self.b_aiflags & AI_DIRECTIONAL) {
if ((normalize (self.last_way.origin - self.origin) * self.b_dir) > 0.4) {
self.b_aiflags &= ~AI_DIRECTIONAL;
bot_lost (self.target1, TRUE);
if (b_aiflags & AI_DIRECTIONAL) {
if ((normalize (last_way.origin - ent.origin) * b_dir) > 0.4) {
b_aiflags &= ~AI_DIRECTIONAL;
[self lost:targets[0] :TRUE];
}
}
if (self.b_aiflags & AI_SNIPER) {
self.b_aiflags |= AI_WAIT | AI_PRECISION | AI_SNIPER;
if (b_aiflags & AI_SNIPER) {
b_aiflags |= AI_WAIT | AI_PRECISION | AI_SNIPER;
// FIXME: Add a switch to wep command
// FIXME: increase delay?
}
if (self.b_aiflags & AI_AMBUSH) {
self.b_aiflags |= AI_WAIT | AI_AMBUSH;
if (b_aiflags & AI_AMBUSH) {
b_aiflags |= AI_WAIT | AI_AMBUSH;
// FIXME: Add a switch to wep command
// FIXME: increase delay?
}
};
}
/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@ -423,26 +416,26 @@ confused
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
void() bot_path =
-(void)path
{
local entity jj, tele;
bot_check_lost (self.target1);
if (!self.target1) {
self.keys=0;
[self check_lost:targets[0]];
if (!targets[0]) {
keys=0;
return;
}
if (target_onstack (self.last_way))
if ([self target_onstack:last_way])
return; // old waypoint still being hunted
jj = FindRoute (self.last_way);
jj = FindRoute (last_way);
if (!jj) {
// this is an ugly hack
if (self.target1.current_way != self.last_way) {
if (self.target1.classname != "temp_waypoint")
if (self.target1.classname != "player")
bot_lost (self.target1, FALSE);
if (targets[0].current_way != last_way) {
if (targets[0].classname != "temp_waypoint")
if (targets[0].classname != "player")
[self lost:targets[0] :FALSE];
}
return;
@ -453,50 +446,50 @@ void() bot_path =
// Readahed types are AI conditions to perform while heading to a waypoint
// point types are AI flags that should be executed once reaching a waypoint
self.b_aiflags = (jj.b_aiflags & AI_READAHEAD_TYPES) | (self.last_way.b_aiflags & AI_POINT_TYPES);
target_add (jj);
if (self.last_way) {
if (CheckLinked (self.last_way, jj) == 2) {
b_aiflags = (jj.b_aiflags & AI_READAHEAD_TYPES) | (last_way.b_aiflags & AI_POINT_TYPES);
[self target_add:jj];
if (last_way) {
if (CheckLinked (last_way, jj) == 2) {
// waypoints are telelinked
tele = FindThing ("trigger_teleport"); // this is probbly the teleport responsible
target_add (tele);
tele = FindThing (ent, "trigger_teleport"); // this is probbly the teleport responsible
[self target_add:tele];
}
traceline (self.last_way.origin, jj.origin, FALSE, self); // check for blockage
traceline (last_way.origin, jj.origin, FALSE, ent); // check for blockage
if (trace_fraction != 1) {
if (trace_ent.classname == "door" && !(self.b_aiflags & AI_DOOR_NO_OPEN)) {
if (trace_ent.classname == "door" && !(b_aiflags & AI_DOOR_NO_OPEN)) {
// a door blocks the way
// linked doors fix
if (trace_ent.owner)
trace_ent = trace_ent.owner;
if ((trace_ent.health > 0) && (self.enemy == NIL)) {
self.enemy = trace_ent;
bot_weapon_switch (1);
self.b_aiflags = self.b_aiflags | AI_BLIND; // nick knack paddy hack
if ((trace_ent.health > 0) && (ent.enemy == NIL)) {
ent.enemy = trace_ent;
[self weapon_switch:1];
b_aiflags = b_aiflags | AI_BLIND; // nick knack paddy hack
} else if (trace_ent.targetname) {
tele = find (NIL, target, trace_ent.targetname);
if (tele.health > 0) {
self.enemy = tele;
bot_weapon_switch (1);
ent.enemy = tele;
[self weapon_switch:1];
} else {
// target_drop (jj);
target_add (tele);
[self target_add:tele];
// bot_get_path (tele, TRUE);
self.b_aiflags |= AI_BLIND; // give a bot a bone
b_aiflags |= AI_BLIND; // give a bot a bone
return;
}
}
} else if (trace_ent.classname == "func_wall") {
// give up
bot_lost (self.target1, FALSE);
[self lost:targets[0] :FALSE];
return;
}
}
}
// this is used for AI_DRIECTIONAL
self.b_dir = normalize (jj.origin - self.last_way.origin);
b_dir = normalize (jj.origin - last_way.origin);
self.last_way = jj;
};
last_way = jj;
}
/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@ -514,7 +507,7 @@ the bot finds things it wants to kill/grab.
// *!* Make sure you add code to bot_check_lost to remove the target *!*
float(entity thing) priority_for_thing =
-(float)priority_for_thing:(entity)thing
{
local float thisp;
@ -522,7 +515,7 @@ float(entity thing) priority_for_thing =
// This is the most executed function in the bot. Careful what you do here.
if ((thing.flags & FL_ITEM) && thing.model && thing.search_time < time) {
// ugly hack
if (thing._last != self)
if (thing._last != ent)
thisp = 20;
if (thing.classname == "item_artifact_super_damage")
thisp = 65;
@ -531,39 +524,39 @@ float(entity thing) priority_for_thing =
else if (thing.classname == "item_health") {
if (thing.spawnflags & 2)
thisp = 55;
if (self.health < 40)
if (ent.health < 40)
thisp = thisp + 50;
} else if (thing.model == "progs/armor.mdl") {
if (self.armorvalue < 200) {
if (ent.armorvalue < 200) {
if (thing.skin == 2)
thisp = 60;
else if (self.armorvalue < 100)
else if (ent.armorvalue < 100)
thisp = thisp + 25;
}
} else if (thing.classname == "weapon_supershotgun") {
if (!(self.items & 2)) // IT_SUPER_SHOTGUN
if (!(ent.items & 2)) // IT_SUPER_SHOTGUN
thisp = 25;
} else if (thing.classname == "weapon_nailgun") {
if (!(self.items & 4)) // IT_NAILGUN
if (!(ent.items & 4)) // IT_NAILGUN
thisp = 30;
} else if (thing.classname == "weapon_supernailgun") {
if (!(self.items & 8)) // IT_SUPER_NAILGUN
if (!(ent.items & 8)) // IT_SUPER_NAILGUN
thisp = 35;
} else if (thing.classname == "weapon_grenadelauncher") {
if (!(self.items & 16)) // IT_GRENADE_LAUNCHER
if (!(ent.items & 16)) // IT_GRENADE_LAUNCHER
thisp = 45;
} else if (thing.classname == "weapon_rocketlauncher") {
if (!(self.items & 32)) // IT_ROCKET_LAUNCHER
if (!(ent.items & 32)) // IT_ROCKET_LAUNCHER
thisp = 60;
} else if (thing.classname == "weapon_lightning") {
if (!(self.items & 64)) // IT_LIGHTNING
if (!(ent.items & 64)) // IT_LIGHTNING
thisp = 50;
}
} else if ((thing.flags & FL_MONSTER) && thing.health > 0)
thisp = 45;
else if (thing.classname == "player") {
if (thing.health > 0) {
if (thing == self)
if (thing == ent)
return 0;
else {
if (thing.items & IT_INVISIBILITY) //FIXME
@ -573,7 +566,7 @@ float(entity thing) priority_for_thing =
if (thing.target1.classname == "player")
if (!thing.target1.ishuman)
return 0;
} else if (teamplay && thing.team == self.team) {
} else if (teamplay && thing.team == ent.team) {
thisp = 100;
if (thing.target1.classname == "player")
return 0;
@ -599,21 +592,21 @@ float(entity thing) priority_for_thing =
}
}
return thisp;
};
}
void(float scope) bot_look_for_crap =
-(void)look_for_crap:(integer)scope
{
local entity foe, best = NIL;
local float thatp, bestp, dist;
if (scope == 1)
foe = findradius (self.origin, 13000);
foe = findradius (ent.origin, 13000);
else
foe = findradius (self.origin, 500);
foe = findradius (ent.origin, 500);
bestp = 1;
while (foe) {
thatp = priority_for_thing (foe);
thatp = [self priority_for_thing:foe];
if (thatp)
if (!scope)
if (!sisible (foe))
@ -621,20 +614,20 @@ void(float scope) bot_look_for_crap =
if (thatp > bestp) {
bestp = thatp;
best = foe;
dist = vlen (self.origin - foe.origin);
dist = vlen (ent.origin - foe.origin);
}
foe = foe.chain;
}
if (best == NIL)
return;
if (!target_onstack (best)) {
target_add (best);
if (![self target_onstack:best]) {
[self target_add:best];
if (scope) {
bot_get_path (best, FALSE);
self.b_aiflags |= AI_WAIT;
b_aiflags |= AI_WAIT;
}
}
};
}
/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@ -647,81 +640,81 @@ generally making the bot look good.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
void() bot_angle_set =
-(void)angle_set
{
local float h;
local vector view;
if (self.enemy) {
if (self.enemy.items & 524288)
if (ent.enemy) {
if (ent.enemy.items & 524288)
if (random () > 0.2)
return;
if (self.missile_speed == 0)
self.missile_speed = 10000;
if (self.enemy.solid == SOLID_BSP) {
view = (((self.enemy.absmin + self.enemy.absmax) * 0.5) - self.origin);
if (missile_speed == 0)
missile_speed = 10000;
if (ent.enemy.solid == SOLID_BSP) {
view = (((ent.enemy.absmin + ent.enemy.absmax) * 0.5) - ent.origin);
} else {
h = vlen (self.enemy.origin - self.origin) / self.missile_speed;
if (self.enemy.flags & FL_ONGROUND)
view = self.enemy.velocity * h;
h = vlen (ent.enemy.origin - ent.origin) / missile_speed;
if (ent.enemy.flags & FL_ONGROUND)
view = ent.enemy.velocity * h;
else
view = (self.enemy.velocity - (sv_gravity * '0 0 1') * h) * h;
view = self.enemy.origin + view;
view = (ent.enemy.velocity - (sv_gravity * '0 0 1') * h) * h;
view = ent.enemy.origin + view;
// FIXME: ?
traceline (self.enemy.origin, view, FALSE, self);
traceline (ent.enemy.origin, view, FALSE, ent);
view = trace_endpos;
if (self.weapon == 32)
if (ent.weapon == 32)
view = view - '0 0 22';
view = normalize (view - self.origin);
view = normalize (view - ent.origin);
}
view = vectoangles (view);
view_x = view_x * -1;
self.b_angle = view;
} else if (self.target1) {
view = realorigin (self.target1);
if (self.target1.flags & FL_ITEM)
b_angle = view;
} else if (targets[0]) {
view = realorigin (targets[0]);
if (targets[0].flags & FL_ITEM)
view = view + '0 0 48';
view -= (self.origin + self.view_ofs);
view -= (ent.origin + ent.view_ofs);
view = vectoangles (view);
view_x *= -1;
self.b_angle = view;
b_angle = view;
} else
self.b_angle_x = 0;
b_angle.x = 0;
// HACK HACK HACK HACK
// The bot falls off ledges a lot because of "turning around"
// so let the bot use instant turn around when not hunting a player
if (self.b_skill == 3) {
self.keys = self.keys & 63;
self.v_angle = self.b_angle;
while (self.v_angle_x < -180)
self.v_angle_x += 360;
while (self.v_angle_x > 180)
self.v_angle_x -= 360;
} else if ((self.enemy == NIL || self.enemy.movetype == MOVETYPE_PUSH) && self.target1.classname != "player") {
self.keys = self.keys & 63;
self.v_angle = self.b_angle;
while (self.v_angle_x < -180)
self.v_angle_x += 360;
while (self.v_angle_x > 180)
self.v_angle_x -= 360;
} else if (self.b_skill < 2) {
if (b_skill == 3) {
keys = keys & 63;
v_angle = b_angle;
while (v_angle.x < -180)
v_angle.x += 360;
while (v_angle.x > 180)
v_angle.x -= 360;
} else if ((ent.enemy == NIL || ent.enemy.movetype == MOVETYPE_PUSH) && targets[0].classname != "player") {
keys = keys & 63;
v_angle = b_angle;
while (v_angle.x < -180)
v_angle.x += 360;
while (v_angle.x > 180)
v_angle.x -= 360;
} else if (b_skill < 2) {
// skill 2 handled in bot_phys
if (self.b_angle_x > 180)
self.b_angle_x -= 360;
self.keys = self.keys & 63;
if (b_angle.x > 180)
b_angle.x -= 360;
keys = keys & 63;
if (angcomp (self.b_angle_y, self.v_angle_y) > 10)
self.keys = KEY_LOOKLEFT;
else if (angcomp(self.b_angle_y, self.v_angle_y) < -10)
self.keys |= KEY_LOOKRIGHT;
if (angcomp(self.b_angle_x, self.v_angle_x) < -10)
self.keys |= KEY_LOOKUP;
else if (angcomp (self.b_angle_x, self.v_angle_x) > 10)
self.keys |= KEY_LOOKDOWN;
if (angcomp (b_angle.y, v_angle.y) > 10)
keys = KEY_LOOKLEFT;
else if (angcomp(b_angle.y, v_angle.y) < -10)
keys |= KEY_LOOKRIGHT;
if (angcomp(b_angle.x, v_angle.x) < -10)
keys |= KEY_LOOKUP;
else if (angcomp (b_angle.x, v_angle.x) > 10)
keys |= KEY_LOOKDOWN;
}
};
}
/*
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@ -733,103 +726,102 @@ frame, the ai_time limits it's actual updating
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
float stagger_think;
void() BotAI =
-(void)AI
{
// am I dead? Fire randomly until I respawn
// health < 1 is used because fractional healths show up as 0 on normal player
// status bars, and the mod probably already compensated for that
if (self.health < 1) {
self.button0 = floor (random() * 2);
self.button2 = 0;
self.keys = 0;
self.b_aiflags = 0;
if (ent.health < 1) {
ent.button0 = floor (random() * 2);
ent.button2 = 0;
keys = 0;
b_aiflags = 0;
ClearMyRoute ();
self.target1 = self.target2 = self.target3 = self.target4 = self.enemy = NIL;
self.last_way = NIL;
targets[0] = targets[1] = targets[2] = targets[3] = ent.enemy = NIL;
last_way = NIL;
return;
}
// stagger the bot's AI out so they all don't think at the same time, causing game
// 'spikes'
if (self.b_skill < 2) {
if (self.ai_time > time)
if (b_skill < 2) {
if (ai_time > time)
return;
self.ai_time = time + 0.05;
ai_time = time + 0.05;
if (bot_count > 0) {
if ((time - stagger_think) < (0.1 / bot_count))
self.ai_time += 0.1 / (2 * bot_count);
ai_time += 0.1 / (2 * bot_count);
} else
return;
}
if (self.view_ofs == '0 0 0')
if (ent.view_ofs == '0 0 0')
bot_start_topic (7);
stagger_think = time;
// shut the bot's buttons off, various functions will turn them on by AI end
self.button2 = 0;
self.button0 = 0;
ent.button2 = 0;
ent.button0 = 0;
// target1 is like goalentity in normal Quake monster AI.
// it's the bot's most immediate target
if (route_table == self) {
if (route_table == ent) {
if (busy_waypoints <= 0) {
if (waypoint_mode < WM_EDITOR)
bot_look_for_crap(TRUE);
[self look_for_crap:TRUE];
}
self.b_aiflags = 0;
self.keys = 0;
} else if (self.target1) {
frik_movetogoal ();
bot_path ();
b_aiflags = 0;
keys = 0;
} else if (targets[0]) {
[self movetogoal];
[self path];
} else {
if (waypoint_mode < WM_EDITOR) {
if (self.route_failed) {
frik_bot_roam();
self.route_failed = 0;
if (route_failed) {
[self roam];
route_failed = 0;
} else if (!begin_route()) {
bot_look_for_crap (FALSE);
[self look_for_crap:FALSE];
}
self.keys = 0;
keys = 0;
} else {
self.b_aiflags = AI_WAIT;
self.keys = 0;
b_aiflags = AI_WAIT;
keys = 0;
}
}
// bot_angle_set points the bot at it's goal (self.enemy or target1)
bot_angle_set ();
// bot_angle_set points the bot at it's goal (ent.enemy or target1)
[self angle_set];
// fight my enemy. Enemy is probably a field QC coders will most likely
// use a lot for their own needs, since it's unused on a normal player
// FIXME
if (self.enemy)
bot_fight_style ();
if (ent.enemy)
[self fight_style];
else if (random () < 0.2)
if (random () < 0.2)
bot_weapon_switch (-1);
bot_dodge_stuff ();
[self weapon_switch:-1];
[self dodge_stuff];
// checks to see if bot needs to start going up for air
if (self.waterlevel > 2) {
if (time > (self.air_finished - 2)) {
traceline (self.origin, self.origin + '0 0 6800', TRUE, self);
if (ent.waterlevel > 2) {
if (time > (ent.air_finished - 2)) {
traceline (ent.origin, ent.origin + '0 0 6800', TRUE, ent);
if (trace_inopen) {
self.keys = KEY_MOVEUP;
self.button2 = TRUE; // swim!
keys = KEY_MOVEUP;
ent.button2 = TRUE; // swim!
return; // skip ai flags for now - this is life or death
}
}
}
// b_aiflags handling
if (self.b_aiflags)
bot_handle_ai ();
if (b_aiflags)
[self handle_ai];
else
bot_chat (); // don't want chat to screw him up if he's rjing or something
};
}
@end

View file

@ -42,10 +42,40 @@ this notice in its entirety.
#include "libfrikbot.h"
.entity avoid;
/*
weapon_range
float (entity e)
bot_size_player =
_x "sweet spot range" - try to maintain this range if possible
_y minimum range bot can be to be effective (rl/gl) (move away)
_z maximum range bot can be to be effective (lg/axe) (move in)
*/
vector (float wep)
weapon_range =
{
switch (wep) {
case 4096: // IT_AXE
return '48 0 64';
case 1: // IT_SHOTGUN
return '128 0 99999';
case 2: // IT_SUPER_SHOTGUN
return '128 0 99999';
case 4: // IT_NAILGUN
return '180 0 3000';
case 8: // IT_SUPER_NAILGUN
return '180 0 3000';
case 16: // IT_GRENADE_LAUNCHER
return '180 48 3000';
case 32: // IT_ROCKET_LAUNCHER
return '180 48 3000';
case 64: // IT_LIGHTNING
return '350 0 512';
default:
break;
}
};
@implementation Bot (Fight)
-(float)size_player:(entity)e
{
local float sz;
@ -86,10 +116,9 @@ bot_size_player =
if (e.items & 524288) // Invis
sz += 250;
return sz;
};
}
void ()
bot_dodge_stuff =
-(void)dodge_stuff
{
local entity foe;
local float foedist, avdist, foesz, flen, tsz;
@ -100,10 +129,10 @@ bot_dodge_stuff =
self.avoid = NIL;
if (self.enemy) {
v = self.origin - realorigin (self.enemy);
if (ent.enemy) {
v = ent.origin - realorigin (ent.enemy);
foedist = vlen (v);
foesz = bot_size_player (self.enemy);
foesz = [self size_player:ent.enemy];
} else {
foedist = 3000;
foesz = 9999999;
@ -112,7 +141,7 @@ bot_dodge_stuff =
foe = find (NIL, classname, "grenade");
while (foe) {
flen = vlen (foe.origin - self.origin);
flen = vlen (foe.origin - ent.origin);
if (flen < avdist) {
avdist = flen;
self.avoid = foe;
@ -122,8 +151,8 @@ bot_dodge_stuff =
if (!self.avoid) {
foe = find (NIL, classname, "missile");
while (foe) {
if (foe.owner != self) {
flen = vlen (foe.origin - self.origin);
if (foe.owner != ent) {
flen = vlen (foe.origin - ent.origin);
if (flen < avdist) {
avdist = flen;
self.avoid = foe;
@ -134,8 +163,8 @@ bot_dodge_stuff =
if (!self.avoid) {
foe = find(NIL, classname, "spike");
while (foe) {
if (foe.owner != self) {
flen = vlen(foe.origin - self.origin);
if (foe.owner != ent) {
flen = vlen(foe.origin - ent.origin);
if (flen < avdist) {
avdist = flen;
self.avoid = foe;
@ -146,17 +175,17 @@ bot_dodge_stuff =
}
}
if (coop) {
if (!self.enemy) {
foe = findradius (self.origin, foedist);
if (!ent.enemy) {
foe = findradius (ent.origin, foedist);
while (foe) {
if (foe.flags & FL_MONSTER) {
if (foe.health > 0) {
flen = vlen (foe.origin - self.origin);
flen = vlen (foe.origin - ent.origin);
if (flen < foedist) {
tsz = bot_size_player (foe);
tsz = [self size_player:foe];
if (tsz < foesz) {
if (fisible (foe)) {
self.enemy = foe;
ent.enemy = foe;
foedist = flen;
foesz = tsz;
}
@ -172,18 +201,18 @@ bot_dodge_stuff =
for (i = 0; i < 32; i++) {
if (!(foe = players[i]))
continue;
if(foe != self) {
if(foe != ent) {
if (foe.modelindex != 0) {
if (foe.health > 0) {
if (!(teamplay && self.team == foe.team)) {
flen = vlen (foe.origin - self.origin);
if (!(teamplay && ent.team == foe.team)) {
flen = vlen (foe.origin - ent.origin);
if (flen < foedist) {
tsz = bot_size_player(foe);
tsz = [self size_player:foe];
if (tsz < foesz) {
if (fov(foe) || foe.b_sound > time || self.b_skill == 3) {
if (fisible (foe)) {
self.enemy = foe;
foedist = vlen (foe.origin - self.origin);
ent.enemy = foe;
foedist = vlen (foe.origin - ent.origin);
}
}
}
@ -194,84 +223,51 @@ bot_dodge_stuff =
}
}
}
};
/*
weapon_range
_x "sweet spot range" - try to maintain this range if possible
_y minimum range bot can be to be effective (rl/gl) (move away)
_z maximum range bot can be to be effective (lg/axe) (move in)
*/
vector (float wep)
weapon_range =
{
switch (wep) {
case 4096: // IT_AXE
return '48 0 64';
case 1: // IT_SHOTGUN
return '128 0 99999';
case 2: // IT_SUPER_SHOTGUN
return '128 0 99999';
case 4: // IT_NAILGUN
return '180 0 3000';
case 8: // IT_SUPER_NAILGUN
return '180 0 3000';
case 16: // IT_GRENADE_LAUNCHER
return '180 48 3000';
case 32: // IT_ROCKET_LAUNCHER
return '180 48 3000';
case 64: // IT_LIGHTNING
return '350 0 512';
default:
break;
}
};
}
/*
bot_weapon_switch
Pick a weapon based on range / ammo
*/
void (float brange)
bot_weapon_switch =
-(void)weapon_switch:(float)brange
{
local float it, flag = 0, pulse = 0;
local vector v;
it = self.items & 127;
it = ent.items & 127;
while (it) {
if ((self.ammo_rockets >= 1) && (it & 32)) {
if ((ent.ammo_rockets >= 1) && (it & 32)) {
flag = 32;
pulse = 7;
} else if (self.waterlevel <= 1 && self.ammo_cells >= 1 && (it & 64)) {
} else if (ent.waterlevel <= 1 && ent.ammo_cells >= 1 && (it & 64)) {
flag = 64;
pulse = 8;
} else if (self.ammo_nails >= 2 && (it & 8)) {
} else if (ent.ammo_nails >= 2 && (it & 8)) {
flag = 8;
pulse = 5;
} else if ((self.ammo_rockets >= 1) && (it & 16)) {
} else if ((ent.ammo_rockets >= 1) && (it & 16)) {
flag = 16;
pulse = 6;
} else if (self.ammo_shells >= 2 && (it & 2)) {
} else if (ent.ammo_shells >= 2 && (it & 2)) {
flag = 2;
pulse = 3;
} else if (self.ammo_nails >= 1 && (it & 4)) {
} else if (ent.ammo_nails >= 1 && (it & 4)) {
flag = 4;
pulse = 4;
} else if (self.ammo_shells >= 1 && (it & 1)) {
} else if (ent.ammo_shells >= 1 && (it & 1)) {
flag = 1;
pulse = 2;
} else {
if (pulse)
self.impulse = pulse;
ent.impulse = pulse;
return;
}
if (brange == -1) {
if (pulse)
self.impulse = pulse;
ent.impulse = pulse;
return;
}
@ -280,26 +276,25 @@ bot_weapon_switch =
it = it - flag;
else {
if (pulse)
self.impulse = pulse;
ent.impulse = pulse;
return;
}
}
};
}
void ()
bot_shoot =
-(void)shoot
{
// quick little function to stop making him shoot the wrong way ! Argh
local float g;
g = angcomp (self.v_angle_x, self.b_angle_x);
g = angcomp (v_angle.x, b_angle.x);
if (fabs (g) > 30)
return; // argh, too far away
g = angcomp (self.v_angle_y, self.b_angle_y);
g = angcomp (v_angle.y, b_angle.y);
if (fabs (g) > 30)
return; // not again!
self.button0 = TRUE;
};
ent.button0 = TRUE;
}
/*
Bot_fight_style
@ -307,44 +302,43 @@ Bot_fight_style
This is the core of the bot's thinking when
attacking an enemy.
*/
void ()
bot_fight_style =
-(void)fight_style
{
local float foedist, mysz, foesz;
local vector v, v1 = '0 0 0', v2 = '0 0 0', org;
if (self.enemy.health <= 0) {
self.enemy = NIL;
if (ent.enemy.health <= 0) {
ent.enemy = NIL;
return;
} else if (!self.enemy.takedamage) {
self.enemy = NIL;
} else if (!ent.enemy.takedamage) {
ent.enemy = NIL;
return;
} else if (!fisible (self.enemy)) {
self.enemy = NIL;
} else if (!fisible (ent.enemy)) {
ent.enemy = NIL;
return;
}
org = realorigin (self.enemy);
org = realorigin (ent.enemy);
makevectors (self.v_angle);
// decide if I should shoot
foedist = vlen (org - self.origin);
v = weapon_range (self.weapon);
foedist = vlen (org - ent.origin);
v = weapon_range (ent.weapon);
if (foedist > v_y && foedist < v_z) {
traceline (self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * v_z, FALSE, self);
if (vlen(trace_endpos - (self.origin + self.view_ofs)) >= v_y) {
traceline (ent.origin + ent.view_ofs, ent.origin + ent.view_ofs + v_forward * v_z, FALSE, ent);
if (vlen(trace_endpos - (ent.origin + ent.view_ofs)) >= v_y) {
// try to avoid shooting teammates
if (trace_ent.classname == "player")
if ((trace_ent.team == self.team && teamplay) || (coop))
if ((trace_ent.team == ent.team && teamplay) || (coop))
return;
bot_shoot ();
[self shoot];
}
} else
bot_weapon_switch (foedist);
[self weapon_switch:foedist];
if (!(self.b_aiflags & (AI_PRECISION | AI_BLIND | AI_OBSTRUCTED))) {
foesz = bot_size_player (self.enemy);
mysz = bot_size_player (self) + 5;
foesz = [self size_player:ent.enemy];
mysz = [self size_player:self] + 5;
if (foesz > mysz) {
if (teamplay) {
@ -360,29 +354,29 @@ bot_fight_style =
if (self.avoid.velocity)
v = self.avoid.velocity;
else
v = normalize (self.avoid.origin - self.origin);
v = normalize (self.avoid.origin - ent.origin);
v1_x = v_y;
v1_y = v_y * -1;
v2_x = v_y;
v2_y = v_y * -1;
foedist = vlen (self.avoid.origin - (self.origin + v1));
if (foedist < vlen (self.avoid.origin - (self.origin + v2)))
frik_walkmove (v2);
foedist = vlen (self.avoid.origin - (ent.origin + v1));
if (foedist < vlen (self.avoid.origin - (ent.origin + v2)))
[self walkmove:v2];
else
frik_walkmove (v1);
} else if (!(self.enemy.flags & FL_MONSTER)) {
[self walkmove:v1];
} else if (!(ent.enemy.flags & FL_MONSTER)) {
if (foedist + 32 < v_x)
frik_walkmove (self.origin - org);
[self walkmove:ent.origin - org];
else if (foedist - 32 > v_x)
frik_walkmove (org - self.origin);
[self walkmove:org - ent.origin];
else if (self.wallhug)
frik_walkmove (v_right);
[self walkmove:v_right];
else
frik_walkmove (v_right * -1);
[self walkmove:v_right * -1];
}
} else {
foesz = bot_size_player (self.enemy);
mysz = bot_size_player (self) + 5;
foesz = [self size_player:ent.enemy];
mysz = [self size_player:self] + 5;
if (foesz > mysz)
return;
@ -390,4 +384,5 @@ bot_fight_style =
return;
self.keys &= 960;
}
};
}
@end

View file

@ -143,7 +143,7 @@ manuever around.
// TODO: something
if (b_aiflags & AI_BLIND)
return;
org = realorigin(ent.target1);
org = realorigin(targets[0]);
if (danger) {
b_aiflags |= AI_DANGER;
@ -153,7 +153,7 @@ manuever around.
return;
if (ent.target1) {
if (targets[0]) {
if (b_aiflags & AI_OBSTRUCTED) {
if (!(b_aiflags & AI_DANGER)) {
b_aiflags &= ~AI_OBSTRUCTED;
@ -243,8 +243,8 @@ Also responsible for jumping gaps.
[self obstructed: ang :TRUE];
return;
} else {
if (ent.target1) {
stop = realorigin(ent.target1);
if (targets[0]) {
stop = realorigin(targets[0]);
if ((stop_z - ent.origin_z) < -32)
return; // safe to fall
}
@ -261,8 +261,8 @@ Also responsible for jumping gaps.
[self obstructed: ang :TRUE];
return;
} else {
if (ent.target1) {
stop = realorigin(ent.target1);
if (targets[0]) {
stop = realorigin(targets[0]);
if ((stop_z - ent.origin_z) < -32)
return; // safe to fall
}
@ -271,10 +271,10 @@ Also responsible for jumping gaps.
}
}
if (ent.target1) {
if (targets[0]) {
// getting furter away from my target?
test = vlen (ent.target1.origin - (ang + ent.origin));
if (test > vlen (ent.target1.origin - ent.origin)) {
test = vlen (targets[0].origin - (ang + ent.origin));
if (test > vlen (targets[0].origin - ent.origin)) {
if (conts < -3) {
// bad stuff down dare
[self obstructed: ang :TRUE];
@ -287,8 +287,8 @@ Also responsible for jumping gaps.
}
}
if (hgt < -18) {
if (ent.target1) {
stop = realorigin (ent.target1);
if (targets[0]) {
stop = realorigin (targets[0]);
if ((stop_z - ent.origin_z) < -32)
return; // safe to fall
}
@ -357,12 +357,12 @@ blah
local vector way;
local float g;
if (ent.target1 == NIL) {
if (targets[0] == NIL) {
makevectors(v_angle);
[self walkmove: v_forward];
return;
}
way = realorigin(ent.target1) - ent.origin;
way = realorigin(targets[0]) - ent.origin;
if (vlen(way) < 25) {
keys = keys & 960;
return;

View file

@ -133,7 +133,6 @@ entity [32] phys_objects;
.float portal_time;
.integer b_skill;
.float switch_wallhug;
.float b_aiflags;
.integer b_num;
.float b_chattime;
.float b_entertime; // QW shtuff
@ -551,7 +550,7 @@ BotFrame =
while (num < max_clients) {
if (self.ishuman == FALSE) {
if (self.b_clientno > 0) {
frik_obstacles ();
[self.@this _obstacles];
CL_KeyMove ();
SV_ClientThink ();
SV_Physics_Client ();

View file

@ -504,7 +504,7 @@ in bot_ai.qc
*/
entity(string s) FindThing =
entity(entity ent, string s) FindThing =
{
local entity t;
local float tdst, dst;
@ -513,7 +513,7 @@ entity(string s) FindThing =
best = NIL;
t = find (NIL, classname, s);
while (t != NIL) {
tdst = vlen(((t.absmin + t.absmax) * 0.5) - self.origin);
tdst = vlen(((t.absmin + t.absmax) * 0.5) - ent.origin);
if (tdst < dst) {
dst = tdst;
best = t;

View file

@ -32,7 +32,8 @@
integer route_failed;
integer dyn_flags, dyn_time, dyn_plat;
entity temp_way, last_way, current_way;
entity [4] target;
entity [4] targets;
entity avoid;
entity _next, _last;
vector obs_dir;
vector b_dir;
@ -61,6 +62,25 @@
@end
@interface Bot (AI)
-(integer)target_onstack:(entity)scot;
-(void)target_add:(entity)e;
-(void)target_drop:(entity)e;
-(void)lost:(entity)targ :(integer)success;
-(void)check_lost:(entity)targ;
-(void)handle_ai;
-(void)path;
-(float)priority_for_thing:(entity)thing;
-(void)look_for_crap:(integer)scope;
-(void)angle_set;
-(void)AI;
@end
@interface Bot (Fight)
-(float)size_player:(entity)e;
-(void)dodge_stuff;
-(void)weapon_switch:(float)brange;
-(void)shoot;
-(void)fight_style;
@end
#define FALSE 0
@ -134,7 +154,7 @@
* wp
* bot
*/
@extern .float b_aiflags;
@extern .integer b_aiflags;
/* b_num
* bot bot number
*/
@ -299,11 +319,6 @@
@extern void() ClientDisconnect;
@extern void() SetNewParms;
// fight
@extern void(float brange) bot_weapon_switch;
@extern void() bot_fight_style;
@extern void() bot_dodge_stuff;
// rankings
@extern integer (entity e) ClientNumber;
@extern float(integer clientno) ClientBitFlag;
@ -339,7 +354,7 @@
@extern void() SV_Physics_Client;
@extern void() SV_ClientThink;
@extern void() CL_KeyMove;
@extern entity(string s) FindThing;
@extern entity(entity ent, string s) FindThing;
// ai & misc
@extern void() BotAI;
@ -350,11 +365,8 @@
@extern float(entity targ) sisible;
@extern float(entity targ) fisible;
@extern vector(entity ent) realorigin;
@extern void(entity ent) target_drop;
@extern void(entity ent) target_add;
@extern void() KickABot;
@extern void() BotImpulses;
@extern void(entity targ, float success) bot_lost;
@extern string(integer r) BotName;
@extern float(float v) frik_anglemod;
@extern void() bot_chat;