]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/gamec/urrebot_ai_main.c
New location escapes: %d - location of last death, %y: location of crosshair
[divverent/nexuiz.git] / data / qcsrc / server / gamec / urrebot_ai_main.c
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
5 \r
6 float(entity targ) UrreBotInfront =\r
7 {\r
8         local float dot;\r
9         local vector vec;\r
10 \r
11         makevectors (self.angles);\r
12         vec = normalize (targ.origin - self.origin);\r
13         dot = vec * v_forward;\r
14 \r
15         if (dot > 0.3)\r
16                 return TRUE;\r
17         return FALSE;\r
18 };\r
19 \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
23 \r
24 void() UrreBotEvalTargets =\r
25 {\r
26         local float old, new;\r
27         local vector v1, v2;\r
28         local entity e;\r
29 \r
30         v1 = self.origin + self.view_ofs;\r
31 \r
32         /*\r
33         if (self.enemy)\r
34         {\r
35                 if (self.enemy.health >= 1 && !self.enemy.deadflag)\r
36                 {\r
37                         if (self.evaltime <= time)\r
38                         {\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
43                                         self.enemy = world;\r
44                         }\r
45                 }\r
46                 else\r
47                         self.enemy = world;\r
48         }\r
49         */\r
50         e = findradius(v1, 1500);\r
51         while (e)\r
52         {\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
56                 if (e != self)\r
57                 if (!e.deadflag)\r
58                 if (UrreBotInfront(e))\r
59                 if (e.health >= 1)\r
60                 {\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
64                         {\r
65                                 if (self.enemy)\r
66                                 {\r
67                                         old = vlen(self.origin - (self.enemy.absmin + self.enemy.absmax)*0.5);\r
68                                         new = vlen(self.origin - v2);\r
69                                         if (new < old)\r
70                                         {\r
71                                                 self.enemy = e;\r
72                                                 self.enemytimeout = time + 3;\r
73                                         }\r
74                                 }\r
75                                 else\r
76                                 {\r
77                                         self.enemy = e;\r
78                                         self.enemytimeout = time + 3;\r
79                                 }\r
80                         }\r
81                 }\r
82                 e = e.chain;\r
83         }\r
84 \r
85         e = world;\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
90         if (e.health >= 1)\r
91         {\r
92                 self.enemy = e;\r
93                 self.enemytimeout = time + 3;\r
94         }\r
95 };\r
96 \r
97 /* --- UrreBotAim ---\r
98 Very crude and simple aiming, with some leading capability*/\r
99 \r
100 void() UrreBotAim =\r
101 {\r
102         //local float dist;\r
103         local float f;\r
104         local float skeel;\r
105         local vector v, desiredang, testang, diffang, aimpoint;\r
106 \r
107         if (self.deadflag)\r
108                 return;\r
109         skeel = bound(1, skill, 10);\r
110 \r
111         v = (self.enemy.absmin + self.enemy.absmax) * 0.5;\r
112 \r
113         if (self.switchweapon == WEP_ELECTRO || self.switchweapon == WEP_HAGAR || self.switchweapon == WEP_LASER)\r
114         {\r
115                 if(math_mod(self.playerid, 2) == 1)\r
116                         v_z = (self.enemy.absmin_z * 0.8 + v_z * 0.2); // aim more at the floor\r
117         }\r
118 \r
119         if (self.enemy)\r
120         {\r
121                 if (time > self.enemytimeout || self.enemy.takedamage == DAMAGE_NO || self.enemy.deadflag)\r
122                         self.enemy = world;\r
123                 else if (self.aimtime <= time)\r
124                 {\r
125                         self.aimtime = time + 0.1; // LordHavoc: changed from time + 0.3 to time + 0.1\r
126                         self.aimfire = FALSE;\r
127                         if (self.enemy)\r
128                         {\r
129                                 traceline(self.origin + self.view_ofs, v, TRUE, self);\r
130                                 if (trace_fraction == 1)\r
131                                 {\r
132                                         self.enemytimeout = time + 3;\r
133                                         self.aimfire = TRUE;\r
134                                 }\r
135                         }\r
136                 }\r
137         }\r
138 \r
139         // get the desired angles to aim at\r
140         desiredang = self.v_angle_y * '0 1 0';\r
141         aimpoint = v;\r
142         if (self.enemy)\r
143         {\r
144                 //dprint("urrebotaim (skeel == ", ftos(skeel), ") : old aimpoint ", vtos(self.aimpoint));\r
145                 aimpoint = v + self.enemy.velocity*vlen(self.origin - v)*self.lead;\r
146                 //dprint(", v = ", vtos(v));\r
147                 //dprint(", self.enemy.velocity = ", vtos(self.enemy.velocity));\r
148                 //dprint(", vlen(self.origin - v) = ", ftos(vlen(self.origin - v)));\r
149                 //dprint(", self.lead = ", ftos(self.lead));\r
150                 aimpoint = aimpoint + randomvec()*max(0, 120 - skeel*12);\r
151                 //dprint(", final aimpoint = ", vtos(self.aimpoint), "\n");\r
152                 //eprint(self);\r
153                 //eprint(self.enemy);\r
154                 desiredang = vectoangles(aimpoint - (self.origin + self.view_ofs));\r
155         }\r
156         else if (vlen(self.velocity) >= 50)\r
157                 desiredang = vectoyaw(self.velocity) * '0 1 0';\r
158         desiredang_x = 0-desiredang_x;\r
159 \r
160         // calculate turn angles\r
161         testang = desiredang - self.v_angle;\r
162         testang_z = 0;\r
163 \r
164         while (testang_y < -180)\r
165                 testang_y = testang_y + 360;\r
166         while (testang_y >= 180)\r
167                 testang_y = testang_y - 360;\r
168         while (testang_x < -180)\r
169                 testang_x = testang_x + 360;\r
170         while (testang_x >= 180)\r
171                 testang_x = testang_x - 360;\r
172 \r
173         // turn\r
174         // LordHavoc: simplified to one line\r
175         diffang = testang * min(1, ((skeel * 2) * frametime));\r
176 \r
177         self.v_angle = self.v_angle + diffang;\r
178         self.angles_y = self.v_angle_y;\r
179 \r
180         if (self.aimfire)\r
181         if (self.enemy)\r
182         {\r
183                 makevectors (self.v_angle);\r
184                 //v = self.origin + '0 0 16';\r
185                 v = self.origin + self.view_ofs; // neuiz trueaim\r
186                 f = vlen(v - aimpoint);\r
187                 traceline (v, v + v_forward*f, FALSE, self);\r
188                 if (vlen(trace_endpos - aimpoint) < (200 - skeel * 15))\r
189                 {\r
190                         f = 0.1 + skeel*0.1;\r
191                         if (f >= 1)\r
192                                 self.button0 = 1;\r
193                         else if (random() < f)\r
194                                 self.button0 = 1;\r
195                 }\r
196         }\r
197 \r
198         if(self.switchweapon == WEP_ROCKET_LAUNCHER)\r
199         {\r
200                 if(self.lastrocket && self.enemy)\r
201                 {\r
202                         if(vlen(self.lastrocket.origin - self.enemy.origin) < cvar("g_balance_rocketlauncher_radius") * 0.85)\r
203                         {\r
204                                 if(vlen(self.lastrocket.origin - self.origin) > cvar("g_balance_rocketlauncher_radius") * 1.05)\r
205                                 {\r
206                                         f = 0.1 + skeel*0.1;\r
207                                         if (random() < f)\r
208                                                 self.button3 = 1;\r
209                                 }\r
210                         }\r
211                 }\r
212         }\r
213 };\r
214 \r
215 /* --- UrreBotMove ---\r
216 Moves towards the closest point on the next goal in the bots list,\r
217 which can be a navnode, item or domination point*/\r
218 \r
219 void() UrreBotMove =\r
220 {\r
221         local float f, bad;\r
222         local vector dir, tvec;\r
223         local entity plane, optpoint;\r
224 \r
225         if (self.link0)\r
226         {\r
227                 if (boxesoverlap(self.origin + self.mins, self.origin + self.maxs, self.link0.origin + self.link0.mins, self.link0.origin + self.link0.maxs))\r
228                 {\r
229                         optpoint = world;\r
230                         plane = self.link0.plane_chain;\r
231                         while (plane)\r
232                         {\r
233                                 tvec = self.maxs;\r
234                                 if (plane.mangle_x < 0)\r
235                                         tvec_x = self.mins_x;\r
236                                 if (plane.mangle_y < 0)\r
237                                         tvec_y = self.mins_y;\r
238                                 if (plane.mangle_z < 0)\r
239                                         tvec_z = self.mins_z;\r
240                                 tvec += self.origin;\r
241                                 f = tvec*plane.mangle - self.link0.origin*plane.mangle-plane.delay;\r
242                                 if (f > 0)\r
243                                         bad = TRUE;\r
244                                 plane = plane.list;\r
245                         }\r
246                         if (!bad)\r
247                         {\r
248                                 PopRoute();\r
249                                 if (self.goalcurrent.sflags & S_TELEPORT)\r
250                                         self.movepoint = self.goalcurrent.origin;\r
251                                 else\r
252                                 {\r
253                                         if (urrebots_navopt)\r
254                                                 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.link0);\r
255                                         if (optpoint)\r
256                                                 self.movepoint = optpoint.origin;\r
257                                         else\r
258                                                 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.link0);\r
259                                 }\r
260                         }\r
261                 }\r
262                 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
263                 {\r
264                         optpoint = world;\r
265                         plane = self.goalcurrent.plane_chain;\r
266                         while (plane)\r
267                         {\r
268                                 tvec = self.maxs;\r
269                                 if (plane.mangle_x < 0)\r
270                                         tvec_x = self.mins_x;\r
271                                 if (plane.mangle_y < 0)\r
272                                         tvec_y = self.mins_y;\r
273                                 if (plane.mangle_z < 0)\r
274                                         tvec_z = self.mins_z;\r
275                                 tvec += self.origin;\r
276                                 f = tvec*plane.mangle - self.goalcurrent.origin*plane.mangle-plane.delay;\r
277                                 if (f > 0)\r
278                                         bad = TRUE;\r
279                                 plane = plane.list;\r
280                         }\r
281                         if (!bad)\r
282                         {\r
283                                 PopRoute();\r
284                                 if (self.goalcurrent.sflags & S_TELEPORT)\r
285                                         self.movepoint = self.goalcurrent.origin;\r
286                                 else\r
287                                 {\r
288                                         if (urrebots_navopt)\r
289                                                 optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.goalcurrent);\r
290                                         if (optpoint)\r
291                                                 self.movepoint = optpoint.origin;\r
292                                         else\r
293                                                 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);\r
294                                 }\r
295                                 if (self.movepoint == '0 0 0')\r
296                                 {\r
297                                         self.strat_me = TRUE;\r
298                                         UrreBotPath(minisearch_distance);\r
299                                 }\r
300                         }\r
301                 }\r
302         }\r
303         else\r
304         {\r
305                 optpoint = world;\r
306                 if (!self.goalcurrent || ((self.goalcurrent.flags & FL_ITEM) && !self.goalcurrent.solid) || (self.goalcurrent.classname == "dom_controlpoint" && self.goalcurrent.enemy.team == self.team))\r
307                 {\r
308                         self.strat_me = TRUE;\r
309                         UrreBotPath(minisearch_distance);\r
310                 }\r
311                 if (urrebots_navopt)\r
312                         optpoint = MatchOptPoint(self.goalcurrent, self.goallist, self.goalcurrent);\r
313                 if (optpoint)\r
314                         self.movepoint = optpoint.origin;\r
315                 else\r
316                         self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);\r
317         }\r
318 //      dir = normalize(ToPointInSpace(self.goalcurrent, self.movepoint));\r
319         dir = ToPointInSpace(self.goalcurrent, self.movepoint);\r
320         dir = dir * sv_maxspeed;\r
321         makevectors(self.v_angle);\r
322         self.movement_x = dir * v_forward;\r
323         self.movement_y = dir * v_right;\r
324         self.movement_z = dir * v_up;\r
325 };\r
326 \r
327 /* --- UrreBotImpulses ---\r
328 Returns the impulse for the best weapon in the given situation*/\r
329 \r
330 float() UrreBotImpulses =\r
331 {\r
332         local float dist, l, w;\r
333         local float cells, rockets, nails, shells;\r
334         local vector v;\r
335 \r
336         if (random() < 0.5)\r
337                 return 0;\r
338 \r
339         dist = 400; // we like nex and mortar\r
340         if (self.enemy)\r
341         {\r
342                 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;\r
343                 dist = vlen(v - self.origin);\r
344         }\r
345 \r
346         cells = self.ammo_cells;\r
347         rockets = self.ammo_rockets;\r
348         nails = self.ammo_nails;\r
349         shells = self.ammo_shells;\r
350 \r
351         l = 0;\r
352         w = 0;\r
353 \r
354         if (!w)\r
355         if (self.items & IT_NEX)\r
356         if (dist > 300)\r
357         if (cells >= cvar("g_balance_nex_ammo"))\r
358         {\r
359                 l = 1000000;\r
360                 w = WEP_NEX;\r
361         }\r
362         if (!w)\r
363         if (self.items & IT_GRENADE_LAUNCHER)\r
364         if (dist >= 200)\r
365         if (dist < 2000)\r
366         if (rockets >= cvar("g_balance_grenadelauncher_primary_ammo"))\r
367         {\r
368                 l = cvar("g_balance_grenadelauncher_primary_speed");\r
369                 w = WEP_GRENADE_LAUNCHER;\r
370         }\r
371         if (!w)\r
372         if (self.items & IT_HAGAR)\r
373         if (dist >= 100)\r
374         if (dist < 2000)\r
375         if (rockets >= cvar("g_balance_hagar_primary_ammo"))\r
376         {\r
377                 l = cvar("g_balance_hagar_primary_speed");\r
378                 w = WEP_HAGAR;\r
379         }\r
380         if (!w)\r
381         if (self.items & IT_ROCKET_LAUNCHER)\r
382         if (dist >= 200)\r
383         if (dist < 800)\r
384         if (rockets >= cvar("g_balance_rocketlauncher_ammo"))\r
385         {\r
386                 l = cvar("g_balance_rocketlauncher_speed");\r
387                 w = WEP_ROCKET_LAUNCHER;\r
388         }\r
389         if (!w)\r
390         if (self.items & IT_ELECTRO)\r
391         if (dist >= 100)\r
392         if (dist < 2000)\r
393         if (cells >= cvar("g_balance_electro_primary_ammo"))\r
394         {\r
395                 l = cvar("g_balance_electro_primary_speed");\r
396                 w = WEP_ELECTRO;\r
397         }\r
398         if (!w)\r
399         if (self.items & IT_CRYLINK)\r
400         if (dist < 800)\r
401         if (cells >= cvar("g_balance_crylink_primary_ammo"))\r
402         {\r
403                 l = cvar("g_balance_crylink_primary_speed");\r
404                 w = WEP_CRYLINK;\r
405         }\r
406         if (!w)\r
407         if (self.items & IT_UZI)\r
408         if (dist < 1000)\r
409         if (nails >= cvar("g_balance_uzi_first_ammo"))\r
410         {\r
411                 l = 1000000;\r
412                 w = WEP_UZI;\r
413         }\r
414         if (!w)\r
415         if (self.items & IT_SHOTGUN)\r
416         if (dist < 1000)\r
417         if (nails >= cvar("g_balance_shotgun_primary_ammo"))\r
418         {\r
419                 l = 1000000;\r
420                 w = WEP_SHOTGUN;\r
421         }\r
422         if (!w)\r
423         {\r
424                 l = cvar("g_balance_laser_speed");\r
425                 w = WEP_LASER;\r
426         }\r
427         if (l < 1)\r
428                 error("UrreBotImpulses: missing cvar for weapon\n");\r
429         self.lead = 1 / l;\r
430         return w;\r
431 };\r
432 \r
433 /* --- BeamBox ---\r
434 Used for some debugging, occasionally*/\r
435 \r
436 float BT_LIGHTNING = 0;\r
437 float BT_BEAM = 1;\r
438 void(float beamtype, vector bmins, vector bmaxs) BeamBox =\r
439 {\r
440         local vector v1, v2;\r
441 \r
442         v1 = bmaxs;\r
443         v2 = bmaxs;\r
444         v2_x = bmins_x;\r
445         if (beamtype == BT_LIGHTNING)\r
446                 te_lightning1(world, v1, v2);\r
447         else\r
448                 te_beam(world, v1, v2);\r
449         v1 = bmaxs;\r
450         v2 = bmaxs;\r
451         v2_y = bmins_y;\r
452         if (beamtype == BT_LIGHTNING)\r
453                 te_lightning1(world, v1, v2);\r
454         else\r
455                 te_beam(world, v1, v2);\r
456         v1 = bmaxs;\r
457         v2 = bmaxs;\r
458         v2_z = bmins_z;\r
459         if (beamtype == BT_LIGHTNING)\r
460                 te_lightning1(world, v1, v2);\r
461         else\r
462                 te_beam(world, v1, v2);\r
463         v1 = bmins;\r
464         v2 = bmins;\r
465         v2_x = bmaxs_x;\r
466         if (beamtype == BT_LIGHTNING)\r
467                 te_lightning1(world, v1, v2);\r
468         else\r
469                 te_beam(world, v1, v2);\r
470         v1 = bmins;\r
471         v2 = bmins;\r
472         v2_y = bmaxs_y;\r
473         if (beamtype == BT_LIGHTNING)\r
474                 te_lightning1(world, v1, v2);\r
475         else\r
476                 te_beam(world, v1, v2);\r
477         v1 = bmins;\r
478         v2 = bmins;\r
479         v2_z = bmaxs_z;\r
480         if (beamtype == BT_LIGHTNING)\r
481                 te_lightning1(world, v1, v2);\r
482         else\r
483                 te_beam(world, v1, v2);\r
484         v1 = bmins;\r
485         v1_z = bmaxs_z;\r
486         v2 = bmins;\r
487         v2_x = bmaxs_x;\r
488         v2_z = bmaxs_z;\r
489         if (beamtype == BT_LIGHTNING)\r
490                 te_lightning1(world, v1, v2);\r
491         else\r
492                 te_beam(world, v1, v2);\r
493         v1 = bmins;\r
494         v1_z = bmaxs_z;\r
495         v2 = bmins;\r
496         v2_y = bmaxs_y;\r
497         v2_z = bmaxs_z;\r
498         if (beamtype == BT_LIGHTNING)\r
499                 te_lightning1(world, v1, v2);\r
500         else\r
501                 te_beam(world, v1, v2);\r
502         v1 = bmaxs;\r
503         v1_z = bmins_z;\r
504         v2 = bmaxs;\r
505         v2_x = bmins_x;\r
506         v2_z = bmins_z;\r
507         if (beamtype == BT_LIGHTNING)\r
508                 te_lightning1(world, v1, v2);\r
509         else\r
510                 te_beam(world, v1, v2);\r
511         v1 = bmaxs;\r
512         v1_z = bmins_z;\r
513         v2 = bmaxs;\r
514         v2_y = bmins_y;\r
515         v2_z = bmins_z;\r
516         if (beamtype == BT_LIGHTNING)\r
517                 te_lightning1(world, v1, v2);\r
518         else\r
519                 te_beam(world, v1, v2);\r
520         v1 = bmins;\r
521         v1_x = bmaxs_x;\r
522         v2 = bmaxs;\r
523         v2_y = bmins_y;\r
524         if (beamtype == BT_LIGHTNING)\r
525                 te_lightning1(world, v1, v2);\r
526         else\r
527                 te_beam(world, v1, v2);\r
528         v1 = bmins;\r
529         v1_y = bmaxs_y;\r
530         v2 = bmaxs;\r
531         v2_x = bmins_x;\r
532         if (beamtype == BT_LIGHTNING)\r
533                 te_lightning1(world, v1, v2);\r
534         else\r
535                 te_beam(world, v1, v2);\r
536 };\r
537 \r
538 /* --- UrreBotPath ---\r
539 Marks route and determines which goal is the most useful to head for*/\r
540 \r
541 void(float sdist) UrreBotPath =\r
542 {\r
543         local float f, f2, f3;\r
544         local entity e, best;\r
545 \r
546         ClearRoute();\r
547         MarkRoute(sdist);\r
548         DistEvalItems();\r
549         f2 = 10000000;\r
550         e = findchainflags(flags, FL_ITEM);\r
551         while (e)\r
552         {\r
553                 f = 0;\r
554                 if (e.evalfunc)\r
555                         f = e.evalfunc(e);\r
556                 if (f > 0)\r
557                 if (e.goallist)\r
558                 {\r
559                         f = f + e.costl;\r
560                         if (f < f2)\r
561                         if (e.solid)\r
562                         {\r
563                                 best = e;\r
564                                 f2 = e.costl;\r
565                         }\r
566                 }\r
567                 e = e.chain;\r
568         }\r
569         if (best)\r
570         {\r
571                 while (best)\r
572                 {\r
573                         PushRoute(best);\r
574                         best = best.goallist;\r
575                 }\r
576         }\r
577         else\r
578         {\r
579                 f3 = 0;\r
580                 while (f3 < 3)\r
581                 {\r
582                         f = 0;\r
583                         f2 = 0;\r
584                         f = ceil(random() * navnodes);\r
585                         e = navnode_chain;\r
586                         while (e)\r
587                         {\r
588                                 if (f == f2)\r
589                                 if (e.goallist)\r
590                                 {\r
591                                         best = e;\r
592                                         f3 = 3;\r
593                                 }\r
594                                 f2 = f2 + 1;\r
595                                 e = e.list;\r
596                         }\r
597                         f3 = f3 + 1;\r
598                 }\r
599                 while (best)\r
600                 {\r
601                         PushRoute(best);\r
602                         best = best.goallist;\r
603                 }\r
604         }\r
605 };\r
606 \r
607 /* --- UrreBotThink ---\r
608 In this version, UrreBot does a path search based on timer and turn\r
609 Then it aims, moves, checks if it's stuck, finds/loses stuff to shoot at,\r
610 picks best weapon, shoots, and optionally displays debug stuff, in that\r
611 order\r
612 Aiming must happen before movement, because movement depends on angles\r
613 He does not yet have any combat movement*/\r
614 \r
615 void() UrreBotThink =\r
616 {\r
617         self.movement = '0 0 0';\r
618         self.button0 = 0;\r
619         self.button2 = 0;\r
620         self.button3 = 0;\r
621         self.impulse = 0;\r
622 \r
623         if (cvar("teamplay") && self.team == self.enemy.team) // don't return fire if hit by a teammate\r
624                 self.enemy = world;\r
625 \r
626         if (self.deadflag)\r
627         {\r
628                 ClearRoute();\r
629                 if (random() < 0.2)\r
630                         self.button0 = 1;\r
631                 return;\r
632         }\r
633 \r
634         if (strategytime <= time)\r
635         if (strategytoken == self)\r
636         {\r
637                 strategytime = time + urrebots_strategytime;\r
638                 strategytoken = self.list;\r
639                 if (!strategytoken)\r
640                         strategytoken = urrebot_chain;\r
641                 if (self.strat_me)\r
642                 {\r
643                         self.strat_me = FALSE;\r
644                         UrreBotPath(stratsearch_distance);\r
645                 }\r
646         }\r
647 \r
648         UrreBotAim();\r
649         UrreBotMove();\r
650 \r
651         if (self.camptime <= time)\r
652         {\r
653                 if (vlen(self.origin - self.campcheck) < 200) // stuckage avoidage\r
654                 {\r
655                         self.camptime = time + urrebots;\r
656                         self.strat_me = TRUE;\r
657                         UrreBotPath(minisearch_distance);\r
658                 }\r
659                 else\r
660                 {\r
661                         self.campcheck = self.origin;\r
662                         self.camptime = time + 2;\r
663                 }\r
664         }\r
665 \r
666         if (self.combattime <= time)\r
667         {\r
668                 self.combattime = time + urrebots_combattime;\r
669                 UrreBotEvalTargets();\r
670                 self.impulse = UrreBotImpulses();\r
671         }\r
672 \r
673         if (cvar("urrebots_debug"))\r
674         {\r
675                 te_lightning1(self, self.origin, self.movepoint);\r
676                 if (!self.goalcurrent)\r
677                 {\r
678                         bprint(self.netname);\r
679                         bprint(" has no goalcurrent\n");\r
680                 }\r
681         }\r
682 };\r