]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/gamec/havocbot_roles.c
cl_nogibs (must be set at connect)
[divverent/nexuiz.git] / data / qcsrc / server / gamec / havocbot_roles.c
1
2 .float havocbot_role_timeout;
3 .void() havocbot_previous_role;
4 .float bot_strategytime;
5 .void() havocbot_role;
6
7 float(entity e) canreach =
8 {
9         return vlen(self.origin - e.origin) < 1500;
10 }
11
12 void(float ratingscale, vector org, float sradius) havocbot_goalrating_items =
13 {
14         local entity head;
15         local float t;
16         head = findchainfloat(bot_pickup, TRUE);
17         while (head)
18         {
19                 if (head.solid) // must be possible to pick up (respawning items don't count)
20                 if (vlen(head.origin - org) < sradius)
21                 {
22                         // debugging
23                         //if (!head.bot_pickupevalfunc || head.model == "")
24                         //      eprint(head);
25                         // get the value of the item
26                         t = head.bot_pickupevalfunc(self, head) * 0.0001;
27                         if (t > 0)
28                                 navigation_routerating(head, t * ratingscale);
29                 }
30                 head = head.chain;
31         }
32 };
33
34 void(float ratingscale, vector org, float sradius) havocbot_goalrating_controlpoints =
35 {
36         local entity head;
37         head = findchain(classname, "dom_controlpoint");
38         while (head)
39         {
40                 if (vlen(head.origin - org) < sradius)
41                 {
42                         if(head.cnt > -1) // this is just being fought for
43                                 navigation_routerating(head, ratingscale);
44                         else if(head.goalentity.cnt == 0) // unclaimed point
45                                 navigation_routerating(head, ratingscale * 0.5);
46                         else if(head.goalentity.team != self.team) // other team's point
47                                 navigation_routerating(head, ratingscale * 0.2);
48                 }
49                 head = head.chain;
50         }
51 };
52
53 void(float ratingscale, vector org, float sradius) havocbot_goalrating_waypoints =
54 {
55         local entity head;
56         head = findchain(classname, "waypoint");
57         while (head)
58         {
59                 if (vlen(head.origin - org) < sradius && vlen(head.origin - org) > 100)
60                         navigation_routerating(head, ratingscale);
61                 head = head.chain;
62         }
63 };
64
65 void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers =
66 {
67         local entity head;
68         local float t, noteam;
69         ratingscale = ratingscale * 1200;
70         noteam = self.team == 0 || teamplay == 0;
71         head = findchain(classname, "player");
72         while (head)
73         {
74                 if (head.health > 0)
75                 if (head.team != self.team || noteam)
76                 if (vlen(head.origin - org) < sradius)
77                 {
78                         t = head.frags + 25;
79                         if (t < 1)
80                                 t = 1;
81                         t = t / (head.health + head.armortype * head.armorvalue);
82                         if (t > 0)
83                                 navigation_routerating(head, t * ratingscale);
84                 }
85                 head = head.chain;
86         }
87 };
88
89
90 void() havocbot_role_ctf_middle;
91 void() havocbot_role_ctf_defense;
92 void() havocbot_role_ctf_offense;
93 void() havocbot_role_ctf_interceptor;
94
95 void(float ratingscale, vector org, float sradius) havocbot_goalrating_ctf_carrieritems =
96 {
97         local entity head;
98         local float t;
99         head = findchainfloat(bot_pickup, TRUE);
100         while (head)
101         {
102                 // look for health and armor only
103                 if (head.solid) // must be possible to pick up (respawning items don't count)
104                 if (head.health || head.armorvalue)
105                 if (vlen(head.origin - org) < sradius)
106                 {
107                         // debugging
108                         //if (!head.bot_pickupevalfunc || head.model == "")
109                         //      eprint(head);
110                         // get the value of the item
111                         t = head.bot_pickupevalfunc(self, head) * 0.0001;
112                         if (t > 0)
113                                 navigation_routerating(head, t * ratingscale);
114                 }
115                 head = head.chain;
116         }
117 };
118
119 void(float ratingscale) havocbot_goalrating_ctf_ourflag =
120 {
121         local entity head;
122         if (self.team == 5) // red
123                 head = find(world, classname, "item_flag_team1"); // red flag
124         else // blue
125                 head = find(world, classname, "item_flag_team2"); // blue flag
126         navigation_routerating(head, ratingscale);
127 };
128
129 void(float ratingscale) havocbot_goalrating_ctf_enemyflag =
130 {
131         local entity head;
132         if (self.team == 5) // red
133                 head = find(world, classname, "item_flag_team2"); // blue flag
134         else // blue
135                 head = find(world, classname, "item_flag_team1"); // red flag
136         navigation_routerating(head, ratingscale);
137 };
138
139 void(float ratingscale) havocbot_goalrating_ctf_enemybase =
140 {
141         // div0: needs a change in the CTF code
142 };
143
144 void(float ratingscale) havocbot_goalrating_ctf_ourstolenflag =
145 {
146         local entity head;
147         if (self.team == 5) // red
148                 head = find(world, classname, "item_flag_team1"); // red flag
149         else // blue
150                 head = find(world, classname, "item_flag_team2"); // blue flag
151         if (head.cnt != FLAG_BASE)
152                 navigation_routerating(head, ratingscale);
153 };
154
155 void(float ratingscale) havocbot_goalrating_ctf_droppedflags =
156 {
157         local entity redflag, blueflag;
158
159         redflag = find(world, classname, "item_flag_team1");
160         blueflag = find(world, classname, "item_flag_team2");
161
162         if (redflag == world)
163                 error("havocbot: item_flag_team1 missing\n");
164         if (blueflag == world)
165                 error("havocbot: item_flag_team2 missing\n");
166
167         if (redflag.cnt != FLAG_BASE) // red flag is carried or out in the field
168                 navigation_routerating(redflag, ratingscale);
169         if (blueflag.cnt != FLAG_BASE) // blue flag is carried or out in the field
170                 navigation_routerating(blueflag, ratingscale);
171 };
172
173 // CTF: (always teamplay)
174
175 //role rogue: (is this used?)
176 //pick up items and dropped flags (with big rating boost to dropped flags)
177 void() havocbot_role_ctf_rogue =
178 {
179         if (self.bot_strategytime < time)
180         {
181                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
182                 navigation_goalrating_start();
183                 havocbot_goalrating_ctf_droppedflags(5000);
184                 //havocbot_goalrating_enemyplayers(3000, self.origin, 3000);
185                 havocbot_goalrating_items(10000, self.origin, 10000);
186                 navigation_goalrating_end();
187         }
188 }
189
190 //role flag carrier:
191 //pick up armor and health
192 //go to our flag spot
193 void() havocbot_role_ctf_carrier =
194 {
195         if (self.flagcarried == world)
196         {
197                 dprint("changing role to middle\n");
198                 self.havocbot_role = havocbot_role_ctf_middle;
199                 self.havocbot_role_timeout = 0;
200                 return;
201         }
202         if (self.bot_strategytime < time)
203         {
204                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
205                 navigation_goalrating_start();
206                 havocbot_goalrating_ctf_ourflag(5000);
207                 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
208                 navigation_goalrating_end();
209         }
210 };
211
212 //role offense:
213 //pick up armor and health
214 //if rockets < 25 || health < 100, change role to middle
215 //if carrying flag, change role to flag carrier
216 //if our flag taken, change role to interceptor
217 //(60-90 second timer) change role to middle
218 //go to enemy flag
219 void() havocbot_role_ctf_offense =
220 {
221         local entity f;
222         if (self.flagcarried)
223         {
224                 dprint("changing role to carrier\n");
225                 self.havocbot_role = havocbot_role_ctf_carrier;
226                 self.havocbot_role_timeout = 0;
227                 return;
228         }
229         // check our flag
230         if (self.team == 5) // red
231                 f = find(world, classname, "item_flag_team1");
232         else // blue
233                 f = find(world, classname, "item_flag_team2");
234         if (f.cnt != FLAG_BASE && canreach(f))
235         {
236                 dprint("changing role to interceptor\n");
237                 self.havocbot_previous_role = self.havocbot_role;
238                 self.havocbot_role = havocbot_role_ctf_interceptor;
239                 self.havocbot_role_timeout = 0;
240                 return;
241         }
242         if (!self.havocbot_role_timeout)
243                 self.havocbot_role_timeout = time + random() * 30 + 60;
244         if (self.ammo_rockets < 15 || time > self.havocbot_role_timeout)
245         {
246                 dprint("changing role to middle\n");
247                 self.havocbot_role = havocbot_role_ctf_middle;
248                 self.havocbot_role_timeout = 0;
249                 return;
250         }
251         if (self.bot_strategytime < time)
252         {
253                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
254                 navigation_goalrating_start();
255                 havocbot_goalrating_ctf_ourstolenflag(5000);
256                 havocbot_goalrating_ctf_enemyflag(3000);
257                 havocbot_goalrating_ctf_enemybase(2000);
258                 havocbot_goalrating_items(10000, self.origin, 10000);
259                 navigation_goalrating_end();
260         }
261 };
262
263 //role interceptor (temporary role):
264 //pick up items
265 //if carrying flag, change role to flag carrier
266 //if our flag is back, change role to previous role
267 //follow our flag
268 //go to least recently visited area
269 void() havocbot_role_ctf_interceptor =
270 {
271         local entity f;
272         if (self.flagcarried)
273         {
274                 dprint("changing role to carrier\n");
275                 self.havocbot_role = havocbot_role_ctf_carrier;
276                 self.havocbot_role_timeout = 0;
277                 return;
278         }
279         // check our flag
280         if (self.team == 5) // red
281                 f = find(world, classname, "item_flag_team1");
282         else // blue
283                 f = find(world, classname, "item_flag_team2");
284         if (f.cnt == FLAG_BASE)
285         {
286                 dprint("changing role back\n");
287                 self.havocbot_role = self.havocbot_previous_role;
288                 self.havocbot_role_timeout = 0;
289                 return;
290         }
291
292         if (self.bot_strategytime < time)
293         {
294                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
295                 navigation_goalrating_start();
296                 havocbot_goalrating_ctf_ourstolenflag(5000);
297                 havocbot_goalrating_ctf_droppedflags(5000);
298                 havocbot_goalrating_items(10000, self.origin, 10000);
299                 navigation_goalrating_end();
300         }
301 };
302
303 //role middle:
304 //pick up items
305 //if carrying flag, change role to flag carrier
306 //if our flag taken, change role to interceptor
307 //if see flag (of either team) follow it (this has many implications)
308 //(10-20 second timer) change role to defense or offense
309 //go to least recently visited area
310 void() havocbot_role_ctf_middle =
311 {
312         local entity f;
313         if (self.flagcarried)
314         {
315                 dprint("changing role to carrier\n");
316                 self.havocbot_role = havocbot_role_ctf_carrier;
317                 self.havocbot_role_timeout = 0;
318                 return;
319         }
320         // check our flag
321         if (self.team == 5) // red
322                 f = find(world, classname, "item_flag_team1");
323         else // blue
324                 f = find(world, classname, "item_flag_team2");
325         if (f.cnt != FLAG_BASE && canreach(f))
326         {
327                 dprint("changing role to interceptor\n");
328                 self.havocbot_previous_role = self.havocbot_role;
329                 self.havocbot_role = havocbot_role_ctf_interceptor;
330                 self.havocbot_role_timeout = 0;
331                 return;
332         }
333         if (!self.havocbot_role_timeout)
334                 self.havocbot_role_timeout = time + random() * 10 + 10;
335         if (time > self.havocbot_role_timeout)
336         if (self.ammo_rockets >= 25)
337         {
338                 if (random() < 0.5)
339                 {
340                         dprint("changing role to offense\n");
341                         self.havocbot_role = havocbot_role_ctf_offense;
342                 }
343                 else
344                 {
345                         dprint("changing role to defense\n");
346                         self.havocbot_role = havocbot_role_ctf_defense;
347                 }
348                 self.havocbot_role_timeout = 0;
349                 return;
350         }
351
352         if (self.bot_strategytime < time)
353         {
354                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
355                 navigation_goalrating_start();
356                 havocbot_goalrating_ctf_ourstolenflag(5000);
357                 havocbot_goalrating_ctf_droppedflags(3000);
358                 //havocbot_goalrating_enemyplayers(1000, self.origin, 1000);
359                 havocbot_goalrating_items(10000, self.origin, 10000);
360                 navigation_goalrating_end();
361         }
362 };
363
364 //role defense:
365 //if rockets < 25 || health < 100, change role to middle
366 //if carrying flag, change role to flag carrier
367 //if our flag taken, change role to interceptor
368 //(30-50 second timer) change role to middle
369 //move to nearest unclaimed defense spot
370 void() havocbot_role_ctf_defense =
371 {
372         local entity f;
373         if (self.flagcarried)
374         {
375                 dprint("changing role to carrier\n");
376                 self.havocbot_role = havocbot_role_ctf_carrier;
377                 self.havocbot_role_timeout = 0;
378                 return;
379         }
380         // check our flag
381         if (self.team == 5) // red
382                 f = find(world, classname, "item_flag_team1");
383         else // blue
384                 f = find(world, classname, "item_flag_team2");
385         if (f.cnt != FLAG_BASE && canreach(f))
386         {
387                 dprint("changing role to interceptor\n");
388                 self.havocbot_previous_role = self.havocbot_role;
389                 self.havocbot_role = havocbot_role_ctf_interceptor;
390                 self.havocbot_role_timeout = 0;
391                 return;
392         }
393         if (!self.havocbot_role_timeout)
394                 self.havocbot_role_timeout = time + random() * 20 + 30;
395         if (self.ammo_rockets < 15 || time > self.havocbot_role_timeout)
396         {
397                 dprint("changing role to middle\n");
398                 self.havocbot_role = havocbot_role_ctf_middle;
399                 self.havocbot_role_timeout = 0;
400                 return;
401         }
402         if (self.bot_strategytime < time)
403         {
404                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
405                 navigation_goalrating_start();
406                 havocbot_goalrating_ctf_ourstolenflag(20000);
407                 havocbot_goalrating_ctf_droppedflags(500);
408                 havocbot_goalrating_items(10000, f.origin, 10000);
409                 navigation_goalrating_end();
410         }
411         /*
412         // FIXME: place info_ctf_defensepoint entities in CTF maps and use them
413         // change position occasionally
414         if (time > self.bot_strategytime || self.goalentity.classname != "info_ctf_defensepoint")
415         {
416                 self.bot_strategytime = time + random() * 45 + 15;
417                 self.goalentity = world;
418                 head = findchain(classname, "info_ctf_defensepoint");
419                 while (head)
420                 {
421                         if (time > head.count)
422                         {
423                                 self.goalentity = head;
424                                 head.chain = world;
425                         }
426                         head = head.chain;
427                 }
428                 // if there are no defensepoints defined, switch to middle
429                 if (self.goalentity == world)
430                 {
431                         dprint("changing role to middle\n");
432                         self.havocbot_role = havocbot_role_ctf_middle;
433                         self.havocbot_role_timeout = 0;
434                         return;
435                 }
436         }
437         // keep anyone else from taking this spot
438         if (self.goalentity != world)
439                 self.goalentity.count = time + 0.5;
440         */
441 };
442
443 // CTF:
444 // choose a role according to the situation
445 void() havocbot_chooserole_ctf =
446 {
447         local float r;
448         dprint("choose CTF role...\n");
449         if (self.team == 13)
450                 self.havocbot_role = havocbot_role_ctf_rogue;
451         else
452         {
453                 r = random() * 3;
454                 if (r < 0)
455                         self.havocbot_role = havocbot_role_ctf_offense;
456                 else if (r < 1)
457                         self.havocbot_role = havocbot_role_ctf_middle;
458                 else
459                         self.havocbot_role = havocbot_role_ctf_defense;
460         }
461 };
462
463 //DOM:
464 //go to best items, or control points you don't own
465 void() havocbot_role_dom =
466 {
467         if (self.bot_strategytime < time)
468         {
469                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
470                 navigation_goalrating_start();
471                 havocbot_goalrating_controlpoints(10000, self.origin, 15000);
472                 havocbot_goalrating_items(8000, self.origin, 8000);
473                 //havocbot_goalrating_enemyplayers(1, self.origin, 2000);
474                 //havocbot_goalrating_waypoints(1, self.origin, 1000);
475                 navigation_goalrating_end();
476         }
477 };
478
479 //DM:
480 //go to best items
481 void() havocbot_role_dm =
482 {
483         if (self.bot_strategytime < time)
484         {
485                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
486                 navigation_goalrating_start();
487                 havocbot_goalrating_items(10000, self.origin, 10000);
488                 havocbot_goalrating_enemyplayers(1, self.origin, 20000);
489                 //havocbot_goalrating_waypoints(1, self.origin, 1000);
490                 navigation_goalrating_end();
491         }
492 };
493
494 void() havocbot_chooserole_dm =
495 {
496         self.havocbot_role = havocbot_role_dm;
497 };
498
499 void() havocbot_chooserole_dom =
500 {
501         self.havocbot_role = havocbot_role_dom;
502 };
503
504 void() havocbot_chooserole =
505 {
506         dprint("choose a role...\n");
507         navigation_routetogoal(world);
508         self.bot_strategytime = -1;
509         if (cvar("g_ctf"))
510                 havocbot_chooserole_ctf();
511         else if (cvar("g_domination"))
512                 havocbot_chooserole_dom();
513         else // assume anything else is deathmatch
514                 havocbot_chooserole_dm();
515 };
516