]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/gamec/urrebot_ai_main.c
git-svn-id: svn://svn.icculus.org/nexuiz/trunk@752 f962a42d-fe04-0410-a3ab-8c8b0445ebaa
[divverent/nexuiz.git] / data / qcsrc / gamec / urrebot_ai_main.c
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, with some leading capability*/\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 goal in the bots list,\r
292 which can be a navnode, item or domination point*/\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) || (self.goalcurrent.classname == "dom_controlpoint" && self.goalcurrent.enemy.team == self.team))\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         if (random() < 0.5)\r
389                 return 0;\r
390 \r
391         dist = 400; // we like nex and mortar\r
392         if (self.enemy)\r
393         {\r
394                 v = (self.enemy.absmin + self.enemy.absmax) * 0.5;\r
395                 dist = vlen(v - self.origin);\r
396         }\r
397 \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
402 \r
403         if (dist > 300 && cells && (self.items & IT_NEX))\r
404         {\r
405                 self.lead = 0;\r
406                 return WEP_NEX;\r
407         }\r
408         else if (rockets)\r
409         {\r
410                 if (dist < 500)\r
411                 if (self.items & IT_GRENADE_LAUNCHER)\r
412                 {\r
413                         self.lead = 1 / cvar("g_balance_grenadelauncher_speed");\r
414                         return WEP_GRENADE_LAUNCHER;\r
415                 }\r
416                 if (self.items & IT_HAGAR)\r
417                 {\r
418                         self.lead = 1 / cvar("g_balance_hagar_speed");\r
419                         return WEP_HAGAR;\r
420                 }\r
421                 else if (self.items & IT_ROCKET_LAUNCHER)\r
422                 {\r
423                         self.lead = 1 / cvar("g_balance_rocketlauncher_speed");\r
424                         return WEP_ROCKET_LAUNCHER;\r
425                 }\r
426         }\r
427         else if (cells)\r
428         {\r
429                 if (self.items & IT_ELECTRO)\r
430                 {\r
431                         self.lead = 1 / cvar("g_balance_electro_speed");\r
432                         return WEP_ELECTRO;\r
433                 }\r
434                 else if (self.items & IT_CRYLINK)\r
435                 {\r
436                         self.lead = 1 / cvar("g_balance_crylink_speed");\r
437                         return WEP_CRYLINK;\r
438                 }\r
439         }\r
440         else if (nails)\r
441         {\r
442                 if (self.items & IT_UZI)\r
443                 {\r
444                         self.lead = 0;\r
445                         return WEP_UZI;\r
446                 }\r
447         }\r
448         else if (shells)\r
449         {\r
450                 if (self.items & IT_SHOTGUN)\r
451                 {\r
452                         self.lead = 0;\r
453                         return WEP_SHOTGUN;\r
454                 }\r
455         }\r
456         self.lead = 1 / cvar("g_balance_laser_speed");\r
457         return WEP_LASER;\r
458 };\r
459 \r
460 /* --- BeamBox ---\r
461 Used for some debugging, occasionally*/\r
462 \r
463 float BT_LIGHTNING = 0;\r
464 float BT_BEAM = 1;\r
465 void(float beamtype, vector bmins, vector bmaxs) BeamBox =\r
466 {\r
467         local vector v1, v2;\r
468 \r
469         v1 = bmaxs;\r
470         v2 = bmaxs;\r
471         v2_x = bmins_x;\r
472         if (beamtype == BT_LIGHTNING)\r
473                 te_lightning1(world, v1, v2);\r
474         else\r
475                 te_beam(world, v1, v2);\r
476         v1 = bmaxs;\r
477         v2 = bmaxs;\r
478         v2_y = bmins_y;\r
479         if (beamtype == BT_LIGHTNING)\r
480                 te_lightning1(world, v1, v2);\r
481         else\r
482                 te_beam(world, v1, v2);\r
483         v1 = bmaxs;\r
484         v2 = bmaxs;\r
485         v2_z = bmins_z;\r
486         if (beamtype == BT_LIGHTNING)\r
487                 te_lightning1(world, v1, v2);\r
488         else\r
489                 te_beam(world, v1, v2);\r
490         v1 = bmins;\r
491         v2 = bmins;\r
492         v2_x = bmaxs_x;\r
493         if (beamtype == BT_LIGHTNING)\r
494                 te_lightning1(world, v1, v2);\r
495         else\r
496                 te_beam(world, v1, v2);\r
497         v1 = bmins;\r
498         v2 = bmins;\r
499         v2_y = bmaxs_y;\r
500         if (beamtype == BT_LIGHTNING)\r
501                 te_lightning1(world, v1, v2);\r
502         else\r
503                 te_beam(world, v1, v2);\r
504         v1 = bmins;\r
505         v2 = bmins;\r
506         v2_z = bmaxs_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 = bmins;\r
512         v1_z = bmaxs_z;\r
513         v2 = bmins;\r
514         v2_x = bmaxs_x;\r
515         v2_z = bmaxs_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_z = bmaxs_z;\r
522         v2 = bmins;\r
523         v2_y = bmaxs_y;\r
524         v2_z = bmaxs_z;\r
525         if (beamtype == BT_LIGHTNING)\r
526                 te_lightning1(world, v1, v2);\r
527         else\r
528                 te_beam(world, v1, v2);\r
529         v1 = bmaxs;\r
530         v1_z = bmins_z;\r
531         v2 = bmaxs;\r
532         v2_x = bmins_x;\r
533         v2_z = bmins_z;\r
534         if (beamtype == BT_LIGHTNING)\r
535                 te_lightning1(world, v1, v2);\r
536         else\r
537                 te_beam(world, v1, v2);\r
538         v1 = bmaxs;\r
539         v1_z = bmins_z;\r
540         v2 = bmaxs;\r
541         v2_y = bmins_y;\r
542         v2_z = bmins_z;\r
543         if (beamtype == BT_LIGHTNING)\r
544                 te_lightning1(world, v1, v2);\r
545         else\r
546                 te_beam(world, v1, v2);\r
547         v1 = bmins;\r
548         v1_x = bmaxs_x;\r
549         v2 = bmaxs;\r
550         v2_y = bmins_y;\r
551         if (beamtype == BT_LIGHTNING)\r
552                 te_lightning1(world, v1, v2);\r
553         else\r
554                 te_beam(world, v1, v2);\r
555         v1 = bmins;\r
556         v1_y = bmaxs_y;\r
557         v2 = bmaxs;\r
558         v2_x = bmins_x;\r
559         if (beamtype == BT_LIGHTNING)\r
560                 te_lightning1(world, v1, v2);\r
561         else\r
562                 te_beam(world, v1, v2);\r
563 };\r
564 \r
565 /* --- UrreBotPath ---\r
566 Marks route and determines which goal is the most useful to head for*/\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(e);\r
583                 if (f > 0)\r
584                 if (e.goallist)\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.goallist;\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.goallist)\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.goallist;\r
630                 }\r
631         }\r
632 };\r
633 \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
638 order\r
639 Aiming must happen before movement, because movement depends on angles\r
640 He does not yet have any combat movement*/\r
641 \r
642 void() UrreBotThink =\r
643 {\r
644         local float f;\r
645         local vector v;\r
646 \r
647         self.movement = '0 0 0';\r
648         self.button0 = 0;\r
649         self.button2 = 0;\r
650         self.impulse = 0;\r
651 \r
652         if (self.deadflag)\r
653         {\r
654                 ClearRoute();\r
655                 if (random() < 0.2)\r
656                         self.button0 = 1;\r
657                 return;\r
658         }\r
659 \r
660         if (strategytime <= time)\r
661         if (strategytoken == self)\r
662         {\r
663                 strategytime = time + urrebots_strategytime;\r
664                 strategytoken = self.list;\r
665                 if (!strategytoken)\r
666                         strategytoken = bot_chain;\r
667                 if (self.strat_me)\r
668                 {\r
669                         self.strat_me = FALSE;\r
670                         UrreBotPath(stratsearch_distance);\r
671                 }\r
672         }\r
673 \r
674         UrreBotAim();\r
675         UrreBotMove();\r
676 \r
677         if (self.camptime <= time)\r
678         {\r
679                 if (vlen(self.origin - self.campcheck) < 200) // stuckage avoidage\r
680                 {\r
681                         self.camptime = time + actualurrebots;\r
682                         self.strat_me = TRUE;\r
683                         UrreBotPath(minisearch_distance);\r
684                 }\r
685                 else\r
686                 {\r
687                         self.campcheck = self.origin;\r
688                         self.camptime = time + 2;\r
689                 }\r
690         }\r
691 \r
692         if (self.combattime <= time)\r
693         {\r
694                 self.combattime = time + urrebots_combattime;\r
695                 UrreBotEvalTargets();\r
696                 self.impulse = UrreBotImpulses();\r
697         }\r
698 \r
699         if (self.enemy)\r
700         {\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
706                 {\r
707                         if (skill < 3)\r
708                         {\r
709                                 if (random() < 0.3)\r
710                                         self.button0 = 1;\r
711                         }\r
712                         else\r
713                                 self.button0 = 1;\r
714                 }\r
715         }\r
716         if (cvar("urrebots_debug"))\r
717         {\r
718                 te_lightning1(self, self.origin, self.movepoint);\r
719                 if (!self.goalcurrent)\r
720                 {\r
721                         bprint(self.netname);\r
722                         bprint(" has no goalcurrent\n");\r
723                 }\r
724         }\r
725 };\r