1 /* --- UrreBotSetup ---
\r
2 Issues a random funky name, random colors, playermodel and team to the bot*/
\r
4 void() UrreBotSetup =
\r
6 local float r, shirt, pants;
\r
11 s = "GrooveMachine";
\r
52 self.playermodel = "models/player/carni.zym";
\r
54 self.playerskin = "0";
\r
56 self.playerskin = "1";
\r
60 self.playermodel = "models/player/crash.zym";
\r
61 self.playerskin = "0";
\r
65 self.playermodel = "models/player/grunt.zym";
\r
66 self.playerskin = "0";
\r
70 self.playermodel = "models/player/headhunter.zym";
\r
71 self.playerskin = "0";
\r
75 self.playermodel = "models/player/insurrectionist.zym";
\r
76 self.playerskin = "0";
\r
80 self.playermodel = "models/player/jeandarc.zym";
\r
81 self.playerskin = "0";
\r
85 self.playermodel = "models/player/lurk.zym";
\r
87 self.playerskin = "0";
\r
89 self.playerskin = "1";
\r
93 self.playermodel = "models/player/lycanthrope.zym";
\r
94 self.playerskin = "0";
\r
98 self.playermodel = "models/player/marine.zym";
\r
99 self.playerskin = "0";
\r
103 self.playermodel = "models/player/nexus.zym";
\r
104 if (random() < 0.5)
\r
105 self.playerskin = "0";
\r
107 self.playerskin = "1";
\r
111 self.playermodel = "models/player/pyria.zym";
\r
112 self.playerskin = "0";
\r
116 self.playermodel = "models/player/shock.zym";
\r
117 self.playerskin = "0";
\r
121 self.playermodel = "models/player/skadi.zym";
\r
122 self.playerskin = "0";
\r
126 self.playermodel = "models/player/specop.zym";
\r
127 self.playerskin = "0";
\r
131 self.playermodel = "models/player/visitant.zym";
\r
132 self.playerskin = "0";
\r
136 JoinBestTeam(self, 0);
\r
139 shirt = floor(random()*15);
\r
140 pants = floor(random()*15);
\r
141 self.clientcolors = pants + shirt * 16;
\r
145 /* --- UrreBotInfront ---
\r
146 I could've used id's infront, but as it wasn't in LordHavoc's multiplayer
\r
147 only mod, I had to add a new one, named something else to not mess with people's
\r
148 possible/eventual plugin-attempts*/
\r
150 float(entity targ) UrreBotInfront =
\r
155 makevectors (self.angles);
\r
156 vec = normalize (targ.origin - self.origin);
\r
157 dot = vec * v_forward;
\r
164 /* --- UrreBotEvalTargets ---
\r
165 Enemies are found and lost using this function
\r
166 If the bot can't see his enemy for 3 seconds, it is dropped*/
\r
168 void() UrreBotEvalTargets =
\r
170 local float old, new;
\r
171 local vector v1, v2;
\r
174 v1 = self.origin + self.view_ofs;
\r
178 if (self.enemy.health >= 1 && !self.enemy.deadflag)
\r
180 if (self.evaltime <= time)
\r
182 self.evaltime = time + 3;
\r
183 v2 = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
184 traceline(v1, v2, TRUE, self);
\r
185 if (trace_fraction < 1)
\r
186 self.enemy = world;
\r
190 self.enemy = world;
\r
192 e = findradius(v1, 1500);
\r
195 if (!(e.flags & FL_NOTARGET) || e.killcount != -666) // -666 is spec/obs
\r
196 if (!(cvar("teamplay") && self.team == e.team)) // don't target teammates
\r
197 if (e.flags & FL_CLIENT)
\r
200 if (UrreBotInfront(e))
\r
203 v2 = (e.absmin + e.absmax) * 0.5;
\r
204 traceline(v1, v2, TRUE, self);
\r
205 if (trace_fraction == 1 || trace_ent == e)
\r
209 old = vlen(self.origin - (self.enemy.absmin + self.enemy.absmax)*0.5);
\r
210 new = vlen(self.origin - v2);
\r
222 if (self.goalcurrent.sflags & S_DOOR)
\r
223 e = self.goalcurrent.goalentity;
\r
224 else if (self.link0.sflags & S_DOOR)
\r
225 e = self.link0.goalentity;
\r
230 /* --- UrreBotAim ---
\r
231 Very crude and simple aiming, with some leading capability*/
\r
233 void() UrreBotAim =
\r
235 local float dist, skeel;
\r
236 local vector v, desiredang, testang, diffang;
\r
238 skeel = bound(1, skill, 10);
\r
240 // get the desired angles to aim at
\r
243 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
244 if (self.enemy.classname == "door")
\r
246 else if (self.aimtime <= time)
\r
248 self.aimtime = time + 0.3;
\r
249 traceline(self.origin + self.view_ofs, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, self);
\r
250 if (trace_fraction == 1)
\r
252 self.aimpoint = v + self.enemy.velocity*vlen(self.origin - v)*self.lead;
\r
253 self.aimpoint = self.aimpoint + randomvec()*max(0, 120 - skeel*12);
\r
256 desiredang = vectoangles(self.aimpoint - (self.origin + self.view_ofs));
\r
259 desiredang = vectoangles(self.velocity);
\r
260 desiredang_x = 0-desiredang_x;
\r
262 if (desiredang_y <= -180)
\r
263 desiredang_y = desiredang_y + 360;
\r
264 else if (desiredang_y >= 180)
\r
265 desiredang_y = desiredang_y - 360;
\r
266 if (desiredang_x <= -180)
\r
267 desiredang_x = desiredang_x + 360;
\r
268 else if (desiredang_x >= 180)
\r
269 desiredang_x = desiredang_x - 360;
\r
271 // calculate turn angles
\r
272 testang = desiredang - self.v_angle;
\r
276 dist = vlen(testang * ((skeel + 1) * frametime));
\r
277 if (vlen(normalize(testang) * skeel) > dist)
\r
279 diffang = normalize(testang) * skeel;
\r
280 dist = vlen(normalize(testang) * skeel);
\r
283 diffang = testang * ((skeel + 1) * frametime);
\r
284 if (dist > vlen(testang))
\r
287 self.v_angle = self.v_angle + diffang;
\r
288 self.angles_y = self.v_angle_y;
\r
291 /* --- UrreBotMove ---
\r
292 Moves towards the closest point on the next goal in the bots list,
\r
293 which can be a navnode, item or domination point*/
\r
295 void() UrreBotMove =
\r
297 local float f, bad;
\r
298 local vector dir, tvec;
\r
299 local entity plane;
\r
303 if (boxesoverlap(self.origin + self.mins, self.origin + self.maxs, self.link0.origin + self.link0.mins, self.link0.origin + self.link0.maxs))
\r
305 plane = self.link0.plane_chain;
\r
309 if (plane.mangle_x < 0)
\r
310 tvec_x = self.mins_x;
\r
311 if (plane.mangle_y < 0)
\r
312 tvec_y = self.mins_y;
\r
313 if (plane.mangle_z < 0)
\r
314 tvec_z = self.mins_z;
\r
315 tvec += self.origin;
\r
316 f = tvec*plane.mangle - self.link0.origin*plane.mangle-plane.delay;
\r
319 plane = plane.list;
\r
324 if (self.goalcurrent.sflags & S_TELEPORT)
\r
325 self.movepoint = self.goalcurrent.origin;
\r
327 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.link0);
\r
330 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
332 plane = self.goalcurrent.plane_chain;
\r
336 if (plane.mangle_x < 0)
\r
337 tvec_x = self.mins_x;
\r
338 if (plane.mangle_y < 0)
\r
339 tvec_y = self.mins_y;
\r
340 if (plane.mangle_z < 0)
\r
341 tvec_z = self.mins_z;
\r
342 tvec += self.origin;
\r
343 f = tvec*plane.mangle - self.goalcurrent.origin*plane.mangle-plane.delay;
\r
346 plane = plane.list;
\r
351 if (self.goalcurrent.sflags & S_TELEPORT)
\r
352 self.movepoint = self.goalcurrent.origin;
\r
354 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
355 if (self.movepoint == '0 0 0')
\r
357 self.strat_me = TRUE;
\r
358 UrreBotPath(minisearch_distance);
\r
365 if (!self.goalcurrent || ((self.goalcurrent.flags & FL_ITEM) && !self.goalcurrent.solid) || (self.goalcurrent.classname == "dom_controlpoint" && self.goalcurrent.enemy.team == self.team))
\r
367 self.strat_me = TRUE;
\r
368 UrreBotPath(minisearch_distance);
\r
370 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
372 dir = normalize(ToPointInSpace(self.goalcurrent, self.movepoint));
\r
373 dir = dir * sv_maxspeed;
\r
374 makevectors(self.v_angle);
\r
375 self.movement_x = dir * v_forward;
\r
376 self.movement_y = dir * v_right;
\r
377 self.movement_z = dir * v_up;
\r
380 /* --- UrreBotImpulses ---
\r
381 Returns the impulse for the best weapon in the given situation*/
\r
383 float() UrreBotImpulses =
\r
386 local float cells, rockets, nails, shells;
\r
389 if (random() < 0.5)
\r
392 dist = 400; // we like nex and mortar
\r
395 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
396 dist = vlen(v - self.origin);
\r
399 cells = self.ammo_cells;
\r
400 rockets = self.ammo_rockets;
\r
401 nails = self.ammo_nails;
\r
402 shells = self.ammo_shells;
\r
404 if (dist > 300 && cells && (self.items & IT_NEX))
\r
412 if (self.items & IT_GRENADE_LAUNCHER)
\r
414 self.lead = 1 / cvar("g_balance_grenadelauncher_speed");
\r
415 return WEP_GRENADE_LAUNCHER;
\r
417 if (self.items & IT_HAGAR)
\r
419 self.lead = 1 / cvar("g_balance_hagar_speed");
\r
422 else if (self.items & IT_ROCKET_LAUNCHER)
\r
424 self.lead = 1 / cvar("g_balance_rocketlauncher_speed");
\r
425 return WEP_ROCKET_LAUNCHER;
\r
430 if (self.items & IT_ELECTRO)
\r
432 self.lead = 1 / cvar("g_balance_electro_speed");
\r
433 return WEP_ELECTRO;
\r
435 else if (self.items & IT_CRYLINK)
\r
437 self.lead = 1 / cvar("g_balance_crylink_speed");
\r
438 return WEP_CRYLINK;
\r
443 if (self.items & IT_UZI)
\r
451 if (self.items & IT_SHOTGUN)
\r
454 return WEP_SHOTGUN;
\r
457 self.lead = 1 / cvar("g_balance_laser_speed");
\r
462 Used for some debugging, occasionally*/
\r
464 float BT_LIGHTNING = 0;
\r
466 void(float beamtype, vector bmins, vector bmaxs) BeamBox =
\r
468 local vector 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
487 if (beamtype == BT_LIGHTNING)
\r
488 te_lightning1(world, v1, v2);
\r
490 te_beam(world, v1, v2);
\r
494 if (beamtype == BT_LIGHTNING)
\r
495 te_lightning1(world, v1, v2);
\r
497 te_beam(world, v1, v2);
\r
501 if (beamtype == BT_LIGHTNING)
\r
502 te_lightning1(world, v1, v2);
\r
504 te_beam(world, v1, v2);
\r
508 if (beamtype == BT_LIGHTNING)
\r
509 te_lightning1(world, v1, v2);
\r
511 te_beam(world, v1, v2);
\r
517 if (beamtype == BT_LIGHTNING)
\r
518 te_lightning1(world, v1, v2);
\r
520 te_beam(world, v1, v2);
\r
526 if (beamtype == BT_LIGHTNING)
\r
527 te_lightning1(world, v1, v2);
\r
529 te_beam(world, v1, v2);
\r
535 if (beamtype == BT_LIGHTNING)
\r
536 te_lightning1(world, v1, v2);
\r
538 te_beam(world, v1, v2);
\r
544 if (beamtype == BT_LIGHTNING)
\r
545 te_lightning1(world, v1, v2);
\r
547 te_beam(world, v1, v2);
\r
552 if (beamtype == BT_LIGHTNING)
\r
553 te_lightning1(world, v1, v2);
\r
555 te_beam(world, v1, v2);
\r
560 if (beamtype == BT_LIGHTNING)
\r
561 te_lightning1(world, v1, v2);
\r
563 te_beam(world, v1, v2);
\r
566 /* --- UrreBotPath ---
\r
567 Marks route and determines which goal is the most useful to head for*/
\r
569 void(float sdist) UrreBotPath =
\r
571 local float f, f2, f3;
\r
572 local entity e, best;
\r
578 e = findchainflags(flags, FL_ITEM);
\r
602 best = best.goallist;
\r
612 f = ceil(random() * navnodes);
\r
630 best = best.goallist;
\r
635 /* --- UrreBotThink ---
\r
636 In this version, UrreBot does a path search based on timer and turn
\r
637 Then it aims, moves, checks if it's stuck, finds/loses stuff to shoot at,
\r
638 picks best weapon, shoots, and optionally displays debug stuff, in that
\r
640 Aiming must happen before movement, because movement depends on angles
\r
641 He does not yet have any combat movement*/
\r
643 void() UrreBotThink =
\r
648 self.movement = '0 0 0';
\r
653 if (cvar("teamplay") && self.team == self.enemy.team) // don't return fire if hit by a teammate
\r
654 self.enemy = world;
\r
659 if (random() < 0.2)
\r
664 if (strategytime <= time)
\r
665 if (strategytoken == self)
\r
667 strategytime = time + urrebots_strategytime;
\r
668 strategytoken = self.list;
\r
669 if (!strategytoken)
\r
670 strategytoken = bot_chain;
\r
673 self.strat_me = FALSE;
\r
674 UrreBotPath(stratsearch_distance);
\r
681 if (self.camptime <= time)
\r
683 if (vlen(self.origin - self.campcheck) < 200) // stuckage avoidage
\r
685 self.camptime = time + actualurrebots;
\r
686 self.strat_me = TRUE;
\r
687 UrreBotPath(minisearch_distance);
\r
691 self.campcheck = self.origin;
\r
692 self.camptime = time + 2;
\r
696 if (self.combattime <= time)
\r
698 self.combattime = time + urrebots_combattime;
\r
699 UrreBotEvalTargets();
\r
700 self.impulse = UrreBotImpulses();
\r
705 makevectors (self.v_angle);
\r
706 v = self.origin + '0 0 16';
\r
707 f = vlen(v - self.aimpoint);
\r
708 traceline (v, v + v_forward*f, FALSE, self);
\r
709 if (vlen(trace_endpos - self.aimpoint) < 150)
\r
713 if (random() < 0.3)
\r
720 if (cvar("urrebots_debug"))
\r
722 te_lightning1(self, self.origin, self.movepoint);
\r
723 if (!self.goalcurrent)
\r
725 bprint(self.netname);
\r
726 bprint(" has no goalcurrent\n");
\r