6 #include "../navigation.qh"
7 #include "../waypoints.qh"
9 #include "../../mutators/mutators_include.qh"
11 #include "../../../common/teams.qh"
13 const int HAVOCBOT_ONS_ROLE_NONE = 0;
14 const int HAVOCBOT_ONS_ROLE_DEFENSE = 2;
15 const int HAVOCBOT_ONS_ROLE_ASSISTANT = 4;
16 const int HAVOCBOT_ONS_ROLE_OFFENSE = 8;
18 .int havocbot_role_flags;
19 .float havocbot_attack_time;
21 .void() havocbot_role;
22 .void() havocbot_previous_role;
24 void() havocbot_role_ons_defense;
25 void() havocbot_role_ons_offense;
26 void() havocbot_role_ons_assistant;
28 void(entity bot) havocbot_ons_reset_role;
29 void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
30 void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
35 .float isgenneighbor_blue, iscpneighbor_blue;
36 .float isgenneighbor_red, iscpneighbor_red;
38 .entity havocbot_ons_target;
40 void havocbot_goalrating_ons_offenseitems(float ratingscale, vector org, float sradius)
43 float t, i, c, needarmor = false, needweapons = false;
45 // Needs armor/health?
51 for(i = WEP_FIRST; i <= WEP_LAST ; ++i)
54 if(self.weapons & WepSet_FromWeapon(i))
62 if(!needweapons && !needarmor)
65 // dprint(self.netname, " needs weapons ", ftos(needweapons) , "\n");
66 // dprint(self.netname, " needs armor ", ftos(needarmor) , "\n");
69 head = findchainfloat(bot_pickup, true);
72 // gather health and armor only
74 if ( ((head.health || head.armorvalue) && needarmor) || (head.weapons && needweapons ) )
75 if (vlen(head.origin - org) < sradius)
77 t = head.bot_pickupevalfunc(self, head);
79 navigation_routerating(head, t * ratingscale, 500);
85 void havocbot_role_ons_setrole(entity bot, float role)
87 dprint(strcat(bot.netname," switched to "));
90 case HAVOCBOT_ONS_ROLE_DEFENSE:
92 bot.havocbot_role = havocbot_role_ons_defense;
93 bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
94 bot.havocbot_role_timeout = 0;
96 case HAVOCBOT_ONS_ROLE_ASSISTANT:
98 bot.havocbot_role = havocbot_role_ons_assistant;
99 bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
100 bot.havocbot_role_timeout = 0;
102 case HAVOCBOT_ONS_ROLE_OFFENSE:
104 bot.havocbot_role = havocbot_role_ons_offense;
105 bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
106 bot.havocbot_role_timeout = 0;
112 float havocbot_ons_teamcount(entity bot, int role)
117 FOR_EACH_PLAYER(head)
118 if(head.team==self.team)
119 if(head.havocbot_role_flags & role)
125 void havocbot_goalrating_ons_controlpoints_attack(float ratingscale)
127 entity cp, cp1, cp2, best, pl, wp;
128 float radius, found, bestvalue, c;
130 cp1 = cp2 = findchain(classname, "onslaught_controlpoint");
132 // Filter control points
133 for (; cp2; cp2 = cp2.chain)
136 cp2.wpconsidered = false;
141 // Ignore owned controlpoints
142 if(self.team == NUM_TEAM_1)
144 if( (cp2.isgenneighbor_blue || cp2.iscpneighbor_blue) && !(cp2.isgenneighbor_red || cp2.iscpneighbor_red) )
147 else if(self.team == NUM_TEAM_2)
149 if( (cp2.isgenneighbor_red || cp2.iscpneighbor_red) && !(cp2.isgenneighbor_blue || cp2.iscpneighbor_blue) )
153 // Count team mates interested in this control point
154 // (easier and cleaner than keeping counters per cp and teams)
156 if(pl.team==self.team)
157 if(pl.havocbot_role_flags & HAVOCBOT_ONS_ROLE_OFFENSE)
158 if(pl.havocbot_ons_target==cp2)
161 // NOTE: probably decrease the cost of attackable control points
163 cp2.wpconsidered = true;
166 // We'll consider only the best case
167 bestvalue = 99999999999;
169 for (; cp1; cp1 = cp1.chain)
171 if (!cp1.wpconsidered)
174 if(cp1.wpcost<bestvalue)
176 bestvalue = cp1.wpcost;
178 self.havocbot_ons_target = cp1;
185 // dprint(self.netname, " chose cp ranked ", ftos(bestvalue), "\n");
189 // Should be attacked
190 // Rate waypoints near it
193 bestvalue = 99999999999;
194 for(radius=0; radius<1000 && !found; radius+=500)
196 for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
198 if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
199 if(wp.classname=="waypoint")
200 if(checkpvs(wp.origin,cp))
214 navigation_routerating(best, ratingscale, 10000);
217 self.havocbot_attack_time = 0;
218 if(checkpvs(self.view_ofs,cp))
219 if(checkpvs(self.view_ofs,best))
220 self.havocbot_attack_time = time + 2;
224 navigation_routerating(cp, ratingscale, 10000);
226 // dprint(self.netname, " found an attackable controlpoint at ", vtos(cp.origin) ,"\n");
231 // dprint(self.netname, " found a touchable controlpoint at ", vtos(cp.origin) ,"\n");
234 // Look for auto generated waypoint
235 if (!bot_waypoints_for_items)
236 for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
238 if(wp.classname=="waypoint")
240 navigation_routerating(wp, ratingscale, 10000);
245 // Nothing found, rate the controlpoint itself
247 navigation_routerating(cp, ratingscale, 10000);
251 float havocbot_goalrating_ons_generator_attack(float ratingscale)
253 entity g, wp, bestwp;
256 for (g = findchain(classname, "onslaught_generator"); g; g = g.chain)
258 if(g.team == self.team || g.isshielded)
261 // Should be attacked
262 // Rate waypoints near it
267 for(wp=findradius(g.origin,400); wp; wp=wp.chain)
269 if(wp.classname=="waypoint")
270 if(checkpvs(wp.origin,g))
283 // dprint("waypoints found around generator\n");
284 navigation_routerating(bestwp, ratingscale, 10000);
287 self.havocbot_attack_time = 0;
288 if(checkpvs(self.view_ofs,g))
289 if(checkpvs(self.view_ofs,bestwp))
290 self.havocbot_attack_time = time + 5;
296 // dprint("generator found without waypoints around\n");
297 // if there aren't waypoints near the generator go straight to it
298 navigation_routerating(g, ratingscale, 10000);
299 self.havocbot_attack_time = 0;
306 void havocbot_role_ons_offense()
308 if(self.deadflag != DEAD_NO)
310 self.havocbot_attack_time = 0;
311 havocbot_ons_reset_role(self);
315 // Set the role timeout if necessary
316 if (!self.havocbot_role_timeout)
317 self.havocbot_role_timeout = time + 120;
319 if (time > self.havocbot_role_timeout)
321 havocbot_ons_reset_role(self);
325 if(self.havocbot_attack_time>time)
328 if (self.bot_strategytime < time)
330 navigation_goalrating_start();
331 havocbot_goalrating_enemyplayers(20000, self.origin, 650);
332 if(!havocbot_goalrating_ons_generator_attack(20000))
333 havocbot_goalrating_ons_controlpoints_attack(20000);
334 havocbot_goalrating_ons_offenseitems(10000, self.origin, 10000);
335 navigation_goalrating_end();
337 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
341 void havocbot_role_ons_assistant()
343 havocbot_ons_reset_role(self);
346 void havocbot_role_ons_defense()
348 havocbot_ons_reset_role(self);
351 void havocbot_ons_reset_role(entity bot)
356 if(self.deadflag != DEAD_NO)
359 bot.havocbot_ons_target = world;
361 // TODO: Defend control points or generator if necessary
363 // if there is only me on the team switch to offense
365 FOR_EACH_PLAYER(head)
366 if(head.team==self.team)
371 havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
375 havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
378 void havocbot_chooserole_ons()
380 havocbot_ons_reset_role(self);