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 local float t, i, c, needarmor, needweapons;
33 // Needs armor/health?
38 for(i = WEP_FIRST; i <= WEP_LAST ; ++i)
41 if(power2of(i-1) & self.weapons)
49 if(!needweapons && !needarmor)
52 // dprint(self.netname, " needs weapons ", ftos(needweapons) , "\n");
53 // dprint(self.netname, " needs armor ", ftos(needarmor) , "\n");
56 head = findchainfloat(bot_pickup, TRUE);
59 // gather health and armor only
61 if ( ((head.health || head.armorvalue) && needarmor) || (head.weapons && needweapons ) )
62 if (vlen(head.origin - org) < sradius)
64 t = head.bot_pickupevalfunc(self, head);
66 navigation_routerating(head, t * ratingscale, 500);
72 void havocbot_role_ons_setrole(entity bot, float role)
74 dprint(strcat(bot.netname," switched to "));
77 case HAVOCBOT_ONS_ROLE_DEFENSE:
79 bot.havocbot_role = havocbot_role_ons_defense;
80 bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
81 bot.havocbot_role_timeout = 0;
83 case HAVOCBOT_ONS_ROLE_ASSISTANT:
85 bot.havocbot_role = havocbot_role_ons_assistant;
86 bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
87 bot.havocbot_role_timeout = 0;
89 case HAVOCBOT_ONS_ROLE_OFFENSE:
91 bot.havocbot_role = havocbot_role_ons_offense;
92 bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
93 bot.havocbot_role_timeout = 0;
99 float havocbot_ons_teamcount(entity bot, float role)
104 FOR_EACH_PLAYER(head)
105 if(head.team==self.team)
106 if(head.havocbot_role_flags & role)
112 void havocbot_goalrating_ons_controlpoints_attack(float ratingscale)
114 entity cp, cp1, cp2, best, pl, wp;
115 float radius, found, bestvalue, c;
117 cp1 = cp2 = findchain(classname, "onslaught_controlpoint");
119 // Filter control points
120 for (; cp2; cp2 = cp2.chain)
123 cp2.wpconsidered = FALSE;
128 // Ignore owned controlpoints
129 if(self.team == COLOR_TEAM1)
131 if( (cp2.isgenneighbor_blue || cp2.iscpneighbor_blue) && !(cp2.isgenneighbor_red || cp2.iscpneighbor_red) )
134 else if(self.team == COLOR_TEAM2)
136 if( (cp2.isgenneighbor_red || cp2.iscpneighbor_red) && !(cp2.isgenneighbor_blue || cp2.iscpneighbor_blue) )
140 // Count team mates interested in this control point
141 // (easier and cleaner than keeping counters per cp and teams)
143 if(pl.team==self.team)
144 if(pl.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
145 if(pl.havocbot_ons_target==cp2)
148 // NOTE: probably decrease the cost of attackable control points
150 cp2.wpconsidered = TRUE;
153 // We'll consider only the best case
154 bestvalue = 99999999999;
155 for (; cp1; cp1 = cp1.chain)
157 if not(cp1.wpconsidered)
160 if(cp1.wpcost<bestvalue)
162 bestvalue = cp1.wpcost;
164 self.havocbot_ons_target = cp1;
171 // dprint(self.netname, " chose cp ranked ", ftos(bestvalue), "\n");
175 // Should be attacked
176 // Rate waypoints near it
179 bestvalue = 99999999999;
180 for(radius=0; radius<1000 && !found; radius+=500)
182 for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
184 if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
185 if(wp.classname=="waypoint")
186 if(checkpvs(wp.origin,cp))
200 navigation_routerating(best, ratingscale, 10000);
203 self.havocbot_attack_time = 0;
204 if(checkpvs(self.view_ofs,cp))
205 if(checkpvs(self.view_ofs,best))
206 self.havocbot_attack_time = time + 2;
210 navigation_routerating(cp, ratingscale, 10000);
212 // dprint(self.netname, " found an attackable controlpoint at ", vtos(cp.origin) ,"\n");
217 // dprint(self.netname, " found a touchable controlpoint at ", vtos(cp.origin) ,"\n");
219 // Look for auto generated waypoint
220 if not(bot_waypoints_for_items)
221 for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
223 if(wp.classname=="waypoint")
225 navigation_routerating(wp, ratingscale, 10000);
230 // Nothing found, rate the controlpoint itself
232 navigation_routerating(cp, ratingscale, 10000);
236 float havocbot_goalrating_ons_generator_attack(float ratingscale)
238 local entity g, wp, bestwp;
239 local float found, best;
241 for (g = findchain(classname, "onslaught_generator"); g; g = g.chain)
243 if(g.team == self.team || g.isshielded)
246 // Should be attacked
247 // Rate waypoints near it
252 for(wp=findradius(g.origin,400); wp; wp=wp.chain)
254 if(wp.classname=="waypoint")
255 if(checkpvs(wp.origin,g))
268 // dprint("waypoints found around generator\n");
269 navigation_routerating(bestwp, ratingscale, 10000);
272 self.havocbot_attack_time = 0;
273 if(checkpvs(self.view_ofs,g))
274 if(checkpvs(self.view_ofs,bestwp))
275 self.havocbot_attack_time = time + 5;
281 // dprint("generator found without waypoints around\n");
282 // if there aren't waypoints near the generator go straight to it
283 navigation_routerating(g, ratingscale, 10000);
284 self.havocbot_attack_time = 0;
291 void havocbot_role_ons_offense()
293 if(self.deadflag != DEAD_NO)
295 self.havocbot_attack_time = 0;
296 havocbot_ons_reset_role(self);
300 // Set the role timeout if necessary
301 if (!self.havocbot_role_timeout)
302 self.havocbot_role_timeout = time + 120;
304 if (time > self.havocbot_role_timeout)
306 havocbot_ons_reset_role(self);
310 if(self.havocbot_attack_time>time)
313 if (self.bot_strategytime < time)
315 navigation_goalrating_start();
316 havocbot_goalrating_enemyplayers(20000, self.origin, 650);
317 if(!havocbot_goalrating_ons_generator_attack(20000))
318 havocbot_goalrating_ons_controlpoints_attack(20000);
319 havocbot_goalrating_ons_offenseitems(10000, self.origin, 10000);
320 navigation_goalrating_end();
322 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
326 void havocbot_role_ons_assistant()
328 havocbot_ons_reset_role(self);
331 void havocbot_role_ons_defense()
333 havocbot_ons_reset_role(self);
336 void havocbot_ons_reset_role(entity bot)
341 if(self.deadflag != DEAD_NO)
344 bot.havocbot_ons_target = world;
346 // TODO: Defend control points or generator if necessary
348 // if there is only me on the team switch to offense
350 FOR_EACH_PLAYER(head)
351 if(head.team==self.team)
356 havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
360 havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
363 void havocbot_chooserole_ons()
365 havocbot_ons_reset_role(self);