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