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