1 #define HAVOCBOT_ONS_ROLE_NONE 0
2 #define HAVOCBOT_ONS_ROLE_DEFENSE 2
3 #define HAVOCBOT_ONS_ROLE_ASSISTANT 4
4 #define HAVOCBOT_ONS_ROLE_OFFENSE 8
6 .float havocbot_role_flags;
7 .float havocbot_attack_time;
10 .void() havocbot_previous_role;
12 void() havocbot_role_ons_defense;
13 void() havocbot_role_ons_offense;
14 void() havocbot_role_ons_assistant;
16 void(entity bot) havocbot_ons_reset_role;
17 void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
18 void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
23 .float isgenneighbor_blue, iscpneighbor_blue;
24 .float isgenneighbor_red, iscpneighbor_red;
26 .entity havocbot_ons_target;
28 void havocbot_goalrating_ons_offenseitems(float ratingscale, vector org, float sradius)
31 float t, i, c, needarmor = FALSE, needweapons = FALSE;
33 // Needs armor/health?
39 for(i = WEP_FIRST; i <= WEP_LAST ; ++i)
42 if(WEPSET_CONTAINS_EW(self, i))
50 if(!needweapons && !needarmor)
53 // dprint(self.netname, " needs weapons ", ftos(needweapons) , "\n");
54 // dprint(self.netname, " needs armor ", ftos(needarmor) , "\n");
57 head = findchainfloat(bot_pickup, TRUE);
60 // gather health and armor only
62 if ( ((head.health || head.armorvalue) && needarmor) || (!WEPSET_EMPTY_E(head) && needweapons ) )
63 if (vlen(head.origin - org) < sradius)
65 t = head.bot_pickupevalfunc(self, head);
67 navigation_routerating(head, t * ratingscale, 500);
73 void havocbot_role_ons_setrole(entity bot, float role)
75 dprint(strcat(bot.netname," switched to "));
78 case HAVOCBOT_ONS_ROLE_DEFENSE:
80 bot.havocbot_role = havocbot_role_ons_defense;
81 bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
82 bot.havocbot_role_timeout = 0;
84 case HAVOCBOT_ONS_ROLE_ASSISTANT:
86 bot.havocbot_role = havocbot_role_ons_assistant;
87 bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
88 bot.havocbot_role_timeout = 0;
90 case HAVOCBOT_ONS_ROLE_OFFENSE:
92 bot.havocbot_role = havocbot_role_ons_offense;
93 bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
94 bot.havocbot_role_timeout = 0;
100 float havocbot_ons_teamcount(entity bot, float role)
105 FOR_EACH_PLAYER(head)
106 if(head.team==self.team)
107 if(head.havocbot_role_flags & role)
113 void havocbot_goalrating_ons_controlpoints_attack(float ratingscale)
115 entity cp, cp1, cp2, best, pl, wp;
116 float radius, found, bestvalue, c;
118 cp1 = cp2 = findchain(classname, "onslaught_controlpoint");
120 // Filter control points
121 for (; cp2; cp2 = cp2.chain)
124 cp2.wpconsidered = FALSE;
129 // Ignore owned controlpoints
130 if(self.team == COLOR_TEAM1)
132 if( (cp2.isgenneighbor_blue || cp2.iscpneighbor_blue) && !(cp2.isgenneighbor_red || cp2.iscpneighbor_red) )
135 else if(self.team == COLOR_TEAM2)
137 if( (cp2.isgenneighbor_red || cp2.iscpneighbor_red) && !(cp2.isgenneighbor_blue || cp2.iscpneighbor_blue) )
141 // Count team mates interested in this control point
142 // (easier and cleaner than keeping counters per cp and teams)
144 if(pl.team==self.team)
145 if(pl.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
146 if(pl.havocbot_ons_target==cp2)
149 // NOTE: probably decrease the cost of attackable control points
151 cp2.wpconsidered = TRUE;
154 // We'll consider only the best case
155 bestvalue = 99999999999;
157 for (; cp1; cp1 = cp1.chain)
159 if not(cp1.wpconsidered)
162 if(cp1.wpcost<bestvalue)
164 bestvalue = cp1.wpcost;
166 self.havocbot_ons_target = cp1;
173 // dprint(self.netname, " chose cp ranked ", ftos(bestvalue), "\n");
177 // Should be attacked
178 // Rate waypoints near it
181 bestvalue = 99999999999;
182 for(radius=0; radius<1000 && !found; radius+=500)
184 for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
186 if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
187 if(wp.classname=="waypoint")
188 if(checkpvs(wp.origin,cp))
202 navigation_routerating(best, ratingscale, 10000);
205 self.havocbot_attack_time = 0;
206 if(checkpvs(self.view_ofs,cp))
207 if(checkpvs(self.view_ofs,best))
208 self.havocbot_attack_time = time + 2;
212 navigation_routerating(cp, ratingscale, 10000);
214 // dprint(self.netname, " found an attackable controlpoint at ", vtos(cp.origin) ,"\n");
219 // dprint(self.netname, " found a touchable controlpoint at ", vtos(cp.origin) ,"\n");
221 // Look for auto generated waypoint
222 if not(bot_waypoints_for_items)
223 for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
225 if(wp.classname=="waypoint")
227 navigation_routerating(wp, ratingscale, 10000);
232 // Nothing found, rate the controlpoint itself
234 navigation_routerating(cp, ratingscale, 10000);
238 float havocbot_goalrating_ons_generator_attack(float ratingscale)
240 entity g, wp, bestwp;
243 for (g = findchain(classname, "onslaught_generator"); g; g = g.chain)
245 if(g.team == self.team || g.isshielded)
248 // Should be attacked
249 // Rate waypoints near it
254 for(wp=findradius(g.origin,400); wp; wp=wp.chain)
256 if(wp.classname=="waypoint")
257 if(checkpvs(wp.origin,g))
270 // dprint("waypoints found around generator\n");
271 navigation_routerating(bestwp, ratingscale, 10000);
274 self.havocbot_attack_time = 0;
275 if(checkpvs(self.view_ofs,g))
276 if(checkpvs(self.view_ofs,bestwp))
277 self.havocbot_attack_time = time + 5;
283 // dprint("generator found without waypoints around\n");
284 // if there aren't waypoints near the generator go straight to it
285 navigation_routerating(g, ratingscale, 10000);
286 self.havocbot_attack_time = 0;
293 void havocbot_role_ons_offense()
295 if(self.deadflag != DEAD_NO)
297 self.havocbot_attack_time = 0;
298 havocbot_ons_reset_role(self);
302 // Set the role timeout if necessary
303 if (!self.havocbot_role_timeout)
304 self.havocbot_role_timeout = time + 120;
306 if (time > self.havocbot_role_timeout)
308 havocbot_ons_reset_role(self);
312 if(self.havocbot_attack_time>time)
315 if (self.bot_strategytime < time)
317 navigation_goalrating_start();
318 havocbot_goalrating_enemyplayers(20000, self.origin, 650);
319 if(!havocbot_goalrating_ons_generator_attack(20000))
320 havocbot_goalrating_ons_controlpoints_attack(20000);
321 havocbot_goalrating_ons_offenseitems(10000, self.origin, 10000);
322 navigation_goalrating_end();
324 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
328 void havocbot_role_ons_assistant()
330 havocbot_ons_reset_role(self);
333 void havocbot_role_ons_defense()
335 havocbot_ons_reset_role(self);
338 void havocbot_ons_reset_role(entity bot)
343 if(self.deadflag != DEAD_NO)
346 bot.havocbot_ons_target = world;
348 // TODO: Defend control points or generator if necessary
350 // if there is only me on the team switch to offense
352 FOR_EACH_PLAYER(head)
353 if(head.team==self.team)
358 havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
362 havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
365 void havocbot_chooserole_ons()
367 havocbot_ons_reset_role(self);