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