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

View file

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

View file

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

View file

@ -133,7 +133,6 @@ entity [32] phys_objects;
.float portal_time; .float portal_time;
.integer b_skill; .integer b_skill;
.float switch_wallhug; .float switch_wallhug;
.float b_aiflags;
.integer b_num; .integer b_num;
.float b_chattime; .float b_chattime;
.float b_entertime; // QW shtuff .float b_entertime; // QW shtuff
@ -551,7 +550,7 @@ BotFrame =
while (num < max_clients) { while (num < max_clients) {
if (self.ishuman == FALSE) { if (self.ishuman == FALSE) {
if (self.b_clientno > 0) { if (self.b_clientno > 0) {
frik_obstacles (); [self.@this _obstacles];
CL_KeyMove (); CL_KeyMove ();
SV_ClientThink (); SV_ClientThink ();
SV_Physics_Client (); 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 entity t;
local float tdst, dst; local float tdst, dst;
@ -513,7 +513,7 @@ entity(string s) FindThing =
best = NIL; best = NIL;
t = find (NIL, classname, s); t = find (NIL, classname, s);
while (t != NIL) { 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) { if (tdst < dst) {
dst = tdst; dst = tdst;
best = t; best = t;

View file

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