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