]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/havocbot_ons.qc
actually read sv_clforceplayermodels
[divverent/nexuiz.git] / data / qcsrc / server / havocbot_ons.qc
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
5
6 .float havocbot_role_flags;
7 .float havocbot_attack_time;
8
9 .void() havocbot_role;
10 .void() havocbot_previous_role;
11
12 void() havocbot_role_ons_defense;
13 void() havocbot_role_ons_offense;
14 void() havocbot_role_ons_assistant;
15
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;
19
20 .float isshielded;
21 .float iscaptured;
22 .float islinked;
23 .float isgenneighbor_blue, iscpneighbor_blue;
24 .float isgenneighbor_red, iscpneighbor_red;
25
26 float havocbot_pickupevalfunc(entity item);
27
28 void havocbot_goalrating_ons_offenseitems(float ratingscale, vector org, float sradius)
29 {
30         local entity head;
31         local float t, i, c, needarmor, needweapons;
32
33         // Needs armor/health?
34         if(self.health<100)
35                 needarmor = TRUE;
36
37         // Needs weapons?
38         for(i = WEP_FIRST; i < WEP_LAST ; ++i)
39         {
40                 // Find weapon
41                 if(power2of(i-1) & self.weapons)
42                 if(++c>=4)
43                         break;
44         }
45
46         if(c<4)
47                 needweapons = TRUE;
48
49         if(!needweapons && !needarmor)
50                 return;
51
52 //      dprint(self.netname, " needs weapons ", ftos(needweapons) , "\n");
53 //      dprint(self.netname, " needs armor ", ftos(needarmor) , "\n");
54
55         // See what is around
56         head = findchainfloat(bot_pickup, TRUE);
57         while (head)
58         {
59                 // gather health and armor only
60                 if (head.solid)
61                 if ( ((head.health || head.armorvalue) && needarmor) || (head.weapons && needweapons ) )
62                 if (vlen(head.origin - org) < sradius)
63                 {
64                         t = havocbot_pickupevalfunc(head);
65                         if (t > 0)
66                                 navigation_routerating(head, t * ratingscale, 500);
67                 }
68                 head = head.chain;
69         }
70 };
71
72 void havocbot_role_ons_setrole(entity bot, float role)
73 {
74         dprint(strcat(bot.netname," switched to "));
75         switch(role)
76         {
77                 case HAVOCBOT_ONS_ROLE_DEFENSE:
78                         dprint("defense");
79                         bot.havocbot_role = havocbot_role_ons_defense;
80                         bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
81                         bot.havocbot_role_timeout = 0;
82                         break;
83                 case HAVOCBOT_ONS_ROLE_ASSISTANT:
84                         dprint("assistant");
85                         bot.havocbot_role = havocbot_role_ons_assistant;
86                         bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
87                         bot.havocbot_role_timeout = 0;
88                         break;
89                 case HAVOCBOT_ONS_ROLE_OFFENSE:
90                         dprint("offense");
91                         bot.havocbot_role = havocbot_role_ons_offense;
92                         bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
93                         bot.havocbot_role_timeout = 0;
94                         break;
95         }
96         dprint("\n");
97 };
98
99 float havocbot_ons_teamcount(entity bot, float role)
100 {
101         local float c;
102         local entity head;
103
104         FOR_EACH_PLAYER(head)
105         if(head.team==self.team)
106         if(head.havocbot_role_flags & role)
107                 ++c;
108
109         return c;
110 };
111
112 float havocbot_goalrating_ons_controlpoints_attack(float ratingscale)
113 {
114         local entity cp, wp, bestwp;
115         local float radius, found, bestcounter;
116
117         for (cp = findchain(classname, "onslaught_controlpoint"); cp; cp = cp.chain)
118         {
119                 if(cp==world)
120                         continue;
121
122                 if(cp.isshielded)
123                         continue;
124
125                 if(self.team == COLOR_TEAM1)
126                 {
127                         if( (cp.isgenneighbor_blue || cp.iscpneighbor_blue) && !(cp.isgenneighbor_red || cp.iscpneighbor_red) )
128                                 continue;
129                 }
130                 else if(self.team == COLOR_TEAM2)
131                 {
132                         if( (cp.isgenneighbor_red || cp.iscpneighbor_red) && !(cp.isgenneighbor_blue || cp.iscpneighbor_blue) )
133                                 continue;
134                 }
135
136                 if(cp.goalentity)
137                 {
138                         // Should be attacked
139                         // Rate waypoints near it
140                         found = FALSE;
141                         bestwp = world;
142                         bestcounter = 99999999999;
143                         for(radius=0; radius<1000 && !found; radius+=500)
144                         {
145                                 for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
146                                 {
147                                         if(!(wp.wpflags & WAYPOINTFLAG_GENERATED))
148                                         if(wp.classname=="waypoint")
149                                         if(checkpvs(wp.origin,cp))
150                                         {
151                                                 found = TRUE;
152                                                 if(wp.cnt<bestcounter)
153                                                 {
154                                                         bestwp = wp;
155                                                         bestcounter = wp.cnt;
156                                                 }
157                                         }
158                                 }
159                         }
160
161                         if(bestwp)
162                         {
163                                 navigation_routerating(bestwp, ratingscale, 10000);
164                                 bestwp.cnt += 1;
165
166                                 self.havocbot_attack_time = 0;
167                                 if(checkpvs(self.view_ofs,cp))
168                                 if(checkpvs(self.view_ofs,bestwp))
169                                         self.havocbot_attack_time = time + 2;
170                         }
171                         else
172                         {
173                                 navigation_routerating(cp, ratingscale, 10000);
174                         }
175                         dprint(self.netname, " found an attackable controlpoint at ", vtos(cp.origin) ,"\n");
176                 }
177                 else
178                 {
179                         dprint(self.netname, " found a touchable controlpoint at ", vtos(cp.origin) ,"\n");
180                         // Should be touched
181                         if not(bot_waypoints_for_items)
182                         {
183                                 navigation_routerating(cp, ratingscale, 10000);
184                                 return TRUE;
185                         }
186
187                         for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
188                         {
189                                 if(wp.classname=="waypoint")
190                                 {
191                                         navigation_routerating(wp, ratingscale, 10000);
192                                         return TRUE;
193                                 }
194                         }
195                         navigation_routerating(cp, ratingscale, 10000);
196                 }
197         }
198         return FALSE;
199 };
200
201 float havocbot_goalrating_ons_generator_attack(float ratingscale)
202 {
203         local entity g, wp, bestwp;
204         local float found, best;
205
206         for (g = findchain(classname, "onslaught_generator"); g; g = g.chain)
207         {
208                 if(g.team == self.team || g.isshielded)
209                         continue;
210
211                 // Should be attacked
212                 // Rate waypoints near it
213                 found = FALSE;
214                 bestwp = world;
215                 best = 99999999999;
216
217                 for(wp=findradius(g.origin,400); wp; wp=wp.chain)
218                 {
219                         if(wp.classname=="waypoint")
220                         if(checkpvs(wp.origin,g))
221                         {
222                                 found = TRUE;
223                                 if(wp.cnt<best)
224                                 {
225                                         bestwp = wp;
226                                         best = wp.cnt;
227                                 }
228                         }
229                 }
230
231                 if(bestwp)
232                 {
233                         dprint("waypoints found around generator\n");
234                         navigation_routerating(bestwp, ratingscale, 10000);
235                         bestwp.cnt += 1;
236
237                         self.havocbot_attack_time = 0;
238                         if(checkpvs(self.view_ofs,g))
239                         if(checkpvs(self.view_ofs,bestwp))
240                                 self.havocbot_attack_time = time + 5;
241
242                         return TRUE;
243                 }
244                 else
245                 {
246                         dprint("generator found without waypoints around\n");
247                         // if there aren't waypoints near the generator go straight to it
248                         navigation_routerating(g, ratingscale, 10000);
249                         self.havocbot_attack_time = 0;
250                         return TRUE;
251                 }
252         }
253         return FALSE;
254 };
255
256 void havocbot_role_ons_offense()
257 {
258         if(self.deadflag != DEAD_NO)
259         {
260                 self.havocbot_attack_time = 0;
261                 havocbot_ons_reset_role(self);
262                 return;
263         }
264
265         // Set the role timeout if necessary
266         if (!self.havocbot_role_timeout)
267                 self.havocbot_role_timeout = time + 120;
268
269         if (time > self.havocbot_role_timeout)
270         {
271                 havocbot_ons_reset_role(self);
272                 return;
273         }
274
275         if(self.havocbot_attack_time>time)
276                 return;
277
278         if (self.bot_strategytime < time)
279         {
280                 navigation_goalrating_start();
281                 havocbot_goalrating_enemyplayers(20000, self.origin, 650);
282                 if(!havocbot_goalrating_ons_generator_attack(20000))
283                         havocbot_goalrating_ons_controlpoints_attack(20000);
284                 havocbot_goalrating_ons_offenseitems(10000, self.origin, 10000);
285                 navigation_goalrating_end();
286
287                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
288         }
289 };
290
291 void havocbot_role_ons_assistant()
292 {
293         havocbot_ons_reset_role(self);
294 };
295
296 void havocbot_role_ons_defense()
297 {
298         havocbot_ons_reset_role(self);
299 };
300
301 void havocbot_ons_reset_role(entity bot)
302 {
303         local entity head;
304         local float c;
305
306         if(self.deadflag != DEAD_NO)
307                 return;
308
309         // TODO: Defend control points or generator if necessary
310
311         // if there is only me on the team switch to offense
312         c = 0;
313         FOR_EACH_PLAYER(head)
314         if(head.team==self.team)
315                 ++c;
316
317         if(c==1)
318         {
319                 havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
320                 return;
321         }
322
323         havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
324 };
325
326 void havocbot_chooserole_ons()
327 {
328         havocbot_ons_reset_role(self);
329 };