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