2 #define HAVOCBOT_ROLE_NONE 0
\r
3 #define HAVOCBOT_CTF_ROLE_DEFENSE 2
\r
4 #define HAVOCBOT_CTF_ROLE_MIDDLE 4
\r
5 #define HAVOCBOT_CTF_ROLE_OFFENSE 8
\r
6 #define HAVOCBOT_CTF_ROLE_CARRIER 16
\r
7 #define HAVOCBOT_CTF_ROLE_RETRIEVER 32
\r
8 #define HAVOCBOT_CTF_ROLE_ESCORT 64
\r
10 .void() havocbot_role;
11 .void() havocbot_previous_role;
13 void() havocbot_role_ctf_middle;
14 void() havocbot_role_ctf_defense;
15 void() havocbot_role_ctf_offense;
16 void() havocbot_role_ctf_carrier;
17 void() havocbot_role_ctf_retriever;
18 void() havocbot_role_ctf_escort;
20 void(entity bot) havocbot_ctf_reset_role;
21 void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
22 void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
24 .float havocbot_cantfindflag;
25 .float havocbot_role_timeout;
26 .entity ctf_worldflagnext;
28 vector havocbot_ctf_middlepoint;
29 float havocbot_ctf_middlepoint_radius;
30 entity ctf_worldflaglist;
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)
\r
60 if not(teams_matter)
\r
66 FOR_EACH_PLAYER(head)
\r
68 if(head.team!=bot.team || head.deadflag != DEAD_NO || head == bot)
\r
71 if(vlen(head.origin - org) < radius)
\r
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)
94 if not(bot_waypoints_for_items)
96 havocbot_goalrating_ctf_ourflag(ratingscale);
101 head = ctf_worldflaglist;
104 if (self.team == head.team)
106 head = head.ctf_worldflagnext;
111 // dropped_origin is set by ctf code whenever the flag is picked up
112 head = findradius(head.dropped_origin, 100);
115 if(head.classname=="waypoint")
117 navigation_routerating(head, ratingscale, 10000);
124 void havocbot_goalrating_ctf_enemyflag(float ratingscale)
127 head = ctf_worldflaglist;
130 if (self.team != head.team)
132 head = head.ctf_worldflagnext;
135 navigation_routerating(head, ratingscale, 10000);
138 void havocbot_goalrating_ctf_enemybase(float ratingscale)
140 if not(bot_waypoints_for_items)
142 havocbot_goalrating_ctf_enemyflag(ratingscale);
148 head = havocbot_ctf_find_enemy_flag(self);
153 head = findradius(head.dropped_origin, 100);
156 if(head.classname=="waypoint")
158 navigation_routerating(head, ratingscale, 10000);
165 void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
169 mf = havocbot_ctf_find_flag(self);
171 if(mf.cnt == FLAG_BASE)
174 navigation_routerating(mf, ratingscale, 10000);
177 void havocbot_goalrating_ctf_droppedflags(float ratingscale, vector org, float radius)
180 head = ctf_worldflaglist;
183 // flag is out in the field
184 if(head.cnt != FLAG_BASE)
185 if(head.tag_entity==world) // dropped
189 if(vlen(org-head.origin)<radius)
190 navigation_routerating(head, ratingscale, 10000);
193 navigation_routerating(head, ratingscale, 10000);
196 head = head.ctf_worldflagnext;
200 void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
204 head = findchainfloat(bot_pickup, TRUE);
207 // gather health and armor only
209 if (head.health || head.armorvalue)
210 if (vlen(head.origin - org) < sradius)
212 // get the value of the item
213 t = head.bot_pickupevalfunc(self, head) * 0.0001;
215 navigation_routerating(head, t * ratingscale, 500);
221 void havocbot_role_ctf_setrole(entity bot, float role)
\r
223 dprint(strcat(bot.netname," switched to "));
\r
226 case HAVOCBOT_CTF_ROLE_CARRIER:
\r
228 bot.havocbot_role = havocbot_role_ctf_carrier;
\r
229 bot.havocbot_role_timeout = 0;
\r
230 bot.havocbot_cantfindflag = time + 10;
\r
232 case HAVOCBOT_CTF_ROLE_DEFENSE:
\r
234 bot.havocbot_role = havocbot_role_ctf_defense;
\r
235 bot.havocbot_role_timeout = 0;
\r
237 case HAVOCBOT_CTF_ROLE_MIDDLE:
\r
239 bot.havocbot_role = havocbot_role_ctf_middle;
\r
240 bot.havocbot_role_timeout = 0;
\r
242 case HAVOCBOT_CTF_ROLE_OFFENSE:
\r
244 bot.havocbot_role = havocbot_role_ctf_offense;
\r
245 bot.havocbot_role_timeout = 0;
\r
247 case HAVOCBOT_CTF_ROLE_RETRIEVER:
\r
249 bot.havocbot_previous_role = bot.havocbot_role;
\r
250 bot.havocbot_role = havocbot_role_ctf_retriever;
\r
251 bot.havocbot_role_timeout = time + 10;
\r
253 case HAVOCBOT_CTF_ROLE_ESCORT:
\r
255 bot.havocbot_previous_role = bot.havocbot_role;
\r
256 bot.havocbot_role = havocbot_role_ctf_escort;
\r
257 bot.havocbot_role_timeout = time + 30;
\r
263 void havocbot_role_ctf_carrier()
\r
265 if(self.deadflag != DEAD_NO)
267 havocbot_ctf_reset_role(self);
\r
271 if (self.flagcarried == world)
\r
273 havocbot_ctf_reset_role(self);
\r
277 if (self.bot_strategytime < time)
\r
279 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
\r
281 navigation_goalrating_start();
\r
282 havocbot_goalrating_ctf_ourbase(50000);
\r
284 if(self.health<100)
\r
285 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
\r
287 navigation_goalrating_end();
\r
289 if (self.navigation_hasgoals)
\r
290 self.havocbot_cantfindflag = time + 10;
\r
291 else if (time > self.havocbot_cantfindflag)
\r
293 // Can't navigate to my own base, suicide!
\r
294 // TODO: drop it and wander around
\r
295 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
\r
301 void havocbot_role_ctf_escort()
\r
303 local entity mf, ef;
\r
305 if(self.deadflag != DEAD_NO)
307 havocbot_ctf_reset_role(self);
\r
311 if (self.flagcarried)
\r
313 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
\r
317 // If enemy flag is back on the base switch to previous role
\r
318 ef = havocbot_ctf_find_enemy_flag(self);
\r
319 if(ef.cnt==FLAG_BASE)
\r
321 self.havocbot_role = self.havocbot_previous_role;
\r
322 self.havocbot_role_timeout = 0;
\r
326 // If the flag carrier reached the base switch to defense
\r
327 mf = havocbot_ctf_find_flag(self);
\r
328 if(mf.cnt!=FLAG_BASE)
\r
329 if(vlen(ef.origin - mf.dropped_origin) < 300)
\r
331 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_DEFENSE);
\r
335 // Set the role timeout if necessary
\r
336 if (!self.havocbot_role_timeout)
338 self.havocbot_role_timeout = time + random() * 30 + 60;
341 // If nothing happened just switch to previous role
\r
342 if (time > self.havocbot_role_timeout)
\r
344 self.havocbot_role = self.havocbot_previous_role;
\r
345 self.havocbot_role_timeout = 0;
\r
349 // Chase the flag carrier
\r
350 if (self.bot_strategytime < time)
\r
352 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
\r
353 navigation_goalrating_start();
\r
354 havocbot_goalrating_ctf_enemyflag(30000);
\r
355 havocbot_goalrating_ctf_ourstolenflag(40000);
\r
356 havocbot_goalrating_items(10000, self.origin, 10000);
\r
357 navigation_goalrating_end();
\r
361 void havocbot_role_ctf_offense()
\r
366 if(self.deadflag != DEAD_NO)
368 havocbot_ctf_reset_role(self);
\r
372 if (self.flagcarried)
\r
374 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
\r
379 mf = havocbot_ctf_find_flag(self);
\r
380 ef = havocbot_ctf_find_enemy_flag(self);
\r
383 if(mf.cnt!=FLAG_BASE)
\r
386 pos = mf.tag_entity.origin;
390 // Try to get it if closer than the enemy base
391 if(vlen(self.origin-ef.dropped_origin)>vlen(self.origin-pos))
\r
393 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
\r
398 // Escort flag carrier
399 if(ef.cnt!=FLAG_BASE)
402 pos = ef.tag_entity.origin;
406 if(vlen(pos-mf.dropped_origin)>700)
\r
408 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_ESCORT);
\r
413 // About to fail, switch to middlefield
\r
416 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_MIDDLE);
\r
420 // Set the role timeout if necessary
\r
421 if (!self.havocbot_role_timeout)
\r
422 self.havocbot_role_timeout = time + 120;
\r
424 if (time > self.havocbot_role_timeout)
\r
426 havocbot_ctf_reset_role(self);
\r
430 if (self.bot_strategytime < time)
\r
432 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
\r
433 navigation_goalrating_start();
\r
434 havocbot_goalrating_ctf_ourstolenflag(50000);
\r
435 havocbot_goalrating_ctf_enemybase(20000);
\r
436 havocbot_goalrating_items(5000, self.origin, 1000);
437 havocbot_goalrating_items(1000, self.origin, 10000);
\r
438 navigation_goalrating_end();
\r
442 // Retriever (temporary role):
\r
443 void havocbot_role_ctf_retriever()
\r
447 if(self.deadflag != DEAD_NO)
449 havocbot_ctf_reset_role(self);
\r
453 if (self.flagcarried)
\r
455 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
\r
459 // If flag is back on the base switch to previous role
\r
460 mf = havocbot_ctf_find_flag(self);
461 if(mf.cnt==FLAG_BASE)
\r
463 havocbot_ctf_reset_role(self);
\r
467 if (!self.havocbot_role_timeout)
468 self.havocbot_role_timeout = time + random() * 30 + 60;
470 if (time > self.havocbot_role_timeout)
472 havocbot_ctf_reset_role(self);
476 if (self.bot_strategytime < time)
\r
478 local float radius;
\r
481 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
482 navigation_goalrating_start();
483 havocbot_goalrating_ctf_ourstolenflag(50000);
484 havocbot_goalrating_ctf_droppedflags(40000, self.origin, radius);
485 havocbot_goalrating_ctf_enemybase(30000);
486 havocbot_goalrating_items(5000, self.origin, radius);
\r
487 navigation_goalrating_end();
491 void havocbot_role_ctf_middle()
\r
495 if(self.deadflag != DEAD_NO)
497 havocbot_ctf_reset_role(self);
\r
501 if (self.flagcarried)
\r
503 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
\r
507 mf = havocbot_ctf_find_flag(self);
\r
508 if(mf.cnt!=FLAG_BASE)
\r
510 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
\r
514 if (!self.havocbot_role_timeout)
\r
515 self.havocbot_role_timeout = time + 10;
\r
517 if (time > self.havocbot_role_timeout)
\r
519 havocbot_ctf_reset_role(self);
\r
523 if (self.bot_strategytime < time)
\r
525 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
\r
526 navigation_goalrating_start();
\r
527 havocbot_goalrating_ctf_ourstolenflag(50000);
\r
528 havocbot_goalrating_ctf_droppedflags(30000, self.origin, 10000);
\r
529 havocbot_goalrating_enemyplayers(10000, havocbot_ctf_middlepoint, havocbot_ctf_middlepoint_radius * 0.5);
\r
530 havocbot_goalrating_items(5000, havocbot_ctf_middlepoint, havocbot_ctf_middlepoint_radius * 0.5);
531 havocbot_goalrating_items(2500, self.origin, 10000);
532 havocbot_goalrating_ctf_enemybase(2500);
533 navigation_goalrating_end();
\r
537 void havocbot_role_ctf_defense()
\r
541 if(self.deadflag != DEAD_NO)
543 havocbot_ctf_reset_role(self);
\r
547 if (self.flagcarried)
\r
549 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
\r
553 // If own flag was captured
\r
554 mf = havocbot_ctf_find_flag(self);
\r
555 if(mf.cnt!=FLAG_BASE)
\r
557 // And its located as far as about half the distance between the two bases
\r
558 if(vlen(self.origin-mf.origin)<havocbot_ctf_middlepoint_radius*1.2)
\r
559 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
\r
563 if (!self.havocbot_role_timeout)
\r
564 self.havocbot_role_timeout = time + 30;
\r
566 if (time > self.havocbot_role_timeout)
\r
568 havocbot_ctf_reset_role(self);
\r
571 if (self.bot_strategytime < time)
\r
576 org = mf.dropped_origin;
577 radius = havocbot_ctf_middlepoint_radius;
\r
579 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
\r
580 navigation_goalrating_start();
\r
581 havocbot_goalrating_ctf_ourstolenflag(200000);
\r
582 havocbot_goalrating_ctf_droppedflags(50000, org, radius);
\r
583 havocbot_goalrating_enemyplayers(20000, org, radius);
584 havocbot_goalrating_items(10000, org, radius);
\r
585 navigation_goalrating_end();
\r
589 void havocbot_calculate_middlepoint()
\r
594 f = ctf_worldflaglist;
\r
602 f = f.ctf_worldflagnext;
\r
604 havocbot_ctf_middlepoint = p1 + ((p2-p1) * 0.5);
605 havocbot_ctf_middlepoint_radius = vlen(p2-p1) * 0.5;
\r
608 void havocbot_ctf_reset_role(entity bot)
\r
610 local float cdefense, cmiddle, coffense;
\r
611 local entity mf, ef;
\r
613 if(self.deadflag != DEAD_NO)
616 if(vlen(havocbot_ctf_middlepoint)==0)
617 havocbot_calculate_middlepoint();
620 if (self.flagcarried)
622 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
626 mf = havocbot_ctf_find_flag(bot);
\r
627 ef = havocbot_ctf_find_enemy_flag(bot);
\r
629 // Retrieve stolen flag
\r
630 if(mf.cnt!=FLAG_BASE)
\r
632 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_RETRIEVER);
\r
636 // Go to the middle to intercept pursuers
\r
637 if(ef.cnt!=FLAG_BASE)
\r
639 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
\r
643 // Evaluate best position to take
\r
644 // Count mates on middle position
\r
645 cmiddle = havocbot_ctf_teamcount(bot, havocbot_ctf_middlepoint, havocbot_ctf_middlepoint_radius * 0.5);
\r
647 // Count mates on defense position
\r
648 cdefense = havocbot_ctf_teamcount(bot, mf.dropped_origin, havocbot_ctf_middlepoint_radius * 0.5);
\r
650 // Count mates on offense position
\r
651 coffense = havocbot_ctf_teamcount(bot, ef.dropped_origin, havocbot_ctf_middlepoint_radius);
\r
653 if(cdefense<=coffense)
\r
654 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_DEFENSE);
\r
655 else if(coffense<=cmiddle)
\r
656 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
\r
658 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
\r
661 void havocbot_chooserole_ctf()
\r
663 havocbot_ctf_reset_role(self);
\r