]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/havocbot_ons.qc
bot scripting: fix a bug that allows only one command to be executed per frame
[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
8 .void() havocbot_role;
9 .void() havocbot_previous_role;
10
11 void() havocbot_role_ons_defense;
12 void() havocbot_role_ons_offense;
13 void() havocbot_role_ons_assistant;
14
15 void(entity bot) havocbot_ons_reset_role;
16 void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
17 void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
18
19 .float isshielded;
20 .float iscaptured;
21 .float islinked;
22 float (entity controlpoint, float team) onslaught_controlpoint_can_be_linked;
23 float (entity controlpoint, float team) onslaught_controlpoint_attackable;
24
25 void havocbot_role_ons_setrole(entity bot, float role)
26 {
27         dprint(strcat(bot.netname," switched to "));
28         switch(role)
29         {
30                 case HAVOCBOT_ONS_ROLE_DEFENSE:
31                         dprint("defense");
32                         bot.havocbot_role = havocbot_role_ons_defense;
33                         bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_DEFENSE;
34                         bot.havocbot_role_timeout = 0;
35                         break;
36                 case HAVOCBOT_ONS_ROLE_ASSISTANT:
37                         dprint("assistant");
38                         bot.havocbot_role = havocbot_role_ons_assistant;
39                         bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_ASSISTANT;
40                         bot.havocbot_role_timeout = 0;
41                         break;
42                 case HAVOCBOT_ONS_ROLE_OFFENSE:
43                         dprint("offense");
44                         bot.havocbot_role = havocbot_role_ons_offense;
45                         bot.havocbot_role_flags = HAVOCBOT_ONS_ROLE_OFFENSE;
46                         bot.havocbot_role_timeout = 0;
47                         break;
48         }
49         dprint("\n");
50 };
51
52 float havocbot_ons_teamcount(entity bot, float role)
53 {
54         local float c;
55         local entity head;
56
57         FOR_EACH_PLAYER(head)
58         if(head.team==self.team)
59         if(head.havocbot_role_flags & role)
60                 ++c;
61
62         return c;
63 };
64
65 void havocbot_goalrating_ons_controlpoints_attack(float ratingscale)
66 {
67         local entity cps, cp, wp, bestwp;
68         local float radius, found, bestcounter, status;
69
70         for (cps = findchain(classname, "onslaught_controlpoint_shield"); cps; cps = cps.chain)
71         {
72                 // Found its corresponding onslaught_controlpoint entity (...)
73                 for (cp = findradius(cps.origin, 100); cp; cp = cp.chain)
74                 {
75                         if(cp.classname=="onslaught_controlpoint")
76                                 break;
77                 }
78
79                 if(cp==world)
80                         continue;
81
82                 status = onslaught_controlpoint_attackable(cp, self.team);
83
84                 dprint(self.classname," found a controlpoint with status ",ftos(status),"\n");
85
86                 if(status==1 || status == 3)
87                 {
88                         // Should be attacked
89                         // Rate waypoints near it
90                         found = FALSE;
91                         bestwp = world;
92                         bestcounter = 99999999999;
93                         for(radius=0; radius<1000 && !found; radius+=500)
94                         {
95                                 for(wp=findradius(cp.origin,radius); wp; wp=wp.chain)
96                                 {
97                                         if(wp.classname=="waypoint")
98                                         if(checkpvs(wp.origin,cp))
99                                         {
100                                                 found = TRUE;
101                                                 if(wp.cnt<bestcounter)
102                                                 {
103                                                         bestwp = wp;
104                                                         bestcounter = wp.cnt;
105                                                 }
106                                         }
107                                 }
108
109                                 if(found)
110                                         break;
111                         }
112
113                         if(bestwp)
114                         {
115                                 navigation_routerating(bestwp, ratingscale, 10000);
116                                 bestwp.cnt += 1;
117                         }
118                         dprint("attackable controlpoint found at ", vtos(cp.origin) ,"\n");
119                 }
120                 else if(status==2 || status==4)
121                 {
122                         // Should be touched
123                         if not(bot_waypoints_for_items)
124                         {
125                                 navigation_routerating(cp, ratingscale, 10000);
126                                 return;
127                         }
128
129                         for (wp = findradius(cp.origin,100); wp; wp = wp.chain)
130                         {
131                                 if(wp.classname=="waypoint")
132                                 {
133                                         navigation_routerating(wp, ratingscale, 10000);
134                                         return;
135                                 }
136                         }
137                         dprint("touchable controlpoint found at ", vtos(cp.origin) ,"\n");
138                 }
139         }
140 };
141
142 void havocbot_goalrating_ons_generator_attack(float ratingscale)
143 {
144         local entity g, wp, bestwp;
145         local float radius, found, bestcounter;
146
147         for (g = findchain(classname, "onslaught_generator"); g; g = g.chain)
148         {
149                 if(g.team == self.team || g.isshielded)
150                         continue;
151
152                 // Should be attacked
153                 // Rate waypoints near it
154                 found = FALSE;
155                 bestwp = world;
156                 bestcounter = 99999999999;
157                 for(radius=0; radius<1500 && !found; radius+=500)
158                 {
159                         for(wp=findradius(g.origin,radius); wp; wp=wp.chain)
160                         {
161                                 if(wp.classname=="waypoint")
162                                 if(checkpvs(wp.origin,g))
163                                 {
164                                         found = TRUE;
165                                         if(wp.cnt<bestcounter)
166                                         {
167                                                 bestwp = wp;
168                                                 bestcounter = wp.cnt;
169                                         }
170                                 }
171                         }
172
173                         if(found)
174                                 break;
175                 }
176
177                 if(bestwp)
178                 {
179                         dprint("waypoints found around generator\n");
180                         navigation_routerating(bestwp, ratingscale, 10000);
181                         bestwp.cnt += 1;
182                 }
183                 else
184                 {
185                         dprint("generator found without waypoints around\n");
186                         // if there aren't waypoints near the generator go straight to it
187                         navigation_routerating(g, ratingscale, 10000);
188                 }
189         }
190 };
191
192 void havocbot_role_ons_offense()
193 {
194         if(self.deadflag != DEAD_NO)
195         {
196                 havocbot_ons_reset_role(self);
197                 return;
198         }
199
200         // Set the role timeout if necessary
201         if (!self.havocbot_role_timeout)
202                 self.havocbot_role_timeout = time + 120;
203
204         if (time > self.havocbot_role_timeout)
205         {
206                 havocbot_ons_reset_role(self);
207                 return;
208         }
209
210         if (self.bot_strategytime < time)
211         {
212                 navigation_goalrating_start();
213                 havocbot_goalrating_enemyplayers(20000, self.origin, 500);
214                 havocbot_goalrating_ons_generator_attack(20000);
215                 havocbot_goalrating_ons_controlpoints_attack(20000);
216                 havocbot_goalrating_items(15000, self.origin, 1000);
217                 havocbot_goalrating_items(2500, self.origin, 10000);
218                 navigation_goalrating_end();
219
220                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
221         }
222 };
223
224 void havocbot_role_ons_assistant()
225 {
226         havocbot_ons_reset_role(self);
227 };
228
229 void havocbot_role_ons_defense()
230 {
231         havocbot_ons_reset_role(self);
232 };
233
234 void havocbot_ons_reset_role(entity bot)
235 {
236         local entity head;
237         local float c;
238
239         if(self.deadflag != DEAD_NO)
240                 return;
241
242         // TODO: Defend control points or generator if necessary
243
244         // if there is only me on the team switch to offense
245         c = 0;
246         FOR_EACH_PLAYER(head)
247         if(head.team==self.team)
248                 ++c;
249
250         if(c==1)
251         {
252                 havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
253                 return;
254         }
255
256         havocbot_role_ons_setrole(bot, HAVOCBOT_ONS_ROLE_OFFENSE);
257 };
258
259 void havocbot_chooserole_ons()
260 {
261         havocbot_ons_reset_role(self);
262 };