diff --git a/fbxa/bot_ai.qc b/fbxa/bot_ai.qc index 325a5cc..985d3db 100644 --- a/fbxa/bot_ai.qc +++ b/fbxa/bot_ai.qc @@ -78,7 +78,7 @@ checks to see if an entity is on the bot's stack targetAdd adds a new entity to the stack, since it's a -LIFO stack, this will be the bot's new target1 +LIFO stack, this will be the bot's new targets[0] -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */ @@ -93,7 +93,7 @@ LIFO stack, this will be the bot's new target1 targets[2] = targets[1]; targets[1] = targets[0]; targets[0] = e; - ent.search_time = time + 5; + [self setSearchTime:time + 5]; } /* @@ -103,7 +103,7 @@ targetDrop Removes an entity from the bot's target stack. The stack will empty everything up to the object -So if you have target2 item_health, target1 +So if you have target2 item_health, targets[0] waypoint, and you drop the health, the waypoint is gone too. @@ -132,7 +132,7 @@ is gone too. default: break; } - ent.search_time = time + 5; + [self setSearchTime:time + 5]; } /* @@ -165,17 +165,15 @@ Bot has lost its target. [self startTopic:3]; if (targ.ent.flags & FL_ITEM) { - /*XXX if (!targ.ent.model) - targ.prev = NIL; + targ._last = NIL; else - targ.prev = ent; - */ + targ._last = self; } } - //XXX if (targ.ent.classname != "player") - //XXX targ.search_time = time + 5; + if (targ.ent.classname != "player") + [self setSearchTime:time + 5]; } /* @@ -232,7 +230,7 @@ removed. keys &= ~KEY_MOVE; [self startTopic:4]; } - ent.search_time = time + 5; // never time out + [self setSearchTime:time + 5]; // never time out } else if (![self canSee:bot]) [self lost:bot :FALSE]; } else if (waypoint_mode > WM_LOADED) { @@ -280,7 +278,7 @@ removed. [self lost:targ :TRUE]; } // targets are lost if the bot's search time has expired - if (time > ent.search_time) + if (time > [self searchTime]) [self lost:targ :FALSE]; } @@ -441,13 +439,12 @@ confused jj = [self findRoute:last_way]; if (!jj) { // this is an ugly hack - /*XXX if (targets[0].current_way != last_way) { - if (targets[0].classname != "temp_waypoint") - if (targets[0].classname != "player") + local string cn = [targets[0] classname]; + if (cn != "temp_waypoint") + if (cn != "player") [self lost:targets[0] :FALSE]; } - */ return; } @@ -457,7 +454,8 @@ confused // 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 - b_aiflags = (jj.flags & AI_READAHEAD_TYPES) | (last_way.flags & AI_POINT_TYPES); + b_aiflags = (jj.flags & AI_READAHEAD_TYPES) + | (last_way.flags & AI_POINT_TYPES); [self targetAdd:jj]; if (last_way) { if ([last_way isLinkedTo:jj] == 2) { @@ -467,7 +465,8 @@ confused } traceline (last_way.origin, jj.origin, FALSE, ent); // check for blockage if (trace_fraction != 1) { - if (trace_ent.classname == "door" && !(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) @@ -537,23 +536,26 @@ the bot finds things it wants to kill/grab. p = 100; } else p = 30; - - if (current_way) { - // check to see if it's unreachable - if (current_way.items == -1) - return 0; - else - p += (integer) ((13000 - current_way.items) * 0.05); - } return p; } -(integer)priorityForThing:(Target)thing { + local integer p; // This is the most executed function in the bot. Careful what you do here. if (pointcontents ([thing origin]) < -3) return 0; - return [thing priority:self]; + + p = [thing priority:self]; + + if (thing.current_way) { + // check to see if it's unreachable + if (thing.current_way.items == -1) + return 0; + else + p += (integer) ((13000 - thing.current_way.items) * 0.05); + } + return p; } -(void)lookForCrap:(integer)scope @@ -584,6 +586,7 @@ the bot finds things it wants to kill/grab. } foe = [Target forEntity:foe.ent.chain]; } + way = [Waypoint find:ent.origin radius:radius]; while (way) { thatp = [self priorityForThing:way]; @@ -597,6 +600,7 @@ the bot finds things it wants to kill/grab. } way = way.chain; } + if (best == NIL) return; if (![self targetOnstack:best]) { @@ -672,7 +676,7 @@ generally making the bot look good. while (ent.v_angle.x > 180) ent.v_angle.x -= 360; } else if ((ent.enemy == NIL || ent.enemy.movetype == MOVETYPE_PUSH) - && (targets[0] ? targets[0].ent.classname != "player" : 1)) { + && (targets[0] ? [targets[0] classname] != "player" : 1)) { keys &= ~KEY_LOOK; ent.v_angle = b_angle; while (ent.v_angle.x < -180) @@ -710,8 +714,8 @@ frame, the ai_time limits it's actual updating -(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 + // health < 1 is used because fractional healths show up as 0 on normal + // playerstatus bars, and the mod probably already compensated for that if (ent.health < 1) { buttons = (integer) (random() * 2); @@ -724,8 +728,8 @@ frame, the ai_time limits it's actual updating return; } - // stagger the bot's AI out so they all don't think at the same time, causing game - // 'spikes' + // stagger the bot's AI out so they all don't think at the same time, + // causing game 'spikes' if (b_skill < 2) { if (ai_time > time) return; @@ -737,14 +741,16 @@ frame, the ai_time limits it's actual updating } else return; } + if (ent.view_ofs == '0 0 0') [self startTopic:7]; 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 buttons = 0; - // target1 is like goalentity in normal Quake monster AI. + // targets[0] is like goalentity in normal Quake monster AI. // it's the bot's most immediate target if (route_table == self) { if (busy_waypoints <= 0) { @@ -771,7 +777,7 @@ frame, the ai_time limits it's actual updating } } - // angleSet points the bot at it's goal (ent.enemy or target1) + // angleSet points the bot at it's goal (ent.enemy or targets[0]) [self angleSet]; // fight my enemy. Enemy is probably a field QC coders will most likely @@ -797,10 +803,11 @@ frame, the ai_time limits it's actual updating } // b_aiflags handling + // don't want chat to screw him up if he's concentrating if (b_aiflags) [self handleAI]; else - [self chat]; // don't want chat to screw him up if he's rjing or something + [self chat]; } @end diff --git a/fbxa/bot_fight.qc b/fbxa/bot_fight.qc index df9349b..1b8f7fc 100644 --- a/fbxa/bot_fight.qc +++ b/fbxa/bot_fight.qc @@ -204,26 +204,19 @@ weapon_range = local integer i = 0; local Bot foe; for (i = 0; i < 32; i++) { - if (!(foe = players[i])) - continue; - if(foe != self) { - if (foe.ent.modelindex != 0) { - if (foe.ent.health > 0) { - if (!(teamplay && ent.team == foe.ent.team)) { - flen = vlen (foe.ent.origin - ent.origin); - if (flen < foedist) { - tsz = [self sizePlayer:foe]; - if (tsz < foesz) { - if ([self fov:foe.ent] || foe.b_sound > time || b_skill == 3) { - if ([self canSee:foe]) { - ent.enemy = foe.ent; - foedist = vlen ([foe origin] - ent.origin); - } - } - } - } - } - } + if (!(foe = players[i])) continue; + if (foe == self) continue; + if (foe.ent.modelindex == 0) continue; + if (foe.ent.health <= 0) continue; + if (teamplay && ent.team == foe.ent.team) continue; + flen = vlen (foe.ent.origin - ent.origin); + if (flen >= foedist) continue; + tsz = [self sizePlayer:foe]; + if (tsz > foesz) continue; + if ([self fov:foe.ent] || foe.b_sound > time || b_skill == 3) { + if ([self canSee:foe]) { + ent.enemy = foe.ent; + foedist = vlen ([foe origin] - ent.origin); } } } diff --git a/fbxa/bot_way.qc b/fbxa/bot_way.qc index cdd21bb..5abf298 100644 --- a/fbxa/bot_way.qc +++ b/fbxa/bot_way.qc @@ -206,7 +206,7 @@ Boy it's confusing. if (last_way != NIL) { last_way.items = vlen(last_way.origin - ent.origin); [last_way queueForThink]; - last_way.keys = TRUE; + last_way.busy = TRUE; busy_waypoints = 1; return TRUE; } else { @@ -256,6 +256,7 @@ Temporary Marker code [tep setOrigin:org]; tep.search_time = 0; + tep.is_temp = 1; [self targetAdd:tep]; } diff --git a/fbxa/libfrikbot.h b/fbxa/libfrikbot.h index 31e6fe6..9577700 100644 --- a/fbxa/libfrikbot.h +++ b/fbxa/libfrikbot.h @@ -13,6 +13,7 @@ typedef struct bot_data_t bot_data_t; { @public Waypoint current_way; + Target _last; } +(Target)forEntity:(entity)e; -(vector)realorigin; @@ -23,6 +24,9 @@ typedef struct bot_data_t bot_data_t; -(integer)ishuman; -(integer)priority:(Bot)bot; -(Waypoint)findWaypoint:(Waypoint)start; +-(float)searchTime; +-(void)setSearchTime:(float)st; +-(string)classname; @end @interface Waypoint: Target @@ -32,8 +36,10 @@ typedef struct bot_data_t bot_data_t; integer flags; vector origin; + integer is_temp; + integer b_sound; - integer keys; + integer busy; //??? float items; Waypoint enemy; float search_time; diff --git a/fbxa/target.r b/fbxa/target.r index acfe60b..49fd037 100644 --- a/fbxa/target.r +++ b/fbxa/target.r @@ -145,8 +145,8 @@ struct target_s = { { if ((ent.flags & FL_ITEM) && ent.model && ent.search_time < time) { // ugly hack - //XXX if (ent._last != bot) - //XXX thisp = 20; + if (_last != bot) + return 20; if (ent.classname == "item_artifact_super_damage") return 65; else if (ent.classname == "item_artifact_invulnerability") @@ -231,4 +231,19 @@ Finds the closest, fisible, waypoint to e return best; } +-(float)searchTime +{ + return ent.search_time; +} + +-(void)setSearchTime:(float)st +{ + ent.search_time = st; +} + +-(string)classname +{ + return ent.classname; +} + @end diff --git a/fbxa/waypoint.r b/fbxa/waypoint.r index 142c6b2..49372e6 100644 --- a/fbxa/waypoint.r +++ b/fbxa/waypoint.r @@ -60,12 +60,6 @@ Array waypoint_array; waypoint_thinker = spawn (); waypoint_thinker.classname = "waypoint_thinker"; } -/*XXX - ent.classname = "temp_waypoint"; - ent.solid = SOLID_TRIGGER; - ent.movetype = MOVETYPE_NOCLIP; - setsize(ent, VEC_HULL_MIN, VEC_HULL_MAX); // FIXME: convert these to numerical -*/ return [super init]; } @@ -74,6 +68,8 @@ Array waypoint_array; [self init]; [waypoint_array addItem: self]; origin = org; + search_time = time; + items = -1; if ([waypoint_array count] == 1) { local id obj = [Waypoint class]; local IMP imp = [obj methodForSelector: @selector (fixWaypoints)]; @@ -86,6 +82,7 @@ Array waypoint_array; -(id)initFromEntity:(entity)ent { [self initAt:ent.origin]; + //FIXME do entity based init } -(void)setOrigin:(vector)org @@ -97,28 +94,6 @@ Array waypoint_array; { return origin; } -/* -entity (vector org) -make_waypoint = -{ - local entity point; - - point = spawn (); - point.classname = "waypoint"; - - point.search_time = time; // don't double back for me; - point.solid = SOLID_TRIGGER; - point.movetype = MOVETYPE_NONE; - point.items = -1; - setorigin (point, org); - - setsize (point, VEC_HULL_MIN, VEC_HULL_MAX); - - if (waypoint_mode > WM_LOADED) // editor modes - setmodel (point, "progs/s_bubble.spr"); - return point; -}; -*/ -(integer)isLinkedTo:(Waypoint)way { @@ -261,7 +236,7 @@ Route & path table management -(void)clearRoute { - keys = FALSE; + busy = FALSE; enemy = NIL; items = -1; // not in table } @@ -316,9 +291,9 @@ tripping the runaway loop counter dist = dist + random() * 100; // add a little chaos if ((dist < e2.items) || (e2.items == -1)) { - if (!e2.keys) + if (!e2.busy) busy_waypoints = busy_waypoints + 1; - e2.keys = TRUE; + e2.busy = TRUE; e2.items = dist; e2.enemy = self; [e2 queueForThink]; @@ -349,7 +324,7 @@ tripping the runaway loop counter } busy_waypoints--; - keys = FALSE; + busy = FALSE; if (busy_waypoints <= 0) { if (direct_route) { @@ -387,6 +362,21 @@ tripping the runaway loop counter return 0; } +-(float)searchTime +{ + return search_time; +} + +-(void)setSearchTime:(float)st +{ + search_time = st; +} + +-(string)classname +{ + return is_temp ? "temp_waypoint" : "waypoint"; +} + @end @@ -401,30 +391,6 @@ BSP/QC Waypoint loading void() waypoint = { local Waypoint way = [[Waypoint alloc] initFromEntity: @self]; -/* - search_time = time; - solid = SOLID_TRIGGER; - movetype = MOVETYPE_NONE; - setorigin(self, origin); - - setsize(self, VEC_HULL_MIN, VEC_HULL_MAX); - waypoints = waypoints + 1; - if (!way_head) { - way_head = self; - way_foot = self; - } else { - way_foot._next = self; - _last = way_foot; - way_foot = self; - } - - count = waypoints; - waypoint_mode = WM_LOADED; - if (count == 1) { - think = FixWaypoints; // wait until all bsp loaded points are spawned - nextthink = time; - } -*/ }; void(vector org, vector bit1, integer bit4, integer flargs) make_way =