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
34 if (self.enemy.health >= 1 && !self.enemy.deadflag)
\r
36 if (self.evaltime <= time)
\r
38 self.evaltime = time + 3;
\r
39 v2 = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
40 traceline(v1, v2, TRUE, self);
\r
41 if (trace_fraction < 1)
\r
48 e = findradius(v1, 1500);
\r
51 if (!(e.flags & FL_NOTARGET))
\r
52 if (!(cvar("teamplay") && self.team == e.team)) // don't target teammates
\r
53 if (e.flags & FL_CLIENT)
\r
56 if (UrreBotInfront(e))
\r
59 v2 = (e.absmin + e.absmax) * 0.5;
\r
60 traceline(v1, v2, TRUE, self);
\r
61 if (trace_fraction == 1 || trace_ent == e)
\r
65 old = vlen(self.origin - (self.enemy.absmin + self.enemy.absmax)*0.5);
\r
66 new = vlen(self.origin - v2);
\r
78 if (self.goalcurrent.sflags & S_DOOR)
\r
79 e = self.goalcurrent.goalentity;
\r
80 else if (self.link0.sflags & S_DOOR)
\r
81 e = self.link0.goalentity;
\r
86 /* --- UrreBotAim ---
\r
87 Very crude and simple aiming, with some leading capability*/
\r
91 local float dist, skeel;
\r
92 local vector v, desiredang, testang, diffang;
\r
94 skeel = bound(1, skill, 10);
\r
96 // get the desired angles to aim at
\r
99 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
100 if (self.enemy.classname == "door")
\r
102 else if (self.aimtime <= time)
\r
104 self.aimtime = time + 0.3;
\r
105 traceline(self.origin + self.view_ofs, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, self);
\r
106 if (trace_fraction == 1)
\r
108 self.aimpoint = v + self.enemy.velocity*vlen(self.origin - v)*self.lead;
\r
109 self.aimpoint = self.aimpoint + randomvec()*max(0, 120 - skeel*12);
\r
112 desiredang = vectoangles(self.aimpoint - (self.origin + self.view_ofs));
\r
115 desiredang = vectoangles(self.velocity);
\r
116 desiredang_x = 0-desiredang_x;
\r
118 if (desiredang_y <= -180)
\r
119 desiredang_y = desiredang_y + 360;
\r
120 else if (desiredang_y >= 180)
\r
121 desiredang_y = desiredang_y - 360;
\r
122 if (desiredang_x <= -180)
\r
123 desiredang_x = desiredang_x + 360;
\r
124 else if (desiredang_x >= 180)
\r
125 desiredang_x = desiredang_x - 360;
\r
127 // calculate turn angles
\r
128 testang = desiredang - self.v_angle;
\r
132 dist = vlen(testang * ((skeel + 1) * frametime));
\r
133 if (vlen(normalize(testang) * skeel) > dist)
\r
135 diffang = normalize(testang) * skeel;
\r
136 dist = vlen(normalize(testang) * skeel);
\r
139 diffang = testang * ((skeel + 1) * frametime);
\r
140 if (dist > vlen(testang))
\r
143 self.v_angle = self.v_angle + diffang;
\r
144 self.angles_y = self.v_angle_y;
\r
147 /* --- UrreBotMove ---
\r
148 Moves towards the closest point on the next goal in the bots list,
\r
149 which can be a navnode, item or domination point*/
\r
151 void() UrreBotMove =
\r
153 local float f, bad;
\r
154 local vector dir, tvec;
\r
155 local entity plane, optpoint;
\r
159 if (boxesoverlap(self.origin + self.mins, self.origin + self.maxs, self.link0.origin + self.link0.mins, self.link0.origin + self.link0.maxs))
\r
161 plane = self.link0.plane_chain;
\r
165 if (plane.mangle_x < 0)
\r
166 tvec_x = self.mins_x;
\r
167 if (plane.mangle_y < 0)
\r
168 tvec_y = self.mins_y;
\r
169 if (plane.mangle_z < 0)
\r
170 tvec_z = self.mins_z;
\r
171 tvec += self.origin;
\r
172 f = tvec*plane.mangle - self.link0.origin*plane.mangle-plane.delay;
\r
175 plane = plane.list;
\r
180 if (self.goalcurrent.sflags & S_TELEPORT)
\r
181 self.movepoint = self.goalcurrent.origin;
\r
184 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.link0);
\r
186 self.movepoint = optpoint.origin;
\r
188 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.link0);
\r
192 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
194 plane = self.goalcurrent.plane_chain;
\r
198 if (plane.mangle_x < 0)
\r
199 tvec_x = self.mins_x;
\r
200 if (plane.mangle_y < 0)
\r
201 tvec_y = self.mins_y;
\r
202 if (plane.mangle_z < 0)
\r
203 tvec_z = self.mins_z;
\r
204 tvec += self.origin;
\r
205 f = tvec*plane.mangle - self.goalcurrent.origin*plane.mangle-plane.delay;
\r
208 plane = plane.list;
\r
213 if (self.goalcurrent.sflags & S_TELEPORT)
\r
214 self.movepoint = self.goalcurrent.origin;
\r
217 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.goalcurrent);
\r
219 self.movepoint = optpoint.origin;
\r
221 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
223 if (self.movepoint == '0 0 0')
\r
225 self.strat_me = TRUE;
\r
226 UrreBotPath(minisearch_distance);
\r
233 if (!self.goalcurrent || ((self.goalcurrent.flags & FL_ITEM) && !self.goalcurrent.solid) || (self.goalcurrent.classname == "dom_controlpoint" && self.goalcurrent.enemy.team == self.team))
\r
235 self.strat_me = TRUE;
\r
236 UrreBotPath(minisearch_distance);
\r
238 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.goalcurrent);
\r
240 self.movepoint = optpoint.origin;
\r
242 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
244 dir = normalize(ToPointInSpace(self.goalcurrent, self.movepoint));
\r
245 dir = dir * sv_maxspeed;
\r
246 makevectors(self.v_angle);
\r
247 self.movement_x = dir * v_forward;
\r
248 self.movement_y = dir * v_right;
\r
249 self.movement_z = dir * v_up;
\r
252 /* --- UrreBotImpulses ---
\r
253 Returns the impulse for the best weapon in the given situation*/
\r
255 float() UrreBotImpulses =
\r
258 local float cells, rockets, nails, shells;
\r
261 if (random() < 0.5)
\r
264 dist = 400; // we like nex and mortar
\r
267 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
268 dist = vlen(v - self.origin);
\r
271 cells = self.ammo_cells;
\r
272 rockets = self.ammo_rockets;
\r
273 nails = self.ammo_nails;
\r
274 shells = self.ammo_shells;
\r
276 if (dist > 300 && cells && (self.items & IT_NEX))
\r
284 if (self.items & IT_GRENADE_LAUNCHER)
\r
286 self.lead = 1 / cvar("g_balance_grenadelauncher_speed");
\r
287 return WEP_GRENADE_LAUNCHER;
\r
289 if (self.items & IT_HAGAR)
\r
291 self.lead = 1 / cvar("g_balance_hagar_speed");
\r
294 else if (self.items & IT_ROCKET_LAUNCHER)
\r
296 self.lead = 1 / cvar("g_balance_rocketlauncher_speed");
\r
297 return WEP_ROCKET_LAUNCHER;
\r
302 if (self.items & IT_ELECTRO)
\r
304 self.lead = 1 / cvar("g_balance_electro_speed");
\r
305 return WEP_ELECTRO;
\r
307 else if (self.items & IT_CRYLINK)
\r
309 self.lead = 1 / cvar("g_balance_crylink_speed");
\r
310 return WEP_CRYLINK;
\r
315 if (self.items & IT_UZI)
\r
323 if (self.items & IT_SHOTGUN)
\r
326 return WEP_SHOTGUN;
\r
329 self.lead = 1 / cvar("g_balance_laser_speed");
\r
334 Used for some debugging, occasionally*/
\r
336 float BT_LIGHTNING = 0;
\r
338 void(float beamtype, vector bmins, vector bmaxs) BeamBox =
\r
340 local vector v1, v2;
\r
345 if (beamtype == BT_LIGHTNING)
\r
346 te_lightning1(world, v1, v2);
\r
348 te_beam(world, v1, v2);
\r
352 if (beamtype == BT_LIGHTNING)
\r
353 te_lightning1(world, v1, v2);
\r
355 te_beam(world, v1, v2);
\r
359 if (beamtype == BT_LIGHTNING)
\r
360 te_lightning1(world, v1, v2);
\r
362 te_beam(world, v1, v2);
\r
366 if (beamtype == BT_LIGHTNING)
\r
367 te_lightning1(world, v1, v2);
\r
369 te_beam(world, v1, v2);
\r
373 if (beamtype == BT_LIGHTNING)
\r
374 te_lightning1(world, v1, v2);
\r
376 te_beam(world, v1, v2);
\r
380 if (beamtype == BT_LIGHTNING)
\r
381 te_lightning1(world, v1, v2);
\r
383 te_beam(world, v1, v2);
\r
389 if (beamtype == BT_LIGHTNING)
\r
390 te_lightning1(world, v1, v2);
\r
392 te_beam(world, v1, v2);
\r
398 if (beamtype == BT_LIGHTNING)
\r
399 te_lightning1(world, v1, v2);
\r
401 te_beam(world, v1, v2);
\r
407 if (beamtype == BT_LIGHTNING)
\r
408 te_lightning1(world, v1, v2);
\r
410 te_beam(world, v1, v2);
\r
416 if (beamtype == BT_LIGHTNING)
\r
417 te_lightning1(world, v1, v2);
\r
419 te_beam(world, v1, v2);
\r
424 if (beamtype == BT_LIGHTNING)
\r
425 te_lightning1(world, v1, v2);
\r
427 te_beam(world, v1, v2);
\r
432 if (beamtype == BT_LIGHTNING)
\r
433 te_lightning1(world, v1, v2);
\r
435 te_beam(world, v1, v2);
\r
438 /* --- UrreBotPath ---
\r
439 Marks route and determines which goal is the most useful to head for*/
\r
441 void(float sdist) UrreBotPath =
\r
443 local float f, f2, f3;
\r
444 local entity e, best;
\r
450 e = findchainflags(flags, FL_ITEM);
\r
474 best = best.goallist;
\r
484 f = ceil(random() * navnodes);
\r
502 best = best.goallist;
\r
507 /* --- UrreBotThink ---
\r
508 In this version, UrreBot does a path search based on timer and turn
\r
509 Then it aims, moves, checks if it's stuck, finds/loses stuff to shoot at,
\r
510 picks best weapon, shoots, and optionally displays debug stuff, in that
\r
512 Aiming must happen before movement, because movement depends on angles
\r
513 He does not yet have any combat movement*/
\r
515 void() UrreBotThink =
\r
520 self.movement = '0 0 0';
\r
525 if (cvar("teamplay") && self.team == self.enemy.team) // don't return fire if hit by a teammate
\r
526 self.enemy = world;
\r
531 if (random() < 0.2)
\r
536 if (strategytime <= time)
\r
537 if (strategytoken == self)
\r
539 strategytime = time + urrebots_strategytime;
\r
540 strategytoken = self.list;
\r
541 if (!strategytoken)
\r
542 strategytoken = urrebot_chain;
\r
545 self.strat_me = FALSE;
\r
546 UrreBotPath(stratsearch_distance);
\r
553 if (self.camptime <= time)
\r
555 if (vlen(self.origin - self.campcheck) < 200) // stuckage avoidage
\r
557 self.camptime = time + urrebots;
\r
558 self.strat_me = TRUE;
\r
559 UrreBotPath(minisearch_distance);
\r
563 self.campcheck = self.origin;
\r
564 self.camptime = time + 2;
\r
568 if (self.combattime <= time)
\r
570 self.combattime = time + urrebots_combattime;
\r
571 UrreBotEvalTargets();
\r
572 self.impulse = UrreBotImpulses();
\r
577 makevectors (self.v_angle);
\r
578 v = self.origin + '0 0 16';
\r
579 f = vlen(v - self.aimpoint);
\r
580 traceline (v, v + v_forward*f, FALSE, self);
\r
581 if (vlen(trace_endpos - self.aimpoint) < 150)
\r
593 if (cvar("urrebots_debug"))
\r
595 te_lightning1(self, self.origin, self.movepoint);
\r
596 if (!self.goalcurrent)
\r
598 bprint(self.netname);
\r
599 bprint(" has no goalcurrent\n");
\r