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