]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/gamec/mauvebot.c
- minplayers doesn't spawn bots on empty servers anymore
[divverent/nexuiz.git] / data / qcsrc / server / gamec / mauvebot.c
1 /*
2 MauveBot v1.0 for Nexuiz
3 */
4
5 string(float r) BotName =
6 {
7         if (r == 1)
8         {
9                 self.playermodel = "models/player/visitant.zym";
10                 self.playerskin = "1";
11                 return "Fricka";
12         }
13         else if (r == 2)
14         {
15                 self.playermodel = "models/player/marine.zym";
16                 self.playerskin = "0";
17                 return "Marine";
18         }
19         else if (r == 3)
20         {
21                 self.playermodel = "models/player/specop.zym";
22                 self.playerskin = "0";
23                 return "Specop";
24         }
25         else if (r == 4)
26         {
27                 self.playermodel = "models/player/nexus.zym";
28                 self.playerskin = "0";
29                 return "Nexus";
30         }
31         else if (r == 5)
32         {
33                 self.playermodel = "models/player/skadi.zym";
34                 self.playerskin = "0";
35                 return "Skadi";
36         }
37         else if (r == 6)
38         {
39                 self.playermodel = "models/player/lurk.zym";
40                 self.playerskin = "0";
41                 return "Lurk";
42         }
43         else if (r == 7)
44         {
45                 self.playermodel = "models/player/headhunter.zym";
46                 self.playerskin = "0";
47                 return "HeadHunter";
48         }
49         else if (r == 8)
50         {
51                 self.playermodel = "models/player/carni.zym";
52                 self.playerskin = "0";
53                 return "Carni";
54         }
55         else if (r == 9)
56         {
57                 self.playermodel = "models/player/grunt.zym";
58                 self.playerskin = "0";
59                 return "Grunt";
60         }
61         else if (r == 10)
62         {
63                 self.playermodel = "models/player/insurrectionist.zym";
64                 self.playerskin = "0";
65                 return "Insurrectionist";
66         }
67         else if (r == 11)
68         {
69                 self.playermodel = "models/player/lycanthrope.zym";
70                 self.playerskin = "0";
71                 return "Lycanthrope";
72         }
73         else if (r == 12)
74         {
75                 self.playermodel = "models/player/pyria.zym";
76                 self.playerskin = "0";
77                 return "Pyria";
78         }
79         else if (r == 13)
80         {
81                 self.playermodel = "models/player/shock.zym";
82                 self.playerskin = "0";
83                 return "Shock";
84         }
85         else if (r == 14)
86         {
87                 self.playermodel = "models/player/lurk.zym";
88                 self.playerskin = "1";
89                 return "Reptile";
90         }
91         else if (r == 15)
92         {
93                 self.playermodel = "models/player/crash.zym";
94                 self.playerskin = "0";
95                 return "Quark";
96         }
97         else if (r == 16)
98         {
99                 self.playermodel = "models/player/insurrectionist.zym";
100                 self.playerskin = "1";
101                 return "Anarchist";
102         }
103         else if (r == 17)
104         {
105                 self.playermodel = "models/player/carni.zym";
106                 self.playerskin = "1";
107                 return "Armored Carni";
108         }
109         else if (r == 18)
110         {
111                 self.playermodel = "models/player/nexus.zym";
112                 self.playerskin = "1";
113                 return "Mulder";
114         }
115         else
116         {
117                 self.playermodel = "models/player/carni.zym";
118                 self.playerskin = "0";
119                 return "Carni";
120         }
121 };
122
123 string () PickARandomName =
124 {
125         local float y, test;
126         local string h;
127         local entity t;
128
129         t = findflags(world, flags, FL_CLIENT);
130         while(t)
131         {
132                 if (clienttype(self) == CLIENTTYPE_BOT)
133                         y = y + 1;
134                 t = findflags(t, flags, FL_CLIENT);
135         }
136
137         if (y > 18)
138         {
139                 self.playermodel = "models/player/marine.zym";
140                 self.playerskin = "0";
141                 return "EJP_Tank";
142         }
143
144         y = TRUE;
145         while(y)
146         {
147                 test = ceil(random() * 18);
148                 h = BotName(test);
149                 t = find(world, netname, h);
150                 if (t == world)
151                         y = FALSE;
152         }
153         return h;
154 };
155
156 // Adds a bot to the server
157 entity(float bottype) add_MauveBot =
158 {
159         local entity oldself, ret;
160         local float shirt, pants;
161
162         oldself = self;
163         self = spawnclient();
164         if (!self)
165         {
166                 bprint("Can not add bot, server full.\n");
167                 if (bottype == BOT_TYPE_MAUVEBOT)
168                         cvar_set("mauvebots", ftos(mauvebots));
169                 else
170                         cvar_set("bot_number", ftos(bot_number));
171                 self = oldself;
172                 return world;
173         }
174
175         if(teamplay)
176         {
177                 // keep teams balanced
178                 JoinBestTeam(self, 0);
179         }
180         else
181         {
182                 shirt = floor(random()*15);
183                 pants = floor(random()*15);
184                 self.clientcolors = pants + shirt * 16;
185         }
186
187         self.netname = PickARandomName();
188  
189         ClientConnect();
190         PutClientInServer();
191         self.autoswitch = 1; // bots currently need autoswitching
192         self.skill_level = cvar("skill");
193         if (self.skill_level > 10)
194                 self.skill_level = 10;
195         if (self.skill_level < 1)
196                 self.skill_level = 1;
197         ret = self;
198         self = oldself;
199
200         return ret;
201 };
202
203 void() remove_MauveBot = 
204 {
205         local float flo, i;
206         local entity ent;
207
208         flo = floor(random() * mauvebots);
209         
210         ent = findflags(world, flags, FL_CLIENT);
211         
212         while(ent)
213         {
214                 if (clienttype(ent) == CLIENTTYPE_BOT)
215                 {
216                         if (ent.bot_type == BOT_TYPE_MAUVEBOT)
217                         {
218                                 if (flo == i)
219                                 {
220                                         self = ent;
221                                         dropclient(ent);
222                                         if (mauvebots > 0)
223                                                 mauvebots = mauvebots - 1;
224                                         return;
225                                 }
226                                 i = i + 1;
227                         }
228                 }
229                 ent = findflags(ent, flags, FL_CLIENT);
230         }
231 };
232
233 float (entity targ) visible =
234 {
235         local vector start, end, org;
236
237 //      if (self.skill_level < 3)
238 //              if (random() > self.skill_level / 10)
239 //                      return FALSE;
240
241         org = targ.origin;
242         if (org == '0 0 0')
243                 org = (targ.absmin + targ.absmax) * 0.5;
244
245         start = self.origin + self.view_ofs;
246         end = org;
247         traceline (start, end, TRUE, self);     
248         if (!(trace_inopen && trace_inwater))   
249                 if (trace_fraction == 1)
250                         return TRUE;
251         return FALSE;
252 };
253
254 void(entity ent) bot_set_angle =
255 {
256         local vector view;
257         local float flo;
258         if (ent != world)
259         {
260                 view = ent.origin;
261                 if (view == '0 0 0')
262                         view = (ent.absmin + ent.absmax) * 0.5;
263                 
264                 if (self.skill_level < 6)
265                         view = view - ent.velocity * (0.5 / self.skill_level);
266
267                 flo = vlen(ent.origin - self.origin) / (self.skill_level * 4);
268
269                 view_x = view_x + (random() * flo * 2) - flo;
270                 view_y = view_y + (random() * flo * 2) - flo;
271                 view_z = view_z + (random() * flo * 2) - flo;
272
273                 view = view - (self.origin + self.view_ofs);
274                 self.v_angle = vectoangles(view);
275                 self.v_angle_x = self.v_angle_x * -1;
276                 self.angles = self.v_angle;
277                 self.angles_x = self.angles_x * -1;
278                 if (self.angles_x > 180)
279                         self.angles_x = self.angles_x - 360;
280                 if (self.angles_x != 0)
281                         self.angles_x = self.angles_x / 6;
282         }
283         else
284                 self.angles_x = 0;// hack!
285 };
286
287 void() MauveToGoal =
288 {
289         local vector vec, en, diff, dir;
290
291         vec = self.origin;
292         movetogoal(20);
293         en = self.origin;
294         self.origin = vec;
295
296         diff = en - self.origin;
297         if (diff == '0 0 0')
298                 diff = self.goalentity.origin - self.origin;
299
300         if (self.search_time < time)
301         {
302                 self.goalentity.search_time = time + 20;
303                 self.goalentity = world;
304                 return;
305         }       
306
307         dir = normalize(diff);
308         dir = dir * cvar("sv_maxspeed");// - (self.velocity - dir * (self.velocity * dir));
309
310         makevectors(self.v_angle);
311         self.movement_x = dir * v_forward;
312         self.movement_y = dir * v_right;
313         self.movement_z = dir * v_up;
314 };
315
316 void() look_for_stuff =
317 {
318         local entity item, best, best2, best3;
319         local float dist, tdist, dist2, topthreat;
320         
321         item = findradius(self.origin, 1000);
322         
323         if (self.search_time < time)
324                 self.enemy = world;
325
326         if (self.enemy.health < 0)
327                 self.enemy = world;
328
329         if (self.enemy.deadflag)
330                 self.enemy = world;
331         
332         dist = dist2 = SEARCH_DIST;
333         topthreat = 0;
334
335         while(item)
336         {
337                 if (item.flags & FL_CLIENT)
338                 {
339                         if (!(item.flags & FL_NOTARGET))
340                         if (item != self && !(cvar("teamplay") && (item.clientcolors == self.clientcolors)))
341                         if ((item.health > 0) && (!item.deadflag))
342                         if (visible(item))
343                         {
344                                 tdist = vlen(item.origin - self.origin);
345                                 if (tdist < dist)
346                                 {
347                                         best = item;
348                                         dist = tdist;
349                                 }
350                         }
351                 }
352                 else if (( (item.flags & FL_ITEM) && item.model != string_null) && (item.search_time < time))
353                 {
354                         if (visible(item))
355                         {
356                                 tdist = vlen(item.origin - self.origin);
357                                 if (tdist < dist2)
358                                 {
359                                         best2 = item;
360                                         dist2 = tdist;
361                                 }
362                         }
363                 }
364                 if (item.threat == THREAT_UNFLAGGED)
365                 {
366                         if (item.classname == "missile")
367                                 item.threat = 100;
368                         else if (item.classname == "laserbolt") 
369                                 item.threat = 10;
370                         else if (item.classname == "grenade") 
371                                 item.threat = 50;
372                         else if (item.classname == "plasma") 
373                                 item.threat = 60;
374                         else if (item.classname == "spike")
375                                 item.threat = 30;
376                         else
377                                 item.threat = THREAT_IGNORE;
378                 }
379                 if (item.threat > 0)
380                 {
381                         if ((item.owner != self) || (item.velocity == '0 0 0'))
382                         {
383                                 tdist = vlen(item.origin - self.origin);
384                                 if (tdist < DODGE_DIST)
385                                 {
386                                         if (item.threat / tdist > topthreat)
387                                         {
388                                                 topthreat = item.threat / tdist;
389                                                 best3 = item;
390                                         }
391                                 }
392                         }
393                 }
394                 item = item.chain;
395         }
396         if ((best != self.enemy) && (best != world))
397                 self.enemy = best;
398         if ((best2 != self.goalentity) && (best2 != world))
399         {
400                 self.goalentity = best2;
401                 self.search_time = time + 5;
402         }
403         self.dodgeent = best3;
404 };
405
406 void() DodgeProjectile =
407 {
408         local vector vec;
409
410         vec = vectoangles(self.dodgeent.origin - self.origin);
411         makevectors(vec);
412         
413         self.goalentity = spawn();
414
415         if (self.dodgeent.velocity != '0 0 0')
416                 setorigin(self.goalentity, self.origin + v_right * 50);
417         else
418                 setorigin(self.goalentity, self.origin - v_forward * 50);
419         
420         MauveToGoal();
421
422         remove(self.goalentity);
423         self.goalentity = world;
424 };
425
426 void() MauveBot_AI =
427 {
428         self.button0 = 0;
429         self.button2 = 0;
430         self.button3 = 0;
431
432         self.movement = '0 0 0';
433
434         if (self.deadflag == DEAD_RESPAWNABLE)
435         {
436                 self.button0 = 1;
437                 return;
438         }
439         else if (self.deadflag)
440                 return;
441
442         if (self.goalentity.model == string_null)
443                 self.goalentity = world;
444
445         if (time > self.ai_time)
446         {
447                 self.ai_time = time + (0.5 / self.skill_level) + (random() * (1 / self.skill_level));
448
449                 look_for_stuff();
450         
451                 if (self.enemy)
452                 {
453                         bot_set_angle(self.enemy);
454                         if (visible(self.enemy))
455                         {
456                                 self.button0 = 1;
457                                 self.search_time = 100000;
458                         }
459                         else    if (self.search_time == 100000)
460                                 self.search_time = time + 5;
461                         if (self.goalentity == world)
462                         {
463                                 if (self.enemy)
464                                 {
465                                         self.goalentity = self.enemy;
466                                         if (vlen(self.enemy.origin - self.origin) < 300)
467                                                 self.dodgeent = self.enemy;
468                                 }
469                         }
470                 }
471                 else if (self.goalentity)
472                         bot_set_angle(self.goalentity);
473
474                 if (random() < 0.03)
475                         self.button2 = 1;
476         }
477         else
478         {
479                 if (self.skill_level > 3)
480                 {
481                         if (visible(self.enemy))
482                         {
483                                 self.button0 = 1;
484                                 self.search_time = 100000;
485                         }
486                 }
487         }
488
489         if (self.dodgeent != world)
490                 DodgeProjectile();
491         else if (self.goalentity != world)
492                 MauveToGoal();
493 };