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