1 #define HAVOCBOT_CTF_ROLE_NONE 0
2 #define HAVOCBOT_CTF_ROLE_DEFENSE 2
3 #define HAVOCBOT_CTF_ROLE_MIDDLE 4
4 #define HAVOCBOT_CTF_ROLE_OFFENSE 8
5 #define HAVOCBOT_CTF_ROLE_CARRIER 16
6 #define HAVOCBOT_CTF_ROLE_RETRIEVER 32
7 #define HAVOCBOT_CTF_ROLE_ESCORT 64
10 .void() havocbot_previous_role;
12 void() havocbot_role_ctf_middle;
13 void() havocbot_role_ctf_defense;
14 void() havocbot_role_ctf_offense;
15 void() havocbot_role_ctf_carrier;
16 void() havocbot_role_ctf_retriever;
17 void() havocbot_role_ctf_escort;
19 void(entity bot) havocbot_ctf_reset_role;
20 void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
21 void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
23 .float havocbot_cantfindflag;
24 .float havocbot_role_timeout;
25 .entity ctf_worldflagnext;
28 entity ctf_worldflaglist;
29 vector havocbot_ctf_middlepoint;
30 float havocbot_ctf_middlepoint_radius;
32 entity havocbot_ctf_find_flag(entity bot)
35 f = ctf_worldflaglist;
38 if (bot.team == f.team)
40 f = f.ctf_worldflagnext;
45 entity havocbot_ctf_find_enemy_flag(entity bot)
48 f = ctf_worldflaglist;
51 if (bot.team != f.team)
53 f = f.ctf_worldflagnext;
58 float havocbot_ctf_teamcount(entity bot, vector org, float radius)
68 if(head.team!=bot.team || head.deadflag != DEAD_NO || head == bot)
71 if(vlen(head.origin - org) < radius)
78 void havocbot_goalrating_ctf_ourflag(float ratingscale)
81 head = ctf_worldflaglist;
84 if (self.team == head.team)
86 head = head.ctf_worldflagnext;
89 navigation_routerating(head, ratingscale, 10000);
92 void havocbot_goalrating_ctf_ourbase(float ratingscale)
95 head = ctf_worldflaglist;
98 if (self.team == head.team)
100 head = head.ctf_worldflagnext;
105 navigation_routerating(head.basewaypoint, ratingscale, 10000);
108 void havocbot_goalrating_ctf_enemyflag(float ratingscale)
111 head = ctf_worldflaglist;
114 if (self.team != head.team)
116 head = head.ctf_worldflagnext;
119 navigation_routerating(head, ratingscale, 10000);
122 void havocbot_goalrating_ctf_enemybase(float ratingscale)
124 if not(bot_waypoints_for_items)
126 havocbot_goalrating_ctf_enemyflag(ratingscale);
132 head = havocbot_ctf_find_enemy_flag(self);
137 navigation_routerating(head.basewaypoint, ratingscale, 10000);
140 void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
144 mf = havocbot_ctf_find_flag(self);
146 if(mf.cnt == FLAG_BASE)
150 navigation_routerating(mf.tag_entity, ratingscale, 10000);
153 void havocbot_goalrating_ctf_droppedflags(float ratingscale, vector org, float radius)
156 head = ctf_worldflaglist;
159 // flag is out in the field
160 if(head.cnt != FLAG_BASE)
161 if(head.tag_entity==world) // dropped
165 if(vlen(org-head.origin)<radius)
166 navigation_routerating(head, ratingscale, 10000);
169 navigation_routerating(head, ratingscale, 10000);
172 head = head.ctf_worldflagnext;
176 void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
180 head = findchainfloat(bot_pickup, TRUE);
183 // gather health and armor only
185 if (head.health || head.armorvalue)
186 if (vlen(head.origin - org) < sradius)
188 // get the value of the item
189 t = head.bot_pickupevalfunc(self, head) * 0.0001;
191 navigation_routerating(head, t * ratingscale, 500);
197 void havocbot_role_ctf_setrole(entity bot, float role)
199 dprint(strcat(bot.netname," switched to "));
202 case HAVOCBOT_CTF_ROLE_CARRIER:
204 bot.havocbot_role = havocbot_role_ctf_carrier;
205 bot.havocbot_role_timeout = 0;
206 bot.havocbot_cantfindflag = time + 10;
208 case HAVOCBOT_CTF_ROLE_DEFENSE:
210 bot.havocbot_role = havocbot_role_ctf_defense;
211 bot.havocbot_role_timeout = 0;
213 case HAVOCBOT_CTF_ROLE_MIDDLE:
215 bot.havocbot_role = havocbot_role_ctf_middle;
216 bot.havocbot_role_timeout = 0;
218 case HAVOCBOT_CTF_ROLE_OFFENSE:
220 bot.havocbot_role = havocbot_role_ctf_offense;
221 bot.havocbot_role_timeout = 0;
223 case HAVOCBOT_CTF_ROLE_RETRIEVER:
225 bot.havocbot_previous_role = bot.havocbot_role;
226 bot.havocbot_role = havocbot_role_ctf_retriever;
227 bot.havocbot_role_timeout = time + 10;
229 case HAVOCBOT_CTF_ROLE_ESCORT:
231 bot.havocbot_previous_role = bot.havocbot_role;
232 bot.havocbot_role = havocbot_role_ctf_escort;
233 bot.havocbot_role_timeout = time + 30;
239 void havocbot_role_ctf_carrier()
241 if(self.deadflag != DEAD_NO)
243 havocbot_ctf_reset_role(self);
247 if (self.flagcarried == world)
249 havocbot_ctf_reset_role(self);
253 if (self.bot_strategytime < time)
255 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
257 navigation_goalrating_start();
258 havocbot_goalrating_ctf_ourbase(50000);
261 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
263 navigation_goalrating_end();
265 if (self.navigation_hasgoals)
266 self.havocbot_cantfindflag = time + 10;
267 else if (time > self.havocbot_cantfindflag)
269 // Can't navigate to my own base, suicide!
270 // TODO: drop it and wander around
271 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
277 void havocbot_role_ctf_escort()
281 if(self.deadflag != DEAD_NO)
283 havocbot_ctf_reset_role(self);
287 if (self.flagcarried)
289 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
293 // If enemy flag is back on the base switch to previous role
294 ef = havocbot_ctf_find_enemy_flag(self);
295 if(ef.cnt==FLAG_BASE)
297 self.havocbot_role = self.havocbot_previous_role;
298 self.havocbot_role_timeout = 0;
302 // If the flag carrier reached the base switch to defense
303 mf = havocbot_ctf_find_flag(self);
304 if(mf.cnt!=FLAG_BASE)
305 if(vlen(ef.origin - mf.dropped_origin) < 300)
307 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_DEFENSE);
311 // Set the role timeout if necessary
312 if (!self.havocbot_role_timeout)
314 self.havocbot_role_timeout = time + random() * 30 + 60;
317 // If nothing happened just switch to previous role
318 if (time > self.havocbot_role_timeout)
320 self.havocbot_role = self.havocbot_previous_role;
321 self.havocbot_role_timeout = 0;
325 // Chase the flag carrier
326 if (self.bot_strategytime < time)
328 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
329 navigation_goalrating_start();
330 havocbot_goalrating_ctf_enemyflag(30000);
331 havocbot_goalrating_ctf_ourstolenflag(40000);
332 havocbot_goalrating_items(10000, self.origin, 10000);
333 navigation_goalrating_end();
337 void havocbot_role_ctf_offense()
342 if(self.deadflag != DEAD_NO)
344 havocbot_ctf_reset_role(self);
348 if (self.flagcarried)
350 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
355 mf = havocbot_ctf_find_flag(self);
356 ef = havocbot_ctf_find_enemy_flag(self);
359 if(mf.cnt!=FLAG_BASE)
362 pos = mf.tag_entity.origin;
366 // Try to get it if closer than the enemy base
367 if(vlen(self.origin-ef.dropped_origin)>vlen(self.origin-pos))
369 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
374 // Escort flag carrier
375 if(ef.cnt!=FLAG_BASE)
378 pos = ef.tag_entity.origin;
382 if(vlen(pos-mf.dropped_origin)>700)
384 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_ESCORT);
389 // About to fail, switch to middlefield
392 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_MIDDLE);
396 // Set the role timeout if necessary
397 if (!self.havocbot_role_timeout)
398 self.havocbot_role_timeout = time + 120;
400 if (time > self.havocbot_role_timeout)
402 havocbot_ctf_reset_role(self);
406 if (self.bot_strategytime < time)
408 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
409 navigation_goalrating_start();
410 havocbot_goalrating_ctf_ourstolenflag(50000);
411 havocbot_goalrating_ctf_enemybase(20000);
412 havocbot_goalrating_items(5000, self.origin, 1000);
413 havocbot_goalrating_items(1000, self.origin, 10000);
414 navigation_goalrating_end();
418 // Retriever (temporary role):
419 void havocbot_role_ctf_retriever()
423 if(self.deadflag != DEAD_NO)
425 havocbot_ctf_reset_role(self);
429 if (self.flagcarried)
431 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
435 // If flag is back on the base switch to previous role
436 mf = havocbot_ctf_find_flag(self);
437 if(mf.cnt==FLAG_BASE)
439 havocbot_ctf_reset_role(self);
443 if (!self.havocbot_role_timeout)
444 self.havocbot_role_timeout = time + 20;
446 if (time > self.havocbot_role_timeout)
448 havocbot_ctf_reset_role(self);
452 if (self.bot_strategytime < time)
457 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
458 navigation_goalrating_start();
459 havocbot_goalrating_ctf_ourstolenflag(50000);
460 havocbot_goalrating_ctf_droppedflags(40000, self.origin, radius);
461 havocbot_goalrating_ctf_enemybase(30000);
462 havocbot_goalrating_items(500, self.origin, radius);
463 navigation_goalrating_end();
467 void havocbot_role_ctf_middle()
471 if(self.deadflag != DEAD_NO)
473 havocbot_ctf_reset_role(self);
477 if (self.flagcarried)
479 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
483 mf = havocbot_ctf_find_flag(self);
484 if(mf.cnt!=FLAG_BASE)
486 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
490 if (!self.havocbot_role_timeout)
491 self.havocbot_role_timeout = time + 10;
493 if (time > self.havocbot_role_timeout)
495 havocbot_ctf_reset_role(self);
499 if (self.bot_strategytime < time)
503 org = havocbot_ctf_middlepoint;
504 org_z = self.origin_z;
506 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
507 navigation_goalrating_start();
508 havocbot_goalrating_ctf_ourstolenflag(50000);
509 havocbot_goalrating_ctf_droppedflags(30000, self.origin, 10000);
510 havocbot_goalrating_enemyplayers(10000, org, havocbot_ctf_middlepoint_radius * 0.5);
511 havocbot_goalrating_items(5000, org, havocbot_ctf_middlepoint_radius * 0.5);
512 havocbot_goalrating_items(2500, self.origin, 10000);
513 havocbot_goalrating_ctf_enemybase(2500);
514 navigation_goalrating_end();
518 void havocbot_role_ctf_defense()
522 if(self.deadflag != DEAD_NO)
524 havocbot_ctf_reset_role(self);
528 if (self.flagcarried)
530 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
534 // If own flag was captured
535 mf = havocbot_ctf_find_flag(self);
536 if(mf.cnt!=FLAG_BASE)
538 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
542 if (!self.havocbot_role_timeout)
543 self.havocbot_role_timeout = time + 30;
545 if (time > self.havocbot_role_timeout)
547 havocbot_ctf_reset_role(self);
550 if (self.bot_strategytime < time)
555 org = mf.dropped_origin;
556 radius = havocbot_ctf_middlepoint_radius;
558 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
559 navigation_goalrating_start();
561 // if enemies are closer to our base, go there
562 local entity head, closestplayer;
563 local float distance, bestdistance;
565 FOR_EACH_PLAYER(head)
567 if(head.deadflag!=DEAD_NO)
570 distance = vlen(org - head.origin);
571 if(distance<bestdistance)
573 closestplayer = head;
574 bestdistance = distance;
579 if(closestplayer.team!=self.team)
580 if(vlen(org - self.origin)>1000)
581 if(checkpvs(self.origin,closestplayer)||random()<0.5)
582 havocbot_goalrating_ctf_ourbase(30000);
584 havocbot_goalrating_ctf_ourstolenflag(20000);
585 havocbot_goalrating_ctf_droppedflags(20000, org, radius);
586 havocbot_goalrating_enemyplayers(15000, org, radius);
587 havocbot_goalrating_items(10000, org, radius);
588 havocbot_goalrating_items(5000, self.origin, 10000);
589 navigation_goalrating_end();
593 void havocbot_calculate_middlepoint()
598 f = ctf_worldflaglist;
606 f = f.ctf_worldflagnext;
608 havocbot_ctf_middlepoint = p1 + ((p2-p1) * 0.5);
609 havocbot_ctf_middlepoint_radius = vlen(p2-p1) * 0.5;
612 void havocbot_ctf_reset_role(entity bot)
614 local float cdefense, cmiddle, coffense;
615 local entity mf, ef, head;
618 if(bot.deadflag != DEAD_NO)
621 if(vlen(havocbot_ctf_middlepoint)==0)
622 havocbot_calculate_middlepoint();
627 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_CARRIER);
631 mf = havocbot_ctf_find_flag(bot);
632 ef = havocbot_ctf_find_enemy_flag(bot);
634 // Retrieve stolen flag
635 if(mf.cnt!=FLAG_BASE)
637 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_RETRIEVER);
641 // If enemy flag is taken go to the middle to intercept pursuers
642 if(ef.cnt!=FLAG_BASE)
644 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
648 // if there is only me on the team switch to offense
650 FOR_EACH_PLAYER(head)
651 if(head.team==bot.team)
656 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
660 // Evaluate best position to take
661 // Count mates on middle position
662 cmiddle = havocbot_ctf_teamcount(bot, havocbot_ctf_middlepoint, havocbot_ctf_middlepoint_radius * 0.5);
664 // Count mates on defense position
665 cdefense = havocbot_ctf_teamcount(bot, mf.dropped_origin, havocbot_ctf_middlepoint_radius * 0.5);
667 // Count mates on offense position
668 coffense = havocbot_ctf_teamcount(bot, ef.dropped_origin, havocbot_ctf_middlepoint_radius);
670 if(cdefense<=coffense)
671 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_DEFENSE);
672 else if(coffense<=cmiddle)
673 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
675 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
678 void havocbot_chooserole_ctf()
680 havocbot_ctf_reset_role(self);