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