merge some changes from my autocvarizer branch that change nothing but make code...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / mode_management.qc
1
2 string(float c) colorname =
3 {
4         // yikes, the quake color set is HARD to describe
5         // many are easy, but, uh, 2 browns???
6         // 2 purples???
7         // that 'pink' is hard to classify
8         // I think 'biege' is a fairly good name for color 10
9         // oh well, gotta do all the color names...
10         if (c ==  0) return "white";
11         else if (c ==  1) return "brown";
12         else if (c ==  2) return "lightblue";
13         else if (c ==  3) return "green";
14         else if (c ==  4) return "red";
15         else if (c ==  5) return "lighterbrown";
16         else if (c ==  6) return "orange";
17         else if (c ==  7) return "pink";
18         else if (c ==  8) return "purple";
19         else if (c ==  9) return "redishpurple";
20         else if (c == 10) return "biege";
21         else if (c == 11) return "aqua";
22         else if (c == 12) return "yellow";
23         else if (c == 13) return "blue";
24         else if (c == 14) return "flamingorange";
25         else if (c == 15) return "psychadelic";
26         else              return "INVALID COLOR";
27 };
28
29 float mode_shirtmustmatchpants;
30 float mode_numteams;
31 float mode_allowedteams[17];
32 float mode_teamcount[17];
33 float mode_teamscore[17];
34
35 void() mode_initallowedteams =
36 {
37         local float c;
38         c = 0;
39         while(c < 17)
40         {
41                 mode_allowedteams[c] = FALSE;
42                 c = c + 1;
43         }
44         mode_allowedteams[5] = TRUE; // red
45         mode_allowedteams[14] = TRUE; // blue
46         if (deathmatch == DM_ELIM
47          || deathmatch == DM_ONEVSALL
48          || deathmatch == DM_CTF_2TEAM
49          || deathmatch == DM_DOMINATION
50          || deathmatch == DM_SUPERDOMINATION)
51                 mode_numteams = 2;
52         else if (deathmatch == DM_CTF_3TEAM)
53         {
54                 mode_numteams = 3;
55                 mode_allowedteams[13] = TRUE; // yellow
56         }
57         else
58         {
59                 mode_numteams = 16;
60                 c = 1;
61                 while(c < 17)
62                 {
63                         mode_allowedteams[c] = TRUE;
64                         c = c + 1;
65                 }
66         }
67 };
68
69 float(float t) validteam =
70 {
71         return mode_allowedteams[t];
72 };
73
74 float() weakestteam =
75 {
76         local float bestteam;
77         local float bestteamcount;
78         local float headcount;
79         local float c;
80         bestteam = -1;
81         bestteamcount = 0;
82         c = 1;
83         while (c < 17)
84         {
85                 if (mode_allowedteams[c])
86                 {
87                         headcount = mode_teamcount[c];
88                         if (bestteamcount > headcount || bestteam == -1)
89                         {
90                                 bestteamcount = headcount;
91                                 bestteam = c;
92                         }
93                 }
94                 c = c + 1;
95         }
96         return bestteam;
97 };
98
99 void() updateteams =
100 {
101         local entity head;
102         local float c;
103         c = 1;
104         while (c < 17)
105         {
106                 mode_teamcount[c] = 0;
107                 mode_teamscore[c] = 0;
108                 c = c + 1;
109         }
110         c = 0;
111         head = nextent(world);
112         while (c < maxclients)
113         {
114                 mode_teamcount[head.team] = mode_teamcount[head.team] + 1;
115                 mode_teamscore[head.team] = mode_teamscore[head.team] + head.frags;
116                 c = c + 1;
117                 head = nextent(head);
118         }
119 };
120
121 float(float p) checkteamcolor =
122 {
123         if (!validteam(p + 1))
124                 p = weakestteam() - 1;
125         return p;
126 };
127
128 void(float c) SV_ChangeTeam =
129 {
130         local float pants, shirt, old;
131         old = self.clientcolors & 15;
132         if (c >= 0)
133         {
134                 pants = c & 15;
135                 shirt = (c / 16) & 15;
136         }
137         else
138         {
139                 pants = -1;
140                 shirt = -1;
141         }
142         pants = checkteamcolor(pants);
143         if (mode_shirtmustmatchpants || shirt < 0)
144                 shirt = pants;
145         setcolor(self, pants + shirt * 16);
146         if (pants != old && old >= 0 && teamplay && deathmatch)
147         {
148                 T_Damage(self, self, self, 0, 0, " changed teams", DT_TELEFRAG, self.origin, '0 0 0', Obituary_Generic);
149                 self.frags = 0;
150                 PutClientInServer ();
151         }
152 };
153
154 void() checkinvalidteam =
155 {
156         // call SV_ChangeTeam to trigger the weakestteam change
157         if (!validteam(self.team))
158                 SV_ChangeTeam(self.team - 1);
159 };
160
161
162 string dmmessage;
163
164 void(string m) setdm =
165 {
166         dmmessage = m;
167         if (cvar("deathmatch") != stof(m))
168                 cvar_set("deathmatch", m);
169 }
170
171 void(string m) setteamplay =
172 {
173         dmmessage = m;
174         if (cvar("teamplay") != stof(m))
175                 cvar_set("teamplay", m);
176 }
177
178 void() mode_updatecvars =
179 {
180         local float dm, tp;
181         dm = cvar("deathmatch");
182         tp = cvar("teamplay");
183         // now set deathmatch cvar
184         if (dm ==  0) setdm("0?Dark Places - Coop");
185         else if (dm ==  1) setdm("1?Dark Places - Deathmatch");
186         else if (dm ==  2) setdm("2?Dark Places - Deathmatch 2 (can only pickup gun once)");
187         else if (dm ==  3) setdm("3?Dark Places - Deathmatch 3 (quick ammo respawn)");
188         else if (dm ==  5) setdm("5?Dark Places - Frag Fest (spawn with full pack)");
189 //      else if (dm ==  6) setdm("6?Dark Places - Random Weapons (spawn with 2 random weapons)"); // removed
190         else if (dm ==  7) setdm("7?Dark Places - Monsters");
191 //      else if (dm ==  8) setdm("8?Dark Places - Elimination");
192 //      else if (dm ==  9) setdm("9?Dark Places - Kill The Leader Mode");
193         else if (dm == 10) setdm("10?Dark Places - Capture The Flag - 2 Team");
194         else if (dm == 11) setdm("11?Dark Places - Capture The Flag - 3 Team");
195         else if (dm == 12) setdm("12?Dark Places - Domination");
196         else if (dm == 13) setdm("13?Dark Places - Monster Capture The Flag - 2 Team");
197         else if (dm == 14) setdm("14?Dark Places - Super Domination");
198         else if (dm == 30) setdm("30?Dark Places - Role Playing Game");
199         else                               setdm("1?Dark Places - Deathmatch");
200
201         // now set teamplay cvar
202         if (dm == 0) setteamplay("4?Dark Places - Coop (Can't hurt other players)");
203         //else if (dm == 8) setteamplay("3?Dark Places - Elimination");
204         //else if (dm == 9) setteamplay("3?Dark Places - Kill The Leader");
205         else if (dm == 10) setteamplay("3?Dark Places - Capture The Flag - 2 Team");
206         else if (dm == 11) setteamplay("3?Dark Places - Capture The Flag - 3 Team");
207         else if (dm == 12) setteamplay("3?Dark Places - Domination");
208         else if (dm == 13) setteamplay("3?Dark Places - Monster Capture The Flag - 2 Team");
209         else
210         {
211                 if (tp == 0) setteamplay("0?Dark Places - No Teamplay");
212                 else if (tp == 1) setteamplay("1?Dark Places - No team damage");
213                 else if (tp == 2) setteamplay("2?Dark Places - Can hurt anyone");
214                 else if (tp == 3) setteamplay("3?Dark Places - No team damage, but can hurt self");
215                 else              setteamplay("0?Dark Places - No Teamplay");
216         }
217 };
218
219 float nextcvarupdate;
220 void() deathmatch7update;
221 void() modeupdate =
222 {
223         if (time > nextcvarupdate)
224         {
225                 nextcvarupdate = time + 1;
226                 mode_updatecvars();
227         }
228         deathmatch7update();
229 };
230
231 // true if items should respawn
232 float itemrespawn;
233 // when the next monster spawning check will occur in deathmatch 7 mode
234 float spawnchecktime;
235
236 void() precachemonsters;
237 void() superdomination_precache;
238 void() modesetup =
239 {
240         mode_shirtmustmatchpants = deathmatch >= DM_TEAM_MODS_START && deathmatch < DM_TEAM_MODS_END;
241         mode_initallowedteams();
242
243         itemrespawn = cvar("deathmatch") + cvar("coop");
244
245         // don't spawn any monsters until 15 seconds
246         spawnchecktime = 15;
247         if (deathmatch == 7 || cvar("spawnmonsters") >= 1)
248                 precachemonsters();
249
250         superdomination_precache();
251 };
252
253 float monsterspawn;
254 void() spawnmonster_think =
255 {
256         //local float c;
257         local void() sfunc;
258         self.nextthink = time;
259         if (time > self.cnt)
260         {
261                 remove(self);
262                 return;
263         }
264         if (vlen(self.velocity) > 5)
265                 return; // try again later
266
267         //if (!(self.flags & FL_FLY))
268         //      droptofloor();
269         // don't spawn if something is in the way
270         /*
271         // walk around a lot
272         if (walkmove(0,0))
273         {
274                 if (self.lefty > 0)
275                 {
276                         c = 100;
277                         self.lefty = self.lefty - 1;
278                         self.angles = '0 0 0';
279                         while(c > 0)
280                         {
281                                 c = c - 1;
282                                 if (!walkmove(self.angles_y, 16))
283                                         self.angles_y = random() * 360;
284                         }
285                         self.angles = '0 0 0';
286                         return;
287                 }
288         }
289         */
290         // don't spawn if something is in the way
291         if (!walkmove(0,0))
292         {
293                 self.lefty = 10;
294                 setorigin(self, self.dest);
295                 self.flags = self.flags - (self.flags & FL_ONGROUND);
296                 self.velocity = randomvec() * 700 + '0 0 1000';
297                 return;
298         }
299         newmis = findchain(classname, "player");
300         while (newmis)
301         {
302                 if (vlen(newmis.origin - self.origin) < 300)
303                         return;
304                 newmis = newmis.chain;
305         }
306
307         if (self.netname == "monster_fish")
308         {
309                 if (pointcontents(self.origin) != CONTENT_WATER)
310                 {
311                         remove(self);
312                         return;
313                 }
314         }
315
316         // spawn in
317         self.movetype = MOVETYPE_NONE;
318         self.solid = SOLID_NOT;
319         self.velocity = '0 0 0';
320         self.flags = 0;
321         self.model = "";
322         self.modelindex = 0;
323         setorigin(self, self.origin);
324         self.angles = '0 360 0' * random();
325         self.classname = self.netname;
326         self.netname = "";
327         self.cnt = 0;
328         self.think = SUB_Remove;
329         sfunc = self.th_run;
330         self.th_run = SUB_Null;
331         te_teleport(self.origin);
332         monsterspawn = TRUE;
333         sfunc();
334         monsterspawn = FALSE;
335 };
336
337 void(vector org, float c1, float c2, string cname, void() spawnfunc, vector m1, vector m2) spawnmonster =
338 {
339         local float c;
340         c = (c2 - c1) * random() + c1;
341         c = rint(c);
342         while (c > 0)
343         {
344                 c = c - 1;
345
346                 newmis = spawn();
347                 newmis.cnt = time + 10;
348                 if (cname == "monster_wizard")
349                         newmis.cnt = time + 2;
350                 newmis.lefty = 10;
351                 newmis.dest = org;
352                 newmis.classname = "spawningmonster";
353                 newmis.netname = cname;
354                 newmis.solid = SOLID_TRIGGER;
355                 newmis.movetype = MOVETYPE_TOSS;
356                 newmis.flags = FL_MONSTER; // make this count as a monster even though it hasn't spawned in yet
357                 newmis.velocity = randomvec() * 700 + '0 0 1000';
358                 newmis.th_run = spawnfunc;
359                 newmis.think = spawnmonster_think;
360                 newmis.nextthink = time + random() * 0.5 + 0.3;
361                 setorigin(newmis, org);
362                 setmodel(newmis, "progs/s_explod.spr");
363                 setsize(newmis, m1, m2);
364         }
365 };
366
367 void() monster_army;
368 void() monster_demon1;
369 void() monster_dog;
370 void() monster_enforcer;
371 void() monster_hell_knight;
372 void() monster_knight;
373 void() monster_ogre;
374 void() monster_shalrath;
375 void() monster_shambler;
376 void() monster_tarbaby;
377 void() monster_wizard;
378 void() monster_zombie;
379 void() monster_fish;
380 void() monster_hellfish;
381
382 void() spawnmonsters =
383 {
384         local float r;
385         local vector org;
386         local entity head, e;
387         head = findchain(classname, "info_player_deathmatch");
388         if (head == world)
389         {
390                 head = findchain(classname, "info_player_coop");
391                 if (head == world)
392                 {
393                         head = findchain(classname, "info_player_start");
394                         if (head == world)
395                                 return;
396                 }
397         }
398
399         // count the spawn points
400         r = 0;
401         e = head;
402         while (e)
403         {
404                 r = r + 1;
405                 e = e.chain;
406         }
407
408         // pick a random one
409         r = random() * r;
410         e = head;
411         while (r > 0)
412         {
413                 r = r - 1;
414                 org = e.origin;
415                 e = e.chain;
416         }
417
418         // pick a type of monster
419         if (cvar("registered"))
420         {
421                 r = floor(random() * 13);
422                 if (r > 12)
423                         r = 12;
424         }
425         else
426         {
427                 r = floor(random() * 8);
428                 if (r > 7)
429                         r = 7;
430         }
431              if (r ==  0) spawnmonster(org,  5, 10, "monster_army"       , monster_army       , '-16 -16 -24', '16 16 32');
432         else if (r ==  1) spawnmonster(org,  3,  6, "monster_demon1"     , monster_demon1     , '-32 -32 -24', '32 32 64');
433         else if (r ==  2) spawnmonster(org,  6, 12, "monster_dog"        , monster_dog        , '-16 -16 -24', '16 16 32');
434         else if (r ==  3) spawnmonster(org,  6, 12, "monster_knight"     , monster_knight     , '-16 -16 -24', '16 16 32');
435         else if (r ==  4) spawnmonster(org,  3,  6, "monster_ogre"       , monster_ogre       , '-32 -32 -24', '32 32 64');
436         else if (r ==  5) spawnmonster(org,  1,  1, "monster_shambler"   , monster_shambler   , '-32 -32 -24', '32 32 64');
437         else if (r ==  6) spawnmonster(org,  6, 10, "monster_wizard"     , monster_wizard     , '-16 -16 -24', '16 16 32');
438         else if (r ==  7) spawnmonster(org,  8, 16, "monster_zombie"     , monster_zombie     , '-16 -16 -24', '16 16 32');
439         else if (r ==  8) spawnmonster(org,  4,  8, "monster_enforcer"   , monster_enforcer   , '-16 -16 -24', '16 16 32');
440         else if (r ==  9) spawnmonster(org,  4,  8, "monster_hell_knight", monster_hell_knight, '-16 -16 -24', '16 16 32');
441         else if (r == 10) spawnmonster(org,  1,  3, "monster_shalrath"   , monster_shalrath   , '-32 -32 -24', '32 32 64');
442         else if (r == 11) spawnmonster(org, 10, 15, "monster_tarbaby"    , monster_tarbaby    , '-16 -16 -24', '16 16 32');
443         else if (r == 12) spawnmonster(org,  4,  8, "monster_fish"       , monster_fish       , '-16 -16 -24', '16 16 32');
444 };
445
446 float monstersprecached;
447 void() precachemonster_army;
448 void() precachemonster_demon1;
449 void() precachemonster_dog;
450 void() precachemonster_enforcer;
451 void() precachemonster_hell_knight;
452 void() precachemonster_knight;
453 void() precachemonster_ogre;
454 void() precachemonster_shalrath;
455 void() precachemonster_shambler;
456 void() precachemonster_tarbaby;
457 void() precachemonster_wizard;
458 void() precachemonster_zombie;
459 void() precachemonster_fish;
460
461 void() precachemonsters =
462 {
463         precachemonster_army();
464         precachemonster_demon1();
465         precachemonster_dog();
466         precachemonster_knight();
467         precachemonster_ogre();
468         precachemonster_shambler();
469         precachemonster_wizard();
470         precachemonster_zombie();
471         if (cvar("registered"))
472         {
473                 precachemonster_enforcer();
474                 precachemonster_hell_knight();
475                 precachemonster_shalrath();
476                 precachemonster_tarbaby();
477                 precachemonster_fish();
478         }
479         monstersprecached = TRUE;
480 };
481
482 float spawnedexitmonsters;
483 void() deathmatch7update =
484 {
485         local entity e;
486         local float f, monster_count, monsters;
487         if (skill >= 5)
488         if (!deathmatch)
489         {
490                 if (!spawnedexitmonsters)
491                 if (time >= 2)
492                 {
493                         spawnedexitmonsters = TRUE;
494                         e = find(world, classname, "target_changelevel");
495                         while (e)
496                         {
497                                 spawnmonster(e.origin + (e.mins + e.maxs) * 0.5, 8, 8, "monster_hellfish", monster_hellfish, '-16 -16 -24', '16 16 32');
498                                 e = find(e, classname, "target_changelevel");
499                         }
500                 }
501                 return;
502         }
503         if (time < spawnchecktime)
504                 return;
505         if (!monstersprecached)
506                 return;
507         spawnchecktime = time + 0.2;
508         monsters = 0;
509         if (deathmatch == 7)
510                 monsters = 50;
511         f = cvar("spawnmonsters");
512         if (f >= 1)
513                 monsters = f;
514         if (monsters < 1)
515                 return;
516         monster_count = 0;
517         e = findchainflags(flags, FL_MONSTER);
518         while (e)
519         {
520                 monster_count = monster_count + 1;
521                 e = e.chain;
522         }
523         if (monster_count >= monsters)
524                 return;
525         spawnmonsters();
526 }