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
35 if (self.enemy.health >= 1 && !self.enemy.deadflag)
\r
37 if (self.evaltime <= time)
\r
39 self.evaltime = time + 3;
\r
40 v2 = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
41 traceline(v1, v2, TRUE, self);
\r
42 if (trace_fraction < 1)
\r
50 e = findradius(v1, 1500);
\r
53 if (!(e.flags & FL_NOTARGET))
\r
54 if (!(cvar("teamplay") && self.team == e.team)) // don't target teammates
\r
55 if (e.flags & FL_CLIENT)
\r
58 if (UrreBotInfront(e))
\r
61 v2 = (e.absmin + e.absmax) * 0.5;
\r
62 traceline(v1, v2, TRUE, self);
\r
63 if (trace_fraction == 1 || trace_ent == e)
\r
67 old = vlen(self.origin - (self.enemy.absmin + self.enemy.absmax)*0.5);
\r
68 new = vlen(self.origin - v2);
\r
72 self.enemytimeout = time + 3;
\r
78 self.enemytimeout = time + 3;
\r
86 if (self.goalcurrent.sflags & S_DOOR)
\r
87 e = self.goalcurrent.goalentity;
\r
88 else if (self.link0.sflags & S_DOOR)
\r
89 e = self.link0.goalentity;
\r
93 self.enemytimeout = time + 3;
\r
97 /* --- UrreBotAim ---
\r
98 Very crude and simple aiming, with some leading capability*/
\r
100 void() UrreBotAim =
\r
102 //local float dist;
\r
105 local vector v, desiredang, testang, diffang, aimpoint;
\r
109 skeel = bound(1, skill, 10);
\r
111 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
115 if (time > self.enemytimeout || self.enemy.takedamage == DAMAGE_NO || self.enemy.deadflag)
\r
116 self.enemy = world;
\r
117 else if (self.aimtime <= time)
\r
119 self.aimtime = time + 0.1; // LordHavoc: changed from time + 0.3 to time + 0.1
\r
120 self.aimfire = FALSE;
\r
123 traceline(self.origin + self.view_ofs, v, TRUE, self);
\r
124 if (trace_fraction == 1)
\r
126 self.enemytimeout = time + 3;
\r
127 self.aimfire = TRUE;
\r
133 // get the desired angles to aim at
\r
134 desiredang = self.v_angle_y * '0 1 0';
\r
138 //dprint("urrebotaim (skeel == ", ftos(skeel), ") : old aimpoint ", vtos(self.aimpoint));
\r
139 aimpoint = v + self.enemy.velocity*vlen(self.origin - v)*self.lead;
\r
140 //dprint(", v = ", vtos(v));
\r
141 //dprint(", self.enemy.velocity = ", vtos(self.enemy.velocity));
\r
142 //dprint(", vlen(self.origin - v) = ", ftos(vlen(self.origin - v)));
\r
143 //dprint(", self.lead = ", ftos(self.lead));
\r
144 aimpoint = aimpoint + randomvec()*max(0, 120 - skeel*12);
\r
145 //dprint(", final aimpoint = ", vtos(self.aimpoint), "\n");
\r
147 //eprint(self.enemy);
\r
148 desiredang = vectoangles(aimpoint - (self.origin + self.view_ofs));
\r
150 else if (vlen(self.velocity) >= 50)
\r
151 desiredang = vectoyaw(self.velocity) * '0 1 0';
\r
152 desiredang_x = 0-desiredang_x;
\r
154 // calculate turn angles
\r
155 testang = desiredang - self.v_angle;
\r
158 while (testang_y < -180)
\r
159 testang_y = testang_y + 360;
\r
160 while (testang_y >= 180)
\r
161 testang_y = testang_y - 360;
\r
162 while (testang_x < -180)
\r
163 testang_x = testang_x + 360;
\r
164 while (testang_x >= 180)
\r
165 testang_x = testang_x - 360;
\r
168 // LordHavoc: simplified to one line
\r
169 diffang = testang * min(1, ((skeel * 2) * frametime));
\r
171 self.v_angle = self.v_angle + diffang;
\r
172 self.angles_y = self.v_angle_y;
\r
177 makevectors (self.v_angle);
\r
178 //v = self.origin + '0 0 16';
\r
179 v = self.origin + self.view_ofs; // neuiz trueaim
\r
180 f = vlen(v - aimpoint);
\r
181 traceline (v, v + v_forward*f, FALSE, self);
\r
182 if (vlen(trace_endpos - aimpoint) < (200 - skeel * 15))
\r
184 f = 0.1 + skeel*0.1;
\r
187 else if (random() < f)
\r
193 /* --- UrreBotMove ---
\r
194 Moves towards the closest point on the next goal in the bots list,
\r
195 which can be a navnode, item or domination point*/
\r
197 void() UrreBotMove =
\r
199 local float f, bad;
\r
200 local vector dir, tvec;
\r
201 local entity plane, optpoint;
\r
205 if (boxesoverlap(self.origin + self.mins, self.origin + self.maxs, self.link0.origin + self.link0.mins, self.link0.origin + self.link0.maxs))
\r
208 plane = self.link0.plane_chain;
\r
212 if (plane.mangle_x < 0)
\r
213 tvec_x = self.mins_x;
\r
214 if (plane.mangle_y < 0)
\r
215 tvec_y = self.mins_y;
\r
216 if (plane.mangle_z < 0)
\r
217 tvec_z = self.mins_z;
\r
218 tvec += self.origin;
\r
219 f = tvec*plane.mangle - self.link0.origin*plane.mangle-plane.delay;
\r
222 plane = plane.list;
\r
227 if (self.goalcurrent.sflags & S_TELEPORT)
\r
228 self.movepoint = self.goalcurrent.origin;
\r
231 if (urrebots_navopt)
\r
232 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.link0);
\r
234 self.movepoint = optpoint.origin;
\r
236 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.link0);
\r
240 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
243 plane = self.goalcurrent.plane_chain;
\r
247 if (plane.mangle_x < 0)
\r
248 tvec_x = self.mins_x;
\r
249 if (plane.mangle_y < 0)
\r
250 tvec_y = self.mins_y;
\r
251 if (plane.mangle_z < 0)
\r
252 tvec_z = self.mins_z;
\r
253 tvec += self.origin;
\r
254 f = tvec*plane.mangle - self.goalcurrent.origin*plane.mangle-plane.delay;
\r
257 plane = plane.list;
\r
262 if (self.goalcurrent.sflags & S_TELEPORT)
\r
263 self.movepoint = self.goalcurrent.origin;
\r
266 if (urrebots_navopt)
\r
267 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.goalcurrent);
\r
269 self.movepoint = optpoint.origin;
\r
271 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
273 if (self.movepoint == '0 0 0')
\r
275 self.strat_me = TRUE;
\r
276 UrreBotPath(minisearch_distance);
\r
284 if (!self.goalcurrent || ((self.goalcurrent.flags & FL_ITEM) && !self.goalcurrent.solid) || (self.goalcurrent.classname == "dom_controlpoint" && self.goalcurrent.enemy.team == self.team))
\r
286 self.strat_me = TRUE;
\r
287 UrreBotPath(minisearch_distance);
\r
289 if (urrebots_navopt)
\r
290 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.goalcurrent);
\r
292 self.movepoint = optpoint.origin;
\r
294 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);
\r
296 // dir = normalize(ToPointInSpace(self.goalcurrent, self.movepoint));
\r
297 dir = ToPointInSpace(self.goalcurrent, self.movepoint);
\r
298 dir = dir * sv_maxspeed;
\r
299 makevectors(self.v_angle);
\r
300 self.movement_x = dir * v_forward;
\r
301 self.movement_y = dir * v_right;
\r
302 self.movement_z = dir * v_up;
\r
305 /* --- UrreBotImpulses ---
\r
306 Returns the impulse for the best weapon in the given situation*/
\r
308 float() UrreBotImpulses =
\r
310 local float dist, l, w;
\r
311 local float cells, rockets, nails, shells;
\r
314 if (random() < 0.5)
\r
317 dist = 400; // we like nex and mortar
\r
320 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;
\r
321 dist = vlen(v - self.origin);
\r
324 cells = self.ammo_cells;
\r
325 rockets = self.ammo_rockets;
\r
326 nails = self.ammo_nails;
\r
327 shells = self.ammo_shells;
\r
333 if (self.items & IT_NEX)
\r
335 if (cells >= cvar("g_balance_nex_ammo"))
\r
341 if (self.items & IT_GRENADE_LAUNCHER)
\r
344 if (rockets >= cvar("g_balance_grenadelauncher_primary_ammo"))
\r
346 l = cvar("g_balance_grenadelauncher_primary_speed");
\r
347 w = WEP_GRENADE_LAUNCHER;
\r
350 if (self.items & IT_HAGAR)
\r
353 if (rockets >= cvar("g_balance_hagar_primary_ammo"))
\r
355 l = cvar("g_balance_hagar_primary_speed");
\r
359 if (self.items & IT_ROCKET_LAUNCHER)
\r
362 if (rockets >= cvar("g_balance_rocketlauncher_ammo"))
\r
364 l = cvar("g_balance_rocketlauncher_speed");
\r
365 w = WEP_ROCKET_LAUNCHER;
\r
368 if (self.items & IT_ELECTRO)
\r
371 if (cells >= cvar("g_balance_electro_primary_ammo"))
\r
373 l = cvar("g_balance_electro_primary_speed");
\r
377 if (self.items & IT_CRYLINK)
\r
379 if (cells >= cvar("g_balance_crylink_primary_ammo"))
\r
381 l = cvar("g_balance_crylink_primary_speed");
\r
385 if (self.items & IT_UZI)
\r
387 if (nails >= cvar("g_balance_uzi_first_ammo"))
\r
393 if (self.items & IT_SHOTGUN)
\r
395 if (nails >= cvar("g_balance_shotgun_primary_ammo"))
\r
402 l = cvar("g_balance_laser_speed");
\r
406 error("UrreBotImpulses: missing cvar for weapon\n");
\r
412 Used for some debugging, occasionally*/
\r
414 float BT_LIGHTNING = 0;
\r
416 void(float beamtype, vector bmins, vector bmaxs) BeamBox =
\r
418 local vector v1, v2;
\r
423 if (beamtype == BT_LIGHTNING)
\r
424 te_lightning1(world, v1, v2);
\r
426 te_beam(world, v1, v2);
\r
430 if (beamtype == BT_LIGHTNING)
\r
431 te_lightning1(world, v1, v2);
\r
433 te_beam(world, v1, v2);
\r
437 if (beamtype == BT_LIGHTNING)
\r
438 te_lightning1(world, v1, v2);
\r
440 te_beam(world, v1, v2);
\r
444 if (beamtype == BT_LIGHTNING)
\r
445 te_lightning1(world, v1, v2);
\r
447 te_beam(world, v1, v2);
\r
451 if (beamtype == BT_LIGHTNING)
\r
452 te_lightning1(world, v1, v2);
\r
454 te_beam(world, v1, v2);
\r
458 if (beamtype == BT_LIGHTNING)
\r
459 te_lightning1(world, v1, v2);
\r
461 te_beam(world, v1, v2);
\r
467 if (beamtype == BT_LIGHTNING)
\r
468 te_lightning1(world, v1, v2);
\r
470 te_beam(world, v1, v2);
\r
476 if (beamtype == BT_LIGHTNING)
\r
477 te_lightning1(world, v1, v2);
\r
479 te_beam(world, v1, v2);
\r
485 if (beamtype == BT_LIGHTNING)
\r
486 te_lightning1(world, v1, v2);
\r
488 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
502 if (beamtype == BT_LIGHTNING)
\r
503 te_lightning1(world, v1, v2);
\r
505 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
516 /* --- UrreBotPath ---
\r
517 Marks route and determines which goal is the most useful to head for*/
\r
519 void(float sdist) UrreBotPath =
\r
521 local float f, f2, f3;
\r
522 local entity e, best;
\r
528 e = findchainflags(flags, FL_ITEM);
\r
552 best = best.goallist;
\r
562 f = ceil(random() * navnodes);
\r
580 best = best.goallist;
\r
585 /* --- UrreBotThink ---
\r
586 In this version, UrreBot does a path search based on timer and turn
\r
587 Then it aims, moves, checks if it's stuck, finds/loses stuff to shoot at,
\r
588 picks best weapon, shoots, and optionally displays debug stuff, in that
\r
590 Aiming must happen before movement, because movement depends on angles
\r
591 He does not yet have any combat movement*/
\r
593 void() UrreBotThink =
\r
595 self.movement = '0 0 0';
\r
600 if (cvar("teamplay") && self.team == self.enemy.team) // don't return fire if hit by a teammate
\r
601 self.enemy = world;
\r
606 if (random() < 0.2)
\r
611 if (strategytime <= time)
\r
612 if (strategytoken == self)
\r
614 strategytime = time + urrebots_strategytime;
\r
615 strategytoken = self.list;
\r
616 if (!strategytoken)
\r
617 strategytoken = urrebot_chain;
\r
620 self.strat_me = FALSE;
\r
621 UrreBotPath(stratsearch_distance);
\r
628 if (self.camptime <= time)
\r
630 if (vlen(self.origin - self.campcheck) < 200) // stuckage avoidage
\r
632 self.camptime = time + urrebots;
\r
633 self.strat_me = TRUE;
\r
634 UrreBotPath(minisearch_distance);
\r
638 self.campcheck = self.origin;
\r
639 self.camptime = time + 2;
\r
643 if (self.combattime <= time)
\r
645 self.combattime = time + urrebots_combattime;
\r
646 UrreBotEvalTargets();
\r
647 self.impulse = UrreBotImpulses();
\r
650 if (cvar("urrebots_debug"))
\r
652 te_lightning1(self, self.origin, self.movepoint);
\r
653 if (!self.goalcurrent)
\r
655 bprint(self.netname);
\r
656 bprint(" has no goalcurrent\n");
\r