]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote-tracking branch 'origin/master' into samual/notification_rewrite
authorSamual Lenks <samual@xonotic.org>
Mon, 4 Feb 2013 23:13:07 +0000 (18:13 -0500)
committerSamual Lenks <samual@xonotic.org>
Mon, 4 Feb 2013 23:13:07 +0000 (18:13 -0500)
Conflicts:
qcsrc/server/teamplay.qc

1  2 
qcsrc/server/attic/domination.qc
qcsrc/server/cl_client.qc
qcsrc/server/g_world.qc
qcsrc/server/mutators/gamemode_domination.qc
qcsrc/server/progs.src
qcsrc/server/teamplay.qc

index 0000000000000000000000000000000000000000,6a0dcdf8b4e01679d23dfd1576c581e2c061e3ce..e0bad53d39f3fecb7975a22d7837d8a6e0db8728
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,525 +1,525 @@@
 -              case COLOR_TEAM1:
+ /*
+ Domination as a plugin for netquake mods
+ by LordHavoc (lordhavoc@ghdigital.com)
+ How to add domination points to a mod:
+ 1. Add this line to progs.src above world.qc:
+ domination.qc
+ 2. Comment out all lines in ClientObituary in client.qc that begin with targ.frags  or attacker.frags.
+ 3. Add this above spawnfunc_worldspawn in world.qc:
+ void() dom_init;
+ 4. Add this line to the end of spawnfunc_worldspawn in world.qc:
+ dom_init();
+ 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).
+ */
+ #define DOMPOINTFRAGS frags
+ .float enemy_playerid;
+ .entity sprite;
+ .float captime;
+ // pps: points per second
+ .float dom_total_pps;
+ .float dom_pps_red;
+ .float dom_pps_blue;
+ .float dom_pps_yellow;
+ .float dom_pps_pink;
+ float total_pps;
+ float pps_red;
+ float pps_blue;
+ float pps_yellow;
+ float pps_pink;
+ void set_dom_state(entity e)
+ {
+       e.dom_total_pps = total_pps;
+       e.dom_pps_red = pps_red;
+       e.dom_pps_blue = pps_blue;
+       if(c3 >= 0)
+               e.dom_pps_yellow = pps_yellow;
+       if(c4 >= 0)
+               e.dom_pps_pink = pps_pink;
+ }
+ void() dom_controlpoint_setup;
+ void LogDom(string mode, float team_before, entity actor)
+ {
+       string s;
+       if(!autocvar_sv_eventlog)
+               return;
+       s = strcat(":dom:", mode);
+       s = strcat(s, ":", ftos(team_before));
+       s = strcat(s, ":", ftos(actor.playerid));
+       GameLogEcho(s);
+ }
+ void() dom_spawnteams;
+ void dompoint_captured ()
+ {
+       entity head;
+       float old_delay, old_team, real_team;
+       // now that the delay has expired, switch to the latest team to lay claim to this point
+       head = self.owner;
+       real_team = self.cnt;
+       self.cnt = -1;
+       LogDom("taken", self.team, self.dmg_inflictor);
+       self.dmg_inflictor = world;
+       self.goalentity = head;
+       self.model = head.mdl;
+       self.modelindex = head.dmg;
+       self.skin = head.skin;
+       //bprint(head.message);
+       //bprint("\n");
+       //bprint(^3head.netname);
+       //bprint(head.netname);
+       //bprint(self.message);
+       //bprint("\n");
+       float points, wait_time;
+       if (autocvar_g_domination_point_amt)
+               points = autocvar_g_domination_point_amt;
+       else
+               points = self.frags;
+       if (autocvar_g_domination_point_rate)
+               wait_time = autocvar_g_domination_point_rate;
+       else
+               wait_time = self.wait;
+       bprint("^3", head.netname, "^3", self.message);
+       if (points != 1)
+               bprint(" ^7(", ftos(points), " points every ", ftos(wait_time), " seconds)\n");
+       else
+               bprint(" ^7(", ftos(points), " point every ", ftos(wait_time), " seconds)\n");
+       if(self.enemy.playerid == self.enemy_playerid)
+               PlayerScore_Add(self.enemy, SP_DOM_TAKES, 1);
+       else
+               self.enemy = world;
+       if (head.noise != "")
+               if(self.enemy)
+                       sound(self.enemy, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
+               else
+                       sound(self, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
+       if (head.noise1 != "")
+               play2all(head.noise1);
+       //self.nextthink = time + autocvar_g_domination_point_rate;
+       //self.think = dompointthink;
+       self.delay = time + wait_time;
+       // do trigger work
+       old_delay = self.delay;
+       old_team = self.team;
+       self.team = real_team;
+       self.delay = 0;
+       activator = self;
+       SUB_UseTargets ();
+       self.delay = old_delay;
+       self.team = old_team;
+       switch(self.goalentity.team)
+       {
 -              case COLOR_TEAM2:
++              case FL_TEAM_1:
+                       WaypointSprite_UpdateSprites(self.sprite, "dom-red", "", "");
+                       break;
 -              case COLOR_TEAM3:
++              case FL_TEAM_2:
+                       WaypointSprite_UpdateSprites(self.sprite, "dom-blue", "", "");
+                       break;
 -              case COLOR_TEAM4:
++              case FL_TEAM_3:
+                       WaypointSprite_UpdateSprites(self.sprite, "dom-yellow", "", "");
+                       break;
 -                      case COLOR_TEAM1:
++              case FL_TEAM_4:
+                       WaypointSprite_UpdateSprites(self.sprite, "dom-pink", "", "");
+       }
+       total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
+       for(head = world; (head = find(head, classname, "dom_controlpoint")) != world; )
+       {
+               if (autocvar_g_domination_point_amt)
+                       points = autocvar_g_domination_point_amt;
+               else
+                       points = head.frags;
+               if (autocvar_g_domination_point_rate)
+                       wait_time = autocvar_g_domination_point_rate;
+               else
+                       wait_time = head.wait;
+               switch(head.goalentity.team)
+               {
 -                      case COLOR_TEAM2:
++                      case FL_TEAM_1:
+                               pps_red += points/wait_time;
+                               break;
 -                      case COLOR_TEAM3:
++                      case FL_TEAM_2:
+                               pps_blue += points/wait_time;
+                               break;
 -                      case COLOR_TEAM4:
++                      case FL_TEAM_3:
+                               pps_yellow += points/wait_time;
+                               break;
 -      dom_spawnteam("Red", COLOR_TEAM1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
 -      dom_spawnteam("Blue", COLOR_TEAM2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
++                      case FL_TEAM_4:
+                               pps_pink += points/wait_time;
+               }
+               total_pps += points/wait_time;
+       }
+       WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, colormapPaletteColor(self.goalentity.team - 1, 0));
+       WaypointSprite_Ping(self.sprite);
+       self.captime = time;
+       FOR_EACH_REALCLIENT(head)
+               set_dom_state(head);
+ }
+ void AnimateDomPoint()
+ {
+       if(self.pain_finished > time)
+               return;
+       self.pain_finished = time + self.t_width;
+       if(self.nextthink > self.pain_finished)
+               self.nextthink = self.pain_finished;
+       self.frame = self.frame + 1;
+       if(self.frame > self.t_length)
+               self.frame = 0;
+ }
+ void dompointthink()
+ {
+       float fragamt;
+       self.nextthink = time + 0.1;
+       //self.frame = self.frame + 1;
+       //if(self.frame > 119)
+       //      self.frame = 0;
+       AnimateDomPoint();
+       // give points
+       if (gameover || self.delay > time || time < game_starttime)     // game has ended, don't keep giving points
+               return;
+       if(autocvar_g_domination_point_rate)
+               self.delay = time + autocvar_g_domination_point_rate;
+       else
+               self.delay = time + self.wait;
+       // give credit to the team
+       // NOTE: this defaults to 0
+       if (self.goalentity.netname != "")
+       {
+               if(autocvar_g_domination_point_amt)
+                       fragamt = autocvar_g_domination_point_amt;
+               else
+                       fragamt = self.DOMPOINTFRAGS;
+               TeamScore_AddToTeam(self.goalentity.team, ST_SCORE, fragamt);
+               TeamScore_AddToTeam(self.goalentity.team, ST_DOM_TICKS, fragamt);
+               // give credit to the individual player, if he is still there
+               if (self.enemy.playerid == self.enemy_playerid)
+               {
+                       PlayerScore_Add(self.enemy, SP_SCORE, fragamt);
+                       PlayerScore_Add(self.enemy, SP_DOM_TICKS, fragamt);
+               }
+               else
+                       self.enemy = world;
+       }
+ }
+ void dompointtouch()
+ {
+       entity head;
+       if (other.classname != "player")
+               return;
+       if (other.health < 1)
+               return;
+       if(time < self.captime + 0.3)
+               return;
+       // only valid teams can claim it
+       head = find(world, classname, "dom_team");
+       while (head && head.team != other.team)
+               head = find(head, classname, "dom_team");
+       if (!head || head.netname == "" || head == self.goalentity)
+               return;
+       // delay capture
+       self.team = self.goalentity.team; // this stores the PREVIOUS team!
+       self.cnt = other.team;
+       self.owner = head; // team to switch to after the delay
+       self.dmg_inflictor = other;
+       // self.state = 1;
+       // self.delay = time + cvar("g_domination_point_capturetime");
+       //self.nextthink = time + cvar("g_domination_point_capturetime");
+       //self.think = dompoint_captured;
+       // go to neutral team in the mean time
+       head = find(world, classname, "dom_team");
+       while (head && head.netname != "")
+               head = find(head, classname, "dom_team");
+       if(head == world)
+               return;
+       WaypointSprite_UpdateSprites(self.sprite, "dom-neut", "", "");
+       WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, '0 1 1');
+       WaypointSprite_Ping(self.sprite);
+       self.goalentity = head;
+       self.model = head.mdl;
+       self.modelindex = head.dmg;
+       self.skin = head.skin;
+       self.enemy = other; // individual player scoring
+       self.enemy_playerid = other.playerid;
+       dompoint_captured();
+ }
+ /*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
+ Team declaration for Domination gameplay, this allows you to decide what team
+ names and control point models are used in your map.
+ Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
+ can have netname set!  The nameless team owns all control points at start.
+ Keys:
+ "netname"
+  Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
+ "cnt"
+  Scoreboard color of the team (for example 4 is red and 13 is blue)
+ "model"
+  Model to use for control points owned by this team (for example
+  "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
+  keycard)
+ "skin"
+  Skin of the model to use (for team skins on a single model)
+ "noise"
+  Sound to play when this team captures a point.
+  (this is a localized sound, like a small alarm or other effect)
+ "noise1"
+  Narrator speech to play when this team captures a point.
+  (this is a global sound, like "Red team has captured a control point")
+ */
+ void spawnfunc_dom_team()
+ {
+       if(!g_domination || autocvar_g_domination_teams_override >= 2)
+       {
+               remove(self);
+               return;
+       }
+       precache_model(self.model);
+       if (self.noise != "")
+               precache_sound(self.noise);
+       if (self.noise1 != "")
+               precache_sound(self.noise1);
+       self.classname = "dom_team";
+       setmodel(self, self.model); // precision not needed
+       self.mdl = self.model;
+       self.dmg = self.modelindex;
+       self.model = "";
+       self.modelindex = 0;
+       // this would have to be changed if used in quakeworld
+       if(self.cnt)
+               self.team = self.cnt + 1; // WHY are these different anyway?
+ }
+ void dom_controlpoint_setup()
+ {
+       entity head;
+       // find the spawnfunc_dom_team representing unclaimed points
+       head = find(world, classname, "dom_team");
+       while(head && head.netname != "")
+               head = find(head, classname, "dom_team");
+       if (!head)
+               objerror("no spawnfunc_dom_team with netname \"\" found\n");
+       // copy important properties from spawnfunc_dom_team entity
+       self.goalentity = head;
+       setmodel(self, head.mdl); // precision already set
+       self.skin = head.skin;
+       self.cnt = -1;
+       if(self.message == "")
+               self.message = " has captured a control point";
+       if(self.DOMPOINTFRAGS <= 0)
+               self.DOMPOINTFRAGS = 1;
+       if(self.wait <= 0)
+               self.wait = 5;
+       float points, waittime;
+       if (autocvar_g_domination_point_amt)
+               points = autocvar_g_domination_point_amt;
+       else
+               points = self.frags;
+       if (autocvar_g_domination_point_rate)
+               waittime = autocvar_g_domination_point_rate;
+       else
+               waittime = self.wait;
+       total_pps += points/waittime;
+       if(!self.t_width)
+               self.t_width = 0.02; // frame animation rate
+       if(!self.t_length)
+               self.t_length = 239; // maximum frame
+       self.think = dompointthink;
+       self.nextthink = time;
+       self.touch = dompointtouch;
+       self.solid = SOLID_TRIGGER;
+       self.flags = FL_ITEM;
+       setsize(self, '-32 -32 -32', '32 32 32');
+       setorigin(self, self.origin + '0 0 20');
+       droptofloor();
+       waypoint_spawnforitem(self);
+       WaypointSprite_SpawnFixed("dom-neut", self.origin + '0 0 32', self, sprite, RADARICON_DOMPOINT, '0 1 1');
+ }
+ /*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
+ Control point for Domination gameplay.
+ */
+ void spawnfunc_dom_controlpoint()
+ {
+       if(!g_domination)
+       {
+               remove(self);
+               return;
+       }
+       self.think = dom_controlpoint_setup;
+       self.nextthink = time + 0.1;
+       self.reset = dom_controlpoint_setup;
+       if(!self.scale)
+               self.scale = 0.6;
+       //if(!self.glow_size)
+       //      self.glow_size = cvar("g_domination_point_glow");
+       self.effects = self.effects | EF_LOWPRECISION;
+       if (autocvar_g_domination_point_fullbright)
+               self.effects |= EF_FULLBRIGHT;
+ }
+ // code from here on is just to support maps that don't have control point and team entities
+ void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, string capsound, string capnarration, string capmessage)
+ {
+       entity oldself;
+       oldself = self;
+       self = spawn();
+       self.classname = "dom_team";
+       self.netname = teamname;
+       self.cnt = teamcolor;
+       self.model = pointmodel;
+       self.skin = pointskin;
+       self.noise = capsound;
+       self.noise1 = capnarration;
+       self.message = capmessage;
+       // this code is identical to spawnfunc_dom_team
+       setmodel(self, self.model); // precision not needed
+       self.mdl = self.model;
+       self.dmg = self.modelindex;
+       self.model = "";
+       self.modelindex = 0;
+       // this would have to be changed if used in quakeworld
+       self.team = self.cnt + 1;
+       //eprint(self);
+       self = oldself;
+ }
+ void dom_spawnpoint(vector org)
+ {
+       entity oldself;
+       oldself = self;
+       self = spawn();
+       self.classname = "dom_controlpoint";
+       self.think = spawnfunc_dom_controlpoint;
+       self.nextthink = time;
+       setorigin(self, org);
+       spawnfunc_dom_controlpoint();
+       self = oldself;
+ }
+ // spawn some default teams if the map is not set up for domination
+ void dom_spawnteams()
+ {
+       float numteams;
+       if(autocvar_g_domination_teams_override < 2)
+               numteams = autocvar_g_domination_default_teams;
+       else
+               numteams = autocvar_g_domination_teams_override;
+       // LordHavoc: edit this if you want to change defaults
 -              dom_spawnteam("Yellow", COLOR_TEAM3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
++      dom_spawnteam("Red", FL_TEAM_1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
++      dom_spawnteam("Blue", FL_TEAM_2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
+       if(numteams > 2)
 -              dom_spawnteam("Pink", COLOR_TEAM4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
++              dom_spawnteam("Yellow", FL_TEAM_3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
+       if(numteams > 3)
++              dom_spawnteam("Pink", FL_TEAM_4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
+       dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
+ }
+ void dom_delayedinit()
+ {
+       entity head;
+       // if no teams are found, spawn defaults, if custom teams are set, use them
+       if (find(world, classname, "dom_team") == world || autocvar_g_domination_teams_override >= 2)
+               dom_spawnteams();
+       // if no control points are found, spawn defaults
+       if (find(world, classname, "dom_controlpoint") == world)
+       {
+               // TODO in a few months (maybe 2011/08): change this into error() and remove this very poor dom point selection
+               backtrace("This map contains no dom_controlpoint entities. A very poor dom point placement will be chosen. Please fix the map.");
+               // if no supported map was found, make every deathmatch spawn a point
+               head = find(world, classname, "info_player_deathmatch");
+               while (head)
+               {
+                       dom_spawnpoint(head.origin);
+                       head = find(head, classname, "info_player_deathmatch");
+               }
+       }
+       ScoreRules_dom();
+ }
+ void dom_init()
+ {
+       // we have to precache default models/sounds even if they might not be
+       // used because spawnfunc_worldspawn is executed before any other entities are read,
+       // so we don't even know yet if this map is set up for domination...
+       precache_model("models/domination/dom_red.md3");
+       precache_model("models/domination/dom_blue.md3");
+       precache_model("models/domination/dom_yellow.md3");
+       precache_model("models/domination/dom_pink.md3");
+       precache_model("models/domination/dom_unclaimed.md3");
+       precache_sound("domination/claim.wav");
+       InitializeEntity(world, dom_delayedinit, INITPRIO_GAMETYPE);
+       addstat(STAT_DOM_TOTAL_PPS, AS_FLOAT, dom_total_pps);
+       addstat(STAT_DOM_PPS_RED, AS_FLOAT, dom_pps_red);
+       addstat(STAT_DOM_PPS_BLUE, AS_FLOAT, dom_pps_blue);
+       if(c3 >= 0) addstat(STAT_DOM_PPS_YELLOW, AS_FLOAT, dom_pps_yellow);
+       if(c4 >= 0) addstat(STAT_DOM_PPS_PINK, AS_FLOAT, dom_pps_pink);
+ }
index 7aa2f1c8ff4d0a1e6669d7ba2ce83ddb1ef43a50,a6bc87f9f6af76752d7e104625483f88b365c584..b2484e0540d863c840fdb446f7ca51f71bb3bc5a
@@@ -564,7 -564,7 +564,7 @@@ void FixPlayermodel(
                if(teamplay)
                {
                        string s;
 -                      s = Team_ColorNameLowerCase(self.team);
 +                      s = Team_ColorName_Lower(self.team);
                        if(s != "neutral")
                        {
                                defaultmodel = cvar_string(strcat("sv_defaultplayermodel_", s));
@@@ -1252,10 -1252,10 +1252,10 @@@ void ClientKill_TeamChange (float targe
                }
                else
                {
 -                      self.killindicator.colormod = TeamColor(targetteam);
 +                      self.killindicator.colormod = Team_ColorRGB(targetteam);
                        if(clienttype(self) == CLIENTTYPE_REAL)
                        if(self.killindicator.cnt > 0)
 -                              Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, strcat("Changing to ", ColoredTeamName(targetteam), " in %d seconds"), 1, self.killindicator.cnt);
 +                              Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, strcat("^7Changing to ", Team_ColoredFullName(targetteam), "^7 in %d seconds"), 1, self.killindicator.cnt);
                }
        }
  
@@@ -1297,7 -1297,7 +1297,7 @@@ void FixClientCvars(entity e
                stuffcmd(e, "cl_cmd settemp cl_movecliptokeyboard 2\n");
        if(autocvar_g_antilag == 3) // client side hitscan
                stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n");
 -      if(sv_gentle)
 +      if(autocvar_sv_gentle)
                stuffcmd(e, "cl_cmd settemp cl_gentle 1\n");
        /*
         * we no longer need to stuff this. Remove this comment block if you feel
@@@ -1346,6 -1346,7 +1346,6 @@@ ClientConnec
  Called when a client connects to the server
  =============
  */
 -string ColoredTeamName(float t);
  void DecodeLevelParms (void);
  //void dom_player_join_team(entity pl);
  void set_dom_state(entity e);
@@@ -1373,16 -1374,6 +1373,16 @@@ void ClientConnect (void
        self.flags = FL_CLIENT;
        self.version_nagtime = time + 10 + random() * 10;
  
 +      if(self.netaddress == "local")
 +      {
 +              print("^3server is local!\n");
 +
 +              if(server_is_local)
 +                      print("Multiple local clients???");
 +              else
 +                      server_is_local = TRUE;
 +      }
 +
        if(player_count<0)
        {
                dprint("BUG player count is lower than zero, this cannot happen!\n");
  
        race_PreSpawnObserver();
  
-       //if(g_domination)
-       //      dom_player_join_team(self);
        // identify the right forced team
        if(autocvar_g_campaign)
        {
                {
                        switch(autocvar_g_campaign_forceteam)
                        {
 -                              case 1: self.team_forced = COLOR_TEAM1; break;
 -                              case 2: self.team_forced = COLOR_TEAM2; break;
 -                              case 3: self.team_forced = COLOR_TEAM3; break;
 -                              case 4: self.team_forced = COLOR_TEAM4; break;
 +                              case 1: self.team_forced = FL_TEAM_1; break;
 +                              case 2: self.team_forced = FL_TEAM_2; break;
 +                              case 3: self.team_forced = FL_TEAM_3; break;
 +                              case 4: self.team_forced = FL_TEAM_4; break;
                                default: self.team_forced = 0;
                        }
                }
        }
        else if(PlayerInIDList(self, autocvar_g_forced_team_red))
 -              self.team_forced = COLOR_TEAM1;
 +              self.team_forced = FL_TEAM_1;
        else if(PlayerInIDList(self, autocvar_g_forced_team_blue))
 -              self.team_forced = COLOR_TEAM2;
 +              self.team_forced = FL_TEAM_2;
        else if(PlayerInIDList(self, autocvar_g_forced_team_yellow))
 -              self.team_forced = COLOR_TEAM3;
 +              self.team_forced = FL_TEAM_3;
        else if(PlayerInIDList(self, autocvar_g_forced_team_pink))
 -              self.team_forced = COLOR_TEAM4;
 +              self.team_forced = FL_TEAM_4;
        else if(autocvar_g_forced_team_otherwise == "red")
 -              self.team_forced = COLOR_TEAM1;
 +              self.team_forced = FL_TEAM_1;
        else if(autocvar_g_forced_team_otherwise == "blue")
 -              self.team_forced = COLOR_TEAM2;
 +              self.team_forced = FL_TEAM_2;
        else if(autocvar_g_forced_team_otherwise == "yellow")
 -              self.team_forced = COLOR_TEAM3;
 +              self.team_forced = FL_TEAM_3;
        else if(autocvar_g_forced_team_otherwise == "pink")
 -              self.team_forced = COLOR_TEAM4;
 +              self.team_forced = FL_TEAM_4;
        else if(autocvar_g_forced_team_otherwise == "spectate")
                self.team_forced = -1;
        else if(autocvar_g_forced_team_otherwise == "spectator")
        bprint("^4", self.netname, "^4 connected");
  
        if(self.classname != "observer" && (g_domination || g_ctf))
 -              bprint(" and joined the ", ColoredTeamName(self.team));
 +              bprint(" and joined the ", Team_ColoredFullName(self.team));
  
        bprint("\n");
  
        else if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca) // teamnagger is currently bad for ca
                send_CSQC_teamnagger();
  
-       if (g_domination)
-               set_dom_state(self);
        CheatInitClient();
  
        if(!autocvar_g_campaign)
diff --combined qcsrc/server/g_world.qc
index 001fbc5bb5d2d5dd718bbd188eddbf1a4dd5c307,7912b2081673358cefade3d4260ea4ac4766e01d..f3f13f38ad9fe59b13d48be47dcbdefe7dc8ff34
@@@ -553,8 -553,6 +553,8 @@@ void spawnfunc___init_dedicated_server(
        // needs to be done so early because of the constants they create
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
        CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
 +      CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
 +      CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
  
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
@@@ -601,8 -599,6 +601,8 @@@ void spawnfunc_worldspawn (void
        // needs to be done so early because of the constants they create
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
        CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
 +      CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
 +      CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
  
        ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
  
  
        WaypointSprite_Init();
  
-       //if (g_domination)
-       //      dom_init();
        GameLogInit(); // prepare everything
        // NOTE for matchid:
        // changing the logic generating it is okay. But:
@@@ -1765,10 -1758,10 +1762,10 @@@ float WinningCondition_Onslaught(
        {
                if (head.health > 0)
                {
 -                      if (head.team == COLOR_TEAM1) t1 = 1;
 -                      if (head.team == COLOR_TEAM2) t2 = 1;
 -                      if (head.team == COLOR_TEAM3) t3 = 1;
 -                      if (head.team == COLOR_TEAM4) t4 = 1;
 +                      if (head.team == FL_TEAM_1) t1 = 1;
 +                      if (head.team == FL_TEAM_2) t2 = 1;
 +                      if (head.team == FL_TEAM_3) t3 = 1;
 +                      if (head.team == FL_TEAM_4) t4 = 1;
                }
                head = find(head, classname, "onslaught_generator");
        }
        {
                // game over, only one team remains (or none)
                ClearWinners();
 -              if (t1) SetWinners(team, COLOR_TEAM1);
 -              if (t2) SetWinners(team, COLOR_TEAM2);
 -              if (t3) SetWinners(team, COLOR_TEAM3);
 -              if (t4) SetWinners(team, COLOR_TEAM4);
 +              if (t1) SetWinners(team, FL_TEAM_1);
 +              if (t2) SetWinners(team, FL_TEAM_2);
 +              if (t3) SetWinners(team, FL_TEAM_3);
 +              if (t4) SetWinners(team, FL_TEAM_4);
                dprint("Have a winner, ending game.\n");
                return WINNING_YES;
        }
@@@ -1817,13 -1810,13 +1814,13 @@@ float WinningCondition_Assault(
  
        status = WINNING_NO;
        // as the timelimit has not yet passed just assume the defending team will win
 -      if(assault_attacker_team == COLOR_TEAM1)
 +      if(assault_attacker_team == FL_TEAM_1)
        {
 -              SetWinners(team, COLOR_TEAM2);
 +              SetWinners(team, FL_TEAM_2);
        }
        else
        {
 -              SetWinners(team, COLOR_TEAM1);
 +              SetWinners(team, FL_TEAM_1);
        }
  
        entity ent;
@@@ -1949,10 -1942,10 +1946,10 @@@ float WinningCondition_Scores(float lim
  
        if(teamplay)
        {
 -              team1_score = TeamScore_GetCompareValue(COLOR_TEAM1);
 -              team2_score = TeamScore_GetCompareValue(COLOR_TEAM2);
 -              team3_score = TeamScore_GetCompareValue(COLOR_TEAM3);
 -              team4_score = TeamScore_GetCompareValue(COLOR_TEAM4);
 +              team1_score = TeamScore_GetCompareValue(FL_TEAM_1);
 +              team2_score = TeamScore_GetCompareValue(FL_TEAM_2);
 +              team3_score = TeamScore_GetCompareValue(FL_TEAM_3);
 +              team4_score = TeamScore_GetCompareValue(FL_TEAM_4);
        }
  
        ClearWinners();
@@@ -2068,25 -2061,25 +2065,25 @@@ float WinningCondition_RanOutOfSpawns(
  
        FOR_EACH_PLAYER(head) if(head.deadflag == DEAD_NO)
        {
 -              if(head.team == COLOR_TEAM1)
 +              if(head.team == FL_TEAM_1)
                        team1_score = 1;
 -              else if(head.team == COLOR_TEAM2)
 +              else if(head.team == FL_TEAM_2)
                        team2_score = 1;
 -              else if(head.team == COLOR_TEAM3)
 +              else if(head.team == FL_TEAM_3)
                        team3_score = 1;
 -              else if(head.team == COLOR_TEAM4)
 +              else if(head.team == FL_TEAM_4)
                        team4_score = 1;
        }
  
        for(head = world; (head = find(head, classname, "info_player_deathmatch")) != world; )
        {
 -              if(head.team == COLOR_TEAM1)
 +              if(head.team == FL_TEAM_1)
                        team1_score = 1;
 -              else if(head.team == COLOR_TEAM2)
 +              else if(head.team == FL_TEAM_2)
                        team2_score = 1;
 -              else if(head.team == COLOR_TEAM3)
 +              else if(head.team == FL_TEAM_3)
                        team3_score = 1;
 -              else if(head.team == COLOR_TEAM4)
 +              else if(head.team == FL_TEAM_4)
                        team4_score = 1;
        }
  
        {
                float t, i;
                if(team1_score)
 -                      t = COLOR_TEAM1;
 +                      t = FL_TEAM_1;
                else if(team2_score)
 -                      t = COLOR_TEAM2;
 +                      t = FL_TEAM_2;
                else if(team3_score)
 -                      t = COLOR_TEAM3;
 +                      t = FL_TEAM_3;
                else // if(team4_score)
 -                      t = COLOR_TEAM4;
 +                      t = FL_TEAM_4;
                CheckAllowedTeams(world);
                for(i = 0; i < MAX_TEAMSCORE; ++i)
                {
 -                      if(t != COLOR_TEAM1) if(c1 >= 0) TeamScore_AddToTeam(COLOR_TEAM1, i, -1000);
 -                      if(t != COLOR_TEAM2) if(c2 >= 0) TeamScore_AddToTeam(COLOR_TEAM2, i, -1000);
 -                      if(t != COLOR_TEAM3) if(c3 >= 0) TeamScore_AddToTeam(COLOR_TEAM3, i, -1000);
 -                      if(t != COLOR_TEAM4) if(c4 >= 0) TeamScore_AddToTeam(COLOR_TEAM4, i, -1000);
 +                      if(t != FL_TEAM_1) if(c1 >= 0) TeamScore_AddToTeam(FL_TEAM_1, i, -1000);
 +                      if(t != FL_TEAM_2) if(c2 >= 0) TeamScore_AddToTeam(FL_TEAM_2, i, -1000);
 +                      if(t != FL_TEAM_3) if(c3 >= 0) TeamScore_AddToTeam(FL_TEAM_3, i, -1000);
 +                      if(t != FL_TEAM_4) if(c4 >= 0) TeamScore_AddToTeam(FL_TEAM_4, i, -1000);
                }
  
                AddWinners(team, t);
index 0000000000000000000000000000000000000000,852fb90c05dc287c0fdfeedeb31b61f6f9f4aa23..1c2ded2dbf893984ee3936e960a5febdabb017f3
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,515 +1,502 @@@
 -      switch(self.goalentity.team)
 -      {
 -              case COLOR_TEAM1:
 -                      WaypointSprite_UpdateSprites(self.sprite, "dom-red", "", "");
 -                      break;
 -              case COLOR_TEAM2:
 -                      WaypointSprite_UpdateSprites(self.sprite, "dom-blue", "", "");
 -                      break;
 -              case COLOR_TEAM3:
 -                      WaypointSprite_UpdateSprites(self.sprite, "dom-yellow", "", "");
 -                      break;
 -              case COLOR_TEAM4:
 -                      WaypointSprite_UpdateSprites(self.sprite, "dom-pink", "", "");
 -      }
 -
+ void dom_EventLog(string mode, float team_before, entity actor) // use an alias for easy changing and quick editing later
+ {
+       if(autocvar_sv_eventlog)
+               GameLogEcho(strcat(":dom:", mode, ":", ftos(team_before), ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
+ }
+ void set_dom_state(entity e)
+ {
+       e.dom_total_pps = total_pps;
+       e.dom_pps_red = pps_red;
+       e.dom_pps_blue = pps_blue;
+       if(c3 >= 0)
+               e.dom_pps_yellow = pps_yellow;
+       if(c4 >= 0)
+               e.dom_pps_pink = pps_pink;
+ }
+ void dompoint_captured ()
+ {
+       entity head;
+       float old_delay, old_team, real_team;
+       // now that the delay has expired, switch to the latest team to lay claim to this point
+       head = self.owner;
+       real_team = self.cnt;
+       self.cnt = -1;
+       dom_EventLog("taken", self.team, self.dmg_inflictor);
+       self.dmg_inflictor = world;
+       self.goalentity = head;
+       self.model = head.mdl;
+       self.modelindex = head.dmg;
+       self.skin = head.skin;
+       
+       float points, wait_time;
+       if (autocvar_g_domination_point_amt)
+               points = autocvar_g_domination_point_amt;
+       else
+               points = self.frags;
+       if (autocvar_g_domination_point_rate)
+               wait_time = autocvar_g_domination_point_rate;
+       else
+               wait_time = self.wait;
+       bprint("^3", head.netname, "^3", self.message);
+       if (points != 1)
+               bprint(" ^7(", ftos(points), " points every ", ftos(wait_time), " seconds)\n");
+       else
+               bprint(" ^7(", ftos(points), " point every ", ftos(wait_time), " seconds)\n");
+       if(self.enemy.playerid == self.enemy_playerid)
+               PlayerScore_Add(self.enemy, SP_DOM_TAKES, 1);
+       else
+               self.enemy = world;
+       if (head.noise != "")
+               if(self.enemy)
+                       sound(self.enemy, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
+               else
+                       sound(self, CH_TRIGGER, head.noise, VOL_BASE, ATTN_NORM);
+       if (head.noise1 != "")
+               play2all(head.noise1);
+       self.delay = time + wait_time;
+       // do trigger work
+       old_delay = self.delay;
+       old_team = self.team;
+       self.team = real_team;
+       self.delay = 0;
+       activator = self;
+       SUB_UseTargets ();
+       self.delay = old_delay;
+       self.team = old_team;
 -                      case COLOR_TEAM1:
++      WaypointSprite_UpdateSprites(self.sprite, strcat("dom-", Team_ColorName_Lower(self.goalentity.team)), "", "");
++      
+       total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
+       for(head = world; (head = find(head, classname, "dom_controlpoint")) != world; )
+       {
+               if (autocvar_g_domination_point_amt)
+                       points = autocvar_g_domination_point_amt;
+               else
+                       points = head.frags;
+               if (autocvar_g_domination_point_rate)
+                       wait_time = autocvar_g_domination_point_rate;
+               else
+                       wait_time = head.wait;
+               switch(head.goalentity.team)
+               {
 -                      case COLOR_TEAM2:
++                      case FL_TEAM_1:
+                               pps_red += points/wait_time;
+                               break;
 -                      case COLOR_TEAM3:
++                      case FL_TEAM_2:
+                               pps_blue += points/wait_time;
+                               break;
 -                      case COLOR_TEAM4:
++                      case FL_TEAM_3:
+                               pps_yellow += points/wait_time;
+                               break;
 -      dom_spawnteam("Red", COLOR_TEAM1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
 -      dom_spawnteam("Blue", COLOR_TEAM2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
++                      case FL_TEAM_4:
+                               pps_pink += points/wait_time;
+               }
+               total_pps += points/wait_time;
+       }
+       WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, colormapPaletteColor(self.goalentity.team - 1, 0));
+       WaypointSprite_Ping(self.sprite);
+       self.captime = time;
+       FOR_EACH_REALCLIENT(head)
+               set_dom_state(head);
+ }
+ void AnimateDomPoint()
+ {
+       if(self.pain_finished > time)
+               return;
+       self.pain_finished = time + self.t_width;
+       if(self.nextthink > self.pain_finished)
+               self.nextthink = self.pain_finished;
+       self.frame = self.frame + 1;
+       if(self.frame > self.t_length)
+               self.frame = 0;
+ }
+ void dompointthink()
+ {
+       float fragamt;
+       self.nextthink = time + 0.1;
+       //self.frame = self.frame + 1;
+       //if(self.frame > 119)
+       //      self.frame = 0;
+       AnimateDomPoint();
+       // give points
+       if (gameover || self.delay > time || time < game_starttime)     // game has ended, don't keep giving points
+               return;
+       if(autocvar_g_domination_point_rate)
+               self.delay = time + autocvar_g_domination_point_rate;
+       else
+               self.delay = time + self.wait;
+       // give credit to the team
+       // NOTE: this defaults to 0
+       if (self.goalentity.netname != "")
+       {
+               if(autocvar_g_domination_point_amt)
+                       fragamt = autocvar_g_domination_point_amt;
+               else
+                       fragamt = self.frags;
+               TeamScore_AddToTeam(self.goalentity.team, ST_SCORE, fragamt);
+               TeamScore_AddToTeam(self.goalentity.team, ST_DOM_TICKS, fragamt);
+               // give credit to the individual player, if he is still there
+               if (self.enemy.playerid == self.enemy_playerid)
+               {
+                       PlayerScore_Add(self.enemy, SP_SCORE, fragamt);
+                       PlayerScore_Add(self.enemy, SP_DOM_TICKS, fragamt);
+               }
+               else
+                       self.enemy = world;
+       }
+ }
+ void dompointtouch()
+ {
+       entity head;
+       if (other.classname != "player")
+               return;
+       if (other.health < 1)
+               return;
+       if(time < self.captime + 0.3)
+               return;
+       // only valid teams can claim it
+       head = find(world, classname, "dom_team");
+       while (head && head.team != other.team)
+               head = find(head, classname, "dom_team");
+       if (!head || head.netname == "" || head == self.goalentity)
+               return;
+       // delay capture
+       self.team = self.goalentity.team; // this stores the PREVIOUS team!
+       self.cnt = other.team;
+       self.owner = head; // team to switch to after the delay
+       self.dmg_inflictor = other;
+       // self.state = 1;
+       // self.delay = time + cvar("g_domination_point_capturetime");
+       //self.nextthink = time + cvar("g_domination_point_capturetime");
+       //self.think = dompoint_captured;
+       // go to neutral team in the mean time
+       head = find(world, classname, "dom_team");
+       while (head && head.netname != "")
+               head = find(head, classname, "dom_team");
+       if(head == world)
+               return;
+       WaypointSprite_UpdateSprites(self.sprite, "dom-neut", "", "");
+       WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_DOMPOINT, '0 1 1');
+       WaypointSprite_Ping(self.sprite);
+       self.goalentity = head;
+       self.model = head.mdl;
+       self.modelindex = head.dmg;
+       self.skin = head.skin;
+       self.enemy = other; // individual player scoring
+       self.enemy_playerid = other.playerid;
+       dompoint_captured();
+ }
+ void dom_controlpoint_setup()
+ {
+       entity head;
+       // find the spawnfunc_dom_team representing unclaimed points
+       head = find(world, classname, "dom_team");
+       while(head && head.netname != "")
+               head = find(head, classname, "dom_team");
+       if (!head)
+               objerror("no spawnfunc_dom_team with netname \"\" found\n");
+       // copy important properties from spawnfunc_dom_team entity
+       self.goalentity = head;
+       setmodel(self, head.mdl); // precision already set
+       self.skin = head.skin;
+       self.cnt = -1;
+       if(self.message == "")
+               self.message = " has captured a control point";
+       if(self.frags <= 0)
+               self.frags = 1;
+       if(self.wait <= 0)
+               self.wait = 5;
+       float points, waittime;
+       if (autocvar_g_domination_point_amt)
+               points = autocvar_g_domination_point_amt;
+       else
+               points = self.frags;
+       if (autocvar_g_domination_point_rate)
+               waittime = autocvar_g_domination_point_rate;
+       else
+               waittime = self.wait;
+       total_pps += points/waittime;
+       if(!self.t_width)
+               self.t_width = 0.02; // frame animation rate
+       if(!self.t_length)
+               self.t_length = 239; // maximum frame
+       self.think = dompointthink;
+       self.nextthink = time;
+       self.touch = dompointtouch;
+       self.solid = SOLID_TRIGGER;
+       self.flags = FL_ITEM;
+       setsize(self, '-32 -32 -32', '32 32 32');
+       setorigin(self, self.origin + '0 0 20');
+       droptofloor();
+       waypoint_spawnforitem(self);
+       WaypointSprite_SpawnFixed("dom-neut", self.origin + '0 0 32', self, sprite, RADARICON_DOMPOINT, '0 1 1');
+ }
+ //go to best items, or control points you don't own
+ void havocbot_role_dom()
+ {
+       if(self.deadflag != DEAD_NO)
+               return;
+       if (self.bot_strategytime < time)
+       {
+               self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
+               navigation_goalrating_start();
+               havocbot_goalrating_controlpoints(10000, self.origin, 15000);
+               havocbot_goalrating_items(8000, self.origin, 8000);
+               //havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
+               //havocbot_goalrating_waypoints(1, self.origin, 1000);
+               navigation_goalrating_end();
+       }
+ }
+ MUTATOR_HOOKFUNCTION(dom_ClientConnect)
+ {
+       set_dom_state(self);
+       return FALSE;
+ }
+ MUTATOR_HOOKFUNCTION(dom_BotRoles)
+ {
+       self.havocbot_role = havocbot_role_dom;
+       return TRUE;
+ }
+ /*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
+ Control point for Domination gameplay.
+ */
+ void spawnfunc_dom_controlpoint()
+ {
+       if(!g_domination)
+       {
+               remove(self);
+               return;
+       }
+       self.think = dom_controlpoint_setup;
+       self.nextthink = time + 0.1;
+       self.reset = dom_controlpoint_setup;
+       if(!self.scale)
+               self.scale = 0.6;
+       self.effects = self.effects | EF_LOWPRECISION;
+       if (autocvar_g_domination_point_fullbright)
+               self.effects |= EF_FULLBRIGHT;
+ }
+ /*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
+ Team declaration for Domination gameplay, this allows you to decide what team
+ names and control point models are used in your map.
+ Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
+ can have netname set!  The nameless team owns all control points at start.
+ Keys:
+ "netname"
+  Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
+ "cnt"
+  Scoreboard color of the team (for example 4 is red and 13 is blue)
+ "model"
+  Model to use for control points owned by this team (for example
+  "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
+  keycard)
+ "skin"
+  Skin of the model to use (for team skins on a single model)
+ "noise"
+  Sound to play when this team captures a point.
+  (this is a localized sound, like a small alarm or other effect)
+ "noise1"
+  Narrator speech to play when this team captures a point.
+  (this is a global sound, like "Red team has captured a control point")
+ */
+ void spawnfunc_dom_team()
+ {
+       if(!g_domination || autocvar_g_domination_teams_override >= 2)
+       {
+               remove(self);
+               return;
+       }
+       precache_model(self.model);
+       if (self.noise != "")
+               precache_sound(self.noise);
+       if (self.noise1 != "")
+               precache_sound(self.noise1);
+       self.classname = "dom_team";
+       setmodel(self, self.model); // precision not needed
+       self.mdl = self.model;
+       self.dmg = self.modelindex;
+       self.model = "";
+       self.modelindex = 0;
+       // this would have to be changed if used in quakeworld
+       if(self.cnt)
+               self.team = self.cnt + 1; // WHY are these different anyway?
+ }
+ // scoreboard setup
+ void ScoreRules_dom()
+ {
+       float sp_domticks, sp_score;
+       sp_score = sp_domticks = 0;
+       if(autocvar_g_domination_disable_frags)
+               sp_domticks = SFL_SORT_PRIO_PRIMARY;
+       else
+               sp_score = SFL_SORT_PRIO_PRIMARY;
+       CheckAllowedTeams(world);
+       ScoreRules_basics(((c4>=0) ? 4 : (c3>=0) ? 3 : 2), sp_score, sp_score, TRUE);
+       ScoreInfo_SetLabel_TeamScore  (ST_DOM_TICKS,    "ticks",     sp_domticks);
+       ScoreInfo_SetLabel_PlayerScore(SP_DOM_TICKS,    "ticks",     sp_domticks);
+       ScoreInfo_SetLabel_PlayerScore(SP_DOM_TAKES,    "takes",     0);
+       ScoreRules_basics_end();
+ }
+ // code from here on is just to support maps that don't have control point and team entities
+ void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, string capsound, string capnarration, string capmessage)
+ {
+       entity oldself;
+       oldself = self;
+       self = spawn();
+       self.classname = "dom_team";
+       self.netname = teamname;
+       self.cnt = teamcolor;
+       self.model = pointmodel;
+       self.skin = pointskin;
+       self.noise = capsound;
+       self.noise1 = capnarration;
+       self.message = capmessage;
+       // this code is identical to spawnfunc_dom_team
+       setmodel(self, self.model); // precision not needed
+       self.mdl = self.model;
+       self.dmg = self.modelindex;
+       self.model = "";
+       self.modelindex = 0;
+       // this would have to be changed if used in quakeworld
+       self.team = self.cnt + 1;
+       //eprint(self);
+       self = oldself;
+ }
+ void dom_spawnpoint(vector org)
+ {
+       entity oldself;
+       oldself = self;
+       self = spawn();
+       self.classname = "dom_controlpoint";
+       self.think = spawnfunc_dom_controlpoint;
+       self.nextthink = time;
+       setorigin(self, org);
+       spawnfunc_dom_controlpoint();
+       self = oldself;
+ }
+ // spawn some default teams if the map is not set up for domination
+ void dom_spawnteams()
+ {
+       float numteams = ((autocvar_g_domination_teams_override < 2) ? autocvar_g_domination_default_teams : autocvar_g_domination_teams_override);
 -              dom_spawnteam("Yellow", COLOR_TEAM3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
++      dom_spawnteam("Red", FL_TEAM_1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
++      dom_spawnteam("Blue", FL_TEAM_2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
+       if(numteams > 2)
 -              dom_spawnteam("Pink", COLOR_TEAM4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
++              dom_spawnteam("Yellow", FL_TEAM_3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
+       if(numteams > 3)
++              dom_spawnteam("Pink", FL_TEAM_4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
+       dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, "", "", "");
+ }
+ void dom_DelayedInit() // Do this check with a delay so we can wait for teams to be set up.
+ {
+       // if no teams are found, spawn defaults
+       if(find(world, classname, "dom_team") == world || autocvar_g_domination_teams_override >= 2)
+       {
+               print("No ""dom_team"" entities found on this map, creating them anyway.\n");
+               dom_spawnteams();
+       }
+       
+       ScoreRules_dom();
+ }
+ void dom_Initialize()
+ {
+       precache_model("models/domination/dom_red.md3");
+       precache_model("models/domination/dom_blue.md3");
+       precache_model("models/domination/dom_yellow.md3");
+       precache_model("models/domination/dom_pink.md3");
+       precache_model("models/domination/dom_unclaimed.md3");
+       precache_sound("domination/claim.wav");
+       
+       addstat(STAT_DOM_TOTAL_PPS, AS_FLOAT, dom_total_pps);
+       addstat(STAT_DOM_PPS_RED, AS_FLOAT, dom_pps_red);
+       addstat(STAT_DOM_PPS_BLUE, AS_FLOAT, dom_pps_blue);
+       if(c3 >= 0) addstat(STAT_DOM_PPS_YELLOW, AS_FLOAT, dom_pps_yellow);
+       if(c4 >= 0) addstat(STAT_DOM_PPS_PINK, AS_FLOAT, dom_pps_pink);
+       
+       InitializeEntity(world, dom_DelayedInit, INITPRIO_GAMETYPE);
+ }
+ MUTATOR_DEFINITION(gamemode_domination)
+ {
+       MUTATOR_HOOK(ClientConnect, dom_ClientConnect, CBC_ORDER_ANY);
+       MUTATOR_HOOK(HavocBot_ChooseRule, dom_BotRoles, CBC_ORDER_ANY);
+       
+       MUTATOR_ONADD
+       {
+               if(time > 1) // game loads at time 1
+                       error("This is a game type and it cannot be added at runtime.");
+               dom_Initialize();
+       }
+       MUTATOR_ONREMOVE
+       {
+               error("This is a game type and it cannot be removed at runtime.");
+       }
+       return 0;
+ }
diff --combined qcsrc/server/progs.src
index 2a733728c532e9a32978a303e6f80979937af702,f1bdb24439ee84eab4c5aef4a59597c79a720b0a..71f088ba5aef0c7538300f2e10c2b096af5405d6
@@@ -13,11 -13,8 +13,11 @@@ sys-post.q
  ../warpzonelib/server.qh
  
  ../common/constants.qh
 +../common/teams.qh
  ../common/util.qh
  ../common/items.qh
 +../common/deathtypes.qh
 +../common/notifications.qh
  ../common/explosion_equation.qh
  ../common/urllib.qh
  ../common/command/markup.qh
@@@ -33,6 -30,7 +33,7 @@@ defs.qh               // Should rename this, it has 
  mutators/base.qh
  mutators/mutators.qh
  mutators/gamemode_ctf.qh
+ mutators/gamemode_domination.qh
  mutators/gamemode_keyhunt.qh // TODO fix this
  mutators/gamemode_keepaway.qh
  mutators/gamemode_nexball.qh 
@@@ -144,7 -142,7 +145,7 @@@ t_plats.q
  antilag.qc
  
  //ctf.qc
- domination.qc
//domination.qc
  //mode_onslaught.qc
  //nexball.qc
  g_hook.qc
@@@ -211,6 -209,7 +212,7 @@@ playerstats.q
  
  mutators/base.qc
  mutators/gamemode_ctf.qc
+ mutators/gamemode_domination.qc
  mutators/gamemode_freezetag.qc
  mutators/gamemode_keyhunt.qc
  mutators/gamemode_keepaway.qc
@@@ -234,6 -233,5 +236,6 @@@ mutators/mutator_superspec.q
  ../warpzonelib/server.qc
  
  ../common/util.qc
 +../common/notifications.qc
  
  ../common/if-this-file-errors-scroll-up-and-fix-the-warnings.fteqccfail
diff --combined qcsrc/server/teamplay.qc
index fd7b554ef33c5ac10cf7c510fbca176604744fd6,1ed2f533b3a923c93981ef14ad5403eb847a0f25..dddd5f1d4258f7409f2a4a0a8d91f5a3538ca681
@@@ -13,7 -13,45 +13,6 @@@ void TeamchangeFrags(entity e
        PlayerScore_Clear(e);
  }
  
- void dom_init();
 -vector TeamColor(float teem)
 -{
 -      switch(teem)
 -      {
 -              case COLOR_TEAM1:
 -                      return '1 0.0625 0.0625';
 -              case COLOR_TEAM2:
 -                      return '0.0625 0.0625 1';
 -              case COLOR_TEAM3:
 -                      return '1 1 0.0625';
 -              case COLOR_TEAM4:
 -                      return '1 0.0625 1';
 -              default:
 -                      return '1 1 1';
 -      }
 -}
 -
 -string TeamName(float t)
 -{
 -      return strcat(Team_ColorName(t), " Team");
 -}
 -string ColoredTeamName(float t)
 -{
 -      return strcat(Team_ColorCode(t), Team_ColorName(t), " Team^7");
 -}
 -string TeamNoName(float t)
 -{
 -      // fixme: Search for team entities and get their .netname's!
 -      if(t == 1)
 -              return "Red Team";
 -      if(t == 2)
 -              return "Blue Team";
 -      if(t == 3)
 -              return "Yellow Team";
 -      if(t == 4)
 -              return "Pink Team";
 -      return "Neutral Team";
 -}
 -
  void runematch_init();
  void tdm_init();
  void entcs_init();
@@@ -95,7 -133,7 +94,7 @@@ void InitGameplayMode(
                ActivateTeamplay();
                fraglimit_override = autocvar_g_domination_point_limit;
                leadlimit_override = autocvar_g_domination_point_leadlimit;
-               dom_init();
+               MUTATOR_ADD(gamemode_domination);
                have_team_spawns = -1; // request team spawns
        }
  
@@@ -378,13 -416,13 +377,13 @@@ void SetPlayerTeam(entity pl, float t, 
        float _color;
  
        if(t == 4)
 -              _color = COLOR_TEAM4 - 1;
 +              _color = FL_TEAM_4 - 1;
        else if(t == 3)
 -              _color = COLOR_TEAM3 - 1;
 +              _color = FL_TEAM_3 - 1;
        else if(t == 2)
 -              _color = COLOR_TEAM2 - 1;
 +              _color = FL_TEAM_2 - 1;
        else
 -              _color = COLOR_TEAM1 - 1;
 +              _color = FL_TEAM_1 - 1;
  
        SetPlayerColors(pl,_color);
  
                LogTeamchange(pl.playerid, pl.team, 3);  // log manual team join
  
                if(!noprint)
 -              bprint(pl.netname, "^7 has changed from ", TeamNoName(s), " to ", TeamNoName(t), "\n");
 +              bprint(pl.netname, "^7 has changed from ", Team_NumberToColoredFullName(s), "^7 to ", Team_NumberToColoredFullName(t), "\n");
        }
  
  }
@@@ -414,10 -452,10 +413,10 @@@ void CheckAllowedTeams (entity for_whom
                head = findchain(classname, "onslaught_generator");
                while (head)
                {
 -                      if (head.team == COLOR_TEAM1) c1 = 0;
 -                      if (head.team == COLOR_TEAM2) c2 = 0;
 -                      if (head.team == COLOR_TEAM3) c3 = 0;
 -                      if (head.team == COLOR_TEAM4) c4 = 0;
 +                      if (head.team == FL_TEAM_1) c1 = 0;
 +                      if (head.team == FL_TEAM_2) c2 = 0;
 +                      if (head.team == FL_TEAM_3) c3 = 0;
 +                      if (head.team == FL_TEAM_4) c4 = 0;
                        head = head.chain;
                }
        }
                {
                        if(!(g_domination && head.netname == ""))
                        {
 -                              if(head.team == COLOR_TEAM1)
 +                              if(head.team == FL_TEAM_1)
                                        c1 = 0;
 -                              else if(head.team == COLOR_TEAM2)
 +                              else if(head.team == FL_TEAM_2)
                                        c2 = 0;
 -                              else if(head.team == COLOR_TEAM3)
 +                              else if(head.team == FL_TEAM_3)
                                        c3 = 0;
 -                              else if(head.team == COLOR_TEAM4)
 +                              else if(head.team == FL_TEAM_4)
                                        c4 = 0;
                        }
                        head = find(head, classname, teament_name);
        }
  
        // if player has a forced team, ONLY allow that one
 -      if(self.team_forced == COLOR_TEAM1 && c1 >= 0)
 +      if(self.team_forced == FL_TEAM_1 && c1 >= 0)
                c2 = c3 = c4 = -1;
 -      else if(self.team_forced == COLOR_TEAM2 && c2 >= 0)
 +      else if(self.team_forced == FL_TEAM_2 && c2 >= 0)
                c1 = c3 = c4 = -1;
 -      else if(self.team_forced == COLOR_TEAM3 && c3 >= 0)
 +      else if(self.team_forced == FL_TEAM_3 && c3 >= 0)
                c1 = c2 = c4 = -1;
 -      else if(self.team_forced == COLOR_TEAM4 && c4 >= 0)
 +      else if(self.team_forced == FL_TEAM_4 && c4 >= 0)
                c1 = c2 = c3 = -1;
  }
  
@@@ -538,7 -576,7 +537,7 @@@ void GetTeamCounts(entity ignore
                                bvalue = value;
                        else
                                bvalue = 0;
 -                      if(t == COLOR_TEAM1)
 +                      if(t == FL_TEAM_1)
                        {
                                if(c1 >= 0)
                                {
                                        cb1 = cb1 + bvalue;
                                }
                        }
 -                      if(t == COLOR_TEAM2)
 +                      if(t == FL_TEAM_2)
                        {
                                if(c2 >= 0)
                                {
                                        cb2 = cb2 + bvalue;
                                }
                        }
 -                      if(t == COLOR_TEAM3)
 +                      if(t == FL_TEAM_3)
                        {
                                if(c3 >= 0)
                                {
                                        cb3 = cb3 + bvalue;
                                }
                        }
 -                      if(t == COLOR_TEAM4)
 +                      if(t == FL_TEAM_4)
                        {
                                if(c4 >= 0)
                                {
@@@ -731,13 -769,13 +730,13 @@@ float JoinBestTeam(entity pl, float onl
        // if he's not on a valid team, then let other code put him on the smallest team
        if(!forcebestteam)
        {
 -              if(     c1 >= 0 && pl.team == COLOR_TEAM1)
 +              if(     c1 >= 0 && pl.team == FL_TEAM_1)
                        selectedteam = pl.team;
 -              else if(c2 >= 0 && pl.team == COLOR_TEAM2)
 +              else if(c2 >= 0 && pl.team == FL_TEAM_2)
                        selectedteam = pl.team;
 -              else if(c3 >= 0 && pl.team == COLOR_TEAM3)
 +              else if(c3 >= 0 && pl.team == FL_TEAM_3)
                        selectedteam = pl.team;
 -              else if(c4 >= 0 && pl.team == COLOR_TEAM4)
 +              else if(c4 >= 0 && pl.team == FL_TEAM_4)
                        selectedteam = pl.team;
                else
                        selectedteam = -1;
                TeamchangeFrags(self);
                if(smallest == 1)
                {
 -                      SetPlayerColors(pl, COLOR_TEAM1 - 1);
 +                      SetPlayerColors(pl, FL_TEAM_1 - 1);
                }
                else if(smallest == 2)
                {
 -                      SetPlayerColors(pl, COLOR_TEAM2 - 1);
 +                      SetPlayerColors(pl, FL_TEAM_2 - 1);
                }
                else if(smallest == 3)
                {
 -                      SetPlayerColors(pl, COLOR_TEAM3 - 1);
 +                      SetPlayerColors(pl, FL_TEAM_3 - 1);
                }
                else if(smallest == 4)
                {
 -                      SetPlayerColors(pl, COLOR_TEAM4 - 1);
 +                      SetPlayerColors(pl, FL_TEAM_4 - 1);
                }
                else
                {
@@@ -806,21 -844,21 +805,21 @@@ void SV_ChangeTeam(float _color
        scolor = self.clientcolors & 0x0F;
        dcolor = _color & 0x0F;
  
 -      if(scolor == COLOR_TEAM1 - 1)
 +      if(scolor == FL_TEAM_1 - 1)
                steam = 1;
 -      else if(scolor == COLOR_TEAM2 - 1)
 +      else if(scolor == FL_TEAM_2 - 1)
                steam = 2;
 -      else if(scolor == COLOR_TEAM3 - 1)
 +      else if(scolor == FL_TEAM_3 - 1)
                steam = 3;
 -      else // if(scolor == COLOR_TEAM4 - 1)
 +      else // if(scolor == FL_TEAM_4 - 1)
                steam = 4;
 -      if(dcolor == COLOR_TEAM1 - 1)
 +      if(dcolor == FL_TEAM_1 - 1)
                dteam = 1;
 -      else if(dcolor == COLOR_TEAM2 - 1)
 +      else if(dcolor == FL_TEAM_2 - 1)
                dteam = 2;
 -      else if(dcolor == COLOR_TEAM3 - 1)
 +      else if(dcolor == FL_TEAM_3 - 1)
                dteam = 3;
 -      else // if(dcolor == COLOR_TEAM4 - 1)
 +      else // if(dcolor == FL_TEAM_4 - 1)
                dteam = 4;
  
        CheckAllowedTeams(self);
@@@ -909,13 -947,13 +908,13 @@@ void ShufflePlayerOutOfTeam (float sour
        }
  
        if(source_team == 1)
 -              steam = COLOR_TEAM1;
 +              steam = FL_TEAM_1;
        else if(source_team == 2)
 -              steam = COLOR_TEAM2;
 +              steam = FL_TEAM_2;
        else if(source_team == 3)
 -              steam = COLOR_TEAM3;
 +              steam = FL_TEAM_3;
        else // if(source_team == 4)
 -              steam = COLOR_TEAM4;
 +              steam = FL_TEAM_4;
  
        lowest_bot = world;
        lowest_bot_score = 999999999;
  
        if(selected.deadflag == DEAD_NO)
                Damage(selected, selected, selected, 100000, DEATH_AUTOTEAMCHANGE, selected.origin, '0 0 0');
 -      centerprint(selected, strcat("You have been moved into a different team to improve team balance\nYou are now on: ", ColoredTeamName(selected.team)));
 +      centerprint(selected, strcat("You have been moved into a different team to improve team balance\nYou are now on: ", Team_ColoredFullName(selected.team)));
  }
  
  // code from here on is just to support maps that don't have team entities
@@@ -1034,12 -1072,12 +1033,12 @@@ void tdm_spawnteams(
                numteams = autocvar_g_tdm_teams;
        numteams = bound(2, numteams, 4);
  
 -      tdm_spawnteam("Red", COLOR_TEAM1-1);
 -      tdm_spawnteam("Blue", COLOR_TEAM2-1);
 +      tdm_spawnteam("Red", FL_TEAM_1-1);
 +      tdm_spawnteam("Blue", FL_TEAM_2-1);
        if(numteams >= 3)
 -              tdm_spawnteam("Yellow", COLOR_TEAM3-1);
 +              tdm_spawnteam("Yellow", FL_TEAM_3-1);
        if(numteams >= 4)
 -              tdm_spawnteam("Pink", COLOR_TEAM4-1);
 +              tdm_spawnteam("Pink", FL_TEAM_4-1);
  }
  
  void tdm_delayedinit()