]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/gamec/urrebot_ai_main.qc
Renamed remotely
[divverent/nexuiz.git] / data / qcsrc / gamec / urrebot_ai_main.qc
1 /* --- UrreBotSetup ---\r
2 Issues a random funky name, random colors, playermodel and team to the bot*/\r
3 \r
4 void() UrreBotSetup =\r
5 {\r
6         local float r, shirt, pants;\r
7         local string s;\r
8 \r
9         r = random()*18;\r
10         if (r <= 1)\r
11                 s = "GrooveMachine";\r
12         else if (r <= 2)\r
13                 s = "Worm";\r
14         else if (r <= 3)\r
15                 s = "ClownLock";\r
16         else if (r <= 4)\r
17                 s = "DiscO";\r
18         else if (r <= 5)\r
19                 s = "FunkyFresh";\r
20         else if (r <= 6)\r
21                 s = "DanceWithMe";\r
22         else if (r <= 7)\r
23                 s = "BodyJiggle";\r
24         else if (r <= 8)\r
25                 s = "CantSwim";\r
26         else if (r <= 9)\r
27                 s = "AtomicDog";\r
28         else if (r <= 10)\r
29                 s = "Follower";\r
30         else if (r <= 11)\r
31                 s = "BrassMonkey";\r
32         else if (r <= 12)\r
33                 s = "SirNose";\r
34         else if (r <= 13)\r
35                 s = "StarChild";\r
36         else if (r <= 14)\r
37                 s = "GeorgeC";\r
38         else if (r <= 15)\r
39                 s = "Bootsy";\r
40         else if (r <= 16)\r
41                 s = "Flashlight";\r
42         else if (r <= 17)\r
43                 s = "Bodysnatcher";\r
44         else\r
45                 s = "Boogieboy";\r
46 \r
47         self.netname = s;\r
48 \r
49         r = random()*15;\r
50         if (r <= 1)\r
51         {\r
52                 self.playermodel = "models/player/carni.zym";\r
53                 if (random() < 0.5)\r
54                         self.playerskin = "0";\r
55                 else\r
56                         self.playerskin = "1";\r
57         }\r
58         else if (r <= 2)\r
59         {\r
60                 self.playermodel = "models/player/crash.zym";\r
61                 self.playerskin = "0";\r
62         }\r
63         else if (r <= 3)\r
64         {\r
65                 self.playermodel = "models/player/grunt.zym";\r
66                 self.playerskin = "0";\r
67         }\r
68         else if (r <= 4)\r
69         {\r
70                 self.playermodel = "models/player/headhunter.zym";\r
71                 self.playerskin = "0";\r
72         }\r
73         else if (r <= 5)\r
74         {\r
75                 self.playermodel = "models/player/insurrectionist.zym";\r
76                 self.playerskin = "0";\r
77         }\r
78         else if (r <= 6)\r
79         {\r
80                 self.playermodel = "models/player/jeandarc.zym";\r
81                 self.playerskin = "0";\r
82         }\r
83         else if (r <= 7)\r
84         {\r
85                 self.playermodel = "models/player/lurk.zym";\r
86                 if (random() < 0.5)\r
87                         self.playerskin = "0";\r
88                 else\r
89                         self.playerskin = "1";\r
90         }\r
91         else if (r <= 8)\r
92         {\r
93                 self.playermodel = "models/player/lycanthrope.zym";\r
94                 self.playerskin = "0";\r
95         }\r
96         else if (r <= 9)\r
97         {\r
98                 self.playermodel = "models/player/marine.zym";\r
99                 self.playerskin = "0";\r
100         }\r
101         else if (r <= 10)\r
102         {\r
103                 self.playermodel = "models/player/nexus.zym";\r
104                 if (random() < 0.5)\r
105                         self.playerskin = "0";\r
106                 else\r
107                         self.playerskin = "1";\r
108         }\r
109         else if (r <= 11)\r
110         {\r
111                 self.playermodel = "models/player/pyria.zym";\r
112                 self.playerskin = "0";\r
113         }\r
114         else if (r <= 12)\r
115         {\r
116                 self.playermodel = "models/player/shock.zym";\r
117                 self.playerskin = "0";\r
118         }\r
119         else if (r <= 13)\r
120         {\r
121                 self.playermodel = "models/player/skadi.zym";\r
122                 self.playerskin = "0";\r
123         }\r
124         else if (r <= 14)\r
125         {\r
126                 self.playermodel = "models/player/specop.zym";\r
127                 self.playerskin = "0";\r
128         }\r
129         else\r
130         {\r
131                 self.playermodel = "models/player/visitant.zym";\r
132                 self.playerskin = "0";\r
133         }\r
134 \r
135         if (teamplay)\r
136                 JoinBestTeam(self, 0);\r
137         else\r
138         {\r
139                 shirt = floor(random()*15);\r
140                 pants = floor(random()*15);\r
141                 self.clientcolors = pants + shirt * 16;\r
142         }\r
143 };\r
144 \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
149 \r
150 float(entity targ) UrreBotInfront =\r
151 {\r
152         local float dot;\r
153         local vector vec;\r
154 \r
155         makevectors (self.angles);\r
156         vec = normalize (targ.origin - self.origin);\r
157         dot = vec * v_forward;\r
158 \r
159         if (dot > 0.3)\r
160                 return TRUE;\r
161         return FALSE;\r
162 };\r
163 \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
167 \r
168 void() UrreBotEvalTargets =\r
169 {\r
170         local float old, new;\r
171         local vector v1, v2;\r
172         local entity e;\r
173 \r
174         v1 = self.origin + self.view_ofs;\r
175 \r
176         if (self.enemy)\r
177         {\r
178                 if (self.enemy.health >= 1 && !self.enemy.deadflag)\r
179                 {\r
180                         if (self.evaltime <= time)\r
181                         {\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
187                         }\r
188                 }\r
189                 else\r
190                         self.enemy = world;\r
191         }\r
192         e = findradius(v1, 1500);\r
193         while (e)\r
194         {\r
195                 if (!(e.flags & FL_NOTARGET) || e.killcount != -666) // -666 is spec/obs\r
196                 if (e.flags & FL_CLIENT)\r
197                 if (e != self)\r
198                 if (!e.deadflag)\r
199                 if (UrreBotInfront(e))\r
200                 if (e.health >= 1)\r
201                 {\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
205                         {\r
206                                 if (self.enemy)\r
207                                 {\r
208                                         old = vlen(self.origin - (self.enemy.absmin + self.enemy.absmax)*0.5);\r
209                                         new = vlen(self.origin - v2);\r
210                                         if (new < old)\r
211                                                 self.enemy = e;\r
212                                 }\r
213                                 else\r
214                                         self.enemy = e;\r
215                         }\r
216                 }\r
217                 e = e.chain;\r
218         }\r
219 \r
220         e = world;\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
225         if (e.health >= 1)\r
226                 self.enemy = e;\r
227 };\r
228 \r
229 /* --- UrreBotAim ---\r
230 Very crude and simple aiming*/\r
231 \r
232 void() UrreBotAim =\r
233 {\r
234         local float dist, skeel;\r
235         local vector v, desiredang, testang, diffang;\r
236 \r
237         skeel = bound(1, skill, 10);\r
238 \r
239         // get the desired angles to aim at\r
240         if (self.enemy)\r
241         {\r
242                 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;\r
243                 if (self.enemy.classname == "door")\r
244                         self.aimpoint = v;\r
245                 else if (self.aimtime <= time)\r
246                 {\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
250                         {\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
253                         }\r
254                 }\r
255                 desiredang = vectoangles(self.aimpoint - (self.origin + self.view_ofs));\r
256         }\r
257         else\r
258                 desiredang = vectoangles(self.velocity);\r
259         desiredang_x = 0-desiredang_x;\r
260 \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
269 \r
270         // calculate turn angles\r
271         testang = desiredang - self.v_angle;\r
272         testang_z = 0;\r
273 \r
274         // turn\r
275         dist = vlen(testang * ((skeel + 1) * frametime));\r
276         if (vlen(normalize(testang) * skeel) > dist)\r
277         {\r
278                 diffang = normalize(testang) * skeel;\r
279                 dist = vlen(normalize(testang) * skeel);\r
280         }\r
281         else\r
282                 diffang = testang * ((skeel + 1) * frametime);\r
283         if (dist > vlen(testang))\r
284                 diffang = testang;\r
285 \r
286         self.v_angle = self.v_angle + diffang;\r
287         self.angles_y = self.v_angle_y;\r
288 };\r
289 \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
293 \r
294 void() UrreBotMove =\r
295 {\r
296         local float f, bad;\r
297         local vector dir, tvec;\r
298         local entity plane;\r
299 \r
300         if (self.link0)\r
301         {\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
303                 {\r
304                         plane = self.link0.plane_chain;\r
305                         while (plane)\r
306                         {\r
307                                 tvec = self.maxs;\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
316                                 if (f > 0)\r
317                                         bad = TRUE;\r
318                                 plane = plane.list;\r
319                         }\r
320                         if (!bad)\r
321                         {\r
322                                 PopRoute();\r
323                                 if (self.goalcurrent.sflags & S_TELEPORT)\r
324                                         self.movepoint = self.goalcurrent.origin;\r
325                                 else\r
326                                         self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.link0);\r
327                         }\r
328                 }\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
330                 {\r
331                         plane = self.goalcurrent.plane_chain;\r
332                         while (plane)\r
333                         {\r
334                                 tvec = self.maxs;\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
343                                 if (f > 0)\r
344                                         bad = TRUE;\r
345                                 plane = plane.list;\r
346                         }\r
347                         if (!bad)\r
348                         {\r
349                                 PopRoute();\r
350                                 if (self.goalcurrent.sflags & S_TELEPORT)\r
351                                         self.movepoint = self.goalcurrent.origin;\r
352                                 else\r
353                                         self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);\r
354                                 if (self.movepoint == '0 0 0')\r
355                                 {\r
356                                         self.strat_me = TRUE;\r
357                                         UrreBotPath(minisearch_distance);\r
358                                 }\r
359                         }\r
360                 }\r
361         }\r
362         else\r
363         {\r
364                 if (!self.goalcurrent || ((self.goalcurrent.flags & FL_ITEM) && !self.goalcurrent.solid))\r
365                 {\r
366                         self.strat_me = TRUE;\r
367                         UrreBotPath(minisearch_distance);\r
368                 }\r
369                 self.movepoint = ClampPointToSpace(self.origin, self.goalcurrent, self.goalcurrent);\r
370         }\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
377 };\r
378 \r
379 /* --- UrreBotImpulses ---\r
380 Returns the impulse for the best weapon in the given situation*/\r
381 \r
382 float() UrreBotImpulses =\r
383 {\r
384         local float dist;\r
385         local float cells, rockets, nails, shells;\r
386         local vector v;\r
387 /*\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
392 */\r
393         if (random() < 0.5)\r
394                 return 0;\r
395 \r
396         dist = 400; // we like nex and mortar\r
397         if (self.enemy)\r
398         {\r
399                 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;\r
400                 dist = vlen(v - self.origin);\r
401         }\r
402 \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
407 \r
408         if (dist > 300 && cells && (self.items & IT_NEX))\r
409         {\r
410                 self.lead = 0;\r
411                 return WEP_NEX;\r
412         }\r
413         else if (rockets)\r
414         {\r
415                 if (dist < 500)\r
416                 if (self.items & IT_GRENADE_LAUNCHER)\r
417                 {\r
418                         self.lead = 1 / cvar("g_balance_grenadelauncher_speed");\r
419                         return WEP_GRENADE_LAUNCHER;\r
420                 }\r
421                 if (self.items & IT_HAGAR)\r
422                 {\r
423                         self.lead = 1 / cvar("g_balance_hagar_speed");\r
424                         return WEP_HAGAR;\r
425                 }\r
426                 else if (self.items & IT_ROCKET_LAUNCHER)\r
427                 {\r
428                         self.lead = 1 / cvar("g_balance_rocketlauncher_speed");\r
429                         return WEP_ROCKET_LAUNCHER;\r
430                 }\r
431         }\r
432         else if (cells)\r
433         {\r
434                 if (self.items & IT_ELECTRO)\r
435                 {\r
436                         self.lead = 1 / cvar("g_balance_electro_speed");\r
437                         return WEP_ELECTRO;\r
438                 }\r
439                 else if (self.items & IT_CRYLINK)\r
440                 {\r
441                         self.lead = 1 / cvar("g_balance_crylink_speed");\r
442                         return WEP_CRYLINK;\r
443                 }\r
444         }\r
445         else if (nails)\r
446         {\r
447                 if (self.items & IT_UZI)\r
448                 {\r
449                         self.lead = 0;\r
450                         return WEP_UZI;\r
451                 }\r
452         }\r
453         else if (shells)\r
454         {\r
455                 if (self.items & IT_SHOTGUN)\r
456                 {\r
457                         self.lead = 0;\r
458                         return WEP_SHOTGUN;\r
459                 }\r
460         }\r
461         self.lead = 1 / cvar("g_balance_laser_speed");\r
462         return WEP_LASER;\r
463 };\r
464 \r
465 float BT_LIGHTNING = 0;\r
466 float BT_BEAM = 1;\r
467 \r
468 void(float beamtype, vector bmins, vector bmaxs) BeamBox =\r
469 {\r
470         local vector v1, v2;\r
471 \r
472         v1 = bmaxs;\r
473         v2 = bmaxs;\r
474         v2_x = bmins_x;\r
475         if (beamtype == BT_LIGHTNING)\r
476                 te_lightning1(world, v1, v2);\r
477         else\r
478                 te_beam(world, v1, v2);\r
479         v1 = bmaxs;\r
480         v2 = bmaxs;\r
481         v2_y = bmins_y;\r
482         if (beamtype == BT_LIGHTNING)\r
483                 te_lightning1(world, v1, v2);\r
484         else\r
485                 te_beam(world, v1, v2);\r
486         v1 = bmaxs;\r
487         v2 = bmaxs;\r
488         v2_z = bmins_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         v2 = bmins;\r
495         v2_x = bmaxs_x;\r
496         if (beamtype == BT_LIGHTNING)\r
497                 te_lightning1(world, v1, v2);\r
498         else\r
499                 te_beam(world, v1, v2);\r
500         v1 = bmins;\r
501         v2 = bmins;\r
502         v2_y = bmaxs_y;\r
503         if (beamtype == BT_LIGHTNING)\r
504                 te_lightning1(world, v1, v2);\r
505         else\r
506                 te_beam(world, v1, v2);\r
507         v1 = bmins;\r
508         v2 = bmins;\r
509         v2_z = bmaxs_z;\r
510         if (beamtype == BT_LIGHTNING)\r
511                 te_lightning1(world, v1, v2);\r
512         else\r
513                 te_beam(world, v1, v2);\r
514         v1 = bmins;\r
515         v1_z = bmaxs_z;\r
516         v2 = bmins;\r
517         v2_x = bmaxs_x;\r
518         v2_z = bmaxs_z;\r
519         if (beamtype == BT_LIGHTNING)\r
520                 te_lightning1(world, v1, v2);\r
521         else\r
522                 te_beam(world, v1, v2);\r
523         v1 = bmins;\r
524         v1_z = bmaxs_z;\r
525         v2 = bmins;\r
526         v2_y = bmaxs_y;\r
527         v2_z = bmaxs_z;\r
528         if (beamtype == BT_LIGHTNING)\r
529                 te_lightning1(world, v1, v2);\r
530         else\r
531                 te_beam(world, v1, v2);\r
532         v1 = bmaxs;\r
533         v1_z = bmins_z;\r
534         v2 = bmaxs;\r
535         v2_x = bmins_x;\r
536         v2_z = bmins_z;\r
537         if (beamtype == BT_LIGHTNING)\r
538                 te_lightning1(world, v1, v2);\r
539         else\r
540                 te_beam(world, v1, v2);\r
541         v1 = bmaxs;\r
542         v1_z = bmins_z;\r
543         v2 = bmaxs;\r
544         v2_y = bmins_y;\r
545         v2_z = bmins_z;\r
546         if (beamtype == BT_LIGHTNING)\r
547                 te_lightning1(world, v1, v2);\r
548         else\r
549                 te_beam(world, v1, v2);\r
550         v1 = bmins;\r
551         v1_x = bmaxs_x;\r
552         v2 = bmaxs;\r
553         v2_y = bmins_y;\r
554         if (beamtype == BT_LIGHTNING)\r
555                 te_lightning1(world, v1, v2);\r
556         else\r
557                 te_beam(world, v1, v2);\r
558         v1 = bmins;\r
559         v1_y = bmaxs_y;\r
560         v2 = bmaxs;\r
561         v2_x = bmins_x;\r
562         if (beamtype == BT_LIGHTNING)\r
563                 te_lightning1(world, v1, v2);\r
564         else\r
565                 te_beam(world, v1, v2);\r
566 };\r
567 \r
568 void(float sdist) UrreBotPath =\r
569 {\r
570         local float f, f2, f3;\r
571         local entity e, best;\r
572 \r
573         ClearRoute();\r
574         MarkRoute(sdist);\r
575         DistEvalItems();\r
576         f2 = 10000000;\r
577         e = findchainflags(flags, FL_ITEM);\r
578         while (e)\r
579         {\r
580                 f = 0;\r
581                 if (e.evalfunc)\r
582                         f = e.evalfunc();\r
583                 if (f > 0)\r
584                 if (e.enemy)\r
585                 {\r
586                         f = f + e.costl;\r
587                         if (f < f2)\r
588                         if (e.solid)\r
589                         {\r
590                                 best = e;\r
591                                 f2 = e.costl;\r
592                         }\r
593                 }\r
594                 e = e.chain;\r
595         }\r
596         if (best)\r
597         {\r
598                 while (best)\r
599                 {\r
600                         PushRoute(best);\r
601                         best = best.enemy;\r
602                 }\r
603         }\r
604         else\r
605         {\r
606                 f3 = 0;\r
607                 while (f3 < 3)\r
608                 {\r
609                         f = 0;\r
610                         f2 = 0;\r
611                         f = ceil(random() * navnodes);\r
612                         e = navnode_chain;\r
613                         while (e)\r
614                         {\r
615                                 if (f == f2)\r
616                                 if (e.enemy)\r
617                                 {\r
618                                         best = e;\r
619                                         f3 = 3;\r
620                                 }\r
621                                 f2 = f2 + 1;\r
622                                 e = e.list;\r
623                         }\r
624                         f3 = f3 + 1;\r
625                 }\r
626                 while (best)\r
627                 {\r
628                         PushRoute(best);\r
629                         best = best.enemy;\r
630                 }\r
631         }\r
632 };\r
633 \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
640 \r
641 void() UrreBotThink =\r
642 {\r
643         local float f;\r
644         local vector v;\r
645 \r
646         self.movement = '0 0 0';\r
647         self.button0 = 0;\r
648         self.button2 = 0;\r
649         self.impulse = 0;\r
650 \r
651         if (self.deadflag)\r
652         {\r
653                 ClearRoute();\r
654                 if (random() < 0.2)\r
655                         self.button0 = 1;\r
656                 return;\r
657         }\r
658 \r
659         if (strategytime <= time)\r
660         if (strategytoken == self)\r
661         {\r
662                 strategytime = time + urrebots_strategytime;\r
663                 strategytoken = self.list;\r
664                 if (!strategytoken)\r
665                         strategytoken = bot_chain;\r
666                 if (self.strat_me)\r
667                 {\r
668                         self.strat_me = FALSE;\r
669                         UrreBotPath(stratsearch_distance);\r
670                 }\r
671         }\r
672 \r
673         UrreBotAim();\r
674         UrreBotMove();\r
675 \r
676         if (self.camptime <= time)\r
677         {\r
678                 if (vlen(self.origin - self.campcheck) < 200) // stuckage avoidage\r
679                 {\r
680                         self.camptime = time + actualurrebots;\r
681                         self.strat_me = TRUE;\r
682                         UrreBotPath(minisearch_distance);\r
683                 }\r
684                 else\r
685                 {\r
686                         self.campcheck = self.origin;\r
687                         self.camptime = time + 2;\r
688                 }\r
689         }\r
690 \r
691         if (self.combattime <= time)\r
692         {\r
693                 self.combattime = time + urrebots_combattime;\r
694                 UrreBotEvalTargets();\r
695                 self.impulse = UrreBotImpulses();\r
696         }\r
697 \r
698         if (self.enemy)\r
699         {\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
705                 {\r
706                         if (skill < 3)\r
707                         {\r
708                                 if (random() < 0.3)\r
709                                         self.button0 = 1;\r
710                         }\r
711                         else\r
712                                 self.button0 = 1;\r
713                 }\r
714         }\r
715         if (cvar("urrebots_debug"))\r
716         {\r
717                 te_lightning1(self, self.origin, self.movepoint);\r
718                 if (!self.goalcurrent)\r
719                 {\r
720                         bprint(self.netname);\r
721                         bprint(" has no goalcurrent\n");\r
722                 }\r
723         }\r
724 };\r