]> icculus.org git repositories - divverent/nexuiz.git/blob - attic/TeamNexuiz/game/gamec/mauvebot.c
moved navnodeedit & TeamNexuiz to attic
[divverent/nexuiz.git] / attic / TeamNexuiz / game / gamec / mauvebot.c
1 /*
2 \r
3 MauveBot v1.0 for Nexuiz
4 \r
5 */
6 \r
7
8 \r
9 //float intermission_running;
10 \r
11
12 \r
13 .float skill_level;
14 \r
15
16 \r
17 .float ai_time;
18 \r
19 .float threat;
20 \r
21 .entity dodgeent;
22 \r
23
24 \r
25 float THREAT_UNFLAGGED = 0;
26 \r
27 float THREAT_IGNORE = -1;
28 \r
29
30 \r
31 float DODGE_DIST = 500;
32 \r
33 float SEARCH_DIST = 1000;
34 \r
35
36 \r
37 .float search_time;
38 \r
39
40 \r
41 float bot_number;
42 \r
43
44 \r
45 string(float r) BotName =
46 {\r
47         string gender, name, cl;\r
48         
49         if(random() > 0.5)\r
50         {\r
51                 gender = "female";\r
52         }\r
53         else\r
54         {\r
55                 gender = "male";\r
56         }\r
57 \r
58         if (r == 1)\r
59         {\r
60                 cl = "scout";\r
61                 self.playerskin = "0";\r
62         }\r
63         else if (r == 2)\r
64         {\r
65                 cl = "spy";\r
66                 self.playerskin = "0";\r
67         }\r
68         else if (r == 3)\r
69         {\r
70                 cl = "soldier";\r
71                 self.playerskin = "0";\r
72         }\r
73         else if (r == 4)\r
74         {\r
75                 cl = "pyro";\r
76                 self.playerskin = "0";\r
77         }\r
78         else if (r == 5)\r
79         {\r
80                 cl = "medic";\r
81                 self.playerskin = "0";\r
82         }\r
83         else
84         {
85                 cl = "engineer";\r
86                 self.playerskin = "0";\r
87         }\r
88 \r
89         name = strzone(strcat("bot", ftos(ceil(random()*99)), "_", cl));\r
90 \r
91         self.playermodel = strzone(strcat("models/class/", cl, "_", gender, ".zym"));\r
92 \r
93         return name;
94 };
95 \r
96
97 \r
98 string () PickARandomName =
99 \r
100 {
101 \r
102         local float y, test;
103 \r
104         local string h;
105 \r
106         local entity t;
107 \r
108
109 \r
110         t = find(world, classname, "player");
111 \r
112         while(t)
113 \r
114         {
115 \r
116                 if (clienttype(self) == CLIENTTYPE_BOT)
117 \r
118                         y = y + 1;
119 \r
120                 t = find(t, classname, "player");
121 \r
122         }
123 \r
124
125 /*\r
126         if (y > 25)
127         {
128                 self.playermodel = "models/class/soldier_female.zym";
129                 self.playerskin = "0";
130                 return "EJP_Tank";
131         }
132 */\r
133
134 \r
135         y = TRUE;
136 \r
137         while(y)
138         {
139                 test = ceil(random() * 6);//25);
140                 h = BotName(test);
141                 t = find(world, netname, h);
142                 if (t == world)
143                         y = FALSE;
144         }
145 \r
146         return h;
147 \r
148 };
149 \r
150
151 \r
152 // Adds a bot to the server
153 \r
154 void() add_MauveBot =
155 \r
156 {
157 \r
158         local entity oldself;
159 \r
160         local float flo;
161 \r
162         local string str;
163 \r
164
165 \r
166         oldself = self;
167 \r
168         self = spawnclient();
169 \r
170         if (!self)
171 \r
172         {
173 \r
174                 bprint("Can not add bot, server full.\n");
175 \r
176                 str = ftos(bot_number);
177 \r
178                 cvar_set("bot_number", str);
179 \r
180                 self = oldself;
181 \r
182                 return;
183 \r
184         }
185 \r
186         
187 \r
188         flo = floor(random() * 5);
189 \r
190         if (flo == 0)
191 \r
192                 self.clientcolors = 0;
193 \r
194         else if (flo == 1)
195 \r
196                 self.clientcolors = 3;
197 \r
198         else if (flo == 2)
199 \r
200                 self.clientcolors = 4;
201 \r
202         else if (flo == 3)
203 \r
204                 self.clientcolors = 12;
205 \r
206         else if (flo == 4)
207 \r
208                 self.clientcolors = 13;
209 \r
210         self.clientcolors = self.clientcolors + self.clientcolors * 16;
211 \r
212
213 \r
214         self.netname = PickARandomName();
215 \r
216
217 \r
218         ClientConnect();
219 \r
220         PutClientInServer();
221 \r
222         self.skill_level = cvar("skill");
223 \r
224         if (self.skill_level > 10)
225 \r
226                 self.skill_level = 10;
227 \r
228         if (self.skill_level < 1)
229 \r
230                 self.skill_level = 1;
231 \r
232         self = oldself;
233 \r
234
235 \r
236         bot_number = bot_number + 1;
237 \r
238 };
239 \r
240
241 \r
242 void() remove_MauveBot = 
243 \r
244 {
245 \r
246         local float flo, i;
247 \r
248         local entity ent;
249 \r
250
251 \r
252         flo = floor(random() * bot_number);
253 \r
254         
255 \r
256         ent = find(world, classname, "player");
257 \r
258         
259 \r
260         while(ent)
261 \r
262         {
263 \r
264                 if (clienttype(ent) == CLIENTTYPE_BOT)
265 \r
266                 {
267 \r
268                         if (flo == i)
269 \r
270                         {
271 \r
272                                 dropclient(ent);
273 \r
274                                 if (bot_number > 0)
275 \r
276                                         bot_number = bot_number - 1;
277 \r
278                                 return;
279 \r
280                         }
281 \r
282                         i = i + 1;
283 \r
284                 }
285 \r
286                 ent = find(ent, classname, "player");
287 \r
288         }
289 \r
290 };
291 \r
292
293 \r
294 float (entity targ) visible =
295 \r
296 {
297 \r
298         local vector start, end, org;
299 \r
300
301 \r
302 //      if (self.skill_level < 3)
303 \r
304 //              if (random() > self.skill_level / 10)
305 \r
306 //                      return FALSE;
307 \r
308
309 \r
310         org = targ.origin;
311 \r
312         if (org == '0 0 0')
313 \r
314                 org = (targ.absmin + targ.absmax) * 0.5;
315 \r
316
317 \r
318         start = self.origin + self.view_ofs;
319 \r
320         end = org;
321 \r
322         traceline (start, end, TRUE, self);     
323 \r
324         if (!(trace_inopen && trace_inwater))   
325 \r
326                 if (trace_fraction == 1)
327 \r
328                         return TRUE;
329 \r
330         return FALSE;
331 \r
332 };
333 \r
334
335 \r
336 void(entity ent) bot_set_angle =
337 \r
338 {
339 \r
340         local vector view;
341 \r
342         local float flo;
343 \r
344         if (ent != world)
345 \r
346         {
347 \r
348                 view = ent.origin;
349 \r
350                 if (view == '0 0 0')
351 \r
352                         view = (ent.absmin + ent.absmax) * 0.5;
353 \r
354                 
355 \r
356                 if (self.skill_level < 6)
357 \r
358                         view = view - ent.velocity * (0.5 / self.skill_level);
359 \r
360
361 \r
362                 flo = vlen(ent.origin - self.origin) / (self.skill_level * 4);
363 \r
364
365 \r
366                 view_x = view_x + (random() * flo * 2) - flo;
367 \r
368                 view_y = view_y + (random() * flo * 2) - flo;
369 \r
370                 view_z = view_z + (random() * flo * 2) - flo;
371 \r
372
373 \r
374                 view = view - (self.origin + self.view_ofs);
375 \r
376                 self.v_angle = vectoangles(view);
377 \r
378                 self.v_angle_x = self.v_angle_x * -1;
379 \r
380                 self.angles = self.v_angle;
381 \r
382                 self.angles_x = self.angles_x * -1;
383 \r
384                 if (self.angles_x > 180)
385 \r
386                         self.angles_x = self.angles_x - 360;
387 \r
388                 if (self.angles_x != 0)
389 \r
390                         self.angles_x = self.angles_x / 6;
391 \r
392         }
393 \r
394         else
395 \r
396                 self.angles_x = 0;// hack!
397 \r
398 };
399 \r
400
401 \r
402 void() MauveToGoal =
403 \r
404 {
405 \r
406         local vector vec, en, diff, dir;
407 \r
408
409 \r
410         vec = self.origin;
411 \r
412         movetogoal(20);
413 \r
414         en = self.origin;
415 \r
416         self.origin = vec;
417 \r
418
419 \r
420         diff = en - self.origin;
421 \r
422         if (diff == '0 0 0')
423 \r
424                 diff = self.goalentity.origin - self.origin;
425 \r
426
427 \r
428         if (self.search_time < time)
429 \r
430         {
431 \r
432                 self.goalentity.search_time = time + 20;
433 \r
434                 self.goalentity = world;
435 \r
436                 return;
437 \r
438         }       
439 \r
440
441 \r
442         dir = normalize(diff);
443 \r
444         dir = dir * cvar("cl_forwardspeed");// - (self.velocity - dir * (self.velocity * dir));
445 \r
446
447 \r
448         makevectors(self.v_angle);
449 \r
450         self.movement_x = dir * v_forward;
451 \r
452         self.movement_y = dir * v_right;
453 \r
454         self.movement_z = dir * v_up;
455 \r
456 };
457 \r
458
459 \r
460 void() look_for_stuff =
461 \r
462 {
463 \r
464         local entity item, best, best2, best3;
465 \r
466         local float dist, tdist, dist2, topthreat;
467 \r
468         
469 \r
470         item = findradius(self.origin, 1000);
471 \r
472         
473 \r
474         if (self.search_time < time)
475 \r
476                 self.enemy = world;
477 \r
478
479 \r
480         if (self.enemy.health < 0)
481 \r
482                 self.enemy = world;
483 \r
484
485 \r
486         if (self.enemy.deadflag)
487 \r
488                 self.enemy = world;
489 \r
490         
491 \r
492         dist = dist2 = SEARCH_DIST;
493 \r
494         topthreat = 0;
495 \r
496
497 \r
498         while(item)
499 \r
500         {
501 \r
502                 if (item.flags & FL_CLIENT)
503 \r
504                 {
505 \r
506                         if (item != self)
507 \r
508                         {
509 \r
510                                 if ((item.health > 0) && (!item.deadflag))
511 \r
512                                 {
513 \r
514                                         if (visible(item))
515 \r
516                                         {
517 \r
518                                                 tdist = vlen(item.origin - self.origin);
519 \r
520                                                 if (tdist < dist)
521 \r
522                                                 {
523 \r
524                                                         best = item;
525 \r
526                                                         dist = tdist;
527 \r
528                                                 }
529 \r
530                                         }
531 \r
532                                 }
533 \r
534                         }
535 \r
536                 }
537 \r
538                 else if (( (item.flags & FL_ITEM) && item.model != string_null) && (item.search_time < time))
539 \r
540                 {
541 \r
542                         if (visible(item))
543 \r
544                         {
545 \r
546                                 tdist = vlen(item.origin - self.origin);
547 \r
548                                 if (tdist < dist2)
549 \r
550                                 {
551 \r
552                                         best2 = item;
553 \r
554                                         dist2 = tdist;
555 \r
556                                 }
557 \r
558                         }
559 \r
560                 }
561 \r
562                 if (item.threat == THREAT_UNFLAGGED)
563 \r
564                 {
565 \r
566                         if (item.classname == "missile")
567 \r
568                                 item.threat = 100;
569 \r
570                         else if (item.classname == "laserbolt") 
571 \r
572                                 item.threat = 10;
573 \r
574                         else if (item.classname == "grenade") 
575 \r
576                                 item.threat = 50;
577 \r
578                         else if (item.classname == "plasma") 
579 \r
580                                 item.threat = 60;
581 \r
582                         else if (item.classname == "spike")
583 \r
584                                 item.threat = 30;
585 \r
586                         else
587 \r
588                                 item.threat = THREAT_IGNORE;
589 \r
590                 }
591 \r
592                 if (item.threat > 0)
593 \r
594                 {
595 \r
596                         if ((item.owner != self) || (item.velocity == '0 0 0'))
597 \r
598                         {
599 \r
600                                 tdist = vlen(item.origin - self.origin);
601 \r
602                                 if (tdist < DODGE_DIST)
603 \r
604                                 {
605 \r
606                                         if (item.threat / tdist > topthreat)
607 \r
608                                         {
609 \r
610                                                 topthreat = item.threat / tdist;
611 \r
612                                                 best3 = item;
613 \r
614                                         }
615 \r
616                                 }
617 \r
618                         }
619 \r
620                 }
621 \r
622                 item = item.chain;
623 \r
624         }
625 \r
626         if ((best != self.enemy) && (best != world))
627 \r
628                 self.enemy = best;
629 \r
630         if ((best2 != self.goalentity) && (best2 != world))
631 \r
632         {
633 \r
634                 self.goalentity = best2;
635 \r
636                 self.search_time = time + 5;
637 \r
638         }
639 \r
640         self.dodgeent = best3;
641 \r
642 };
643 \r
644
645 \r
646 void() DodgeProjectile =
647 \r
648 {
649 \r
650         local vector vec;
651 \r
652
653 \r
654         vec = vectoangles(self.dodgeent.origin - self.origin);
655 \r
656         makevectors(vec);
657 \r
658         
659 \r
660         self.goalentity = spawn();
661 \r
662
663 \r
664         if (self.dodgeent.velocity != '0 0 0')
665 \r
666                 setorigin(self.goalentity, self.origin + v_right * 50);
667 \r
668         else
669 \r
670                 setorigin(self.goalentity, self.origin - v_forward * 50);
671 \r
672         
673 \r
674         MauveToGoal();
675 \r
676
677 \r
678         remove(self.goalentity);
679 \r
680         self.goalentity = world;
681 \r
682 };
683 \r
684
685 \r
686 void() MauveBot_AI =
687 \r
688 {
689 \r
690         
691 \r
692         if (clienttype(self) != CLIENTTYPE_BOT)
693 \r
694         {
695 \r
696                 //local entity ent;
697 \r
698                 local float flo;
699 \r
700
701 \r
702                 if (time >= 3)
703 \r
704                 {
705 \r
706                         flo = cvar("bot_number");
707 \r
708         
709 \r
710                         if (flo > bot_number)
711 \r
712                                 add_MauveBot();
713 \r
714                         else if (flo < bot_number)
715 \r
716                                 remove_MauveBot();
717 \r
718                 }
719 \r
720                 else
721 \r
722                         remove_MauveBot();
723 \r
724                 return;
725 \r
726         }
727 \r
728
729 \r
730         self.button0 = 0;
731 \r
732         self.button2 = 0;
733 \r
734         self.button3 = 0;
735 \r
736
737 \r
738         self.movement = '0 0 0';
739 \r
740
741 \r
742         if (self.deadflag == DEAD_RESPAWNABLE)
743 \r
744         {
745 \r
746                 self.button0 = 1;
747 \r
748                 return;
749 \r
750         }
751 \r
752         else if (self.deadflag)
753 \r
754                 return;
755 \r
756
757 \r
758         if (self.goalentity.model == string_null)
759 \r
760                 self.goalentity = world;
761 \r
762
763 \r
764         if (time > self.ai_time)
765 \r
766         {
767 \r
768                 self.ai_time = time + (0.5 / self.skill_level) + (random() * (1 / self.skill_level));
769 \r
770
771 \r
772                 look_for_stuff();
773 \r
774         
775 \r
776                 if (self.enemy)
777 \r
778                 {
779 \r
780                         bot_set_angle(self.enemy);
781 \r
782                         if (visible(self.enemy))
783 \r
784                         {
785 \r
786                                 self.button0 = 1;
787 \r
788                                 self.search_time = 100000;
789 \r
790                         }
791 \r
792                         else    if (self.search_time == 100000)
793 \r
794                                 self.search_time = time + 5;
795 \r
796                         if (self.goalentity == world)
797 \r
798                         {
799 \r
800                                 if (self.enemy)
801 \r
802                                 {
803 \r
804                                         self.goalentity = self.enemy;
805 \r
806                                         if (vlen(self.enemy.origin - self.origin) < 300)
807 \r
808                                                 self.dodgeent = self.enemy;
809 \r
810                                 }
811 \r
812                         }
813 \r
814                 }
815 \r
816                 else if (self.goalentity)
817 \r
818                         bot_set_angle(self.goalentity);
819 \r
820
821 \r
822                 if (random() < 0.03)
823 \r
824                         self.button2 = 1;
825 \r
826         }
827 \r
828         else
829 \r
830         {
831 \r
832                 if (self.skill_level > 3)
833 \r
834                 {
835 \r
836                         if (visible(self.enemy))
837 \r
838                         {
839 \r
840                                 self.button0 = 1;
841 \r
842                                 self.search_time = 100000;
843 \r
844                         }
845 \r
846                 }
847 \r
848         }
849 \r
850
851 \r
852         if (self.dodgeent != world)
853 \r
854                 DodgeProjectile();
855 \r
856         else if (self.goalentity != world)
857 \r
858                 MauveToGoal();
859 \r
860 };