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*/
\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 waybox in the bots list, or
\r
292 towards the item he's hunting in case they are in the same waybox*/
\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))
\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 cvar("g_balance_electro_radius");
\r
389 cvar("g_balance_grenadelauncher_radius");
\r
390 cvar("g_balance_hagar_radius");
\r
391 cvar("g_balance_rocketlauncher_radius");
\r
393 if (random() < 0.5)
\r
396 dist = 400; // we like nex and mortar
\r
399 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
400 dist = vlen(v - self.origin);
\r
403 cells = self.ammo_cells;
\r
404 rockets = self.ammo_rockets;
\r
405 nails = self.ammo_nails;
\r
406 shells = self.ammo_shells;
\r
408 if (dist > 300 && cells && (self.items & IT_NEX))
\r
416 if (self.items & IT_GRENADE_LAUNCHER)
\r
418 self.lead = 1 / cvar("g_balance_grenadelauncher_speed");
\r
419 return WEP_GRENADE_LAUNCHER;
\r
421 if (self.items & IT_HAGAR)
\r
423 self.lead = 1 / cvar("g_balance_hagar_speed");
\r
426 else if (self.items & IT_ROCKET_LAUNCHER)
\r
428 self.lead = 1 / cvar("g_balance_rocketlauncher_speed");
\r
429 return WEP_ROCKET_LAUNCHER;
\r
434 if (self.items & IT_ELECTRO)
\r
436 self.lead = 1 / cvar("g_balance_electro_speed");
\r
437 return WEP_ELECTRO;
\r
439 else if (self.items & IT_CRYLINK)
\r
441 self.lead = 1 / cvar("g_balance_crylink_speed");
\r
442 return WEP_CRYLINK;
\r
447 if (self.items & IT_UZI)
\r
455 if (self.items & IT_SHOTGUN)
\r
458 return WEP_SHOTGUN;
\r
461 self.lead = 1 / cvar("g_balance_laser_speed");
\r
465 float BT_LIGHTNING = 0;
\r
468 void(float beamtype, vector bmins, vector bmaxs) BeamBox =
\r
470 local vector v1, v2;
\r
475 if (beamtype == BT_LIGHTNING)
\r
476 te_lightning1(world, v1, v2);
\r
478 te_beam(world, v1, v2);
\r
482 if (beamtype == BT_LIGHTNING)
\r
483 te_lightning1(world, v1, v2);
\r
485 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
496 if (beamtype == BT_LIGHTNING)
\r
497 te_lightning1(world, v1, v2);
\r
499 te_beam(world, v1, v2);
\r
503 if (beamtype == BT_LIGHTNING)
\r
504 te_lightning1(world, v1, v2);
\r
506 te_beam(world, v1, v2);
\r
510 if (beamtype == BT_LIGHTNING)
\r
511 te_lightning1(world, v1, v2);
\r
513 te_beam(world, v1, v2);
\r
519 if (beamtype == BT_LIGHTNING)
\r
520 te_lightning1(world, v1, v2);
\r
522 te_beam(world, v1, v2);
\r
528 if (beamtype == BT_LIGHTNING)
\r
529 te_lightning1(world, v1, v2);
\r
531 te_beam(world, v1, v2);
\r
537 if (beamtype == BT_LIGHTNING)
\r
538 te_lightning1(world, v1, v2);
\r
540 te_beam(world, v1, v2);
\r
546 if (beamtype == BT_LIGHTNING)
\r
547 te_lightning1(world, v1, v2);
\r
549 te_beam(world, v1, v2);
\r
554 if (beamtype == BT_LIGHTNING)
\r
555 te_lightning1(world, v1, v2);
\r
557 te_beam(world, v1, v2);
\r
562 if (beamtype == BT_LIGHTNING)
\r
563 te_lightning1(world, v1, v2);
\r
565 te_beam(world, v1, v2);
\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
611 f = ceil(random() * navnodes);
\r
634 /* --- UrreBotThink ---
\r
635 In this version, UrreBot does a waybox search based on time and turn
\r
636 Then it aims, moves, finds/loses stuff to shoot at, picks best weapon,
\r
637 shoots, in that order
\r
638 Aiming must happen before movement, because movement depends on angles
\r
639 He does not yet have any combat movement*/
\r
641 void() UrreBotThink =
\r
646 self.movement = '0 0 0';
\r
654 if (random() < 0.2)
\r
659 if (strategytime <= time)
\r
660 if (strategytoken == self)
\r
662 strategytime = time + urrebots_strategytime;
\r
663 strategytoken = self.list;
\r
664 if (!strategytoken)
\r
665 strategytoken = bot_chain;
\r
668 self.strat_me = FALSE;
\r
669 UrreBotPath(stratsearch_distance);
\r
676 if (self.camptime <= time)
\r
678 if (vlen(self.origin - self.campcheck) < 200) // stuckage avoidage
\r
680 self.camptime = time + actualurrebots;
\r
681 self.strat_me = TRUE;
\r
682 UrreBotPath(minisearch_distance);
\r
686 self.campcheck = self.origin;
\r
687 self.camptime = time + 2;
\r
691 if (self.combattime <= time)
\r
693 self.combattime = time + urrebots_combattime;
\r
694 UrreBotEvalTargets();
\r
695 self.impulse = UrreBotImpulses();
\r
700 makevectors (self.v_angle);
\r
701 v = self.origin + '0 0 16';
\r
702 f = vlen(v - self.aimpoint);
\r
703 traceline (v, v + v_forward*f, FALSE, self);
\r
704 if (vlen(trace_endpos - self.aimpoint) < 150)
\r
708 if (random() < 0.3)
\r
715 if (cvar("urrebots_debug"))
\r
717 te_lightning1(self, self.origin, self.movepoint);
\r
718 if (!self.goalcurrent)
\r
720 bprint(self.netname);
\r
721 bprint(" has no goalcurrent\n");
\r