1 /* --- UrreBotInfront ---
\r
2 I could've used id's infront, but as it wasn't in LordHavoc's multiplayer
\r
3 only mod, I had to add a new one, named something else to not mess with people's
\r
4 possible/eventual plugin-attempts*/
\r
6 float(entity targ) UrreBotInfront =
\r
11 makevectors (self.angles);
\r
12 vec = normalize (targ.origin - self.origin);
\r
13 dot = vec * v_forward;
\r
20 /* --- UrreBotEvalTargets ---
\r
21 Enemies are found and lost using this function
\r
22 If the bot can't see his enemy for 3 seconds, it is dropped*/
\r
24 void() UrreBotEvalTargets =
\r
26 local float old, new;
\r
27 local vector v1, v2;
\r
30 v1 = self.origin + self.view_ofs;
\r
35 if (self.enemy.health >= 1 && !self.enemy.deadflag)
\r
37 if (self.evaltime <= time)
\r
39 self.evaltime = time + 3;
\r
40 v2 = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
41 traceline(v1, v2, TRUE, self);
\r
42 if (trace_fraction < 1)
\r
50 e = findradius(v1, 1500);
\r
53 if (!(e.flags & FL_NOTARGET))
\r
54 if (!(cvar("teamplay") && self.team == e.team)) // don't target teammates
\r
55 if (e.flags & FL_CLIENT)
\r
58 if (UrreBotInfront(e))
\r
61 v2 = (e.absmin + e.absmax) * 0.5;
\r
62 traceline(v1, v2, TRUE, self);
\r
63 if (trace_fraction == 1 || trace_ent == e)
\r
67 old = vlen(self.origin - (self.enemy.absmin + self.enemy.absmax)*0.5);
\r
68 new = vlen(self.origin - v2);
\r
72 self.enemytimeout = time + 3;
\r
78 self.enemytimeout = time + 3;
\r
86 if (self.goalcurrent.sflags & S_DOOR)
\r
87 e = self.goalcurrent.goalentity;
\r
88 else if (self.link0.sflags & S_DOOR)
\r
89 e = self.link0.goalentity;
\r
93 self.enemytimeout = time + 3;
\r
97 /* --- UrreBotAim ---
\r
98 Very crude and simple aiming, with some leading capability*/
\r
100 void() UrreBotAim =
\r
102 //local float dist;
\r
105 local vector v, desiredang, testang, diffang, aimpoint;
\r
109 skeel = bound(1, skill, 10);
\r
111 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
113 if (self.switchweapon == WEP_ELECTRO || self.switchweapon == WEP_HAGAR || self.switchweapon == WEP_LASER)
\r
115 if(math_mod(self.playerid, 2) == 1)
\r
116 v_z = (self.enemy.absmin_z * 0.8 + v_z * 0.2); // aim more at the floor
\r
121 if (time > self.enemytimeout || self.enemy.takedamage == DAMAGE_NO || self.enemy.deadflag)
\r
122 self.enemy = world;
\r
123 else if (self.aimtime <= time)
\r
125 self.aimtime = time + 0.1; // LordHavoc: changed from time + 0.3 to time + 0.1
\r
126 self.aimfire = FALSE;
\r
129 traceline(self.origin + self.view_ofs, v, TRUE, self);
\r
130 if (trace_fraction == 1)
\r
132 self.enemytimeout = time + 3;
\r
133 self.aimfire = TRUE;
\r
139 // get the desired angles to aim at
\r
140 desiredang = self.v_angle_y * '0 1 0';
\r
144 //dprint("urrebotaim (skeel == ", ftos(skeel), ") : old aimpoint ", vtos(self.aimpoint));
\r
145 aimpoint = v + self.enemy.velocity*vlen(self.origin - v)*self.lead;
\r
146 //dprint(", v = ", vtos(v));
\r
147 //dprint(", self.enemy.velocity = ", vtos(self.enemy.velocity));
\r
148 //dprint(", vlen(self.origin - v) = ", ftos(vlen(self.origin - v)));
\r
149 //dprint(", self.lead = ", ftos(self.lead));
\r
150 aimpoint = aimpoint + randomvec()*max(0, 120 - skeel*12);
\r
151 //dprint(", final aimpoint = ", vtos(self.aimpoint), "\n");
\r
153 //eprint(self.enemy);
\r
154 desiredang = vectoangles(aimpoint - (self.origin + self.view_ofs));
\r
156 else if (vlen(self.velocity) >= 50)
\r
157 desiredang = vectoyaw(self.velocity) * '0 1 0';
\r
158 desiredang_x = 0-desiredang_x;
\r
160 // calculate turn angles
\r
161 testang = desiredang - self.v_angle;
\r
164 while (testang_y < -180)
\r
165 testang_y = testang_y + 360;
\r
166 while (testang_y >= 180)
\r
167 testang_y = testang_y - 360;
\r
168 while (testang_x < -180)
\r
169 testang_x = testang_x + 360;
\r
170 while (testang_x >= 180)
\r
171 testang_x = testang_x - 360;
\r
174 // LordHavoc: simplified to one line
\r
175 diffang = testang * min(1, ((skeel * 2) * frametime));
\r
177 self.v_angle = self.v_angle + diffang;
\r
178 self.angles_y = self.v_angle_y;
\r
183 makevectors (self.v_angle);
\r
184 //v = self.origin + '0 0 16';
\r
185 v = self.origin + self.view_ofs; // neuiz trueaim
\r
186 f = vlen(v - aimpoint);
\r
187 traceline (v, v + v_forward*f, FALSE, self);
\r
188 if (vlen(trace_endpos - aimpoint) < (200 - skeel * 15))
\r
190 f = 0.1 + skeel*0.1;
\r
193 else if (random() < f)
\r
198 if(self.switchweapon == WEP_ROCKET_LAUNCHER)
\r
200 if(self.lastrocket && self.enemy)
\r
202 if(vlen(self.lastrocket.origin - self.enemy.origin) < cvar("g_balance_rocketlauncher_radius") * 0.85)
\r
204 if(vlen(self.lastrocket.origin - self.origin) > cvar("g_balance_rocketlauncher_radius") * 1.05)
\r
206 f = 0.1 + skeel*0.1;
\r
215 /* --- UrreBotMove ---
\r
216 Moves towards the closest point on the next goal in the bots list,
\r
217 which can be a navnode, item or domination point*/
\r
219 void() UrreBotMove =
\r
221 local float f, bad;
\r
222 local vector dir, tvec;
\r
223 local entity plane, optpoint;
\r
227 if (boxesoverlap(self.origin + self.mins, self.origin + self.maxs, self.link0.origin + self.link0.mins, self.link0.origin + self.link0.maxs))
\r
230 plane = self.link0.plane_chain;
\r
234 if (plane.mangle_x < 0)
\r
235 tvec_x = self.mins_x;
\r
236 if (plane.mangle_y < 0)
\r
237 tvec_y = self.mins_y;
\r
238 if (plane.mangle_z < 0)
\r
239 tvec_z = self.mins_z;
\r
240 tvec += self.origin;
\r
241 f = tvec*plane.mangle - self.link0.origin*plane.mangle-plane.delay;
\r
244 plane = plane.list;
\r
249 if (self.goalcurrent.sflags & S_TELEPORT)
\r
250 self.movepoint = self.goalcurrent.origin;
\r
253 if (urrebots_navopt)
\r
254 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.link0);
\r
256 self.movepoint = optpoint.origin;
\r
258 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.link0);
\r
262 else if (((self.goalcurrent.sflags & S_TOUCH) && boxesoverlap(self.origin + self.mins, self.origin + self.maxs, self.goalcurrent.origin + self.goalcurrent.mins, self.goalcurrent.origin + self.goalcurrent.maxs)) || boxenclosed(self.origin + self.mins, self.origin + self.maxs, self.goalcurrent.origin + self.goalcurrent.mins, self.goalcurrent.origin + self.goalcurrent.maxs))
\r
265 plane = self.goalcurrent.plane_chain;
\r
269 if (plane.mangle_x < 0)
\r
270 tvec_x = self.mins_x;
\r
271 if (plane.mangle_y < 0)
\r
272 tvec_y = self.mins_y;
\r
273 if (plane.mangle_z < 0)
\r
274 tvec_z = self.mins_z;
\r
275 tvec += self.origin;
\r
276 f = tvec*plane.mangle - self.goalcurrent.origin*plane.mangle-plane.delay;
\r
279 plane = plane.list;
\r
284 if (self.goalcurrent.sflags & S_TELEPORT)
\r
285 self.movepoint = self.goalcurrent.origin;
\r
288 if (urrebots_navopt)
\r
289 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.goalcurrent);
\r
291 self.movepoint = optpoint.origin;
\r
293 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
295 if (self.movepoint == '0 0 0')
\r
297 self.strat_me = TRUE;
\r
298 UrreBotPath(minisearch_distance);
\r
306 if (!self.goalcurrent || ((self.goalcurrent.flags & FL_ITEM) && !self.goalcurrent.solid) || (self.goalcurrent.classname == "dom_controlpoint" && self.goalcurrent.enemy.team == self.team))
\r
308 self.strat_me = TRUE;
\r
309 UrreBotPath(minisearch_distance);
\r
311 if (urrebots_navopt)
\r
312 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.goalcurrent);
\r
314 self.movepoint = optpoint.origin;
\r
316 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
318 // dir = normalize(ToPointInSpace(self.goalcurrent, self.movepoint));
\r
319 dir = ToPointInSpace(self.goalcurrent, self.movepoint);
\r
320 dir = dir * sv_maxspeed;
\r
321 makevectors(self.v_angle);
\r
322 self.movement_x = dir * v_forward;
\r
323 self.movement_y = dir * v_right;
\r
324 self.movement_z = dir * v_up;
\r
327 /* --- UrreBotImpulses ---
\r
328 Returns the impulse for the best weapon in the given situation*/
\r
330 float() UrreBotImpulses =
\r
332 local float dist, l, w;
\r
333 local float cells, rockets, nails, shells;
\r
336 if (random() < 0.5)
\r
339 dist = 400; // we like nex and mortar
\r
342 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
343 dist = vlen(v - self.origin);
\r
346 cells = self.ammo_cells;
\r
347 rockets = self.ammo_rockets;
\r
348 nails = self.ammo_nails;
\r
349 shells = self.ammo_shells;
\r
355 if (self.items & IT_NEX)
\r
357 if (cells >= cvar("g_balance_nex_ammo"))
\r
363 if (self.items & IT_GRENADE_LAUNCHER)
\r
366 if (rockets >= cvar("g_balance_grenadelauncher_primary_ammo"))
\r
368 l = cvar("g_balance_grenadelauncher_primary_speed");
\r
369 w = WEP_GRENADE_LAUNCHER;
\r
372 if (self.items & IT_HAGAR)
\r
375 if (rockets >= cvar("g_balance_hagar_primary_ammo"))
\r
377 l = cvar("g_balance_hagar_primary_speed");
\r
381 if (self.items & IT_ROCKET_LAUNCHER)
\r
384 if (rockets >= cvar("g_balance_rocketlauncher_ammo"))
\r
386 l = cvar("g_balance_rocketlauncher_speed");
\r
387 w = WEP_ROCKET_LAUNCHER;
\r
390 if (self.items & IT_ELECTRO)
\r
393 if (cells >= cvar("g_balance_electro_primary_ammo"))
\r
395 l = cvar("g_balance_electro_primary_speed");
\r
399 if (self.items & IT_CRYLINK)
\r
401 if (cells >= cvar("g_balance_crylink_primary_ammo"))
\r
403 l = cvar("g_balance_crylink_primary_speed");
\r
407 if (self.items & IT_UZI)
\r
409 if (nails >= cvar("g_balance_uzi_first_ammo"))
\r
415 if (self.items & IT_SHOTGUN)
\r
417 if (nails >= cvar("g_balance_shotgun_primary_ammo"))
\r
424 l = cvar("g_balance_laser_speed");
\r
428 error("UrreBotImpulses: missing cvar for weapon\n");
\r
434 Used for some debugging, occasionally*/
\r
436 float BT_LIGHTNING = 0;
\r
438 void(float beamtype, vector bmins, vector bmaxs) BeamBox =
\r
440 local vector v1, v2;
\r
445 if (beamtype == BT_LIGHTNING)
\r
446 te_lightning1(world, v1, v2);
\r
448 te_beam(world, v1, v2);
\r
452 if (beamtype == BT_LIGHTNING)
\r
453 te_lightning1(world, v1, v2);
\r
455 te_beam(world, v1, v2);
\r
459 if (beamtype == BT_LIGHTNING)
\r
460 te_lightning1(world, v1, v2);
\r
462 te_beam(world, v1, v2);
\r
466 if (beamtype == BT_LIGHTNING)
\r
467 te_lightning1(world, v1, v2);
\r
469 te_beam(world, v1, v2);
\r
473 if (beamtype == BT_LIGHTNING)
\r
474 te_lightning1(world, v1, v2);
\r
476 te_beam(world, v1, v2);
\r
480 if (beamtype == BT_LIGHTNING)
\r
481 te_lightning1(world, v1, v2);
\r
483 te_beam(world, v1, v2);
\r
489 if (beamtype == BT_LIGHTNING)
\r
490 te_lightning1(world, v1, v2);
\r
492 te_beam(world, v1, v2);
\r
498 if (beamtype == BT_LIGHTNING)
\r
499 te_lightning1(world, v1, v2);
\r
501 te_beam(world, v1, v2);
\r
507 if (beamtype == BT_LIGHTNING)
\r
508 te_lightning1(world, v1, v2);
\r
510 te_beam(world, v1, v2);
\r
516 if (beamtype == BT_LIGHTNING)
\r
517 te_lightning1(world, v1, v2);
\r
519 te_beam(world, v1, v2);
\r
524 if (beamtype == BT_LIGHTNING)
\r
525 te_lightning1(world, v1, v2);
\r
527 te_beam(world, v1, v2);
\r
532 if (beamtype == BT_LIGHTNING)
\r
533 te_lightning1(world, v1, v2);
\r
535 te_beam(world, v1, v2);
\r
538 /* --- UrreBotPath ---
\r
539 Marks route and determines which goal is the most useful to head for*/
\r
541 void(float sdist) UrreBotPath =
\r
543 local float f, f2, f3;
\r
544 local entity e, best;
\r
550 e = findchainflags(flags, FL_ITEM);
\r
574 best = best.goallist;
\r
584 f = ceil(random() * navnodes);
\r
602 best = best.goallist;
\r
607 /* --- UrreBotThink ---
\r
608 In this version, UrreBot does a path search based on timer and turn
\r
609 Then it aims, moves, checks if it's stuck, finds/loses stuff to shoot at,
\r
610 picks best weapon, shoots, and optionally displays debug stuff, in that
\r
612 Aiming must happen before movement, because movement depends on angles
\r
613 He does not yet have any combat movement*/
\r
615 void() UrreBotThink =
\r
617 self.movement = '0 0 0';
\r
623 if (cvar("teamplay") && self.team == self.enemy.team) // don't return fire if hit by a teammate
\r
624 self.enemy = world;
\r
629 if (random() < 0.2)
\r
634 if (strategytime <= time)
\r
635 if (strategytoken == self)
\r
637 strategytime = time + urrebots_strategytime;
\r
638 strategytoken = self.list;
\r
639 if (!strategytoken)
\r
640 strategytoken = urrebot_chain;
\r
643 self.strat_me = FALSE;
\r
644 UrreBotPath(stratsearch_distance);
\r
651 if (self.camptime <= time)
\r
653 if (vlen(self.origin - self.campcheck) < 200) // stuckage avoidage
\r
655 self.camptime = time + urrebots;
\r
656 self.strat_me = TRUE;
\r
657 UrreBotPath(minisearch_distance);
\r
661 self.campcheck = self.origin;
\r
662 self.camptime = time + 2;
\r
666 if (self.combattime <= time)
\r
668 self.combattime = time + urrebots_combattime;
\r
669 UrreBotEvalTargets();
\r
670 self.impulse = UrreBotImpulses();
\r
673 if (cvar("urrebots_debug"))
\r
675 te_lightning1(self, self.origin, self.movepoint);
\r
676 if (!self.goalcurrent)
\r
678 bprint(self.netname);
\r
679 bprint(" has no goalcurrent\n");
\r