]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/domination.qc
2b6650b3d310ee3e8f514c30b58c8c37936a28ef
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / domination.qc
1
2 /*
3 Domination as a plugin for netquake mods
4 by LordHavoc (lordhavoc@ghdigital.com)
5
6 How to add domination points to a mod:
7 1. Add this line to progs.src above world.qc:
8 domination.qc
9 2. Comment out all lines in ClientObituary in client.qc that begin with targ.frags  or attacker.frags.
10 3. Add this above spawnfunc_worldspawn in world.qc:
11 void() dom_init;
12 4. Add this line to the end of spawnfunc_worldspawn in world.qc:
13 dom_init();
14
15 Note: The only teams who can use dom control points are identified by spawnfunc_dom_team entities (if none exist these default to red and blue and use only quake models/sounds).
16 */
17
18 #define DOMPOINTFRAGS frags
19
20 .float enemy_playerid;
21 .entity sprite;
22 .float captime;
23
24 // pps: points per second
25 float dom_total_pps;
26 float dom_pps_red;
27 float dom_pps_blue;
28 float dom_pps_yellow;
29 float dom_pps_pink;
30 void send_CSQC_dom_state()
31 {
32         WriteByte(MSG_ALL, SVC_TEMPENTITY);
33         WriteByte(MSG_ALL, TE_CSQC_DOM);
34         WriteShort(MSG_ALL, dom_pps_red * 100.0);
35         WriteShort(MSG_ALL, dom_pps_blue * 100.0);
36         if (c3 >= 0) WriteShort(MSG_ALL, dom_pps_yellow * 100.0);
37         if (c4 >= 0) WriteShort(MSG_ALL, dom_pps_pink * 100.0);
38 }
39 //Must be called ONLY when a client connects to send total pps and state
40 //If yellow/pink team doesn't exist sends a negative dom_pps_yellow/dom_pps_pink
41 //to let know the client to not read these values anymore
42 void send_CSQC_dom_all()
43 {
44         WriteByte(MSG_ALL, SVC_TEMPENTITY);
45         WriteByte(MSG_ALL, TE_CSQC_DOM);
46         WriteShort(MSG_ALL, dom_total_pps * 100.0);
47         WriteShort(MSG_ALL, dom_pps_red * 100.0);
48         WriteShort(MSG_ALL, dom_pps_blue * 100.0);
49         WriteShort(MSG_ALL, dom_pps_yellow * 100.0);
50         WriteShort(MSG_ALL, dom_pps_pink * 100.0);
51 }
52
53 void() dom_controlpoint_setup;
54
55 void LogDom(string mode, float team_before, entity actor)
56 {
57         string s;
58         if(!autocvar_sv_eventlog)
59                 return;
60         s = strcat(":dom:", mode);
61         s = strcat(s, ":", ftos(team_before));
62         s = strcat(s, ":", ftos(actor.playerid));
63         GameLogEcho(s);
64 }
65
66 void() dom_spawnteams;
67
68 void dompoint_captured ()
69 {
70         local entity head;
71         local float old_delay, old_team, real_team;
72
73         // now that the delay has expired, switch to the latest team to lay claim to this point
74         head = self.owner;
75
76         real_team = self.cnt;
77         self.cnt = -1;
78
79         LogDom("taken", self.team, self.dmg_inflictor);
80         self.dmg_inflictor = world;
81
82         self.goalentity = head;
83         self.model = head.mdl;
84         self.modelindex = head.dmg;
85         self.skin = head.skin;
86
87         //bprint(head.message);
88         //bprint("\n");
89
90         //bprint(^3head.netname);
91         //bprint(head.netname);
92         //bprint(self.message);
93         //bprint("\n");
94
95         float points, wait_time;
96         if (autocvar_g_domination_point_amt)
97                 points = autocvar_g_domination_point_amt;
98         else
99                 points = self.frags;
100         if (autocvar_g_domination_point_rate)
101                 wait_time = autocvar_g_domination_point_rate;
102         else
103                 wait_time = self.wait;
104
105         bprint("^3", head.netname, "^3", self.message);
106         if (points != 1)
107                 bprint(" ^7(", ftos(points), " points every ", ftos(wait_time), " seconds)\n");
108         else
109                 bprint(" ^7(", ftos(points), " point every ", ftos(wait_time), " seconds)\n");
110
111         if(self.enemy.playerid == self.enemy_playerid)
112                 PlayerScore_Add(self.enemy, SP_DOM_TAKES, 1);
113         else
114                 self.enemy = world;
115
116         if (head.noise != "")
117                 if(self.enemy)
118                         sound(self.enemy, CHAN_AUTO, head.noise, VOL_BASE, ATTN_NORM);
119                 else
120                         sound(self, CHAN_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
121         if (head.noise1 != "")
122                 play2all(head.noise1);
123
124         //self.nextthink = time + autocvar_g_domination_point_rate;
125         //self.think = dompointthink;
126
127         self.delay = time + wait_time;
128
129         // do trigger work
130         old_delay = self.delay;
131         old_team = self.team;
132         self.team = real_team;
133         self.delay = 0;
134         activator = self;
135         SUB_UseTargets ();
136         self.delay = old_delay;
137         self.team = old_team;
138
139         switch(self.team)
140         {
141                 // "fix" pps when slightly under 0 because of approximation errors
142                 case COLOR_TEAM1:
143                         dom_pps_red -= (points/wait_time);
144                         if (dom_pps_red < 0) dom_pps_red = 0;
145                         break;
146                 case COLOR_TEAM2:
147                         dom_pps_blue -= (points/wait_time);
148                         if (dom_pps_blue < 0) dom_pps_blue = 0;
149                         break;
150                 case COLOR_TEAM3:
151                         dom_pps_yellow -= (points/wait_time);
152                         if (dom_pps_yellow < 0) dom_pps_yellow = 0;
153                         break;
154                 case COLOR_TEAM4:
155                         dom_pps_pink -= (points/wait_time);
156                         if (dom_pps_pink < 0) dom_pps_pink = 0;
157         }
158
159         switch(self.goalentity.team)
160         {
161                 // "fix" pps when slightly over dom_total_pps because of approximation errors
162                 case COLOR_TEAM1:
163                         dom_pps_red += (points/wait_time);
164                         if (dom_pps_red > dom_total_pps) dom_pps_red = dom_total_pps;
165                         WaypointSprite_UpdateSprites(self.sprite, "dom-red", "", "");
166                         break;
167                 case COLOR_TEAM2:
168                         dom_pps_blue += (points/wait_time);
169                         if (dom_pps_blue > dom_total_pps) dom_pps_blue = dom_total_pps;
170                         WaypointSprite_UpdateSprites(self.sprite, "dom-blue", "", "");
171                         break;
172                 case COLOR_TEAM3:
173                         dom_pps_yellow += (points/wait_time);
174                         if (dom_pps_yellow > dom_total_pps) dom_pps_yellow = dom_total_pps;
175                         WaypointSprite_UpdateSprites(self.sprite, "dom-yellow", "", "");
176                         break;
177                 case COLOR_TEAM4:
178                         dom_pps_pink += (points/wait_time);
179                         if (dom_pps_pink > dom_total_pps) dom_pps_pink = dom_total_pps;
180                         WaypointSprite_UpdateSprites(self.sprite, "dom-pink", "", "");
181         }
182
183         send_CSQC_dom_state();
184
185         WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, colormapPaletteColor(self.goalentity.team - 1, 0));
186         WaypointSprite_Ping(self.sprite);
187
188         self.captime = time;
189 };
190
191 void AnimateDomPoint()
192 {
193         if(self.pain_finished > time)
194                 return;
195         self.pain_finished = time + self.t_width;
196         if(self.nextthink > self.pain_finished)
197                 self.nextthink = self.pain_finished;
198
199         self.frame = self.frame + 1;
200         if(self.frame > self.t_length)
201                 self.frame = 0;
202 }
203
204 void dompointthink()
205 {
206         local float fragamt;
207
208         self.nextthink = time + 0.1;
209
210         //self.frame = self.frame + 1;
211         //if(self.frame > 119)
212         //      self.frame = 0;
213         AnimateDomPoint();
214
215         // give points
216
217         if (gameover || self.delay > time || time < game_starttime)     // game has ended, don't keep giving points
218                 return;
219
220         if(autocvar_g_domination_point_rate)
221                 self.delay = time + autocvar_g_domination_point_rate;
222         else
223                 self.delay = time + self.wait;
224
225         // give credit to the team
226         // NOTE: this defaults to 0
227         if (self.goalentity.netname != "")
228         {
229                 if(autocvar_g_domination_point_amt)
230                         fragamt = autocvar_g_domination_point_amt;
231                 else
232                         fragamt = self.DOMPOINTFRAGS;
233                 TeamScore_AddToTeam(self.goalentity.team, ST_SCORE, fragamt);
234                 TeamScore_AddToTeam(self.goalentity.team, ST_DOM_TICKS, fragamt);
235
236                 // give credit to the individual player, if he is still there
237                 if (self.enemy.playerid == self.enemy_playerid)
238                 {
239                         PlayerScore_Add(self.enemy, SP_SCORE, fragamt);
240                         PlayerScore_Add(self.enemy, SP_DOM_TICKS, fragamt);
241                 }
242                 else
243                         self.enemy = world;
244         }
245 }
246
247 void dompointtouch()
248 {
249         local entity head;
250         if (other.classname != "player")
251                 return;
252         if (other.health < 1)
253                 return;
254
255         if(time < self.captime + 0.3)
256                 return;
257
258         // only valid teams can claim it
259         head = find(world, classname, "dom_team");
260         while (head && head.team != other.team)
261                 head = find(head, classname, "dom_team");
262         if (!head || head.netname == "" || head == self.goalentity)
263                 return;
264
265         // delay capture
266
267         self.team = self.goalentity.team; // this stores the PREVIOUS team!
268
269         self.cnt = other.team;
270         self.owner = head; // team to switch to after the delay
271         self.dmg_inflictor = other;
272
273         // self.state = 1;
274         // self.delay = time + cvar("g_domination_point_capturetime");
275         //self.nextthink = time + cvar("g_domination_point_capturetime");
276         //self.think = dompoint_captured;
277
278         // go to neutral team in the mean time
279         head = find(world, classname, "dom_team");
280         while (head && head.netname != "")
281                 head = find(head, classname, "dom_team");
282         if(head == world)
283                 return;
284
285         WaypointSprite_UpdateSprites(self.sprite, "dom-neut", "", "");
286         WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, '0 1 1');
287         WaypointSprite_Ping(self.sprite);
288
289         self.goalentity = head;
290         self.model = head.mdl;
291         self.modelindex = head.dmg;
292         self.skin = head.skin;
293
294         self.enemy = other; // individual player scoring
295         self.enemy_playerid = other.playerid;
296         dompoint_captured();
297 };
298
299 /*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
300 Team declaration for Domination gameplay, this allows you to decide what team
301 names and control point models are used in your map.
302
303 Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
304 can have netname set!  The nameless team owns all control points at start.
305
306 Keys:
307 "netname"
308  Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
309 "cnt"
310  Scoreboard color of the team (for example 4 is red and 13 is blue)
311 "model"
312  Model to use for control points owned by this team (for example
313  "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
314  keycard)
315 "skin"
316  Skin of the model to use (for team skins on a single model)
317 "noise"
318  Sound to play when this team captures a point.
319  (this is a localized sound, like a small alarm or other effect)
320 "noise1"
321  Narrator speech to play when this team captures a point.
322  (this is a global sound, like "Red team has captured a control point")
323 */
324
325 void spawnfunc_dom_team()
326 {
327         if(!g_domination || autocvar_g_domination_teams_override >= 2)
328         {
329                 remove(self);
330                 return;
331         }
332         precache_model(self.model);
333         if (self.noise != "")
334                 precache_sound(self.noise);
335         if (self.noise1 != "")
336                 precache_sound(self.noise1);
337         self.classname = "dom_team";
338         setmodel(self, self.model); // precision not needed
339         self.mdl = self.model;
340         self.dmg = self.modelindex;
341         self.model = "";
342         self.modelindex = 0;
343         // this would have to be changed if used in quakeworld
344         if(self.cnt)
345                 self.team = self.cnt + 1; // WHY are these different anyway?
346 };
347
348 void dom_controlpoint_setup()
349 {
350         local entity head;
351         // find the spawnfunc_dom_team representing unclaimed points
352         head = find(world, classname, "dom_team");
353         while(head && head.netname != "")
354                 head = find(head, classname, "dom_team");
355         if (!head)
356                 objerror("no spawnfunc_dom_team with netname \"\" found\n");
357
358         // copy important properties from spawnfunc_dom_team entity
359         self.goalentity = head;
360         setmodel(self, head.mdl); // precision already set
361         self.skin = head.skin;
362
363         self.cnt = -1;
364
365         if(!self.message)
366                 self.message = " has captured a control point";
367
368         if(self.DOMPOINTFRAGS <= 0)
369                 self.DOMPOINTFRAGS = 1;
370         if(self.wait <= 0)
371                 self.wait = 5;
372
373         float points, waittime;
374         if (g_domination_point_rate)
375                 points = g_domination_point_rate;
376         else
377                 points = self.frags;
378         if (g_domination_point_amt)
379                 waittime = g_domination_point_amt;
380         else
381                 waittime = self.wait;
382
383         dom_total_pps += points/waittime;
384
385         if(!self.t_width)
386                 self.t_width = 0.02; // frame animation rate
387         if(!self.t_length)
388                 self.t_length = 239; // maximum frame
389
390         self.think = dompointthink;
391         self.nextthink = time;
392         self.touch = dompointtouch;
393         self.solid = SOLID_TRIGGER;
394         self.flags = FL_ITEM;
395         setsize(self, '-32 -32 -32', '32 32 32');
396         setorigin(self, self.origin + '0 0 20');
397         droptofloor();
398
399         waypoint_spawnforitem(self);
400         WaypointSprite_SpawnFixed("dom-neut", self.origin + '0 0 32', self, sprite);
401         WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, '0 1 1');
402 };
403
404
405
406 // player has joined game, get him on a team
407 // depreciated
408 /*void dom_player_join_team(entity pl)
409 {
410         entity head;
411         float c1, c2, c3, c4, totalteams, smallestteam, smallestteam_count, selectedteam;
412         float balance_teams, force_balance, balance_type;
413
414         balance_teams = autocvar_g_balance_teams;
415         balance_teams = autocvar_g_balance_teams_force;
416
417         c1 = c2 = c3 = c4 = -1;
418         totalteams = 0;
419
420         // first find out what teams are allowed
421         head = find(world, classname, "dom_team");
422         while(head)
423         {
424                 if(head.netname != "")
425                 {
426                         //if(head.team == pl.team)
427                         //      selected = head;
428                         if(head.team == COLOR_TEAM1)
429                         {
430                                         c1 = 0;
431                         }
432                         if(head.team == COLOR_TEAM2)
433                         {
434                                         c2 = 0;
435                         }
436                         if(head.team == COLOR_TEAM3)
437                         {
438                                         c3 = 0;
439                         }
440                         if(head.team == COLOR_TEAM4)
441                         {
442                                         c4 = 0;
443                         }
444                 }
445                 head = find(head, classname, "dom_team");
446         }
447
448         // make sure there are at least 2 teams to join
449         if(c1 >= 0)
450                 totalteams = totalteams + 1;
451         if(c2 >= 0)
452                 totalteams = totalteams + 1;
453         if(c3 >= 0)
454                 totalteams = totalteams + 1;
455         if(c4 >= 0)
456                 totalteams = totalteams + 1;
457
458         if(totalteams <= 1)
459                 error("dom_player_join_team: Too few teams available for domination\n");
460
461         // whichever teams that are available are set to 0 instead of -1
462
463         // if we don't care what team he ends up on, put him on whatever team he entered as.
464         // if he's not on a valid team, then put him on the smallest team
465         if(!balance_teams && !force_balance)
466         {
467                 if(     c1 >= 0 && pl.team == COLOR_TEAM1)
468                         selectedteam = pl.team;
469                 else if(c2 >= 0 && pl.team == COLOR_TEAM2)
470                         selectedteam = pl.team;
471                 else if(c3 >= 0 && pl.team == COLOR_TEAM3)
472                         selectedteam = pl.team;
473                 else if(c4 >= 0 && pl.team == COLOR_TEAM4)
474                         selectedteam = pl.team;
475                 else
476                         selectedteam = -1;
477                 if(selectedteam > 0)
478                 {
479                         SetPlayerColors(pl, selectedteam - 1);
480                         return;
481                 }
482                 // otherwise end up on the smallest team (handled below)
483         }
484
485         // now count how many players are on each team already
486
487         head = find(world, classname, "player");
488         while(head)
489         {
490                 //if(head.netname != "")
491                 {
492                         if(head.team == COLOR_TEAM1)
493                         {
494                                 if(c1 >= 0)
495                                         c1 = c1 + 1;
496                         }
497                         if(head.team == COLOR_TEAM2)
498                         {
499                                 if(c2 >= 0)
500                                         c2 = c2 + 1;
501                         }
502                         if(head.team == COLOR_TEAM3)
503                         {
504                                 if(c3 >= 0)
505                                         c3 = c3 + 1;
506                         }
507                         if(head.team == COLOR_TEAM4)
508                         {
509                                 if(c4 >= 0)
510                                         c4 = c4 + 1;
511                         }
512                 }
513                 head = find(head, classname, "player");
514         }
515
516         // c1...c4 now have counts of each team
517         // figure out which is smallest, giving priority to the team the player is already on as a tie-breaker
518
519         smallestteam = 0;
520         smallestteam_count = 999;
521
522         // 2 gives priority to what team you're already on, 1 goes in order
523         balance_type = 1;
524
525         if(balance_type == 1)
526         {
527                 if(c1 >= 0 && c1 < smallestteam_count)
528                 {
529                         smallestteam = 1;
530                         smallestteam_count = c1;
531                 }
532                 if(c2 >= 0 && c2 < smallestteam_count)
533                 {
534                         smallestteam = 2;
535                         smallestteam_count = c2;
536                 }
537                 if(c3 >= 0 && c3 < smallestteam_count)
538                 {
539                         smallestteam = 3;
540                         smallestteam_count = c3;
541                 }
542                 if(c4 >= 0 && c4 < smallestteam_count)
543                 {
544                         smallestteam = 4;
545                         smallestteam_count = c4;
546                 }
547         }
548         else
549         {
550                 if(c1 >= 0 && (c1 < smallestteam_count ||
551                                         (c1 == smallestteam_count && self.team == COLOR_TEAM1) ) )
552                 {
553                         smallestteam = 1;
554                         smallestteam_count = c1;
555                 }
556                 if(c2 >= 0 && c2 < (c2 < smallestteam_count ||
557                                         (c2 == smallestteam_count && self.team == COLOR_TEAM2) ) )
558                 {
559                         smallestteam = 2;
560                         smallestteam_count = c2;
561                 }
562                 if(c3 >= 0 && c3 < (c3 < smallestteam_count ||
563                                         (c3 == smallestteam_count && self.team == COLOR_TEAM3) ) )
564                 {
565                         smallestteam = 3;
566                         smallestteam_count = c3;
567                 }
568                 if(c4 >= 0 && c4 < (c4 < smallestteam_count ||
569                                         (c4 == smallestteam_count && self.team == COLOR_TEAM4) ) )
570                 {
571                         smallestteam = 4;
572                         smallestteam_count = c4;
573                 }
574         }
575
576         if(smallestteam == 1)
577         {
578                 selectedteam = COLOR_TEAM1 - 1;
579         }
580         if(smallestteam == 2)
581         {
582                 selectedteam = COLOR_TEAM2 - 1;
583         }
584         if(smallestteam == 3)
585         {
586                 selectedteam = COLOR_TEAM3 - 1;
587         }
588         if(smallestteam == 4)
589         {
590                 selectedteam = COLOR_TEAM4 - 1;
591         }
592
593         SetPlayerColors(pl, selectedteam);
594 }
595 */
596 /*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
597 Control point for Domination gameplay.
598 */
599 void spawnfunc_dom_controlpoint()
600 {
601         if(!g_domination)
602         {
603                 remove(self);
604                 return;
605         }
606         self.think = dom_controlpoint_setup;
607         self.nextthink = time + 0.1;
608         self.reset = dom_controlpoint_setup;
609
610         if(!self.scale)
611                 self.scale = 0.6;
612
613         //if(!self.glow_size)
614         //      self.glow_size = cvar("g_domination_point_glow");
615         self.effects = self.effects | EF_LOWPRECISION;
616         if (autocvar_g_domination_point_fullbright)
617                 self.effects |= EF_FULLBRIGHT;
618 };
619
620 // code from here on is just to support maps that don't have control point and team entities
621 void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, string capsound, string capnarration, string capmessage)
622 {
623         local entity oldself;
624         oldself = self;
625         self = spawn();
626         self.classname = "dom_team";
627         self.netname = teamname;
628         self.cnt = teamcolor;
629         self.model = pointmodel;
630         self.skin = pointskin;
631         self.noise = capsound;
632         self.noise1 = capnarration;
633         self.message = capmessage;
634
635         // this code is identical to spawnfunc_dom_team
636         setmodel(self, self.model); // precision not needed
637         self.mdl = self.model;
638         self.dmg = self.modelindex;
639         self.model = "";
640         self.modelindex = 0;
641         // this would have to be changed if used in quakeworld
642         self.team = self.cnt + 1;
643
644         //eprint(self);
645         self = oldself;
646 };
647
648 void dom_spawnpoint(vector org)
649 {
650         local entity oldself;
651         oldself = self;
652         self = spawn();
653         self.classname = "dom_controlpoint";
654         self.think = spawnfunc_dom_controlpoint;
655         self.nextthink = time;
656         setorigin(self, org);
657         spawnfunc_dom_controlpoint();
658         self = oldself;
659 };
660
661 // spawn some default teams if the map is not set up for domination
662 void dom_spawnteams()
663 {
664         float numteams;
665         if(autocvar_g_domination_teams_override < 2)
666                 numteams = autocvar_g_domination_default_teams;
667         else
668                 numteams = autocvar_g_domination_teams_override;
669         // LordHavoc: edit this if you want to change defaults
670         dom_spawnteam("Red", COLOR_TEAM1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
671         dom_spawnteam("Blue", COLOR_TEAM2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
672         if(numteams > 2)
673                 dom_spawnteam("Yellow", COLOR_TEAM3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
674         if(numteams > 3)
675                 dom_spawnteam("Pink", COLOR_TEAM4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
676         dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
677 };
678
679 void dom_delayedinit()
680 {
681         local entity head;
682
683         // if no teams are found, spawn defaults, if custom teams are set, use them
684         if (find(world, classname, "dom_team") == world || autocvar_g_domination_teams_override >= 2)
685                 dom_spawnteams();
686         // if no control points are found, spawn defaults
687         if (find(world, classname, "dom_controlpoint") == world)
688         {
689                 // here follow default domination points for each map
690                 /*
691                 if (world.model == "maps/e1m1.bsp")
692                 {
693                         dom_spawnpoint('0 0 0');
694                 }
695                 else
696                 */
697                 {
698                         // if no supported map was found, make every deathmatch spawn a point
699                         head = find(world, classname, "info_player_deathmatch");
700                         while (head)
701                         {
702                                 dom_spawnpoint(head.origin);
703                                 head = find(head, classname, "info_player_deathmatch");
704                         }
705                 }
706         }
707         if (c3 == -1) dom_pps_yellow = -1;
708         if (c4 == -1) dom_pps_pink = -1;
709
710         ScoreRules_dom();
711 };
712
713 void dom_init()
714 {
715         // we have to precache default models/sounds even if they might not be
716         // used because spawnfunc_worldspawn is executed before any other entities are read,
717         // so we don't even know yet if this map is set up for domination...
718         precache_model("models/domination/dom_red.md3");
719         precache_model("models/domination/dom_blue.md3");
720         precache_model("models/domination/dom_yellow.md3");
721         precache_model("models/domination/dom_pink.md3");
722         precache_model("models/domination/dom_unclaimed.md3");
723         precache_sound("domination/claim.wav");
724         InitializeEntity(world, dom_delayedinit, INITPRIO_GAMETYPE);
725
726         g_domination_point_rate = cvar("g_domination_point_rate");
727         g_domination_point_amt = cvar("g_domination_point_amt");
728 };
729