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