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