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
187 // bprint("^3LIST^7 succeeded!!!\n");
\r
188 self.movepoint = optpoint.origin;
\r
192 // bprint("No ^3LIST^7 success\n");
\r
193 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.link0);
\r
198 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
200 plane = self.goalcurrent.plane_chain;
\r
204 if (plane.mangle_x < 0)
\r
205 tvec_x = self.mins_x;
\r
206 if (plane.mangle_y < 0)
\r
207 tvec_y = self.mins_y;
\r
208 if (plane.mangle_z < 0)
\r
209 tvec_z = self.mins_z;
\r
210 tvec += self.origin;
\r
211 f = tvec*plane.mangle - self.goalcurrent.origin*plane.mangle-plane.delay;
\r
214 plane = plane.list;
\r
219 if (self.goalcurrent.sflags & S_TELEPORT)
\r
220 self.movepoint = self.goalcurrent.origin;
\r
223 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.goalcurrent);
\r
226 // bprint("^2SINGLE^7 succeeded!!!\n");
\r
227 self.movepoint = optpoint.origin;
\r
231 // bprint("No ^2SINGLE^7 success\n");
\r
232 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
235 if (self.movepoint == '0 0 0')
\r
237 self.strat_me = TRUE;
\r
238 UrreBotPath(minisearch_distance);
\r
245 if (!self.goalcurrent || ((self.goalcurrent.flags & FL_ITEM) && !self.goalcurrent.solid) || (self.goalcurrent.classname == "dom_controlpoint" && self.goalcurrent.enemy.team == self.team))
\r
247 self.strat_me = TRUE;
\r
248 UrreBotPath(minisearch_distance);
\r
250 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.goalcurrent);
\r
253 // bprint("^2SINGLE^7 succeeded!!!\n");
\r
254 self.movepoint = optpoint.origin;
\r
258 // bprint("No ^2SINGLE^7 success\n");
\r
259 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
262 dir = normalize(ToPointInSpace(self.goalcurrent, self.movepoint));
\r
263 dir = dir * sv_maxspeed;
\r
264 makevectors(self.v_angle);
\r
265 self.movement_x = dir * v_forward;
\r
266 self.movement_y = dir * v_right;
\r
267 self.movement_z = dir * v_up;
\r
270 /* --- UrreBotImpulses ---
\r
271 Returns the impulse for the best weapon in the given situation*/
\r
273 float() UrreBotImpulses =
\r
276 local float cells, rockets, nails, shells;
\r
279 if (random() < 0.5)
\r
282 dist = 400; // we like nex and mortar
\r
285 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
286 dist = vlen(v - self.origin);
\r
289 cells = self.ammo_cells;
\r
290 rockets = self.ammo_rockets;
\r
291 nails = self.ammo_nails;
\r
292 shells = self.ammo_shells;
\r
294 if (dist > 300 && cells && (self.items & IT_NEX))
\r
302 if (self.items & IT_GRENADE_LAUNCHER)
\r
304 self.lead = 1 / cvar("g_balance_grenadelauncher_speed");
\r
305 return WEP_GRENADE_LAUNCHER;
\r
307 if (self.items & IT_HAGAR)
\r
309 self.lead = 1 / cvar("g_balance_hagar_speed");
\r
312 else if (self.items & IT_ROCKET_LAUNCHER)
\r
314 self.lead = 1 / cvar("g_balance_rocketlauncher_speed");
\r
315 return WEP_ROCKET_LAUNCHER;
\r
320 if (self.items & IT_ELECTRO)
\r
322 self.lead = 1 / cvar("g_balance_electro_speed");
\r
323 return WEP_ELECTRO;
\r
325 else if (self.items & IT_CRYLINK)
\r
327 self.lead = 1 / cvar("g_balance_crylink_speed");
\r
328 return WEP_CRYLINK;
\r
333 if (self.items & IT_UZI)
\r
341 if (self.items & IT_SHOTGUN)
\r
344 return WEP_SHOTGUN;
\r
347 self.lead = 1 / cvar("g_balance_laser_speed");
\r
352 Used for some debugging, occasionally*/
\r
354 float BT_LIGHTNING = 0;
\r
356 void(float beamtype, vector bmins, vector bmaxs) BeamBox =
\r
358 local vector v1, v2;
\r
363 if (beamtype == BT_LIGHTNING)
\r
364 te_lightning1(world, v1, v2);
\r
366 te_beam(world, v1, v2);
\r
370 if (beamtype == BT_LIGHTNING)
\r
371 te_lightning1(world, v1, v2);
\r
373 te_beam(world, v1, v2);
\r
377 if (beamtype == BT_LIGHTNING)
\r
378 te_lightning1(world, v1, v2);
\r
380 te_beam(world, v1, v2);
\r
384 if (beamtype == BT_LIGHTNING)
\r
385 te_lightning1(world, v1, v2);
\r
387 te_beam(world, v1, v2);
\r
391 if (beamtype == BT_LIGHTNING)
\r
392 te_lightning1(world, v1, v2);
\r
394 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
425 if (beamtype == BT_LIGHTNING)
\r
426 te_lightning1(world, v1, v2);
\r
428 te_beam(world, v1, v2);
\r
434 if (beamtype == BT_LIGHTNING)
\r
435 te_lightning1(world, v1, v2);
\r
437 te_beam(world, v1, v2);
\r
442 if (beamtype == BT_LIGHTNING)
\r
443 te_lightning1(world, v1, v2);
\r
445 te_beam(world, v1, v2);
\r
450 if (beamtype == BT_LIGHTNING)
\r
451 te_lightning1(world, v1, v2);
\r
453 te_beam(world, v1, v2);
\r
456 /* --- UrreBotPath ---
\r
457 Marks route and determines which goal is the most useful to head for*/
\r
459 void(float sdist) UrreBotPath =
\r
461 local float f, f2, f3;
\r
462 local entity e, best;
\r
468 e = findchainflags(flags, FL_ITEM);
\r
492 best = best.goallist;
\r
502 f = ceil(random() * navnodes);
\r
520 best = best.goallist;
\r
525 /* --- UrreBotThink ---
\r
526 In this version, UrreBot does a path search based on timer and turn
\r
527 Then it aims, moves, checks if it's stuck, finds/loses stuff to shoot at,
\r
528 picks best weapon, shoots, and optionally displays debug stuff, in that
\r
530 Aiming must happen before movement, because movement depends on angles
\r
531 He does not yet have any combat movement*/
\r
533 void() UrreBotThink =
\r
538 self.movement = '0 0 0';
\r
543 if (cvar("teamplay") && self.team == self.enemy.team) // don't return fire if hit by a teammate
\r
544 self.enemy = world;
\r
549 if (random() < 0.2)
\r
554 if (strategytime <= time)
\r
555 if (strategytoken == self)
\r
557 strategytime = time + urrebots_strategytime;
\r
558 strategytoken = self.list;
\r
559 if (!strategytoken)
\r
560 strategytoken = urrebot_chain;
\r
563 self.strat_me = FALSE;
\r
564 UrreBotPath(stratsearch_distance);
\r
571 if (self.camptime <= time)
\r
573 if (vlen(self.origin - self.campcheck) < 200) // stuckage avoidage
\r
575 self.camptime = time + urrebots;
\r
576 self.strat_me = TRUE;
\r
577 UrreBotPath(minisearch_distance);
\r
581 self.campcheck = self.origin;
\r
582 self.camptime = time + 2;
\r
586 if (self.combattime <= time)
\r
588 self.combattime = time + urrebots_combattime;
\r
589 UrreBotEvalTargets();
\r
590 self.impulse = UrreBotImpulses();
\r
595 makevectors (self.v_angle);
\r
596 v = self.origin + '0 0 16';
\r
597 f = vlen(v - self.aimpoint);
\r
598 traceline (v, v + v_forward*f, FALSE, self);
\r
599 if (vlen(trace_endpos - self.aimpoint) < 150)
\r
611 if (cvar("urrebots_debug"))
\r
613 te_lightning1(self, self.origin, self.movepoint);
\r
614 if (!self.goalcurrent)
\r
616 bprint(self.netname);
\r
617 bprint(" has no goalcurrent\n");
\r