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 (e.flags & FL_CLIENT)
\r
199 if (UrreBotInfront(e))
\r
202 v2 = (e.absmin + e.absmax) * 0.5;
\r
203 traceline(v1, v2, TRUE, self);
\r
204 if (trace_fraction == 1 || trace_ent == e)
\r
208 old = vlen(self.origin - (self.enemy.absmin + self.enemy.absmax)*0.5);
\r
209 new = vlen(self.origin - v2);
\r
221 if (self.goalcurrent.sflags & S_DOOR)
\r
222 e = self.goalcurrent.goalentity;
\r
223 else if (self.link0.sflags & S_DOOR)
\r
224 e = self.link0.goalentity;
\r
229 /* --- UrreBotAim ---
\r
230 Very crude and simple aiming, with some leading capability*/
\r
232 void() UrreBotAim =
\r
234 local float dist, skeel;
\r
235 local vector v, desiredang, testang, diffang;
\r
237 skeel = bound(1, skill, 10);
\r
239 // get the desired angles to aim at
\r
242 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
243 if (self.enemy.classname == "door")
\r
245 else if (self.aimtime <= time)
\r
247 self.aimtime = time + 0.3;
\r
248 traceline(self.origin + self.view_ofs, (self.enemy.absmin + self.enemy.absmax) * 0.5, TRUE, self);
\r
249 if (trace_fraction == 1)
\r
251 self.aimpoint = v + self.enemy.velocity*vlen(self.origin - v)*self.lead;
\r
252 self.aimpoint = self.aimpoint + randomvec()*max(0, 120 - skeel*12);
\r
255 desiredang = vectoangles(self.aimpoint - (self.origin + self.view_ofs));
\r
258 desiredang = vectoangles(self.velocity);
\r
259 desiredang_x = 0-desiredang_x;
\r
261 if (desiredang_y <= -180)
\r
262 desiredang_y = desiredang_y + 360;
\r
263 else if (desiredang_y >= 180)
\r
264 desiredang_y = desiredang_y - 360;
\r
265 if (desiredang_x <= -180)
\r
266 desiredang_x = desiredang_x + 360;
\r
267 else if (desiredang_x >= 180)
\r
268 desiredang_x = desiredang_x - 360;
\r
270 // calculate turn angles
\r
271 testang = desiredang - self.v_angle;
\r
275 dist = vlen(testang * ((skeel + 1) * frametime));
\r
276 if (vlen(normalize(testang) * skeel) > dist)
\r
278 diffang = normalize(testang) * skeel;
\r
279 dist = vlen(normalize(testang) * skeel);
\r
282 diffang = testang * ((skeel + 1) * frametime);
\r
283 if (dist > vlen(testang))
\r
286 self.v_angle = self.v_angle + diffang;
\r
287 self.angles_y = self.v_angle_y;
\r
290 /* --- UrreBotMove ---
\r
291 Moves towards the closest point on the next goal in the bots list,
\r
292 which can be a navnode, item or domination point*/
\r
294 void() UrreBotMove =
\r
296 local float f, bad;
\r
297 local vector dir, tvec;
\r
298 local entity plane;
\r
302 if (boxesoverlap(self.origin + self.mins, self.origin + self.maxs, self.link0.origin + self.link0.mins, self.link0.origin + self.link0.maxs))
\r
304 plane = self.link0.plane_chain;
\r
308 if (plane.mangle_x < 0)
\r
309 tvec_x = self.mins_x;
\r
310 if (plane.mangle_y < 0)
\r
311 tvec_y = self.mins_y;
\r
312 if (plane.mangle_z < 0)
\r
313 tvec_z = self.mins_z;
\r
314 tvec += self.origin;
\r
315 f = tvec*plane.mangle - self.link0.origin*plane.mangle-plane.delay;
\r
318 plane = plane.list;
\r
323 if (self.goalcurrent.sflags & S_TELEPORT)
\r
324 self.movepoint = self.goalcurrent.origin;
\r
326 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.link0);
\r
329 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
331 plane = self.goalcurrent.plane_chain;
\r
335 if (plane.mangle_x < 0)
\r
336 tvec_x = self.mins_x;
\r
337 if (plane.mangle_y < 0)
\r
338 tvec_y = self.mins_y;
\r
339 if (plane.mangle_z < 0)
\r
340 tvec_z = self.mins_z;
\r
341 tvec += self.origin;
\r
342 f = tvec*plane.mangle - self.goalcurrent.origin*plane.mangle-plane.delay;
\r
345 plane = plane.list;
\r
350 if (self.goalcurrent.sflags & S_TELEPORT)
\r
351 self.movepoint = self.goalcurrent.origin;
\r
353 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
354 if (self.movepoint == '0 0 0')
\r
356 self.strat_me = TRUE;
\r
357 UrreBotPath(minisearch_distance);
\r
364 if (!self.goalcurrent || ((self.goalcurrent.flags & FL_ITEM) && !self.goalcurrent.solid) || (self.goalcurrent.classname == "dom_controlpoint" && self.goalcurrent.enemy.team == self.team))
\r
366 self.strat_me = TRUE;
\r
367 UrreBotPath(minisearch_distance);
\r
369 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
371 dir = normalize(ToPointInSpace(self.goalcurrent, self.movepoint));
\r
372 dir = dir * sv_maxspeed;
\r
373 makevectors(self.v_angle);
\r
374 self.movement_x = dir * v_forward;
\r
375 self.movement_y = dir * v_right;
\r
376 self.movement_z = dir * v_up;
\r
379 /* --- UrreBotImpulses ---
\r
380 Returns the impulse for the best weapon in the given situation*/
\r
382 float() UrreBotImpulses =
\r
385 local float cells, rockets, nails, shells;
\r
388 if (random() < 0.5)
\r
391 dist = 400; // we like nex and mortar
\r
394 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
395 dist = vlen(v - self.origin);
\r
398 cells = self.ammo_cells;
\r
399 rockets = self.ammo_rockets;
\r
400 nails = self.ammo_nails;
\r
401 shells = self.ammo_shells;
\r
403 if (dist > 300 && cells && (self.items & IT_NEX))
\r
411 if (self.items & IT_GRENADE_LAUNCHER)
\r
413 self.lead = 1 / cvar("g_balance_grenadelauncher_speed");
\r
414 return WEP_GRENADE_LAUNCHER;
\r
416 if (self.items & IT_HAGAR)
\r
418 self.lead = 1 / cvar("g_balance_hagar_speed");
\r
421 else if (self.items & IT_ROCKET_LAUNCHER)
\r
423 self.lead = 1 / cvar("g_balance_rocketlauncher_speed");
\r
424 return WEP_ROCKET_LAUNCHER;
\r
429 if (self.items & IT_ELECTRO)
\r
431 self.lead = 1 / cvar("g_balance_electro_speed");
\r
432 return WEP_ELECTRO;
\r
434 else if (self.items & IT_CRYLINK)
\r
436 self.lead = 1 / cvar("g_balance_crylink_speed");
\r
437 return WEP_CRYLINK;
\r
442 if (self.items & IT_UZI)
\r
450 if (self.items & IT_SHOTGUN)
\r
453 return WEP_SHOTGUN;
\r
456 self.lead = 1 / cvar("g_balance_laser_speed");
\r
461 Used for some debugging, occasionally*/
\r
463 float BT_LIGHTNING = 0;
\r
465 void(float beamtype, vector bmins, vector bmaxs) BeamBox =
\r
467 local vector v1, v2;
\r
472 if (beamtype == BT_LIGHTNING)
\r
473 te_lightning1(world, v1, v2);
\r
475 te_beam(world, v1, v2);
\r
479 if (beamtype == BT_LIGHTNING)
\r
480 te_lightning1(world, v1, v2);
\r
482 te_beam(world, v1, v2);
\r
486 if (beamtype == BT_LIGHTNING)
\r
487 te_lightning1(world, v1, v2);
\r
489 te_beam(world, v1, v2);
\r
493 if (beamtype == BT_LIGHTNING)
\r
494 te_lightning1(world, v1, v2);
\r
496 te_beam(world, v1, v2);
\r
500 if (beamtype == BT_LIGHTNING)
\r
501 te_lightning1(world, v1, v2);
\r
503 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
525 if (beamtype == BT_LIGHTNING)
\r
526 te_lightning1(world, v1, v2);
\r
528 te_beam(world, v1, v2);
\r
534 if (beamtype == BT_LIGHTNING)
\r
535 te_lightning1(world, v1, v2);
\r
537 te_beam(world, v1, v2);
\r
543 if (beamtype == BT_LIGHTNING)
\r
544 te_lightning1(world, v1, v2);
\r
546 te_beam(world, v1, v2);
\r
551 if (beamtype == BT_LIGHTNING)
\r
552 te_lightning1(world, v1, v2);
\r
554 te_beam(world, v1, v2);
\r
559 if (beamtype == BT_LIGHTNING)
\r
560 te_lightning1(world, v1, v2);
\r
562 te_beam(world, v1, v2);
\r
565 /* --- UrreBotPath ---
\r
566 Marks route and determines which goal is the most useful to head for*/
\r
568 void(float sdist) UrreBotPath =
\r
570 local float f, f2, f3;
\r
571 local entity e, best;
\r
577 e = findchainflags(flags, FL_ITEM);
\r
601 best = best.goallist;
\r
611 f = ceil(random() * navnodes);
\r
629 best = best.goallist;
\r
634 /* --- UrreBotThink ---
\r
635 In this version, UrreBot does a path search based on timer and turn
\r
636 Then it aims, moves, checks if it's stuck, finds/loses stuff to shoot at,
\r
637 picks best weapon, shoots, and optionally displays debug stuff, in that
\r
639 Aiming must happen before movement, because movement depends on angles
\r
640 He does not yet have any combat movement*/
\r
642 void() UrreBotThink =
\r
647 self.movement = '0 0 0';
\r
655 if (random() < 0.2)
\r
660 if (strategytime <= time)
\r
661 if (strategytoken == self)
\r
663 strategytime = time + urrebots_strategytime;
\r
664 strategytoken = self.list;
\r
665 if (!strategytoken)
\r
666 strategytoken = bot_chain;
\r
669 self.strat_me = FALSE;
\r
670 UrreBotPath(stratsearch_distance);
\r
677 if (self.camptime <= time)
\r
679 if (vlen(self.origin - self.campcheck) < 200) // stuckage avoidage
\r
681 self.camptime = time + actualurrebots;
\r
682 self.strat_me = TRUE;
\r
683 UrreBotPath(minisearch_distance);
\r
687 self.campcheck = self.origin;
\r
688 self.camptime = time + 2;
\r
692 if (self.combattime <= time)
\r
694 self.combattime = time + urrebots_combattime;
\r
695 UrreBotEvalTargets();
\r
696 self.impulse = UrreBotImpulses();
\r
701 makevectors (self.v_angle);
\r
702 v = self.origin + '0 0 16';
\r
703 f = vlen(v - self.aimpoint);
\r
704 traceline (v, v + v_forward*f, FALSE, self);
\r
705 if (vlen(trace_endpos - self.aimpoint) < 150)
\r
709 if (random() < 0.3)
\r
716 if (cvar("urrebots_debug"))
\r
718 te_lightning1(self, self.origin, self.movepoint);
\r
719 if (!self.goalcurrent)
\r
721 bprint(self.netname);
\r
722 bprint(" has no goalcurrent\n");
\r