]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Mario/classname_checks
authorMario <mario.mario@y7mail.com>
Tue, 7 May 2013 05:49:31 +0000 (15:49 +1000)
committerMario <mario.mario@y7mail.com>
Tue, 7 May 2013 05:49:31 +0000 (15:49 +1000)
41 files changed:
1  2 
qcsrc/server/assault.qc
qcsrc/server/attic/runematch.qc
qcsrc/server/bot/aim.qc
qcsrc/server/bot/bot.qc
qcsrc/server/cl_client.qc
qcsrc/server/cl_physics.qc
qcsrc/server/cl_player.qc
qcsrc/server/cl_weaponsystem.qc
qcsrc/server/command/cmd.qc
qcsrc/server/command/common.qc
qcsrc/server/command/sv_cmd.qc
qcsrc/server/command/vote.qc
qcsrc/server/g_damage.qc
qcsrc/server/g_triggers.qc
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/gamemode_ctf.qc
qcsrc/server/mutators/gamemode_domination.qc
qcsrc/server/mutators/gamemode_freezetag.qc
qcsrc/server/mutators/gamemode_keepaway.qc
qcsrc/server/mutators/gamemode_keyhunt.qc
qcsrc/server/mutators/gamemode_nexball.qc
qcsrc/server/mutators/gamemode_onslaught.qc
qcsrc/server/mutators/mutator_nix.qc
qcsrc/server/mutators/mutator_superspec.qc
qcsrc/server/portals.qc
qcsrc/server/race.qc
qcsrc/server/scores.qc
qcsrc/server/sv_main.qc
qcsrc/server/t_items.qc
qcsrc/server/t_jumppads.qc
qcsrc/server/teamplay.qc
qcsrc/server/vehicles/bumblebee.qc
qcsrc/server/vehicles/vehicles.qc
qcsrc/server/w_common.qc
qcsrc/server/w_electro.qc
qcsrc/server/w_fireball.qc
qcsrc/server/w_grenadelauncher.qc
qcsrc/server/w_minelayer.qc
qcsrc/server/w_rocketlauncher.qc
qcsrc/server/w_shotgun.qc

diff --combined qcsrc/server/assault.qc
index fe5fb5ef04da10914e70498abc5d8027e792ba93,7a5662c9799fb51f738b7293a3e5ce04f9a99f44..71ac7239a675a75f93a2dc33334dd4b66ed5c6c3
@@@ -9,7 -9,7 +9,7 @@@ void spawnfunc_info_player_attacker() 
                remove(self);
                return;
        }
-       self.team = COLOR_TEAM1; // red, gets swapped every round
+       self.team = NUM_TEAM_1; // red, gets swapped every round
        spawnfunc_info_player_deathmatch();
  }
  
@@@ -19,7 -19,7 +19,7 @@@ void spawnfunc_info_player_defender() 
                remove(self);
                return;
        }
-       self.team = COLOR_TEAM2; // blue, gets swapped every round
+       self.team = NUM_TEAM_2; // blue, gets swapped every round
        spawnfunc_info_player_deathmatch();
  }
  
@@@ -216,10 -216,10 +216,10 @@@ void spawnfunc_func_assault_destructibl
        }
        self.spawnflags = 3;
        self.classname = "func_assault_destructible";
-       if(assault_attacker_team == COLOR_TEAM1) {
-               self.team = COLOR_TEAM2;
+       if(assault_attacker_team == NUM_TEAM_1) {
+               self.team = NUM_TEAM_2;
        } else {
-               self.team = COLOR_TEAM1;
+               self.team = NUM_TEAM_1;
        }
        spawnfunc_func_breakable();
  }
@@@ -289,10 -289,10 +289,10 @@@ void assault_roundstart_use() 
        ent = find(world, classname, "turret_main");
        while(ent) {
                // Swap turret teams
-               if(ent.team == COLOR_TEAM1)
-                       ent.team = COLOR_TEAM2;
+               if(ent.team == NUM_TEAM_1)
+                       ent.team = NUM_TEAM_2;
                else
-                       ent.team = COLOR_TEAM1;
+                       ent.team = NUM_TEAM_1;
  
                self = ent;
  
@@@ -313,7 -313,7 +313,7 @@@ void spawnfunc_target_assault_roundstar
                remove(self);
                return;
        }
-       assault_attacker_team = COLOR_TEAM1;
+       assault_attacker_team = NUM_TEAM_1;
        self.classname = "target_assault_roundstart";
        self.use = assault_roundstart_use;
        self.reset2 = assault_roundstart_use;
@@@ -351,22 -351,22 +351,22 @@@ void assault_new_round(
        self.winning = self.winning + 1;
  
        // swap attacker/defender roles
-       if(assault_attacker_team == COLOR_TEAM1) {
-               assault_attacker_team = COLOR_TEAM2;
+       if(assault_attacker_team == NUM_TEAM_1) {
+               assault_attacker_team = NUM_TEAM_2;
        } else {
-               assault_attacker_team = COLOR_TEAM1;
+               assault_attacker_team = NUM_TEAM_1;
        }
  
  
        entity ent;
        for(ent = world; (ent = nextent(ent)); )
        {
 -              if(clienttype(ent) == CLIENTTYPE_NOTACLIENT)
 +              if(IS_NOT_A_CLIENT(ent))
                {
-                       if(ent.team_saved == COLOR_TEAM1)
-                               ent.team_saved = COLOR_TEAM2;
-                       else if(ent.team_saved == COLOR_TEAM2)
-                               ent.team_saved = COLOR_TEAM1;
+                       if(ent.team_saved == NUM_TEAM_1)
+                               ent.team_saved = NUM_TEAM_2;
+                       else if(ent.team_saved == NUM_TEAM_2)
+                               ent.team_saved = NUM_TEAM_1;
                }
        }
  
index 0000000000000000000000000000000000000000,ba8f648c888b33e0e312cdf8774b3e1cd0169cad..1b6cc5dbb16266a3a585c0b0645edcb5c00a4afb
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,604 +1,604 @@@
 -      if(self.owner.classname != "player" || time < game_starttime)
+ float rune_numspawns;
+ float RUNE_FIRST      = 1;
+ float RUNE_STRENGTH   = 1;
+ float RUNE_DEFENSE    = 2;
+ float RUNE_REGEN      = 4;
+ float RUNE_SPEED      = 8;
+ float RUNE_VAMPIRE    = 16;
+ float RUNE_LAST       = 16;
+ float CURSE_FIRST     = 8192;
+ float CURSE_WEAK      = 8192;
+ float CURSE_VULNER    = 16384;
+ float CURSE_VENOM     = 32768;
+ float CURSE_SLOW      = 65536;
+ float CURSE_EMPATHY   = 131072;
+ float CURSE_LAST      = 131072;
+ float RUNE_COUNT = 5;
+ /* rune ideas:
+       Doom/Death
+       Rune: When you damage enemies, you have a slight chance of instant-killing them (porportional to damage dealt / their health)
+       Curse: When you are damaged, you have a chance of being instant-killed
+       Vengence/Slothful
+       Rune: The lower your health below 100, the more damage you deal (does not decrease your damage if you're above 100)
+       Curse: The higher your health (up to 100), the less damage you deal (at 100 hp deal 1/5th damage)
+ */
+ /*QUAKED spawnfunc_runematch_spawn_point (1 0 0) (-16 -16 -24) (16 16 24)
+ spawn point for runes in runematch
+ */
+ void spawnfunc_runematch_spawn_point()
+ {
+       if(!g_runematch || !autocvar_g_runematch_fixedspawns)
+       {
+               remove(self);
+               return;
+       }
+       setsize(self, '0 0 -35', '0 0 0');
+       droptofloor();
+       ++rune_numspawns;
+ }
+ // only used if using rune spawns at all
+ entity rune_find_spawnpoint()
+ {
+       entity e;
+       if(rune_numspawns < RUNE_COUNT)
+               return world;
+       RandomSelection_Init();
+       for(e = world; (e = find(e, classname, "runematch_spawn_point")); )
+               if(e.owner == world)
+                       RandomSelection_Add(e, 0, string_null, e.cnt, 0);
+       return RandomSelection_chosen_ent;
+ }
+ float rune_spawn_somewhere(entity e)
+ {
+       entity spot;
+       spot = rune_find_spawnpoint();
+       if(spot)
+       {
+               spot.owner = e;
+               setorigin(e, spot.origin);
+               e.owner = spot;
+               spot.owner = e;
+               return TRUE;
+       }
+       else
+       {
+               if(MoveToRandomMapLocation(e, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
+               {
+                       // great
+                       makevectors(self.angles),
+                       self.velocity = v_forward * 250;
+                       self.angles = '0 0 0';
+                       return TRUE;
+               }
+               else
+               {
+                       // sorry, can't spawn, better luck next frame
+                       return FALSE;
+               }
+       }
+ }
+ void rune_unmark_spot(entity e)
+ {
+       if(e.owner.classname == "runematch_spawn_point")
+       {
+               e.owner.owner = world;
+               e.owner = world;
+       }
+ }
+ string RuneName(float r)
+ {
+       if(r == RUNE_STRENGTH)
+               return "^1Strength^7";
+       if(r == RUNE_DEFENSE)
+               return "^4Defense^7";
+       if(r == RUNE_REGEN)
+               return "^2Vitality^7";
+       if(r == RUNE_SPEED)
+               return "^3Speed^7";
+       if(r == RUNE_VAMPIRE)
+               return "^6Vampire^7";
+       if(r == CURSE_WEAK)
+               return "^1Weakness^7";
+       if(r == CURSE_VULNER)
+               return "^4Vulnerability^7";
+       if(r == CURSE_VENOM)
+               return "^2Venom^7";
+       if(r == CURSE_SLOW)
+               return "^3Slow^7";
+       if(r == CURSE_EMPATHY)
+               return "^6Empathy^7";
+       return strcat("^8[unnamed", ftos(r), "]^7");
+ }
+ vector RuneColormod(float r)
+ {
+       vector _color = '255 0 255';
+       if(r == RUNE_STRENGTH)
+               _color = '255 0 0';
+       if(r == RUNE_DEFENSE)
+               _color = '0 0 255';//'0 102 255';//
+       if(r == RUNE_REGEN)
+               _color = '0 204 0';//'0 255 0';
+       if(r == RUNE_SPEED)
+               _color = 0.35*'185 185 0';//255 230 0';//'255 255 0';
+       if(r == RUNE_VAMPIRE)
+               _color = '64 0 128';//'108 0 217';//'128 0 255';//'179 0 204';//
+       if(r == CURSE_WEAK)
+               _color = '255 0 0';
+       if(r == CURSE_VULNER)
+               _color = '0 0 255';//'0 102 255';//
+       if(r == CURSE_VENOM)
+               _color = '0 204 0';//'0 255 0';
+       if(r == CURSE_SLOW)
+               _color = 0.5*'185 185 0';//'255 255 0';
+       if(r == CURSE_EMPATHY)
+               _color = '179 0 204';//'128 0 255';
+       return _color * (1 / 255) * autocvar_g_runematch_rune_color_strength;
+ }
+ void rune_respawn();
+ void RuneCarriedThink()
+ {
+       float rcount, rnum;
+       vector ang = '0 0 0';
+       entity rune;
 -      if(other.classname != "player" || other.health < 1)
++      if(!IS_PLAYER(self.owner) || time < game_starttime)
+       {
+               rune_respawn();
+               return;
+       }
+       self.nextthink = time + 0.1;
+       // count runes my owner holds
+       rcount = 0;
+       rune = find(world, classname, "rune");
+       rnum = -1;
+       while(rune)
+       {
+               if(rune.owner == self.owner)
+                       rcount = rcount + 1;
+               if(rune == self)
+                       rnum = rcount;
+               rune = find(rune, classname, "rune");
+       }
+       ang_y = rnum*(360 / rcount) + mod(time, 360)*45;//180;
+       makevectors(ang);
+       setorigin(self, v_forward*32);
+ }
+ void rune_touch()
+ {
+       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+       {
+               self.think = rune_respawn;
+               self.nextthink = time;
+               return;
+       }
 -              if(rune.owner.classname == "player")
++      if(!IS_PLAYER(other) || other.health < 1)
+               return;
+       if(self.wait > time)
+               return; // "notouch" time isn't finished
+       // detach from the spawn point you're on
+       rune_unmark_spot(self);
+       self.owner = other;
+       self.enemy.owner = other;
+       setattachment(self, other, "");
+       other.runes = other.runes | self.runes | self.enemy.runes;
+       //self.think = func_null;
+       //self.nextthink = 0;
+       self.think = RuneCarriedThink;
+       self.nextthink = time;
+       self.touch = func_null;
+       self.solid = SOLID_NOT;
+       setorigin(self, self.origin);
+       //sprint(other, strcat("^3You have picked up ",
+       //      RuneName(self.runes & (RUNE_LAST*2-1)), " and "));
+       //sprint(other, strcat(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"));
+       bprint("^3", other.netname, "^7 has picked up ",
+               RuneName(self.runes & (RUNE_LAST*2-1)), "^7 and ");
+       bprint(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n");
+ }
+ void rune_respawn()
+ {
+       rune_unmark_spot(self);
+       if(rune_spawn_somewhere(self))
+       {
+               self.solid = SOLID_TRIGGER;
+               self.touch = rune_touch;
+               self.think = rune_respawn;
+               self.nextthink = time + autocvar_g_runematch_shuffletime;//30 + random()*5; // fixme: cvar
+       }
+       else
+       {
+               // try again later
+               self.think = rune_respawn;
+               self.nextthink = time;
+       }
+ }
+ entity FindRune(entity own, string clname, float r)
+ {
+       entity rune;
+       float _count, c;
+       c = _count = 0;
+       rune = world;
+       do
+       {
+               rune = find(rune, classname, clname);
+               if(!rune)
+                       rune = find(rune, classname, clname);
+               if(!rune)
+                       break;
+               if(rune.owner == own)
+               {
+                       _count = _count + 1;
+                       if(_count >= r)
+                               return rune;
+                       if(r <= 1)
+                               return rune;
+               }
+               c = c + 1;
+       }while(c < 30);
+       return world;
+ }
+ void DropRune(entity pl, entity e)
+ {
+       //entity pl;
+       //pl = e.owner;
+       // detach from player
+       setattachment(e, world, "");
+       e.owner = world;
+       e.enemy.owner = world;
+       // don't instantly touch player again
+       e.wait = time + 1; // "notouch" time
+       e.movetype = MOVETYPE_TOSS;
+       e.solid = SOLID_TRIGGER;
+       // reposition itself if not picked up soon
+       e.think = rune_respawn;
+       e.nextthink = time + autocvar_g_runematch_respawntime;//15 + random()*5; // fixme: cvar
+       e.touch = rune_touch;
+       pl.runes = pl.runes - (pl.runes & (e.runes | e.enemy.runes));
+       // toss from player
+       setorigin(e, pl.origin + '0 0 10');
+       e.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
+       bprint("^3", pl.netname, "^7 has lost ",
+               RuneName(e.runes & (RUNE_LAST*2-1)), "^7 and ");
+       bprint(RuneName(e.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n");
+ }
+ float RuneMatchesCurse(float r, float c)
+ {
+       float cr;
+       if(r & RUNE_STRENGTH)
+               cr = CURSE_WEAK;
+       else if(r & RUNE_DEFENSE)
+               cr = CURSE_VULNER;
+       else if(r & RUNE_REGEN)
+               cr = CURSE_VENOM;
+       else if(r & RUNE_SPEED)
+               cr = CURSE_SLOW;
+       else if(r & RUNE_VAMPIRE)
+               cr = CURSE_EMPATHY;
+       else return FALSE; // fixme: error?
+       if(c & cr)
+               return TRUE;
+       return FALSE;
+ }
+ // player died, drop runes
+ // each rune should pair up with a random curse and then be tossed from the player
+ void DropAllRunes(entity pl)
+ {
+       entity rune, curse;
+       float rcount, ccount, r, c, rand, prevent_same, numtodrop, tries;
+       entity curse1, rune1, curse2, rune2;
+       rcount = ccount = r = c = 0;
+       rune = find(world, classname, "rune");
+       while(rune)
+       {
+               if(rune.owner == pl)
+                       rcount = rcount + 1;
+               rune = find(rune, classname, "rune");
+       }
+       curse = find(world, classname, "curse");
+       while(curse)
+       {
+               if(curse.owner == pl)
+                       ccount = ccount + 1;
+               curse = find(curse, classname, "curse");
+       }
+       numtodrop = autocvar_g_runematch_drop_runes_max;
+       prevent_same = !autocvar_g_runematch_allow_same;
+       do
+       {
+               rune = find(rune, classname, "rune");
+               if(!rune)
+                       break;
+               if(rune.owner != pl)
+                       continue;
+               // find a random curse
+               tries = 15;
+               if(ccount > 1 && prevent_same)
+               {
+                       // avoid pairing runes and curses that match each other
+                       do{
+                               rand = floor(random()*ccount) + 1;
+                               curse = FindRune(pl, "curse", rand);
+                               tries = tries - 1;
+                       }while(RuneMatchesCurse(rune.runes, curse.runes) && tries > 0);
+                       if(tries <= 0)
+                       {
+                               bprint("warning: couldn't prevent same rune\n");
+                       }
+               }
+               else
+               {
+                               rand = floor(random()*ccount) + 1;
+                               curse = FindRune(pl, "curse", rand);
+               }
+               if(!curse)
+                       error("Couldn't fine curse to bind rune to\n");
+               // pair rune and curse
+               rune1 = rune;
+               curse1 = curse;
+               rune2 = curse1.enemy;
+               curse2 = rune1.enemy;
+               if(rune1 != rune2) // not already attached to each other
+               {
+                       rune1.enemy = curse1;
+                       curse1.enemy = rune1;
+                       setattachment(curse1, rune1, "");
+                       rune2.enemy = curse2;
+                       curse2.enemy = rune2;
+                       setattachment(curse2, rune2, "");
+                       //DropRune(pl, rune2);
+                       //ccount = ccount - 1;
+                       //rcount = rcount - 1;
+               }
+               DropRune(pl, rune1);
+               if(numtodrop <=0)
+               {
+                       rune1.think = rune_respawn;
+                       rune1.nextthink = time;
+               }
+               numtodrop = numtodrop - 1;
+               ccount = ccount - 1;
+               rcount = rcount - 1;
+       }while(rune);
+ }
+ void rune_reset()
+ {
+       if(self.owner)
+               if(self.owner.classname != "runematch_spawn_point")
+                       DropAllRunes(self.owner);
+       rune_respawn();
+ }
+ void spawn_runes()
+ {
+       float rn, cs, runes_used, curses_used, prevent_same, numrunes;
+       entity e;
+       if(self)
+               remove(self);
+       // fixme: instead of placing them all now, why not
+       // simply create them all and let them call rune_respawn() as their think?
+       runes_used  = 0;
+       curses_used = 0;
+       prevent_same = !autocvar_g_runematch_allow_same;
+       numrunes = RUNE_COUNT;
+       while(numrunes > 0)
+       {
+               RandomSelection_Init();
+               for(rn = RUNE_FIRST; rn <= RUNE_LAST; rn *= 2)
+                       if not(runes_used & rn)
+                               RandomSelection_Add(world, rn, string_null, 1, 1);
+               rn = RandomSelection_chosen_float;
+               RandomSelection_Init();
+               for(cs = CURSE_FIRST; cs <= CURSE_LAST; cs *= 2)
+                       if not(curses_used & cs)
+                               if not(prevent_same && cs == RuneMatchesCurse(rn, cs))
+                                       RandomSelection_Add(world, cs, string_null, 1, 1);
+               cs = RandomSelection_chosen_float;
+               if(!rn || !cs)
+                       error("No rune/curse left");
+               runes_used |= rn;
+               curses_used |= cs;
+               e = spawn();
+               e.runes = rn;
+               e.classname = "rune";
+               e.touch = rune_touch;
+               e.think = rune_respawn;
+               e.nextthink = time;
+               e.movetype = MOVETYPE_TOSS;
+               e.solid = SOLID_TRIGGER;
+               e.flags = FL_ITEM;
+               e.reset = rune_reset;
+               setmodel(e, "models/runematch/rune.mdl"); // precision set below
+               setsize(e, '0 0 -35', '0 0 0');
+               e.enemy = spawn();
+               e.enemy.enemy = e;
+               e.enemy.classname = "curse";
+               e.enemy.runes = cs;
+               //e.enemy.avelocity = '300 500 200';
+               setmodel(e.enemy, "models/runematch/curse.mdl"); // precision set below
+               setorigin(e, '0 0 0');
+               setattachment(e.enemy, e, "");
+               e.colormod = RuneColormod(rn);
+               e.enemy.colormod = RuneColormod(cs);
+               e.alpha = e.enemy.alpha = autocvar_g_runematch_rune_alpha;//0.78;
+               e.effects = e.enemy.effects = autocvar_g_runematch_rune_effects | EF_LOWPRECISION;//EF_ADDITIVE;// | EF_FULLBRIGHT;
+               //e.glow_size = e.enemy.glow_size = cvar("g_runematch_rune_glow_size");
+               //e.glow_color = e.enemy.glow_color = cvar("g_runematch_rune_glow_color");
+               //rn = RUNE_FIRST;
+               //cs = CURSE_FIRST;
+               numrunes = numrunes - 1;
+       }
+ }
+ void runematch_init()
+ {
+       if(!g_runematch)
+               return;
+       entity e;
+       e = spawn();
+       e.think = spawn_runes;
+       e.nextthink = time + 0.1;
+ }
+ float runematch_point_time;
+ // give points to players who are holding runes
+ void RuneMatchGivePoints()
+ {
+       entity rune;
+       if(!g_runematch || !autocvar_g_runematch_pointamt)
+               return;
+       if(gameover)
+               return;
+       if(runematch_point_time > time)
+               return;
+       runematch_point_time = time + autocvar_g_runematch_pointrate;
+       rune = world;
+       do
+       {
+               rune = find(rune, classname, "rune");
+               if(!rune)
+                       return;
++              if(IS_PLAYER(rune.owner))
+               {
+                       UpdateFrags(rune.owner, autocvar_g_runematch_pointamt);
+               }
+       }while(rune);
+ }
+ float RunematchHandleFrags(entity attacker, entity targ, float f)
+ {
+       entity head;
+       float arunes, trunes, newfrags;
+       if(f <= 0)
+               return f;
+       if(attacker == targ)
+               return f;
+       arunes = trunes = 0;
+       head = find(world, classname, "rune");
+       while(head)
+       {
+               if(head.owner == attacker)
+               {
+                       arunes = arunes + 1;
+               }
+               else if(head.owner == targ)
+               {
+                       trunes = trunes + 1;
+               }
+               head = find(head, classname, "rune");
+       }
+       if(!arunes && !trunes)
+               return f - 1 + autocvar_g_runematch_frags_norune; // don't give points to players when no runes are involved.
+       newfrags = 0;
+       if(arunes)
+       {       // got a kill while holding runes
+               newfrags = newfrags + autocvar_g_runematch_frags_killedby_runeholder;//5;
+       }
+       if(trunes)
+       {       // killed an enemy holding runes
+               newfrags = newfrags + autocvar_g_runematch_frags_killed_runeholder;//5;
+       }
+       if(newfrags)
+               f = f - 1 + newfrags;
+       return f;
+ }
diff --combined qcsrc/server/bot/aim.qc
index c381893b7870b3a9ce2d39a45518c084c143f996,cb42aa5c2c4b0b158697b4122a51c27e88543d7d..5bb63654ea11d70498aa4df9dfca12c9b5faad81
@@@ -111,9 -111,8 +111,8 @@@ float bot_shouldattack(entity e
                        return FALSE;
        }
  
-       if(g_freezetag)
-               if(e.freezetag_frozen)
-                       return FALSE;
+       if(e.freezetag_frozen)
+               return FALSE;
  
        // If neither player has ball then don't attack unless the ball is on the
        // ground.
                        return FALSE;
        }
        else if(bot_ignore_bots)
 -              if(clienttype(e) == CLIENTTYPE_BOT)
 +              if(IS_BOT_CLIENT(e))
                        return FALSE;
  
        if (!e.takedamage)
diff --combined qcsrc/server/bot/bot.qc
index ee4933cc464ef8f2ddcaf4fbd62c291a92999584,f6e7f6f1b6921f5745982030050f76e1f350cee4..b45f35aa8fffb0d80b2e1b700f6636f7153e25ef
@@@ -148,7 -148,7 +148,7 @@@ void bot_setnameandstuff(
                        prio = 1;
                        FOR_EACH_CLIENT(p)
                        {
 -                              if(clienttype(p) == CLIENTTYPE_BOT)
 +                              if(IS_BOT_CLIENT(p))
                                if(s == p.cleanname)
                                {
                                        prio = 0;
        i = 0;
        FOR_EACH_CLIENT(p)
        {
 -              if(clienttype(p) == CLIENTTYPE_BOT)
 +              if(IS_BOT_CLIENT(p))
                        if(p.cleanname == name)
                                ++i;
        }
@@@ -342,7 -342,7 +342,7 @@@ void bot_relinkplayerlist(
        {
                player_count = player_count + 1;
                e.nextplayer = e.chain;
 -              if (clienttype(e) == CLIENTTYPE_BOT)
 +              if (IS_BOT_CLIENT(e))
                {
                        if (prevbot)
                                prevbot.nextbot = e;
  
  void bot_clientdisconnect()
  {
 -      if (clienttype(self) != CLIENTTYPE_BOT)
 +      if not(IS_BOT_CLIENT(self))
                return;
        bot_clearqueue(self);
        if(self.cleanname)
  
  void bot_clientconnect()
  {
 -      if (clienttype(self) != CLIENTTYPE_BOT)
 +      if not(IS_BOT_CLIENT(self))
                return;
        self.bot_preferredcolors = self.clientcolors;
        self.bot_nextthink = time - random();
                bot_setnameandstuff();
  
        if(self.bot_forced_team==1)
-               self.team = COLOR_TEAM1;
+               self.team = NUM_TEAM_1;
        else if(self.bot_forced_team==2)
-               self.team = COLOR_TEAM2;
+               self.team = NUM_TEAM_2;
        else if(self.bot_forced_team==3)
-               self.team = COLOR_TEAM3;
+               self.team = NUM_TEAM_3;
        else if(self.bot_forced_team==4)
-               self.team = COLOR_TEAM4;
+               self.team = NUM_TEAM_4;
        else
                JoinBestTeam(self, FALSE, TRUE);
  
@@@ -425,13 -425,13 +425,13 @@@ void bot_removefromlargestteam(
        bestcount = 0;
        while (head)
        {
-               if(head.team == COLOR_TEAM1)
+               if(head.team == NUM_TEAM_1)
                        thiscount = c1;
-               else if(head.team == COLOR_TEAM2)
+               else if(head.team == NUM_TEAM_2)
                        thiscount = c2;
-               else if(head.team == COLOR_TEAM3)
+               else if(head.team == NUM_TEAM_3)
                        thiscount = c3;
-               else if(head.team == COLOR_TEAM4)
+               else if(head.team == NUM_TEAM_4)
                        thiscount = c4;
                else
                        thiscount = 0;
@@@ -491,7 -491,7 +491,7 @@@ void autoskill(float factor
        bestplayer = -1;
        FOR_EACH_PLAYER(head)
        {
 -              if(clienttype(head) == CLIENTTYPE_REAL)
 +              if(IS_REAL_CLIENT(head))
                        bestplayer = max(bestplayer, head.totalfrags - head.totalfrags_lastcheck);
                else
                        bestbot = max(bestbot, head.totalfrags - head.totalfrags_lastcheck);
@@@ -551,7 -551,7 +551,7 @@@ float bot_fixcount(
  
        FOR_EACH_REALCLIENT(head)
        {
-               if(IS_PLAYER(head) || g_lms || g_arena || g_ca)
 -              if(head.classname == "player" || g_lms || g_arena || head.caplayer == 1)
++              if(IS_PLAYER(head) || g_lms || g_arena || head.caplayer == 1)
                        ++activerealplayers;
                ++realplayers;
        }
index c8b64a175f95a88e136f1a6cc3a98a3a10180022,5d29bf7e1537e4099fba46418a467cb2bde7cb57..4f741fa4435abe5481cecf737e67e0a1ced851fb
@@@ -6,22 -6,6 +6,6 @@@ void send_CSQC_teamnagger() 
        WriteByte(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
  }
  
- void Announce(string snd) {
-       WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-       WriteByte(MSG_BROADCAST, TE_CSQC_ANNOUNCE);
-       WriteString(MSG_BROADCAST, snd);
- }
- void AnnounceTo(entity e, string snd) {
-       if (IS_REAL_CLIENT(e))
-       {
-               msg_entity = e;
-               WriteByte(MSG_ONE, SVC_TEMPENTITY);
-               WriteByte(MSG_ONE, TE_CSQC_ANNOUNCE);
-               WriteString(MSG_ONE, snd);
-       }
- }
  float ClientData_Send(entity to, float sf)
  {
        if(to != self.owner)
@@@ -33,7 -17,7 +17,7 @@@
        entity e;
  
        e = to;
 -      if(to.classname == "spectator")
 +      if(IS_SPEC(to))
                e = to.enemy;
  
        sf = 0;
@@@ -84,7 -68,7 +68,7 @@@ void ClientData_Touch(entity e
        FOR_EACH_REALCLIENT(e2)
        {
                if(e2 != e)
 -                      if(e2.classname == "spectator")
 +                      if(IS_SPEC(e2))
                                if(e2.enemy == e)
                                        e2.clientdata.SendFlags = 1;
        }
@@@ -140,7 -124,7 +124,7 @@@ vector Spawn_Score(entity spot, float m
                if(spot.target == "")
                        return '-1 0 0';
  
 -      if(clienttype(self) == CLIENTTYPE_REAL)
 +      if(IS_REAL_CLIENT(self))
        {
                if(spot.restriction == 1)
                        return '-1 0 0';
@@@ -293,7 -277,7 +277,7 @@@ entity SelectSpawnPoint (float anypoint
        else
        {
                float mindist;
-               if (arena_roundbased && !g_ca)
+               if (g_arena && arena_roundbased)
                        mindist = 800;
                else
                        mindist = 100;
@@@ -394,14 -378,31 +378,31 @@@ void PutObserverInServer (void
                error("No spawnpoints for observers?!?\n");
        RemoveGrapplingHook(self); // Wazat's Grappling Hook
  
 -      if(clienttype(self) == CLIENTTYPE_REAL)
 +      if(IS_REAL_CLIENT(self))
        {
                msg_entity = self;
                WriteByte(MSG_ONE, SVC_SETVIEW);
                WriteEntity(MSG_ONE, self);
        }
  
-       DropAllRunes(self);
+       if(g_lms)
+       {
+               // Only if the player cannot play at all
+               if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
+                       self.frags = FRAGS_SPECTATOR;
+               else
+                       self.frags = FRAGS_LMS_LOSER;
+       }
+       else if((g_race && g_race_qualifying) || g_cts)
+       {
+               if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
+                       self.frags = FRAGS_LMS_LOSER;
+               else
+                       self.frags = FRAGS_SPECTATOR;
+       }
+       else
+               self.frags = FRAGS_SPECTATOR;
        MUTATOR_CALLHOOK(MakePlayerObserver);
  
        minstagib_stop_countdown(self);
  
        if(self.killcount != -666) {
                if(g_lms) {
-                       if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0)
-                               bprint ("^4", self.netname, "^4 has no more lives left\n");
+                       if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0 && self.lms_spectate_warning != 2)
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_NOLIVES, self.netname);
                        else
-                               bprint ("^4", self.netname, "^4 is spectating now\n"); // TODO turn this into a proper forfeit?
-               } else
-                       bprint ("^4", self.netname, "^4 is spectating now\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_FORFEIT, self.netname);
+               } else { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_SPECTATE, self.netname); }
  
                if(self.just_joined == FALSE) {
                        LogTeamchange(self.playerid, -1, 4);
        self.pauseregen_finished = 0;
        self.damageforcescale = 0;
        self.death_time = 0;
+       self.respawn_flags = 0;
        self.respawn_time = 0;
+       self.stat_respawn_time = 0;
        self.alpha = 0;
        self.scale = 0;
        self.fade_time = 0;
        self.think = func_null;
        self.nextthink = 0;
        self.hook_time = 0;
-       self.runes = 0;
        self.deadflag = DEAD_NO;
        self.angles = spot.angles;
        self.angles_z = 0;
        self.punchvector = '0 0 0';
        self.oldvelocity = self.velocity;
        self.fire_endtime = -1;
-       if(g_arena)
-       {
-               if(self.version_mismatch)
-               {
-                       self.frags = FRAGS_SPECTATOR;
-                       Spawnqueue_Unmark(self);
-                       Spawnqueue_Remove(self);
-               }
-               else
-               {
-                       self.frags = FRAGS_LMS_LOSER;
-                       Spawnqueue_Insert(self);
-               }
-       }
-       else if(g_lms)
-       {
-               // Only if the player cannot play at all
-               if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
-                       self.frags = FRAGS_SPECTATOR;
-               else
-                       self.frags = FRAGS_LMS_LOSER;
-       }
-       else if(g_ca)
-       {
-               if(self.caplayer)
-                       self.frags = FRAGS_LMS_LOSER;
-               else
-                       self.frags = FRAGS_SPECTATOR;
-       }
-       else if((g_race && g_race_qualifying) || g_cts)
-       {
-               if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
-                       self.frags = FRAGS_LMS_LOSER;
-               else
-                       self.frags = FRAGS_SPECTATOR;
-       }
-       else
-               self.frags = FRAGS_SPECTATOR;
  }
  
  .float model_randomizer;
@@@ -564,7 -526,7 +526,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));
                                setcolor(self, stof(autocvar_sv_defaultplayercolors));
  }
  
- void PlayerTouchExplode(entity p1, entity p2)
- {
-       vector org;
-       org = (p1.origin + p2.origin) * 0.5;
-       org_z += (p1.mins_z + p2.mins_z) * 0.5;
-       te_explosion(org);
-       entity e;
-       e = spawn();
-       setorigin(e, org);
-       RadiusDamage(e, world, g_touchexplode_damage, g_touchexplode_edgedamage, g_touchexplode_radius, world, g_touchexplode_force, DEATH_TOUCHEXPLODE, world);
-       remove(e);
- }
  /*
  =============
  PutClientInServer
@@@ -655,13 -602,9 +602,9 @@@ Called when a client spawns in the serv
  
  void PutClientInServer (void)
  {
-       if(IS_BOT_CLIENT(self))
-       {
+       if(clienttype(self) == CLIENTTYPE_BOT)
                self.classname = "player";
-               if(g_ca)
-                       self.caplayer = 1;
-       }
-       else if(IS_REAL_CLIENT(self))
+       else if(clienttype(self) == CLIENTTYPE_REAL)
        {
                msg_entity = self;
                WriteByte(MSG_ONE, SVC_SETVIEW);
                        self.classname = "observer";
        }
  
-       if((g_arena && !self.spawned) || (g_ca && !allowed_to_spawn))
-               self.classname = "observer";
+       MUTATOR_CALLHOOK(PutClientInServer);
  
        if(gameover)
                self.classname = "observer";
  
-       if(IS_PLAYER(self) && (!g_ca || (g_ca && allowed_to_spawn))) {
 -      if(self.classname == "player") {
++      if(IS_PLAYER(self))
++      {
                entity spot, oldself;
                float j;
  
                spot = SelectSpawnPoint (FALSE);
                if(!spot)
                {
-                       centerprint(self, "Sorry, no spawnpoints available!\nHope your team can fix it...");
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_NOSPAWNS);
                        return; // spawn failed
                }
  
                self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID;
                if(autocvar_g_playerclip_collisions)
                        self.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP;
 -              if(clienttype(self) == CLIENTTYPE_BOT && autocvar_g_botclip_collisions)
 +              if(IS_BOT_CLIENT(self) && autocvar_g_botclip_collisions)
                        self.dphitcontentsmask |= DPCONTENTS_BOTCLIP;
                self.frags = FRAGS_PLAYER;
                if(INDEPENDENT_PLAYERS)
                }
                self.damageforcescale = 2;
                self.death_time = 0;
+               self.respawn_flags = 0;
                self.respawn_time = 0;
+               self.stat_respawn_time = 0;
                self.scale = 0;
                self.fade_time = 0;
                self.pain_frame = 0;
  
                self.metertime = 0;
  
-               self.runes = 0;
                self.deadflag = DEAD_NO;
  
                self.angles = spot.angles;
                self.lastteleporttime = time; // prevent insane speeds due to changing origin
          self.hud = HUD_NORMAL;
  
-               if(g_arena)
-               {
-                       Spawnqueue_Remove(self);
-                       Spawnqueue_Mark(self);
-               }
-               else if(g_ca)
-                       self.caplayer = 1;
                self.event_damage = PlayerDamage;
  
                self.bot_attack = TRUE;
  
                if(g_assault) {
                        if(self.team == assault_attacker_team)
-                               centerprint(self, "You are attacking!");
+                               Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
                        else
-                               centerprint(self, "You are defending!");
+                               Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
                }
  
                target_voicescript_clear(self);
  
                if (autocvar_g_spawnsound)
                        soundat(world, self.origin, CH_TRIGGER, "misc/spawn.wav", VOL_BASE, ATTN_NORM);
 -      } else if(self.classname == "observer") {
 +      } else if(IS_OBSERVER(self)) {
                PutObserverInServer ();
        }
  }
@@@ -1083,14 -1017,13 +1018,13 @@@ void ClientKill_Now_TeamChange(
        }
        else if(self.killindicator_teamchange == -2)
        {
-               if(g_ca)
-                       self.caplayer = 0;
                if(blockSpectators)
-                       sprint(self, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
                PutObserverInServer();
        }
        else
                SV_ChangeTeam(self.killindicator_teamchange - 1);
+       self.killindicator_teamchange = 0;
  }
  
  void ClientKill_Now()
@@@ -1149,10 -1082,10 +1083,10 @@@ void KillIndicator_Think(
        {
                if(self.cnt <= 10)
                        setmodel(self, strcat("models/sprites/", ftos(self.cnt), ".spr32"));
 -              if(clienttype(self.owner) == CLIENTTYPE_REAL)
 +              if(IS_REAL_CLIENT(self.owner))
                {
                        if(self.cnt <= 10)
-                               AnnounceTo(self.owner, strcat(ftos(self.cnt), ""));
+                               { Send_Notification(NOTIF_ONE, self.owner, MSG_ANNCE, Announcer_PickNumber(self.cnt)); }
                }
                self.nextthink = time + 1;
                self.cnt -= 1;
@@@ -1193,7 -1126,7 +1127,7 @@@ void ClientKill_TeamChange (float targe
                        self.clientkill_nexttime = time + killtime + autocvar_g_balance_kill_antispam;
                }
  
 -              if(killtime <= 0 || self.classname != "player" || self.deadflag != DEAD_NO)
 +              if(killtime <= 0 || !IS_PLAYER(self) || self.deadflag != DEAD_NO)
                {
                        ClientKill_Now();
                }
                if(targetteam == 0) // just die
                {
                        self.killindicator.colormod = '0 0 0';
 -                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "^1Suicide in %d seconds", 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SUICIDE, self.killindicator.cnt);
                }
                else if(targetteam == -1) // auto
                {
                        self.killindicator.colormod = '0 1 0';
 -                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Changing team in %d seconds", 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_AUTO, self.killindicator.cnt);
                }
                else if(targetteam == -2) // spectate
                {
                        self.killindicator.colormod = '0.5 0.5 0.5';
 -                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Spectating in %d seconds", 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SPECTATE, self.killindicator.cnt);
                }
                else
                {
-                       self.killindicator.colormod = TeamColor(targetteam);
+                       self.killindicator.colormod = Team_ColorRGB(targetteam);
 -                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(self))
                        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_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, APP_TEAM_NUM_4(targetteam, CENTER_TEAMCHANGE_), self.killindicator.cnt);
                }
        }
  
  
  void ClientKill (void)
  {
-       if (gameover)
-               return;
-       if((g_arena || g_ca) && ((champion && IS_PLAYER(champion) && player_count > 1) || player_count == 1)) // don't allow a kill in this case either
-       {
-               // do nothing
-       }
-     else if(self.freezetag_frozen)
-     {
-         // do nothing
-     }
-       else
-               ClientKill_TeamChange(0);
+       if(gameover) return;
+       if(self.player_blocked) return;
+       if(self.freezetag_frozen) return;
 -
++      
+       ClientKill_TeamChange(0);
  }
  
  void CTS_ClientKill (entity e) // silent version of ClientKill, used when player finishes a CTS run. Useful to prevent cheating by running back to the start line and starting out with more speed
@@@ -1300,7 -1225,7 +1226,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
@@@ -1349,7 -1274,6 +1275,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);
@@@ -1357,7 -1281,7 +1282,7 @@@ void ClientConnect (void
  {
        float t;
  
 -      if(self.flags & FL_CLIENT)
 +      if(IS_CLIENT(self))
        {
                print("Warning: ClientConnect, but already connected!\n");
                return;
        DecodeLevelParms();
  
  #ifdef WATERMARK
-       sprint(self, strcat("^4SVQC Build information: ^1", WATERMARK, "\n"));
+       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_WATERMARK, WATERMARK);
  #endif
  
        self.classname = "player_joining";
        // identify the right forced team
        if(autocvar_g_campaign)
        {
 -              if(clienttype(self) == CLIENTTYPE_REAL) // only players, not bots
 +              if(IS_REAL_CLIENT(self)) // only players, not bots
                {
                        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 = NUM_TEAM_1; break;
+                               case 2: self.team_forced = NUM_TEAM_2; break;
+                               case 3: self.team_forced = NUM_TEAM_3; break;
+                               case 4: self.team_forced = NUM_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 = NUM_TEAM_1;
        else if(PlayerInIDList(self, autocvar_g_forced_team_blue))
-               self.team_forced = COLOR_TEAM2;
+               self.team_forced = NUM_TEAM_2;
        else if(PlayerInIDList(self, autocvar_g_forced_team_yellow))
-               self.team_forced = COLOR_TEAM3;
+               self.team_forced = NUM_TEAM_3;
        else if(PlayerInIDList(self, autocvar_g_forced_team_pink))
-               self.team_forced = COLOR_TEAM4;
+               self.team_forced = NUM_TEAM_4;
        else if(autocvar_g_forced_team_otherwise == "red")
-               self.team_forced = COLOR_TEAM1;
+               self.team_forced = NUM_TEAM_1;
        else if(autocvar_g_forced_team_otherwise == "blue")
-               self.team_forced = COLOR_TEAM2;
+               self.team_forced = NUM_TEAM_2;
        else if(autocvar_g_forced_team_otherwise == "yellow")
-               self.team_forced = COLOR_TEAM3;
+               self.team_forced = NUM_TEAM_3;
        else if(autocvar_g_forced_team_otherwise == "pink")
-               self.team_forced = COLOR_TEAM4;
+               self.team_forced = NUM_TEAM_4;
        else if(autocvar_g_forced_team_otherwise == "spectate")
                self.team_forced = -1;
        else if(autocvar_g_forced_team_otherwise == "spectator")
  
        PlayerStats_AddEvent(sprintf("kills-%d", self.playerid));
  
 -    if(clienttype(self) == CLIENTTYPE_BOT)
 +    if(IS_BOT_CLIENT(self))
          PlayerStats_AddPlayer(self);
  
        if(autocvar_sv_eventlog)
 -              GameLogEcho(strcat(":join:", ftos(self.playerid), ":", ftos(num_for_edict(self)), ":", ((clienttype(self) == CLIENTTYPE_REAL) ? self.netaddress : "bot"), ":", self.netname));
 +              GameLogEcho(strcat(":join:", ftos(self.playerid), ":", ftos(num_for_edict(self)), ":", ((IS_REAL_CLIENT(self)) ? self.netaddress : "bot"), ":", self.netname));
  
        LogTeamchange(self.playerid, self.team, 1);
  
  
        self.netname_previous = strzone(self.netname);
  
-       bprint("^4", self.netname, "^4 connected");
-       if(!IS_OBSERVER(self) && (g_domination || g_ctf))
-               bprint(" and joined the ", ColoredTeamName(self.team));
-       bprint("\n");
 -      if((self.classname == STR_PLAYER && teamplay))
++      if(IS_PLAYER(self) && teamplay)
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(self, INFO_JOIN_CONNECT_TEAM_), self.netname);
+       else
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_CONNECT, self.netname);
  
        stuffcmd(self, strcat(clientstuff, "\n"));
        stuffcmd(self, "cl_particles_reloadeffects\n"); // TODO do we still need this?
        else
                stuffcmd(self, "set _teams_available 0\n");
  
-       if(g_arena || g_ca)
-       {
-               self.classname = "observer";
-               if(g_arena)
-                       Spawnqueue_Insert(self);
-       }
        attach_entcs();
  
        bot_relinkplayerlist();
        self.spectatortime = time;
        if(blockSpectators)
        {
-               sprint(self, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
+               Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
        }
  
        self.jointime = time;
        self.allowed_timeouts = autocvar_sv_timeout_number;
  
 -      if(clienttype(self) == CLIENTTYPE_REAL)
 +      if(IS_REAL_CLIENT(self))
        {
+               if(!autocvar_g_campaign)
+               {
+                       self.motd_actived_time = -1;
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
+               }
                if(autocvar_g_bugrigs || WEPSET_EQ_AW(g_weaponarena_weapons, WEP_TUBA))
                        stuffcmd(self, "cl_cmd settemp chase_active 1\n");
        }
  
        CheatInitClient();
  
-       if(!autocvar_g_campaign)
-               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), autocvar_welcome_message_time, 0);
        CSQCMODEL_AUTOINIT();
  
        self.model_randomizer = random();
-     
-     if not(IS_REAL_CLIENT(self))
-         return;
-         
-     sv_notice_join();
-     
-     MUTATOR_CALLHOOK(ClientConnect);
 -      if(clienttype(self) == CLIENTTYPE_REAL)
++      if(IS_REAL_CLIENT(self))
+               sv_notice_join();
+       MUTATOR_CALLHOOK(ClientConnect);
  }
  /*
  =============
@@@ -1610,7 -1526,7 +1527,7 @@@ void ClientDisconnect (void
        if(self.vehicle)
            vehicles_exit(VHEF_RELESE);
  
 -      if not(self.flags & FL_CLIENT)
 +      if not(IS_CLIENT(self))
        {
                print("Warning: ClientDisconnect without ClientConnect\n");
                return;
  
        if(autocvar_sv_eventlog)
                GameLogEcho(strcat(":part:", ftos(self.playerid)));
-       bprint ("^4",self.netname);
-       bprint ("^4 disconnected\n");
+               
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_DISCONNECT, self.netname);
  
-       DropAllRunes(self);
        MUTATOR_CALLHOOK(ClientDisconnect);
  
        Portal_ClearAll(self);
  
        bot_relinkplayerlist();
  
-       if(g_arena)
-       {
-               Spawnqueue_Unmark(self);
-               Spawnqueue_Remove(self);
-       }
        accuracy_free(self);
        ClientData_Detach();
        PlayerScore_Detach(self);
@@@ -1774,7 -1683,7 +1684,7 @@@ void respawn(void
  
  void play_countdown(float finished, string samp)
  {
 -      if(clienttype(self) == CLIENTTYPE_REAL)
 +      if(IS_REAL_CLIENT(self))
                if(floor(finished - time - frametime) != floor(finished - time))
                        if(finished - time < 6)
                                sound (self, CH_INFO, samp, VOL_BASE, ATTN_NORM);
@@@ -1810,7 -1719,8 +1720,8 @@@ void player_powerups (void
                                self.alpha = default_player_alpha;
                                self.exteriorweaponentity.alpha = default_weapon_alpha;
                                self.items &~= IT_STRENGTH;
-                               sprint(self, "^3Invisibility has worn off\n");
+                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_INVISIBILITY, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
                        }
                }
                else
                                self.alpha = g_minstagib_invis_alpha;
                                self.exteriorweaponentity.alpha = g_minstagib_invis_alpha;
                                self.items |= IT_STRENGTH;
-                               sprint(self, "^3You are invisible\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
                        }
                }
  
                        if (time > self.invincible_finished)
                        {
                                self.items = self.items - (self.items & IT_INVINCIBLE);
-                               sprint(self, "^3Speed has worn off\n");
+                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_SPEED, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SPEED);
                        }
                }
                else
                        if (time < self.invincible_finished)
                        {
                                self.items = self.items | IT_INVINCIBLE;
-                               sprint(self, "^3You are on speed\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED);
                        }
                }
        }
                        if (time > self.strength_finished)
                        {
                                self.items = self.items - (self.items & IT_STRENGTH);
-                               sprint(self, "^3Strength has worn off\n");
+                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_STRENGTH, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_STRENGTH);
                        }
                }
                else
                        if (time < self.strength_finished)
                        {
                                self.items = self.items | IT_STRENGTH;
-                               sprint(self, "^3Strength infuses your weapons with devastating power\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_STRENGTH, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_STRENGTH);
                        }
                }
                if (self.items & IT_INVINCIBLE)
                        if (time > self.invincible_finished)
                        {
                                self.items = self.items - (self.items & IT_INVINCIBLE);
-                               sprint(self, "^3Shield has worn off\n");
+                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_SHIELD, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SHIELD);
                        }
                }
                else
                        if (time < self.invincible_finished)
                        {
                                self.items = self.items | IT_INVINCIBLE;
-                               sprint(self, "^3Shield surrounds you\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SHIELD, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SHIELD);
                        }
                }
                if (self.items & IT_SUPERWEAPON)
                        {
                                self.superweapons_finished = 0;
                                self.items = self.items - (self.items & IT_SUPERWEAPON);
-                               sprint(self, "^3Superweapons have been lost\n");
+                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_SUPERWEAPON_LOST, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_SUPERWEAPON_LOST);
                        }
                        else if (self.items & IT_UNLIMITED_SUPERWEAPONS)
                        {
                                {
                                        self.items = self.items - (self.items & IT_SUPERWEAPON);
                                        WEPSET_ANDNOT_EA(self, WEPBIT_SUPERWEAPONS);
-                                       sprint(self, "^3Superweapons have broken down\n");
+                                       //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_SUPERWEAPON_BROKEN, self.netname);
+                                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_SUPERWEAPON_BROKEN);
                                }
                        }
                }
                        if (time < self.superweapons_finished || (self.items & IT_UNLIMITED_SUPERWEAPONS))
                        {
                                self.items = self.items | IT_SUPERWEAPON;
-                               sprint(self, "^3You now have a superweapon\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_SUPERWEAPON_PICKUP, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_SUPERWEAPON_PICKUP);
                        }
                        else
                        {
@@@ -2004,32 -1924,6 +1925,6 @@@ void player_regen (void
  
        max_mod = regen_mod = rot_mod = limit_mod = 1;
  
-       if (self.runes & RUNE_REGEN)
-       {
-               if (self.runes & CURSE_VENOM) // do we have both rune/curse?
-               {
-                       regen_mod = autocvar_g_balance_rune_regen_combo_regenrate;
-                       max_mod = autocvar_g_balance_rune_regen_combo_hpmod;
-                       limit_mod = autocvar_g_balance_rune_regen_combo_limitmod;
-               }
-               else
-               {
-                       regen_mod = autocvar_g_balance_rune_regen_regenrate;
-                       max_mod = autocvar_g_balance_rune_regen_hpmod;
-                       limit_mod = autocvar_g_balance_rune_regen_limitmod;
-               }
-       }
-       else if (self.runes & CURSE_VENOM)
-       {
-               max_mod = autocvar_g_balance_curse_venom_hpmod;
-               if (self.runes & RUNE_REGEN) // do we have both rune/curse?
-                       rot_mod = autocvar_g_balance_rune_regen_combo_rotrate;
-               else
-                       rot_mod = autocvar_g_balance_curse_venom_rotrate;
-               limit_mod = autocvar_g_balance_curse_venom_limitmod;
-               //if (!self.runes & RUNE_REGEN)
-               //      rot_mod = autocvar_g_balance_curse_venom_rotrate;
-       }
        maxh = maxh * max_mod;
        //maxa = maxa * max_mod;
        //maxf = maxf * max_mod;
        limita = limita * limit_mod;
        //limitf = limitf * limit_mod;
  
-       if(g_lms && g_ca)
+       if(g_ca)
                rot_mod = 0;
  
        if (!g_minstagib && !g_ca && (!g_lms || autocvar_g_lms_regenerate))
@@@ -2165,7 -2059,6 +2060,6 @@@ void SpectateCopy(entity spectatee) 
        self.dmg_inflictor = spectatee.dmg_inflictor;
        self.v_angle = spectatee.v_angle;
        self.angles = spectatee.v_angle;
-       self.stat_respawn_time = spectatee.stat_respawn_time;
        if(!self.BUTTON_USE)
                self.fixangle = TRUE;
        setorigin(self, spectatee.origin);
@@@ -2207,7 -2100,7 +2101,7 @@@ float SpectateUpdate() 
        if (self == self.enemy)
                return 0;
  
 -      if(self.enemy.classname != "player")
 +      if not(IS_PLAYER(self.enemy))
                return 0;
  
        SpectateCopy(self.enemy);
@@@ -2258,7 -2151,7 +2152,7 @@@ float SpectateNext(entity _prefer) 
        if (other)
                self.enemy = other;
  
 -      if(self.enemy.classname == "player") {
 +      if(IS_PLAYER(self.enemy)) {
            /*if(self.enemy.vehicle)
            {      
              
@@@ -2309,55 -2202,40 +2203,40 @@@ void ShowRespawnCountdown(
                {
                        self.respawn_countdown = number - 1;
                        if(ceil(self.respawn_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds
-                               AnnounceTo(self, strcat(ftos(number), ""));
+                               Send_Notification(NOTIF_ONE, self, MSG_ANNCE, Announcer_PickNumber(number)); 
                }
        }
  }
  
- .float prevent_join_msgtime;
  void LeaveSpectatorMode()
  {
-       if(nJoinAllowed(self)) {
-               if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0) {
+       if(self.caplayer)
+               return;
+       if(nJoinAllowed(self))
+       {
+               if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
+               {
                        self.classname = "player";
  
                        if(autocvar_g_campaign || autocvar_g_balance_teams)
-                               JoinBestTeam(self, FALSE, TRUE);
+                               { JoinBestTeam(self, FALSE, TRUE); }
  
                        if(autocvar_g_campaign)
-                               campaign_bots_may_start = 1;
+                               { campaign_bots_may_start = 1; }
  
-                       PutClientInServer();
-                       if(IS_PLAYER(self))
-                               bprint ("^4", self.netname, "^4 is playing now\n");
-                       if(!autocvar_g_campaign)
-                       if (time < self.jointime + autocvar_welcome_message_time)
-                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD); // clear MOTD
+                       Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
  
-                       if (self.prevent_join_msgtime)
-                       {
-                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_PREVENT_JOIN);
-                               self.prevent_join_msgtime = 0;
-                       }
+                       PutClientInServer();
  
-                       return;
-               } else {
-                       if (g_ca && self.caplayer) {
-                       }       // do nothing
-                       else
-                               stuffcmd(self,"menu_showteamselect\n");
-                       return;
+                       if(IS_PLAYER(self)) { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_PLAY, self.netname); }
                }
+               else
+                       stuffcmd(self, "menu_showteamselect\n");
        }
-       else {
-               //player may not join because of g_maxplayers is set
-               if (time - self.prevent_join_msgtime > 2)
-               {
-                       Send_CSQC_Centerprint_Generic(self, CPID_PREVENT_JOIN, PREVENT_JOIN_TEXT, 0, 0);
-                       self.prevent_join_msgtime = time;
-               }
+       else
+       {
+               // Player may not join because g_maxplayers is set
+               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT);
        }
  }
  
@@@ -2392,8 -2270,9 +2271,9 @@@ float nJoinAllowed(entity ignore) 
                return maxclients - totalClients;
  
        float currentlyPlaying = 0;
-       FOR_EACH_REALPLAYER(e)
-               currentlyPlaying += 1;
+       FOR_EACH_REALCLIENT(e)
 -              if(e.classname == "player" || e.caplayer == 1)
++              if(IS_PLAYER(e) || e.caplayer == 1)
+                       currentlyPlaying += 1;
  
        if(currentlyPlaying < autocvar_g_maxplayers)
                return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
   * g_maxplayers_spectator_blocktime seconds
   */
  void checkSpectatorBlock() {
 -      if(self.classname == "spectator" || self.classname == "observer") {
 +      if(IS_SPEC(self) || IS_OBSERVER(self)) {
                if( time > (self.spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) {
-                       sprint(self, "^7You were kicked from the server because you are spectator and spectators aren't allowed at the moment.\n");
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_QUIT_KICK_SPECTATING);
                        dropclient(self);
                }
        }
  }
  
- .float motd_actived_time; // used for both motd and campaign_message
  void PrintWelcomeMessage()
  {
-       if (self.motd_actived_time == 0) { // is there already a message showing?
+       if(self.motd_actived_time == 0)
+       {
                if (autocvar_g_campaign) {
 -                      if ((self.classname == "player" && self.BUTTON_INFO) || (self.classname != "player")) {
 +                      if ((IS_PLAYER(self) && self.BUTTON_INFO) || (!IS_PLAYER(self))) {
                                self.motd_actived_time = time;
-                               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, campaign_message, -1, 0);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, campaign_message);
                        }
                } else {
-                       if ((time - self.jointime > autocvar_welcome_message_time) && self.BUTTON_INFO) {
+                       if (self.BUTTON_INFO) {
                                self.motd_actived_time = time;
-                               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), -1, 0);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
                        }
                }
-       } else { // showing MOTD or campaign message
+       }
+       else if(self.motd_actived_time > 0) // showing MOTD or campaign message
+       {
                if (autocvar_g_campaign) {
                        if (self.BUTTON_INFO)
                                self.motd_actived_time = time;
 -                      else if ((time - self.motd_actived_time > 2) && self.classname == "player") { // hide it some seconds after BUTTON_INFO has been released
 +                      else if ((time - self.motd_actived_time > 2) && IS_PLAYER(self)) { // hide it some seconds after BUTTON_INFO has been released
                                self.motd_actived_time = 0;
-                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD);
+                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                        }
                } else {
-                       if ((time - self.jointime) > autocvar_welcome_message_time) {
-                               if (self.BUTTON_INFO)
-                                       self.motd_actived_time = time;
-                               else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
-                                       self.motd_actived_time = 0;
-                                       Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD);
-                               }
+                       if (self.BUTTON_INFO)
+                               self.motd_actived_time = time;
+                       else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
+                               self.motd_actived_time = 0;
+                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                        }
                }
        }
+       else //if(self.motd_actived_time < 0) // just connected, motd is active
+       {
+               if(self.BUTTON_INFO) // BUTTON_INFO hides initial MOTD
+                       self.motd_actived_time = -2; // wait until BUTTON_INFO gets released
+               else if(self.motd_actived_time == -2 || IS_PLAYER(self) || time - self.jointime > autocvar_welcome_message_time)
+               {
+                       // instanctly hide MOTD
+                       self.motd_actived_time = 0;
+                       Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
+               }
+       }
  }
  
  void ObserverThink()
                        }
                }
        }
-       PrintWelcomeMessage();
  }
  
  void SpectatorThink()
                        PutObserverInServer();
        }
  
-       PrintWelcomeMessage();
        self.flags |= FL_CLIENT | FL_NOTARGET;
  }
  
  void PlayerUseKey()
  {
 -      if(self.classname != "player")
 +      if not(IS_PLAYER(self))
                return;
  
        if(self.vehicle)
        MUTATOR_CALLHOOK(PlayerUseKey);
  }
  
- .float touchexplode_time;
  /*
  =============
  PlayerPreThink
@@@ -2554,14 -2439,10 +2440,10 @@@ void PlayerPreThink (void
        WarpZone_PlayerPhysics_FixVAngle();
  
        self.stat_game_starttime = game_starttime;
+       self.stat_round_starttime = round_starttime;
        self.stat_allow_oldnexbeam = autocvar_g_allow_oldnexbeam;
        self.stat_leadlimit = autocvar_leadlimit;
  
-       if(g_arena || (g_ca && !allowed_to_spawn))
-               self.stat_respawn_time = 0;
-       else
-               self.stat_respawn_time = self.respawn_time;
        if(frametime)
        {
                // physics frames: update anticheat stuff
                                        {
                                                // notify release users if connecting to git
                                                dprint("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
-                                               sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"));
+                                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, self.cvar_g_xonoticversion);
                                        }
                                        else
                                        {
                                                {
                                                        // give users new version
                                                        dprint("^1NOTE^7 to ", self.netname, "^7 - ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n");
-                                                       sprint(self, strcat("\{1}^1NOTE: ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n"));
+                                                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, self.cvar_g_xonoticversion);
                                                }
                                                else if(r > 0)
                                                {
                                                        // notify users about old server version
                                                        print("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
-                                                       sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"));
+                                                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, self.cvar_g_xonoticversion);
                                                }
                                        }
                                }
        // GOD MODE info
        if(!(self.flags & FL_GODMODE)) if(self.max_armorvalue)
        {
-               sprint(self, strcat("godmode saved you ", ftos(self.max_armorvalue), " units of damage, cheater!\n"));
+               Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_GODMODE_OFF, self.max_armorvalue);
                self.max_armorvalue = 0;
        }
  
                self.usekeypressed = self.BUTTON_USE;
        }
  
-       PrintWelcomeMessage();
 -      if(clienttype(self) == CLIENTTYPE_REAL)
++      if(IS_REAL_CLIENT(self))
+               PrintWelcomeMessage();
  
-       if(IS_PLAYER(self)) {
- //            if(self.netname == "Wazat")
- //                    bprint(self.classname, "\n");
 -      if(self.classname == "player") {
++      if(IS_PLAYER(self))
++      {
  
                CheckRules_Player();
  
  
                if (self.deadflag != DEAD_NO)
                {
-                       float button_pressed, force_respawn;
                        if(self.personal && g_race_qualifying)
                        {
                                if(time > self.respawn_time)
                                {
                                        self.respawn_time = time + 1; // only retry once a second
+                                       self.stat_respawn_time = self.respawn_time;
                                        respawn();
                                        self.impulse = 141;
                                }
                        }
                        else
                        {
+                               float button_pressed;
                                if(frametime)
                                        player_anim();
                                button_pressed = (self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_HOOK || self.BUTTON_USE);
-                               force_respawn = (g_lms || g_ca || g_cts || autocvar_g_forced_respawn);
                                if (self.deadflag == DEAD_DYING)
                                {
-                                       if(force_respawn)
+                                       if(self.respawn_flags & RESPAWN_FORCE)
                                                self.deadflag = DEAD_RESPAWNING;
                                        else if(!button_pressed)
                                                self.deadflag = DEAD_DEAD;
                                                respawn();
                                        }
                                }
                                ShowRespawnCountdown();
+                               if(self.respawn_flags & RESPAWN_SILENT)
+                                       self.stat_respawn_time = 0;
+                               else
+                                       self.stat_respawn_time = self.respawn_time;
                        }
  
                        // if respawning, invert stat_respawn_time to indicate this, the client translates it
  
                        return;
                }
-               // FIXME from now on self.deadflag is always 0 (and self.health is never < 1)
-               // so (self.deadflag == DEAD_NO) is always true in the code below
-               if(g_touchexplode)
-               if(time > self.touchexplode_time)
-               if(IS_PLAYER(self))
-               if(self.deadflag == DEAD_NO)
-               if not(IS_INDEPENDENT_PLAYER(self))
-               FOR_EACH_PLAYER(other) if(self != other)
-               {
-                       if(time > other.touchexplode_time)
-                       if(other.deadflag == DEAD_NO)
-                       if not(IS_INDEPENDENT_PLAYER(other))
-                       if(boxesoverlap(self.absmin, self.absmax, other.absmin, other.absmax))
-                       {
-                               PlayerTouchExplode(self, other);
-                               self.touchexplode_time = other.touchexplode_time = time + 0.2;
-                       }
-               }
  
                if(g_lms && !self.deadflag && autocvar_g_lms_campcheck_interval)
                {
                                //sprint(self, "distance: ", ftos(self.lms_traveled_distance), "\n");
                                if(self.lms_traveled_distance < autocvar_g_lms_campcheck_distance)
                                {
-                                       centerprint(self, autocvar_g_lms_campcheck_message);
+                                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_CAMPCHECK);
                                        // FIXME KadaverJack: gibbing player here causes playermodel to bounce around, instead of eye.md3
                                        // I wasn't able to find out WHY that happens, so I put a workaround in place that shall prevent players from being gibbed :(
-                                       Damage(self, self, self, bound(0, autocvar_g_lms_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP, self.origin, '0 0 0');
+                                       if(self.vehicle)
+                                               Damage(self.vehicle, self, self, autocvar_g_lms_campcheck_damage * 2, DEATH_CAMP, self.vehicle.origin, '0 0 0');
+                                       else
+                                               Damage(self, self, self, bound(0, autocvar_g_lms_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP, self.origin, '0 0 0');
                                }
                                self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval;
                                self.lms_traveled_distance = 0;
                if (intermission_running)
                        IntermissionThink ();   // otherwise a button could be missed between
                return;
 -      } else if(self.classname == "observer") {
 +      } else if(IS_OBSERVER(self)) {
                ObserverThink();
 -      } else if(self.classname == "spectator") {
 +      } else if(IS_SPEC(self)) {
                SpectatorThink();
        }
  
  
        float oldspectatee_status;
        oldspectatee_status = self.spectatee_status;
 -      if(self.classname == "spectator")
 +      if(IS_SPEC(self))
                self.spectatee_status = num_for_edict(self.enemy);
 -      else if(self.classname == "observer")
 +      else if(IS_OBSERVER(self))
                self.spectatee_status = num_for_edict(self);
        else
                self.spectatee_status = 0;
@@@ -2976,11 -2847,7 +2849,7 @@@ void PlayerPostThink (void
        {
                if (time - self.parm_idlesince < 1) // instead of (time == self.parm_idlesince) to support sv_maxidle <= 10
                {
-                       if(self.idlekick_lasttimeleft)
-                       {
-                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_DISCONNECT_IDLING);
-                               self.idlekick_lasttimeleft = 0;
-                       }
+                       if(self.idlekick_lasttimeleft) { self.idlekick_lasttimeleft = 0; }
                }
                else
                {
                        if(timeleft == min(10, sv_maxidle - 1)) // - 1 to support sv_maxidle <= 10
                        {
                                if(!self.idlekick_lasttimeleft)
-                                       Send_CSQC_Centerprint_Generic(self, CPID_DISCONNECT_IDLING, "^3Stop idling!\n^3Disconnecting in %d seconds...", 1, timeleft);
+                                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_DISCONNECT_IDLING, timeleft);
                        }
                        if(timeleft <= 0)
                        {
-                               bprint("^3", self.netname, "^3 was kicked for idling.\n");
-                               AnnounceTo(self, "terminated");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_KICK_IDLING, self.netname);
                                dropclient(self);
                                return;
                        }
                        else if(timeleft <= 10)
                        {
                                if(timeleft != self.idlekick_lasttimeleft)
-                                       AnnounceTo(self, ftos(timeleft));
+                                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, Announcer_PickNumber(timeleft));
                                self.idlekick_lasttimeleft = timeleft;
                        }
                }
  
        //CheckPlayerJump();
  
 -      if(self.classname == "player") {
 +      if(IS_PLAYER(self)) {
                CheckRules_Player();
                UpdateChatBubble();
                if (self.impulse)
index b1497846b5128477623b4e0604927fde57c0c09e,a929e368c184f3f1a0ea6431318ac5a96c772de8..ea0ba7f8c2fd1b43e829f686474f6dbbee5b8977
@@@ -358,7 -358,7 +358,7 @@@ void RaceCarPhysics(
                rigvel_z -= frametime * autocvar_sv_gravity; // 4x gravity plays better
                rigvel_xy = vec2(rigvel);
  
-               if(g_bugrigs_planar_movement_car_jumping && !g_touchexplode) // touchexplode is a better way to handle collisions
+               if(g_bugrigs_planar_movement_car_jumping)
                        mt = MOVE_NORMAL;
                else
                        mt = MOVE_NOMONSTERS;
@@@ -712,20 -712,6 +712,6 @@@ void SV_PlayerPhysics(
                else if(g_keepaway)
                        maxspd_mod *= autocvar_g_keepaway_ballcarrier_highspeed;
  
-       if(g_runematch)
-       {
-               if(self.runes & RUNE_SPEED)
-               {
-                       if(self.runes & CURSE_SLOW)
-                               maxspd_mod *= autocvar_g_balance_rune_speed_combo_highspeed;
-                       else
-                               maxspd_mod *= autocvar_g_balance_rune_speed_highspeed;
-               }
-               else if(self.runes & CURSE_SLOW)
-               {
-                       maxspd_mod *= autocvar_g_balance_curse_slow_highspeed;
-               }
-       }
        maxspd_mod *= autocvar_g_movement_highspeed;
  
        // fix physics stats for g_movement_highspeed
                        self.punchvector = '0 0 0';
        }
  
 -      if (clienttype(self) == CLIENTTYPE_BOT)
 +      if (IS_BOT_CLIENT(self))
        {
                if(playerdemo_read())
                        return;
        
        self.items &~= IT_USING_JETPACK;
  
 -      if(self.classname == "player")
 +      if(IS_PLAYER(self))
        {
                if(self.race_penalty)
                        if(time > self.race_penalty)
        if(self.conveyor.state)
                self.velocity -= self.conveyor.movedir;
  
 -      if(self.classname != "player")
 +      if not(IS_PLAYER(self))
        {
                maxspd_mod = autocvar_sv_spectator_speed_multiplier;
                if(!self.spectatorspeed)
        }
  
        if(self.flags & FL_ONGROUND)
 -      if(self.classname == "player") // no fall sounds for observers thank you very much
 +      if(IS_PLAYER(self)) // no fall sounds for observers thank you very much
        if(self.wasFlying)
        {
                self.wasFlying = 0;
        if(IsFlying(self))
                self.wasFlying = 1;
  
 -      if(self.classname == "player")
 +      if(IS_PLAYER(self))
                CheckPlayerJump();
  
        if (self.flags & FL_WATERJUMP )
                        self.teleport_time = 0;
                }
        }
 -      else if (g_bugrigs && self.classname == "player")
 +      else if (g_bugrigs && IS_PLAYER(self))
        {
                RaceCarPhysics();
        }
                }
        }
  
 -      if((g_cts || g_race) && self.classname != "observer") {
 +      if((g_cts || g_race) && !IS_OBSERVER(self)) {
                if(vlen(self.velocity - self.velocity_z * '0 0 1') > speedaward_speed) {
                        speedaward_speed = vlen(self.velocity - self.velocity_z * '0 0 1');
                        speedaward_holder = self.netname;
index 3014b03cb3d171e05eaa4d0952a1c4d7adb5ec9f,95aeced31b308b5db10fa4ab9da332baab5151aa..aa6258468b05a78ab157949a3cd0049c96422ba4
@@@ -338,7 -338,6 +338,6 @@@ void PlayerCorpseDamage (entity inflict
  }
  
  void ClientKill_Now_TeamChange();
- void freezetag_CheckWinner();
  
  void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
  {
        float valid_damage_for_weaponstats;
        float excess;
  
-       if((g_arena && numspawned < 2) || (g_ca && allowed_to_spawn) && !inWarmupStage)
-               return;
        dh = max(self.health, 0);
        da = max(self.armorvalue, 0);
  
                //self.pushltime = 0;
                self.istypefrag = 0;
        }
 -      else if(attacker.classname == "player")
 +      else if(IS_PLAYER(attacker))
        {
                self.pusher = attacker;
                self.pushltime = time + autocvar_g_maxpushtime;
                        {
                                self.pain_finished = time + 0.5;        //Supajoe
  
-                               if(sv_gentle < 1) {
+                               if(autocvar_sv_gentle < 1) {
                                        if(self.classname != "body") // pain anim is BORKED on our ZYMs, FIXME remove this once we have good models
                                        {
                                                if (!self.animstate_override)
        self.dmg_take = self.dmg_take + take;//max(take - 10, 0);
        self.dmg_inflictor = inflictor;
  
 -      if(g_ca && self != attacker && attacker.classname == "player")
 +      if(g_ca && self != attacker && IS_PLAYER(attacker))
                PlayerScore_Add(attacker, SP_SCORE, (damage - excess) * autocvar_g_ca_damage2score_multiplier);
  
        float abot, vbot, awep;
 -      abot = (clienttype(attacker) == CLIENTTYPE_BOT);
 -      vbot = (clienttype(self) == CLIENTTYPE_BOT);
 +      abot = (IS_BOT_CLIENT(attacker));
 +      vbot = (IS_BOT_CLIENT(self));
  
        valid_damage_for_weaponstats = 0;
        awep = 0;
  
 -      if(vbot || clienttype(self) == CLIENTTYPE_REAL)
 -      if(abot || clienttype(attacker) == CLIENTTYPE_REAL)
 +      if(vbot || IS_REAL_CLIENT(self))
 +      if(abot || IS_REAL_CLIENT(attacker))
        if(attacker && self != attacker)
        if(IsDifferentTeam(self, attacker))
        {
                if(valid_damage_for_weaponstats)
                        WeaponStats_LogKill(awep, abot, self.weapon, vbot);
  
-               if(sv_gentle < 1) // TODO make a "gentle" version?
+               if(autocvar_sv_gentle < 1) // TODO make a "gentle" version?
                if(sound_allowed(MSG_BROADCAST, attacker))
                {
                        if(deathtype == DEATH_DROWN)
                        }
                }
  
-               if(!g_freezetag)
-               {
-                       // become fully visible
-                       self.alpha = default_player_alpha;
-                       // throw a weapon
-                       SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
-               }
                // print an obituary message
                Obituary (attacker, inflictor, self, deathtype);
                race_PreDie();
-               DropAllRunes(self);
  
          // increment frag counter for used weapon type
          float w;
        if(accuracy_isgooddamage(attacker, self))
          attacker.accuracy.(accuracy_frags[w-1]) += 1;
  
-               if(deathtype == DEATH_HURTTRIGGER && g_freezetag)
-               {
-                       PutClientInServer();
-                       count_alive_players(); // re-count players
-                       freezetag_CheckWinner();
-                       return;
-               }
                frag_attacker = attacker;
                frag_inflictor = inflictor;
                frag_target = self;
+               frag_deathtype = deathtype;
                MUTATOR_CALLHOOK(PlayerDies);
                weapon_action(self.weapon, WR_PLAYERDEATH);
  
                RemoveGrapplingHook(self);
  
                Portal_ClearAllLater(self);
  
 -              if(clienttype(self) == CLIENTTYPE_REAL)
 +              if(IS_REAL_CLIENT(self))
                {
-                       stuffcmd(self, "-zoom\n");
                        self.fixangle = TRUE;
                        //msg_entity = self;
                        //WriteByte (MSG_ONE, SVC_SETANGLE);
                        //WriteAngle (MSG_ONE, 80);
                }
  
-               if(defer_ClientKill_Now_TeamChange) // TODO does this work with FreezeTag?
-                       ClientKill_Now_TeamChange();
-               if(g_arena)
-                       Spawnqueue_Unmark(self);
+               if(defer_ClientKill_Now_TeamChange)
+                       ClientKill_Now_TeamChange(); // can turn player into spectator
  
-               if(g_freezetag)
+               // player could have been miraculously resuscitated ;)
+               // e.g. players in freezetag get frozen, they don't really die
 -              if(self.health >= 1 || self.classname != "player")
++              if(self.health >= 1 || !IS_PLAYER(self))
                        return;
  
                // when we get here, player actually dies
-               // clear waypoints (do this AFTER FreezeTag)
+               // clear waypoints
                WaypointSprite_PlayerDead();
+               // throw a weapon
+               SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
  
+               // become fully visible
+               self.alpha = default_player_alpha;
                // make the corpse upright (not tilted)
                self.angles_x = 0;
                self.angles_z = 0;
                        self.respawn_countdown = 10; // first number to count down from is 10
                else
                        self.respawn_countdown = -1; // do not count down
+               if(g_lms || g_cts || autocvar_g_forced_respawn)
+                       self.respawn_flags = self.respawn_flags | RESPAWN_FORCE;
                self.death_time = time;
                if (random() < 0.5)
                        animdecide_setstate(self, self.anim_state | ANIMSTATE_DEAD1, TRUE);
                // set up to fade out later
                SUB_SetFade (self, time + 6 + random (), 1);
  
-               if(sv_gentle > 0 || autocvar_ekg) {
+               if(autocvar_sv_gentle > 0 || autocvar_ekg) {
                        // remove corpse
                        PlayerCorpseDamage (inflictor, attacker, autocvar_sv_gibhealth+1.0, deathtype, hitloc, force);
                }
@@@ -731,7 -719,7 +719,7 @@@ float Say(entity source, float teamsay
  
        msgin = formatmessage(msgin);
  
 -      if(source.classname != "player")
 +      if not(IS_PLAYER(source))
                colorstr = "^0"; // black for spectators
        else if(teamplay)
                colorstr = Team_ColorCode(source.team);
        }
  
        if(!privatesay)
 -      if(source.classname != "player")
 +      if not(IS_PLAYER(source))
        {
                if not(intermission_running)
                        if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !(inWarmupStage || gameover)))
                        if(sourcecmsgstr != "" && !privatesay)
                                centerprint(source, sourcecmsgstr);
                }
-               else if(privatesay) // private message, between 2 people only, not sent to server console
+               else if(privatesay) // private message, between 2 people only
                {
                        sprint(source, sourcemsgstr);
                        sprint(privatesay, msgstr);
+                       if not(autocvar_g_chat_tellprivacy) { dedicated_print(msgstr); } // send to server console too if "tellprivacy" is disabled
                        if(cmsgstr != "")
                                centerprint(privatesay, cmsgstr);
                }
                else if(teamsay > 0) // team message, only sent to team mates
                {
                        sprint(source, sourcemsgstr);
-                       //print(msgstr); // send to server console too
+                       dedicated_print(msgstr); // send to server console too
                        if(sourcecmsgstr != "")
                                centerprint(source, sourcecmsgstr);
                        FOR_EACH_REALPLAYER(head) if(head.team == source.team)
                else if(teamsay < 0) // spectator message, only sent to spectators
                {
                        sprint(source, sourcemsgstr);
-                       //print(msgstr); // send to server console too
+                       dedicated_print(msgstr); // send to server console too
 -                      FOR_EACH_REALCLIENT(head) if(head.classname != "player")
 +                      FOR_EACH_REALCLIENT(head) if not(IS_PLAYER(head))
                                if(head != source)
                                        sprint(head, msgstr);
                }
                else if(sourcemsgstr != msgstr) // trimmed/server fixed message, sent to all players
                {
                        sprint(source, sourcemsgstr);
-                       //print(msgstr); // send to server console too
+                       dedicated_print(msgstr); // send to server console too
                        FOR_EACH_REALCLIENT(head)
                                if(head != source)
                                        sprint(head, msgstr);
@@@ -1131,7 -1120,7 +1120,7 @@@ void FakeGlobalSound(string sample, flo
                        if(self.pusher)
                        {
                                msg_entity = self;
 -                              if(clienttype(msg_entity) == CLIENTTYPE_REAL)
 +                              if(IS_REAL_CLIENT(msg_entity))
                                        soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTN_NONE);
                        }
                        break;
                                break;
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        tauntrand = random();
                        msg_entity = self;
                        }
                        break;
                case VOICETYPE_TAUNT:
 -                      if(self.classname == "player")
 +                      if(IS_PLAYER(self))
                                if(self.deadflag == DEAD_NO)
                                        animdecide_setaction(self, ANIMACTION_TAUNT, TRUE);
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        msg_entity = self;
                        if (msg_entity.cvar_cl_voice_directional >= 1)
@@@ -1204,7 -1193,7 +1193,7 @@@ void GlobalSound(string sample, float c
                        if(self.pusher)
                        {
                                msg_entity = self.pusher;
 -                              if(clienttype(msg_entity) == CLIENTTYPE_REAL)
 +                              if(IS_REAL_CLIENT(msg_entity))
                                {
                                        if(msg_entity.cvar_cl_voice_directional == 1)
                                                soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_MIN);
                        if(self.pusher)
                        {
                                msg_entity = self.pusher;
 -                              if(clienttype(msg_entity) == CLIENTTYPE_REAL)
 +                              if(IS_REAL_CLIENT(msg_entity))
                                {
                                        if(msg_entity.cvar_cl_voice_directional == 1)
                                                soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_MIN);
                                                soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE);
                                }
                                msg_entity = self;
 -                              if(clienttype(msg_entity) == CLIENTTYPE_REAL)
 +                              if(IS_REAL_CLIENT(msg_entity))
                                        soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTN_NONE);
                        }
                        break;
                                break;
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        tauntrand = random();
                        FOR_EACH_REALCLIENT(msg_entity)
                                }
                        break;
                case VOICETYPE_TAUNT:
 -                      if(self.classname == "player")
 +                      if(IS_PLAYER(self))
                                if(self.deadflag == DEAD_NO)
                                        animdecide_setaction(self, ANIMACTION_TAUNT, TRUE);
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        FOR_EACH_REALCLIENT(msg_entity)
                        {
@@@ -1310,14 -1299,8 +1299,8 @@@ void VoiceMessage(string type, string m
                FakeGlobalSound(self.sample, CH_VOICE, voicetype);
  }
  
- void MoveToTeam(entity client, float team_colour, float type, float show_message)
+ void MoveToTeam(entity client, float team_colour, float type)
  {
- //    show_message
- //    0 (00) automove centerprint, admin message
- //    1 (01) automove centerprint, no admin message
- //    2 (10) no centerprint, admin message
- //    3 (11) no centerprint, no admin message
        float lockteams_backup;
  
        lockteams_backup = lockteams;  // backup any team lock
  
        TeamchangeFrags(client);  // move the players frags
        SetPlayerColors(client, team_colour - 1);  // set the players colour
-       Damage(client, client, client, 100000, ((show_message & 2) ? DEATH_QUIET : DEATH_AUTOTEAMCHANGE), client.origin, '0 0 0');  // kill the player
+       Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE, client.origin, '0 0 0');  // kill the player
  
        lockteams = lockteams_backup;  // restore the team lock
  
        LogTeamchange(client.playerid, client.team, type);
-       if not(show_message & 1) // admin message
-               sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: You have been moved to the ", Team_ColorNameLowerCase(team_colour), " team\n"));  // send a chat message
-       bprint(strcat(client.netname, " joined the ", ColoredTeamName(client.team), "\n"));
  }
index 8d83c975e944009a90a250db74c6a8e8c03879ba,afabe1820284522acf4d4dc0211d610d277de559..405904565e187a02dfc5552a2e6f5a3adce1783f
@@@ -14,21 -14,6 +14,6 @@@ float W_WeaponRateFactor(
        float t;
        t = 1.0 / g_weaponratefactor;
  
-       if(g_runematch)
-       {
-               if(self.runes & RUNE_SPEED)
-               {
-                       if(self.runes & CURSE_SLOW)
-                               t = t * autocvar_g_balance_rune_speed_combo_atkrate;
-                       else
-                               t = t * autocvar_g_balance_rune_speed_atkrate;
-               }
-               else if(self.runes & CURSE_SLOW)
-               {
-                       t = t * autocvar_g_balance_curse_slow_atkrate;
-               }
-       }
        return t;
  }
  
@@@ -108,12 -93,12 +93,12 @@@ void W_HitPlotAnalysis(entity player, v
                lag = ANTILAG_LATENCY(player);
                if(lag < 0.001)
                        lag = 0;
 -              if(clienttype(player) != CLIENTTYPE_REAL)
 +              if not(IS_REAL_CLIENT(player))
                        lag = 0; // only antilag for clients
  
                org = player.origin + player.view_ofs;
                traceline_antilag_force(player, org, org + screenforward * MAX_SHOT_DISTANCE, MOVE_NORMAL, player, lag);
 -              if(trace_ent.flags & FL_CLIENT)
 +              if(IS_CLIENT(trace_ent))
                {
                        antilag_takeback(trace_ent, time - lag);
                        hitplot = W_HitPlotNormalizedUntransform(org, trace_ent, screenforward, screenright, screenup, trace_endpos);
@@@ -213,7 -198,7 +198,7 @@@ void W_SetupShot_Dir_ProjectileSize_Ran
                        if (!trace_ent.takedamage)
                        {
                                traceline_antilag_force (ent, w_shotorg, w_shotorg + w_shotdir * range, MOVE_NORMAL, ent, ANTILAG_LATENCY(ent));
 -                              if (trace_ent.takedamage && trace_ent.classname == "player")
 +                              if (trace_ent.takedamage && IS_PLAYER(trace_ent))
                                {
                                        entity e;
                                        e = trace_ent;
                        if (ent.cursor_trace_ent)                 // client was aiming at someone
                        if (ent.cursor_trace_ent != ent)         // just to make sure
                        if (ent.cursor_trace_ent.takedamage)      // and that person is killable
 -                      if (ent.cursor_trace_ent.classname == "player") // and actually a player
 +                      if (IS_PLAYER(ent.cursor_trace_ent)) // and actually a player
                        {
                                // verify that the shot would miss without antilag
                                // (avoids an issue where guns would always shoot at their origin)
  float CL_Weaponentity_CustomizeEntityForClient()
  {
        self.viewmodelforclient = self.owner;
 -      if(other.classname == "spectator")
 +      if(IS_SPEC(other))
                if(other.enemy == self.owner)
                        self.viewmodelforclient = other;
        return TRUE;
@@@ -711,10 -696,9 +696,9 @@@ float client_hasweapon(entity cl, floa
                        if (!f)
                        {
                                if (complain)
 -                              if(clienttype(cl) == CLIENTTYPE_REAL)
 +                              if(IS_REAL_CLIENT(cl))
                                {
                                        play2(cl, "weapons/unavailable.wav");
-                                       sprint(cl, strcat("You don't have any ammo for the ^2", W_Name(wpn), "\n"));
                                        Send_WeaponComplain (cl, wpn, W_Name(wpn), 0);
                                }
                                return FALSE;
                // Report Proper Weapon Status / Modified Weapon Ownership Message
                if (WEPSET_CONTAINS_AW(weaponsInMap, wpn))
                {
-                       sprint(cl, strcat("You do not have the ^2", W_Name(wpn), "\n") );
-                       Send_WeaponComplain (cl, wpn, W_Name(wpn), 1);
+                       Send_WeaponComplain(cl, wpn, W_Name(wpn), 1);
  
                        if(autocvar_g_showweaponspawns)
                        {
                else
                {
                        Send_WeaponComplain (cl, wpn, W_Name(wpn), 2);
-                       sprint(cl, strcat("The ^2", W_Name(wpn), "^7 is ^1NOT AVAILABLE^7 in this map\n") );
                }
  
                play2(cl, "weapons/unavailable.wav");
@@@ -823,14 -805,6 +805,6 @@@ void W_SwitchToOtherWeapon(entity pl
                W_SwitchWeapon_Force(pl, ww);
  }
  
- string PrimaryOrSecondary(float secondary)
- {
-       if(secondary)
-               return "secondary";
-       else
-               return "primary";
- }
  .float prevdryfire;
  .float prevwarntime;
  float weapon_prepareattack_checkammo(float secondary)
                {
                        if(time - self.prevwarntime > 1)
                        {
-                               sprint(self, strcat("^2", W_Name(self.weapon), " ", PrimaryOrSecondary(secondary), "^7 is unable to fire, but its ^2", PrimaryOrSecondary(1 - secondary), "^7 can.\n"));
+                               Send_Notification(
+                                       NOTIF_ONE,
+                                       self,
+                                       MSG_MULTI,
+                                       ITEM_WEAPON_PRIMORSEC,
+                                       self.weapon,
+                                       secondary,
+                                       (1 - secondary)
+                               );
                        }
                        self.prevwarntime = time;
                }
@@@ -1371,7 -1353,7 +1353,7 @@@ void W_Reload(float sent_ammo_min, floa
        if(!self.(self.current_ammo) && self.reload_ammo_min)
        if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
        {
 -              if(clienttype(self) == CLIENTTYPE_REAL && self.reload_complain < time)
 +              if(IS_REAL_CLIENT(self) && self.reload_complain < time)
                {
                        play2(self, "weapons/unavailable.wav");
                        sprint(self, strcat("You don't have enough ammo to reload the ^2", W_Name(self.weapon), "\n"));
index c7fcdeacb8bc1914c7d4094e624cb37c62de0fce,e22399f4acd14ed8b42b8901d1dc2f9c056050e2..ec9c33b1987b093005f28c5df16c062d3d9e9c65
@@@ -81,7 -81,7 +81,7 @@@ void ClientCommand_clientversion(float 
                {
                        if(argv(1) != "")
                        {
 -                              if(self.flags & FL_CLIENT)
 +                              if(IS_CLIENT(self))
                                {
                                        self.version = ((argv(1) == "$gameversion") ? 1 : stof(argv(1)));
                                        
@@@ -148,24 -148,24 +148,24 @@@ void ClientCommand_join(float request
        {
                case CMD_REQUEST_COMMAND:
                {
 -                      if(self.flags & FL_CLIENT)
 +                      if(IS_CLIENT(self))
                        {
 -                              if(self.classname != "player" && !lockteams && !g_arena)
 +                              if(!IS_PLAYER(self) && !lockteams && !g_arena)
                                {
                                        if(nJoinAllowed(self)) 
                                        {
-                                               if(g_ca) { self.caplayer = 1; }
                                                if(autocvar_g_campaign) { campaign_bots_may_start = 1; }
-                                               
                                                self.classname = "player";
                                                PlayerScore_Clear(self);
-                                               bprint ("^4", self.netname, "^4 is playing now\n");
+                                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
+                                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_PLAY, self.netname);
                                                PutClientInServer();
                                        }
                                        else 
                                        {
                                                //player may not join because of g_maxplayers is set
-                                               centerprint(self, PREVENT_JOIN_TEXT);
+                                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT);
                                        }
                                }
                        }
@@@ -188,12 -188,14 +188,14 @@@ void ClientCommand_ready(float request
        {
                case CMD_REQUEST_COMMAND:
                {
 -                      if(self.flags & FL_CLIENT)
 +                      if(IS_CLIENT(self))
                        {
                                if(inWarmupStage || autocvar_sv_ready_restart || g_race_qualifying == 2)
                                {
                                        if(!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
                                        {
+                                               if(time < game_starttime) // game is already restarting
+                                                       return;
                                                if (self.ready) // toggle
                                                {
                                                        self.ready = FALSE;
@@@ -274,7 -276,7 +276,7 @@@ void ClientCommand_selectteam(float req
                {
                        if(argv(1) != "")
                        {
 -                              if(self.flags & FL_CLIENT)
 +                              if(IS_CLIENT(self))
                                {
                                        if(teamplay)
                                                if not(self.team_forced > 0) 
                                                                
                                                                switch(argv(1))
                                                                {
-                                                                       case "red": selection = COLOR_TEAM1; break;
-                                                                       case "blue": selection = COLOR_TEAM2; break;
-                                                                       case "yellow": selection = COLOR_TEAM3; break;
-                                                                       case "pink": selection = COLOR_TEAM4; break;
+                                                                       case "red": selection = NUM_TEAM_1; break;
+                                                                       case "blue": selection = NUM_TEAM_2; break;
+                                                                       case "yellow": selection = NUM_TEAM_3; break;
+                                                                       case "pink": selection = NUM_TEAM_4; break;
                                                                        case "auto": selection = (-1); break;
                                                                        
                                                                        default: selection = 0; break;
@@@ -390,13 -392,15 +392,15 @@@ void ClientCommand_spectate(float reque
        {
                case CMD_REQUEST_COMMAND:
                {
 -                      if(self.flags & FL_CLIENT)
 +                      if(IS_CLIENT(self))
                        {
                                if(g_arena) { return; } 
                                if(g_lms)
                                {
                                        if(self.lms_spectate_warning)
                                        {
+                                               // for the forfeit message...
+                                               self.lms_spectate_warning = 2;
                                                // mark player as spectator
                                                PlayerScore_Add(self, SP_LMS_RANK, 666 - PlayerScore_Add(self, SP_LMS_RANK, 0));
                                        }
                                        }
                                }
                                
 -                              if(self.classname == "player" && autocvar_sv_spectate == 1) 
 +                              if(IS_PLAYER(self) && autocvar_sv_spectate == 1) 
                                        ClientKill_TeamChange(-2); // observe
-                               
                                // in CA, allow a dead player to move to spectators (without that, caplayer!=0 will be moved back to the player list)
                                // note: if arena game mode is ever done properly, this needs to be removed.
-                               if(g_ca && self.caplayer && (IS_SPEC(self) || IS_OBSERVER(self)))
 -                              if(self.caplayer && (self.classname == "spectator" || self.classname == "observer"))
++                              if(self.caplayer && (IS_SPEC(self) || IS_OBSERVER(self)))
                                {
                                        sprint(self, "WARNING: you will spectate in the next round.\n");
                                        self.caplayer = 0;
index 42fba4f0e8c45e9ae24e6c239e10f292d3ffdc8d,132a0af70e31be2fbc97bbc79006ae5b5c1f263c..73bf0df4f7d279bb92709f1203a711c290831edf
@@@ -24,11 -24,11 +24,11 @@@ string GetCallerName(entity caller
  // verify that the client provided is acceptable for use
  float VerifyClientEntity(entity client, float must_be_real, float must_be_bots)
  {
 -      if not(client.flags & FL_CLIENT)
 +      if not(IS_CLIENT(client))
                return CLIENT_DOESNT_EXIST;
 -      else if(must_be_real && (clienttype(client) != CLIENTTYPE_REAL))
 +      else if(must_be_real && !IS_REAL_CLIENT(client))
                return CLIENT_NOT_REAL;
 -      else if(must_be_bots && (clienttype(client) != CLIENTTYPE_BOT))
 +      else if(must_be_bots && !IS_BOT_CLIENT(client))
                return CLIENT_NOT_BOT;
                
        return CLIENT_ACCEPTABLE;
@@@ -162,14 -162,9 +162,9 @@@ void print_to(entity to, string input
  // used by CommonCommand_timeout() and CommonCommand_timein() to handle game pausing and messaging and such.
  void timeout_handler_reset()
  {
-       entity tmp_player;
-       
        timeout_caller = world;
        timeout_time = 0;
        timeout_leadtime = 0;
-       
-       FOR_EACH_REALPLAYER(tmp_player)
-               Send_CSQC_Centerprint_Generic_Expire(tmp_player, CPID_TIMEOUT_COUNTDOWN);
                                
        remove(self);
  }
@@@ -184,11 -179,10 +179,10 @@@ void timeout_handler_think(
                {
                        if(timeout_time > 0) // countdown is still going
                        {
-                               FOR_EACH_REALPLAYER(tmp_player)
-                                       Send_CSQC_Centerprint_Generic(tmp_player, CPID_TIMEOUT_COUNTDOWN, "Timeout ends in %d seconds!", 1, timeout_time);
+                               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_TIMEOUT_ENDING, timeout_time);
  
                                if(timeout_time == autocvar_sv_timeout_resumetime) // play a warning sound when only <sv_timeout_resumetime> seconds are left
-                                       Announce("prepareforbattle");
+                                       Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_PREPARE);
  
                                self.nextthink = time + TIMEOUT_SLOWMO_VALUE; // think again in one second
                                timeout_time -= 1; // decrease the time counter
                {
                        if(timeout_leadtime > 0) // countdown is still going
                        {
-                               // centerprint the information to every player
-                               FOR_EACH_REALPLAYER(tmp_player) 
-                                       Send_CSQC_Centerprint_Generic(tmp_player, CPID_TIMEOUT_COUNTDOWN, "Timeout begins in %d seconds!", 1, timeout_leadtime);
+                               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_TIMEOUT_BEGINNING, timeout_leadtime);
                                
                                self.nextthink = time + 1; // think again in one second
                                timeout_leadtime -= 1; // decrease the time counter
@@@ -565,7 -557,7 +557,7 @@@ void CommonCommand_timeout(float reques
                                else if(inWarmupStage && !g_warmup_allow_timeout) { print_to(caller, "^7Error: You can not call a timeout in warmup-stage."); }
                                else if(time < game_starttime) { print_to(caller, "^7Error: You can not call a timeout while the map is being restarted."); }
                                else if(caller && (caller.allowed_timeouts < 1)) { print_to(caller, "^7Error: You already used all your timeout calls for this map."); }
 -                              else if(caller && (caller.classname != "player")) { print_to(caller, "^7Error: You must be a player to call a timeout."); }
 +                              else if(caller && !IS_PLAYER(caller)) { print_to(caller, "^7Error: You must be a player to call a timeout."); }
                                else if((autocvar_timelimit) && (last_possible_timeout < time - game_starttime)) { print_to(caller, "^7Error: It is too late to call a timeout now!"); }
                                
                                else // everything should be okay, proceed with starting the timeout
                                        timeout_handler.think = timeout_handler_think;
                                        timeout_handler.nextthink = time; // always let the entity think asap
  
-                                       Announce("timeoutcalled");
+                                       Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_TIMEOUT);
                                }
                        }
                        else { print_to(caller, "^1Timeouts are not allowed to be called, enable them with sv_timeout 1.\n"); }
@@@ -607,7 -599,7 +599,7 @@@ void CommonCommand_who(float request, e
        {
                case CMD_REQUEST_COMMAND:
                {
-                       float total_listed_players, tmp_hours, tmp_minutes, tmp_seconds, is_bot;
+                       float total_listed_players, is_bot;
                        entity tmp_player;
                        
                        float privacy = (caller && autocvar_sv_status_privacy);
                        total_listed_players = 0;
                        FOR_EACH_CLIENT(tmp_player)
                        {
 -                              is_bot = (clienttype(tmp_player) == CLIENTTYPE_BOT);
 +                              is_bot = (IS_BOT_CLIENT(tmp_player));
                                
                                if(is_bot)
                                {
                                        tmp_netaddress = tmp_player.netaddress;
                                        tmp_crypto_idfp = tmp_player.crypto_idfp;
                                }
-                               
-                               tmp_hours = tmp_minutes = tmp_seconds = 0;
-                               
-                               tmp_seconds = floor(time - tmp_player.jointime);
-                               tmp_minutes = floor(tmp_seconds / 60);
-                               tmp_hours = floor(tmp_minutes / 60);
-                               if(tmp_minutes) { tmp_seconds -= (tmp_minutes * 60); }                          
-                               if(tmp_hours) { tmp_minutes -= (tmp_hours * 60); }
  
                                print_to(caller, sprintf(strreplace(" ", separator, " #%-3d %-20.20s %-5d %-3d %-9s %-16s %s "), 
                                        num_for_edict(tmp_player), 
                                        tmp_player.netname,
                                        tmp_player.ping, 
                                        tmp_player.ping_packetloss, 
-                                       sprintf("%02d:%02d:%02d", tmp_hours, tmp_minutes, tmp_seconds),
+                                       process_time(1, time - tmp_player.jointime),
                                        tmp_netaddress,
                                        tmp_crypto_idfp));
                                
index dbc09c0ee3dde52081538de63c6d3f65b321f3a2,0944f04fbbe06799f4f523d37eb243af42bddb92..4c0445f1d33a99c3313dc01eca27b44a7f25dd0f
@@@ -972,7 -972,6 +972,6 @@@ void GameCommand_moveplayer(float reque
                        string targets = strreplace(",", " ", argv(1));
                        string original_targets = strreplace(" ", ", ", targets);
                        string destination = argv(2);
-                       string notify = argv(3);
                        
                        string successful, t;
                        successful = string_null;
                                        // Where are we putting this player?
                                        if(destination == "spec" || destination == "spectator") 
                                        {
 -                                              if(client.classname != "spectator" && client.classname != "observer")
 +                                              if(!IS_SPEC(client) && !IS_OBSERVER(client))
                                                {
                                                        self = client;
                                                        PutObserverInServer();
                                        }
                                        else
                                        {
 -                                              if(client.classname != "spectator" && client.classname != "observer")
 +                                              if(!IS_SPEC(client) && !IS_OBSERVER(client))
                                                {
                                                        if(teamplay)
                                                        {
                                                                // set up
-                                                               float team_color;
+                                                               float team_id;
                                                                float save = client.team_forced;
                                                                client.team_forced = 0;
  
                                                                // find the team to move the player to
-                                                               team_color = ColourToNumber(destination);
-                                                               if(team_color == client.team) // already on the destination team
+                                                               team_id = Team_ColorToTeam(destination);
+                                                               if(team_id == client.team) // already on the destination team
                                                                {
                                                                        // keep the forcing undone
-                                                                       print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") is already on the ", ColoredTeamName(client.team), (targets ? ", skipping to next player.\n" : ".\n"));
+                                                                       print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") is already on the ", Team_ColoredFullName(client.team), (targets ? "^7, skipping to next player.\n" : "^7.\n"));
                                                                        continue;
                                                                } 
-                                                               else if(team_color == 0)  // auto team
+                                                               else if(team_id == 0)  // auto team
                                                                {
-                                                                       team_color = NumberToTeamNumber(FindSmallestTeam(client, FALSE));
+                                                                       team_id = Team_NumberToTeam(FindSmallestTeam(client, FALSE));
                                                                }
                                                                else
                                                                {
                                                                client.team_forced = save;
                                                                
                                                                // Check to see if the destination team is even available
-                                                               switch(team_color
+                                                               switch(team_id
                                                                {
-                                                                       case COLOR_TEAM1: if(c1 == -1) { print("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break;
-                                                                       case COLOR_TEAM2: if(c2 == -1) { print("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break;
-                                                                       case COLOR_TEAM3: if(c3 == -1) { print("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break;
-                                                                       case COLOR_TEAM4: if(c4 == -1) { print("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break;
+                                                                       case NUM_TEAM_1: if(c1 == -1) { print("Sorry, can't move player to red team if it doesn't exist.\n"); return; } break;
+                                                                       case NUM_TEAM_2: if(c2 == -1) { print("Sorry, can't move player to blue team if it doesn't exist.\n"); return; } break;
+                                                                       case NUM_TEAM_3: if(c3 == -1) { print("Sorry, can't move player to yellow team if it doesn't exist.\n"); return; } break;
+                                                                       case NUM_TEAM_4: if(c4 == -1) { print("Sorry, can't move player to pink team if it doesn't exist.\n"); return; } break;
                                                                        
                                                                        default: print("Sorry, can't move player here if team ", destination, " doesn't exist.\n"); return;
                                                                }
                                                                
                                                                // If so, lets continue and finally move the player
                                                                client.team_forced = 0;
-                                                               MoveToTeam(client, team_color, 6, stof(notify));
+                                                               MoveToTeam(client, team_id, 6);
                                                                successful = strcat(successful, (successful ? ", " : ""), client.netname);
-                                                               print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") has been moved to the ", ColoredTeamName(team_color), ".\n");
+                                                               print("Player ", ftos(GetFilteredNumber(t)), " (", client.netname, ") has been moved to the ", Team_ColoredFullName(team_id), "^7.\n");
                                                                continue;
                                                        }
                                                        else
                        print("Incorrect parameters for ^2moveplayer^7\n");
                case CMD_REQUEST_USAGE:
                {
-                       print("\nUsage:^3 sv_cmd moveplayer clients destination [notify]\n");
+                       print("\nUsage:^3 sv_cmd moveplayer clients destination\n");
                        print("  'clients' is a list (separated by commas) of player entity ID's or nicknames\n");
                        print("  'destination' is what to send the player to, be it team or spectating\n");
                        print("  Full list of destinations here: \"spec, spectator, red, blue, yellow, pink, auto.\"\n");
-                       print("  'notify' is whether or not to send messages notifying of the move. Detail below.\n");
-                       print("    0 (00) automove centerprint, admin message; 1 (01) automove centerprint, no admin message\n");
-                       print("    2 (10) no centerprint, admin message; 3 (11) no centerprint, no admin message\n");
                        print("Examples: sv_cmd moveplayer 1,3,5 red 3\n");
                        print("          sv_cmd moveplayer 2 spec \n");
                        print("See also: ^2allspec, shuffleteams^7\n");
@@@ -1109,10 -1105,10 +1105,10 @@@ void GameCommand_nospectators(float req
                        entity plr;
                        FOR_EACH_CLIENT(plr) //give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
                        {
 -                              if(plr.classname == "spectator" || plr.classname == "observer")
 +                              if(IS_SPEC(plr) || IS_OBSERVER(plr))
                                {
                                        plr.spectatortime = time;
-                                       sprint(plr, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
+                                       Send_Notification(NOTIF_ONE_ONLY, plr, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
                                }
                        }
                        bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds!\n"));
@@@ -1354,7 -1350,7 +1350,7 @@@ void GameCommand_shuffleteams(float req
                                        x = (t_players / t_teams);
                                        x = ((i == 1) ? ceil(x) : floor(x));
                                        
-                                       team_color = NumberToTeamNumber(i);
+                                       team_color = Team_NumberToTeam(i);
                                        
                                        // sort through the random list of players made earlier 
                                        for(z = 1; z <= maxclients; ++z)
                                                                self = edict_num(shuffleteams_players[z]);
  
                                                        if(self.team != team_color) 
-                                                               MoveToTeam(self, team_color, 6, 0);
+                                                               MoveToTeam(self, team_color, 6);
  
                                                        shuffleteams_players[z] = 0;
                                                        shuffleteams_teams[i] = shuffleteams_teams[i] + 1;
@@@ -1413,7 -1409,7 +1409,7 @@@ void GameCommand_stuffto(float request
        // This... is a fairly dangerous and powerful command... - It allows any arguments to be sent to a client via rcon.
        // Because of this, it is disabled by default and must be enabled by the server owner when doing compilation. That way,
        // we can be certain they understand the risks of it... So to enable, compile server with -DSTUFFTO_ENABLED argument.
-       
        #ifdef STUFFTO_ENABLED
        #message "stuffto command enabled"
        switch(request)
index cdb3a1290e0b2e5b0c1267daccd0ca4898b713d9,3e564e39ae93f055226d64ad8e3caf5b40e13fe0..337f8260aee8eba31d1ed44001f937228f6a4db1
@@@ -63,7 -63,7 +63,7 @@@ float Nagger_SendEntity(entity to, floa
                for(i = 1; i <= maxclients; i += 8)
                {
                        for(f = 0, e = edict_num(i), b = 1; b < 256; b *= 2, e = nextent(e))
 -                              if(clienttype(e) != CLIENTTYPE_REAL || e.ready)
 +                              if(!IS_REAL_CLIENT(e) || e.ready)
                                        f |= b;
                        WriteByte(MSG_ENTITY, f);
                }
@@@ -148,21 -148,21 +148,21 @@@ void VoteAccept(
        if(vote_caller) { vote_caller.vote_waittime = 0; } // people like your votes, you don't need to wait to vote again
  
        VoteReset();
-       Announce("voteaccept");
+       Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_ACCEPT);
  }
  
  void VoteReject() 
  {
        bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 was rejected\n");
        VoteReset();
-       Announce("votefail");
+       Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_FAIL);
  }
  
  void VoteTimeout() 
  {
        bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2's vote for ", vote_called_display, "^2 timed out\n");
        VoteReset();
-       Announce("votefail");
+       Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_FAIL);
  }
  
  void VoteSpam(float notvoters, float mincount, string result)
@@@ -194,7 -194,7 +194,7 @@@ void VoteCount(float first_count
                                || ((autocvar_sv_vote_nospectators == 1) && (inWarmupStage || gameover))
                                || (autocvar_sv_vote_nospectators == 0));
                                
 -      float vote_player_count = 0, is_player, notvoters = 0;
 +      float vote_player_count = 0, notvoters = 0;
        float vote_real_player_count = 0, vote_real_accept_count = 0;
        float vote_real_reject_count = 0, vote_real_abstain_count = 0;
        float vote_needed_of_voted, final_needed_votes;
        // add up all the votes from each connected client
        FOR_EACH_REALCLIENT(tmp_player)
        {
 -              is_player = (tmp_player.classname == "player");
 -              
                ++vote_player_count;
 -              if(is_player) { ++vote_real_player_count; }
 +              if(IS_PLAYER(tmp_player)) { ++vote_real_player_count; }
                
                switch(tmp_player.vote_selection)
                {
 -                      case VOTE_SELECT_REJECT: { ++vote_reject_count; { if(is_player) ++vote_real_reject_count; } break; }
 -                      case VOTE_SELECT_ACCEPT: { ++vote_accept_count; { if(is_player) ++vote_real_reject_count; } break; }
 -                      case VOTE_SELECT_ABSTAIN: { ++vote_abstain_count; { if(is_player) ++vote_real_abstain_count; } break; }
 +                      case VOTE_SELECT_REJECT: { ++vote_reject_count; { if(IS_PLAYER(tmp_player)) ++vote_real_reject_count; } break; }
 +                      case VOTE_SELECT_ACCEPT: { ++vote_accept_count; { if(IS_PLAYER(tmp_player)) ++vote_real_reject_count; } break; }
 +                      case VOTE_SELECT_ABSTAIN: { ++vote_abstain_count; { if(IS_PLAYER(tmp_player)) ++vote_real_abstain_count; } break; }
                        default: break;
                }
        }
@@@ -317,6 -319,84 +317,84 @@@ void VoteThink(
  //  Game logic for warmup
  // =======================
  
+ // Resets the state of all clients, items, weapons, waypoints, ... of the map.
+ void reset_map(float dorespawn)
+ {
+       entity oldself;
+       oldself = self;
+       if(time <= game_starttime && round_handler_IsActive())
+               round_handler_Reset(game_starttime);
+       if(g_race || g_cts)
+               race_ReadyRestart();
+       else MUTATOR_CALLHOOK(reset_map_global);
+       lms_lowest_lives = 999;
+       lms_next_place = player_count;
+       for(self = world; (self = nextent(self)); )
+       if(clienttype(self) == CLIENTTYPE_NOTACLIENT)
+       {
+               if(self.reset)
+               {
+                       self.reset();
+                       continue;
+               }
+               if(self.team_saved)
+                       self.team = self.team_saved;
+               if(self.flags & FL_PROJECTILE) // remove any projectiles left
+                       remove(self);
+       }
+       // Waypoints and assault start come LAST
+       for(self = world; (self = nextent(self)); )
+       if(clienttype(self) == CLIENTTYPE_NOTACLIENT)
+       {
+               if(self.reset2)
+               {
+                       self.reset2();
+                       continue;
+               }
+       }
+       // Moving the player reset code here since the player-reset depends
+       // on spawnpoint entities which have to be reset first --blub
+       if(dorespawn)
+       if(!MUTATOR_CALLHOOK(reset_map_players))
+       FOR_EACH_CLIENT(self) // reset all players
+       {
+               /*
+               only reset players if a restart countdown is active
+               this can either be due to cvar sv_ready_restart_after_countdown having set
+               restart_mapalreadyrestarted to 1 after the countdown ended or when
+               sv_ready_restart_after_countdown is not used and countdown is still running
+               */
+               if (restart_mapalreadyrestarted || (time < game_starttime))
+               {
+                       //NEW: changed behaviour so that it prevents that previous spectators/observers suddenly spawn as players
+                       if (IS_PLAYER(self)) {
+                               //PlayerScore_Clear(self);
+                               if(g_lms)
+                                       PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives());
+                               self.killcount = 0;
+                               //stop the player from moving so that he stands still once he gets respawned
+                               self.velocity = '0 0 0';
+                               self.avelocity = '0 0 0';
+                               self.movement = '0 0 0';
+                               PutClientInServer();
+                       }
+               }
+       }
+       if(g_keyhunt)
+               kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round + (game_starttime - time), kh_StartRound);
+       self = oldself;
+ }
  // Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set)
  void ReadyRestart_think() 
  {
@@@ -343,13 -423,13 +421,13 @@@ void ReadyRestart_force(
        checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;
  
        readyrestart_happened = 1;
-       game_starttime = time;
-       if(!g_ca && !g_arena) { game_starttime += RESTART_COUNTDOWN; }
+       game_starttime = time + RESTART_COUNTDOWN;
  
-       // clear alivetime
+       // clear player attributes
        FOR_EACH_CLIENT(tmp_player)
        {
                tmp_player.alivetime = 0;
+               tmp_player.killcount = 0;
                PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, -PlayerStats_Event(tmp_player, PLAYERSTATS_ALIVETIME, 0));
        }
  
        inWarmupStage = 0; // once the game is restarted the game is in match stage
  
        // reset the .ready status of all players (also spectators)
-       FOR_EACH_CLIENTSLOT(tmp_player) { tmp_player.ready = 0; }
+       FOR_EACH_REALCLIENT(tmp_player) { tmp_player.ready = 0; }
        readycount = 0;
        Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
  
        // lock teams with lockonrestart
-       if(autocvar_teamplay_lockonrestart && teamplay) 
+       if(autocvar_teamplay_lockonrestart && teamplay)
        {
                lockteams = 1;
                bprint("^1The teams are now locked.\n");
        }
  
        //initiate the restart-countdown-announcer entity
-       if(autocvar_sv_ready_restart_after_countdown && !g_ca && !g_arena)
+       if(autocvar_sv_ready_restart_after_countdown)
        {
                restart_timer = spawn();
                restart_timer.think = ReadyRestart_think;
@@@ -411,10 -491,13 +489,13 @@@ void ReadyCount(
        float ready_needed_factor, ready_needed_count;
        float t_ready = 0, t_players = 0;
  
-       FOR_EACH_REALPLAYER(tmp_player)
+       FOR_EACH_REALCLIENT(tmp_player)
        {
-               ++t_players;
-               if(tmp_player.ready) { ++t_ready; }
+               if(IS_PLAYER(tmp_player) || tmp_player.caplayer == 1)
+               {
+                       ++t_players;
+                       if(tmp_player.ready) { ++t_ready; }
+               }
        }
  
        readycount = t_ready;
@@@ -608,7 -691,7 +689,7 @@@ float VoteCommand_parse(entity caller, 
                        
                        if(accepted > 0)
                        {
-                               string reason = ((argc > next_token) ? substring(vote_command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)) : "No reason provided");
+                               string reason = ((argc > next_token) ? substring(vote_command, argv_start_index(next_token), strlen(vote_command) - argv_start_index(next_token)) : "No reason provided");
                                string command_arguments;
                                
                                if(first_command == "kickban")
@@@ -701,7 -784,7 +782,7 @@@ void VoteCommand_call(float request, en
                        if not(autocvar_sv_vote_call || !caller) { print_to(caller, "^1Vote calling is not allowed."); }
                        else if(!autocvar_sv_vote_gamestart && time < game_starttime) { print_to(caller, "^1Vote calling is not allowed before the match has started."); }
                        else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
 -                      else if(!spectators_allowed && (caller && (caller.classname != "player"))) { print_to(caller, "^1Only players can call a vote."); }
 +                      else if(!spectators_allowed && (caller && !IS_PLAYER(caller))) { print_to(caller, "^1Only players can call a vote."); }
                        else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
                        else if(caller && (time < caller.vote_waittime)) { print_to(caller, strcat("^1You have to wait ^2", ftos(ceil(caller.vote_waittime - time)), "^1 seconds before you can again call a vote.")); }
                        else if not(VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
                                }
                                
                                FOR_EACH_REALCLIENT(tmp_player) { ++tmp_playercount; }
-                               if(tmp_playercount > 1) { Announce("votecall"); } // don't announce a "vote now" sound if player is alone
+                               if(tmp_playercount > 1) { Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_VOTE_CALL); } // don't announce a "vote now" sound if player is alone
                                
                                bprint("\{1}^2* ^3", GetCallerName(vote_caller), "^2 calls a vote for ", vote_called_display, "\n");
                                if(autocvar_sv_eventlog) { GameLogEcho(strcat(":vote:vcall:", ftos(vote_caller.playerid), ":", vote_called_display)); }
@@@ -800,7 -883,7 +881,7 @@@ void VoteCommand_master(float request, 
                                                
                                                if not(autocvar_sv_vote_master_callable) { print_to(caller, "^1Vote to become vote master is not allowed."); }
                                                else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
 -                                              else if(!spectators_allowed && (caller && (caller.classname != "player"))) { print_to(caller, "^1Only players can call a vote."); }
 +                                              else if(!spectators_allowed && (caller && !IS_PLAYER(caller))) { print_to(caller, "^1Only players can call a vote."); }
                                                else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
                                                
                                                else // everything went okay, continue with creating vote
diff --combined qcsrc/server/g_damage.qc
index f94f9ef2ce4d2b4ae3b6aaa5274556be62b2665d,16a6a04afa6d22fa659a1eda9ff030fcd42a8787..c057619f6ed5b0c62c750e86d5db0b3a353de7cd
@@@ -120,10 -120,6 +120,6 @@@ void GiveFrags (entity attacker, entit
  
        PlayerScore_Add(targ, SP_DEATHS, 1);
  
-       if(g_arena || g_ca)
-               if(autocvar_g_arena_roundbased)
-                       return;
        if(targ != attacker) // not for suicides
        if(g_weaponarena_random)
        {
        else
        {
                self = oldself;
-               if(g_runematch)
-               {
-                       f = RunematchHandleFrags(attacker, targ, f);
-               }
-               else if(g_lms)
+               if(g_lms)
                {
                        // remove a life
                        float tl;
                UpdateFrags(attacker, f);
  }
  
- string Obituary_ExtraFragInfo(entity player) // Extra fragmessage information
- {
-       string health_output = string_null;
-       string ping_output = string_null;
-       string handicap_output = string_null;
-       string output = string_null;
-       if(autocvar_sv_fraginfo && ((autocvar_sv_fraginfo == 2) || inWarmupStage))
-       {
-               // health/armor of attacker (person who killed you)
-               if(autocvar_sv_fraginfo_stats && (player.health >= 1))
-                       health_output = strcat("^7(Health ^1", ftos(rint(player.health)), "^7 / Armor ^2", ftos(rint(player.armorvalue)), "^7)");
-               
-               // ping display
-               if(autocvar_sv_fraginfo_ping)
-                       ping_output = ((IS_BOT_CLIENT(player)) ? "^2Bot" : strcat("Ping ", ((player.ping >= 150) ? "^1" : "^2"), ftos(rint(player.ping)), "ms"));
-                       
-               // handicap display 
-               if(autocvar_sv_fraginfo_handicap) 
-               {
-                       if(autocvar_sv_fraginfo_handicap == 2)  
-                               handicap_output = strcat(output, strcat("Handicap ^2", ((player.cvar_cl_handicap <= 1) ? "Off" : ftos(rint(player.cvar_cl_handicap)))));
-                       else if(player.cvar_cl_handicap) // with _handicap 1, only show this if there actually is a handicap enabled.   
-                               handicap_output = strcat("Handicap ^2", ftos(rint(player.cvar_cl_handicap)));
-               }
-               
-               // format the string
-               output = strcat(health_output, (health_output ? ((ping_output || handicap_output) ? " ^7(" : "") : ((ping_output || handicap_output) ? "^7(" : "")), 
-                       ping_output, (handicap_output ? "^7 / " : ""), 
-                       handicap_output, ((ping_output || handicap_output) ? "^7)" : ""));
-               
-               // add new line to the beginning if there is a message
-               if(output) { output = strcat("\n", output); }
-       }
-       
-       return output;
- }
  string AppendItemcodes(string s, entity player)
  {
        float w;
                s = strcat(s, "T");
        if(player.kh_next)
                s = strcat(s, "K");
-       if(player.runes)
-               s = strcat(s, "|", ftos(player.runes));
        return s;
  }
  
@@@ -286,7 -238,7 +238,7 @@@ void LogDeath(string mode, float deatht
        s = strcat(":kill:", mode);
        s = strcat(s, ":", ftos(killer.playerid));
        s = strcat(s, ":", ftos(killed.playerid));
-       s = strcat(s, ":type=", ftos(deathtype));
+       s = strcat(s, ":type=", Deathtype_Name(deathtype));
        s = strcat(s, ":items=");
        s = AppendItemcodes(s, killer);
        if(killed != killer)
        GameLogEcho(s);
  }
  
- void Send_KillNotification (string s1, string s2, string s3, float msg, float type)
+ void Obituary_SpecialDeath(
+       entity notif_target,
+       float murder,
+       float deathtype,
+       string s1, string s2, string s3,
+       float f1, float f2, float f3)
  {
-       WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-       WriteByte(MSG_BROADCAST, TE_CSQC_KILLNOTIFY);
-       WriteString(MSG_BROADCAST, s1);
-       WriteString(MSG_BROADCAST, s2);
-       WriteString(MSG_BROADCAST, s3);
-       WriteShort(MSG_BROADCAST, msg);
-       WriteByte(MSG_BROADCAST, type);
+       if(DEATH_ISSPECIAL(deathtype))
+       {
+               entity deathent = deathtypes[(deathtype - DT_FIRST) - 1];
+               if not(deathent) { backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n"); return; }
+               if(murder)
+               {
+                       if(deathent.death_msgmurder)
+                       {
+                               Send_Notification_WOVA(
+                                       NOTIF_ONE,
+                                       notif_target,
+                                       MSG_MULTI,
+                                       deathent.death_msgmurder.nent_id,
+                                       s1, s2, s3, "",
+                                       f1, f2, f3, 0
+                               );
+                               Send_Notification_WOVA(
+                                       NOTIF_ALL_EXCEPT,
+                                       notif_target,
+                                       MSG_INFO,
+                                       deathent.death_msgmurder.nent_msginfo.nent_id,
+                                       s1, s2, s3, "",
+                                       f1, f2, f3, 0
+                               );
+                       }
+               }
+               else
+               {
+                       if(deathent.death_msgself)
+                       {
+                               Send_Notification_WOVA(
+                                       NOTIF_ONE,
+                                       notif_target,
+                                       MSG_MULTI,
+                                       deathent.death_msgself.nent_id,
+                                       s1, s2, s3, "",
+                                       f1, f2, f3, 0
+                               );
+                               Send_Notification_WOVA(
+                                       NOTIF_ALL_EXCEPT,
+                                       notif_target,
+                                       MSG_INFO,
+                                       deathent.death_msgself.nent_msginfo.nent_id,
+                                       s1, s2, s3, "",
+                                       f1, f2, f3, 0
+                               );
+                       }
+               }
+       }
+       else { backtrace("Obituary_SpecialDeath called without a special deathtype?\n"); return; }
  }
  
- // Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
- void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
+ float w_deathtype;
+ float Obituary_WeaponDeath(
+       entity notif_target,
+       float murder,
+       float deathtype,
+       string s1, string s2, string s3,
+       float f1, float f2)
  {
-       if (IS_REAL_CLIENT(e))
+       float death_weapon = DEATH_WEAPONOF(deathtype);
+       if(death_weapon)
        {
-               msg_entity = e;
-               WRITESPECTATABLE_MSG_ONE({
-                       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                       WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
-                       WriteString(MSG_ONE, s1);
-                       WriteString(MSG_ONE, s2);
-                       WriteShort(MSG_ONE, msg);
-                       WriteByte(MSG_ONE, type);
-               });
+               w_deathtype = deathtype;
+               float death_message = weapon_action(death_weapon, ((murder) ? WR_KILLMESSAGE : WR_SUICIDEMESSAGE));
+               w_deathtype = FALSE;
+               if(death_message)
+               {
+                       Send_Notification_WOVA(
+                               NOTIF_ONE,
+                               notif_target,
+                               MSG_MULTI,
+                               death_message,
+                               s1, s2, s3, "",
+                               f1, f2, 0, 0
+                       );
+                       Send_Notification_WOVA(
+                               NOTIF_ALL_EXCEPT,
+                               notif_target,
+                               MSG_INFO,
+                               msg_multi_notifs[death_message - 1].nent_msginfo.nent_id,
+                               s1, s2, s3, "",
+                               f1, f2, 0, 0
+                       );
+               }
+               else
+               {
+                       dprint(sprintf(
+                               "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %d!\n",
+                               deathtype,
+                               death_weapon
+                       ));
+               }
+               return TRUE;
        }
+       return FALSE;
  }
  
- void Obituary (entity attacker, entity inflictor, entity targ, float deathtype)
+ void Obituary(entity attacker, entity inflictor, entity targ, float deathtype)
  {
-       string  s, a, msg;
-       float type;
-       if (IS_PLAYER(targ))
+       // Sanity check
+       if not(IS_PLAYER(targ)) { backtrace("Obituary called on non-player?!\n"); return; }
+       // Declarations
+       float notif_firstblood = FALSE;
+       float kill_count_to_attacker, kill_count_to_target;
+       // Set final information for the death
+       targ.death_origin = targ.origin;
+       if(targ != attacker) { targ.killer_origin = attacker.origin; }
+       string deathlocation = (autocvar_notification_server_allows_location ? NearestLocation(targ.death_origin) : "");
+       #ifdef NOTIFICATIONS_DEBUG
+       Debug_Notification(
+               sprintf(
+                       "Obituary(%s, %s, %s, %s = %d);\n",
+                       attacker.netname,
+                       inflictor.netname,
+                       targ.netname,
+                       Deathtype_Name(deathtype),
+                       deathtype
+               )
+       );
+       #endif
+       
+       // =======
+       // SUICIDE
+       // =======
+       if(targ == attacker)
        {
-               s = targ.netname;
-               a = attacker.netname;
-               if (targ == attacker) // suicides
+               if(DEATH_ISSPECIAL(deathtype))
                {
-                       if (deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE)
-                               msg = ColoredTeamName(targ.team); // TODO: check if needed?
-                       else
-                               msg = "";
-             if(!g_cts) // no "killed your own dumb self" message in CTS
-                 Send_CSQC_KillCenterprint(targ, msg, "", deathtype, MSG_SUICIDE);
-                       if(deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_QUIET)
+                       if(deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE)
                        {
-                               LogDeath("suicide", deathtype, targ, targ);
-                               GiveFrags(attacker, targ, -1, deathtype);
+                               Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.team, 0, 0);
                        }
-                       if (targ.killcount > 2)
-                               msg = ftos(targ.killcount);
                        else
-                               msg = "";
-                       if(teamplay && deathtype == DEATH_MIRRORDAMAGE)
                        {
-                               if(attacker.team == COLOR_TEAM1)
-                                       deathtype = KILL_TEAM_RED;
-                               else
-                                       deathtype = KILL_TEAM_BLUE;
+                               switch(deathtype)
+                               {
+                                       case DEATH_MIRRORDAMAGE:
+                                       {
+                                               Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0);
+                                               break;
+                                       }
+                                       
+                                       default:
+                                       {
+                                               Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0);
+                                               break;
+                                       }
+                               }
                        }
-                       Send_KillNotification(s, msg, "", deathtype, MSG_SUICIDE);
                }
-               else if (IS_PLAYER(attacker))
+               else if not(Obituary_WeaponDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0))
                {
-                       if(!IsDifferentTeam(attacker, targ))
-                       {
-                               if(attacker.team == COLOR_TEAM1)
-                                       type = KILL_TEAM_RED;
-                               else
-                                       type = KILL_TEAM_BLUE;
-                               GiveFrags(attacker, targ, -1, deathtype);
+                       backtrace("SUICIDE: what the hell happened here?\n");
+                       return;
+               }
+               LogDeath("suicide", deathtype, targ, targ);
+               GiveFrags(attacker, targ, -1, deathtype);
+       }
  
-                               Send_CSQC_KillCenterprint(attacker, s, "", type, MSG_KILL);
+       // ======
+       // MURDER
+       // ======
+       else if(IS_PLAYER(attacker))
+       {
+               if(!IsDifferentTeam(attacker, targ))
+               {
+                       LogDeath("tk", deathtype, attacker, targ);
+                       GiveFrags(attacker, targ, -1, deathtype);
  
-                               if (targ.killcount > 2)
-                                       msg = ftos(targ.killcount);
-                               else
-                                       msg = "";
+                       attacker.killcount = 0;
+                       
+                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAG, targ.netname);
+                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAGGED, attacker.netname);
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(targ.team, INFO_DEATH_TEAMKILL_), targ.netname, attacker.netname, deathlocation, targ.killcount);
  
-                               if (attacker.killcount > 2) {
-                                       msg = ftos(attacker.killcount);
-                                       type = KILL_TEAM_SPREE;
+                       // In this case, the death message will ALWAYS be "foo was betrayed by bar"
+                       // No need for specific death/weapon messages...
+               }
+               else
+               {
+                       LogDeath("frag", deathtype, attacker, targ);
+                       GiveFrags(attacker, targ, 1, deathtype);
+                       attacker.taunt_soundtime = time + 1;
+                       attacker.killcount = attacker.killcount + 1;
+                       #define SPREE_ITEM(counta,countb,center,normal,gentle) \
+                               case counta: \
+                               { \
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
+                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
+                                       break; \
                                }
-                               Send_KillNotification(a, s, msg, type, MSG_KILL);
-                               attacker.killcount = 0;
+                       switch(attacker.killcount)
+                       {
+                               KILL_SPREE_LIST
+                               default: break;
+                       }
+                       #undef SPREE_ITEM
  
-                               LogDeath("tk", deathtype, attacker, targ);
+                       if(!checkrules_firstblood)
+                       {
+                               checkrules_firstblood = TRUE;
+                               notif_firstblood = TRUE; // modify the current messages so that they too show firstblood information
+                               PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
+                               PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
+                               // tell spree_inf and spree_cen that this is a first-blood and first-victim event
+                               kill_count_to_attacker = -1;
+                               kill_count_to_target = -2;
                        }
                        else
                        {
-                               if (!checkrules_firstblood)
-                               {
-                                       checkrules_firstblood = TRUE;
-                                       Send_KillNotification(a, "", "", KILL_FIRST_BLOOD, MSG_KILL);
-                                       // TODO: make these print a newline if they dont
-                                       Send_CSQC_KillCenterprint(attacker, "", "", KILL_FIRST_BLOOD, MSG_KILL);
-                                       Send_CSQC_KillCenterprint(targ, "", "", KILL_FIRST_VICTIM, MSG_KILL);
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
-                                       PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
-                               }
-                               if(targ.istypefrag) {
-                                       Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_TYPEFRAG, MSG_KILL);
-                                       Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_TYPEFRAGGED, MSG_KILL);
-                               } else {
-                                       Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_FRAG, MSG_KILL);
-                                       Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_FRAGGED, MSG_KILL);
-                               }
-                               attacker.taunt_soundtime = time + 1;
+                               kill_count_to_attacker = attacker.killcount;
+                               kill_count_to_target = 0;
+                       }
  
-                               if (deathtype == DEATH_HURTTRIGGER && inflictor.message2 != "")
-                                       msg = inflictor.message2;
-                               else if (deathtype == DEATH_CUSTOM)
-                                       msg = deathmessage;
+                       float verbose_allowed = (autocvar_notification_server_allows_frag_verbose && ((autocvar_notification_server_allows_frag_verbose == 2) || inWarmupStage));
+                       if(targ.istypefrag)
+                       {
+                               if(attacker.FRAG_VERBOSE && verbose_allowed)
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
                                else
-                                       msg = "";
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG, targ.netname, kill_count_to_attacker);
  
-                               if(strstrofs(msg, "%", 0) < 0)
-                                       msg = strcat("%s ", msg, " by %s");
-                               Send_KillNotification(a, s, msg, deathtype, MSG_KILL);
+                               if(targ.FRAG_VERBOSE && verbose_allowed)
+                                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE, attacker.netname, kill_count_to_target, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
+                               else
+                                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED, attacker.netname, kill_count_to_target);
+                       }
+                       else
+                       {
+                               if(attacker.FRAG_VERBOSE && verbose_allowed)
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG_VERBOSE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
+                               else
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG, targ.netname, kill_count_to_attacker);
  
-                               GiveFrags(attacker, targ, 1, deathtype);
+                               if(targ.FRAG_VERBOSE && verbose_allowed)
+                                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED_VERBOSE, attacker.netname, kill_count_to_target, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
+                               else
+                                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED, attacker.netname, kill_count_to_target);
+                       }
  
-                               if (targ.killcount > 2) {
-                                       Send_KillNotification(s, ftos(targ.killcount), a, KILL_END_SPREE, MSG_SPREE);
-                               }
+                       if not(Obituary_WeaponDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker))
+                               Obituary_SpecialDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker, 0);
+               }
+       }
  
-                               attacker.killcount = attacker.killcount + 1;
+       // =============
+       // ACCIDENT/TRAP
+       // =============
+       else
+       {
+               switch(deathtype)
+               {
+                       // For now, we're just forcing HURTTRIGGER to behave as "DEATH_VOID" and giving it no special options...
+                       // Later on you will only be able to make custom messages using DEATH_CUSTOM,
+                       // and there will be a REAL DEATH_VOID implementation which mappers will use.
+                       /*case DEATH_HURTTRIGGER:
+                       {
+                               s1 = targ.netname;
+                               s2 = inflictor.message;
+                               if(strstrofs(s2, "%", 0) < 0) { s2 = strcat("%s ", s2); }
+                               break;
+                       }*/
  
-                               if (attacker.killcount == 3)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_3, MSG_SPREE);
-                                       AnnounceTo(attacker, "03kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_3, 1);
-                               }
-                               else if (attacker.killcount == 5)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_5, MSG_SPREE);
-                                       AnnounceTo(attacker, "05kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_5, 1);
-                               }
-                               else if (attacker.killcount == 10)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_10, MSG_SPREE);
-                                       AnnounceTo(attacker, "10kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_10, 1);
-                               }
-                               else if (attacker.killcount == 15)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_15, MSG_SPREE);
-                                       AnnounceTo(attacker, "15kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_15, 1);
-                               }
-                               else if (attacker.killcount == 20)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_20, MSG_SPREE);
-                                       AnnounceTo(attacker, "20kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_20, 1);
-                               }
-                               else if (attacker.killcount == 25)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_25, MSG_SPREE);
-                                       AnnounceTo(attacker, "25kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_25, 1);
-                               }
-                               else if (attacker.killcount == 30)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_30, MSG_SPREE);
-                                       AnnounceTo(attacker, "30kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_30, 1);
-                               }
-                               else if (attacker.killcount > 2) {
-                                       Send_KillNotification(a, ftos(attacker.killcount), "", KILL_SPREE, MSG_SPREE);
-                               }
-                               LogDeath("frag", deathtype, attacker, targ);
+                       case DEATH_CUSTOM:
+                       {
+                               Obituary_SpecialDeath(targ, FALSE, deathtype,
+                                       targ.netname,
+                                       ((strstrofs(deathmessage, "%", 0) < 0) ? strcat("%s ", deathmessage) : deathmessage),
+                                       deathlocation,
+                                       targ.killcount,
+                                       0,
+                                       0);
+                               break;
                        }
-               }
-               else
-               {
-                       Send_CSQC_KillCenterprint(targ, "", "", deathtype, MSG_KILL_ACTION);
-                       if (deathtype == DEATH_HURTTRIGGER && inflictor.message != "")
-                               msg = inflictor.message;
-                       else if (deathtype == DEATH_CUSTOM)
-                               msg = deathmessage;
-                       else
-                               msg = "";
-                       if(strstrofs(msg, "%", 0) < 0)
-                               msg = strcat("%s ", msg);
-                       GiveFrags(targ, targ, -1, deathtype);
-                       if(PlayerScore_Add(targ, SP_SCORE, 0) == -5) {
-                               AnnounceTo(targ, "botlike");
-                               PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
+                       
+                       default:
+                       {
+                               Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0);
+                               break;
                        }
-                       Send_KillNotification(s, msg, "", deathtype, MSG_KILL_ACTION);
-                       if (targ.killcount > 2)
-                               Send_KillNotification(s, ftos(targ.killcount), "", 0, MSG_KILL_ACTION_SPREE);
-                       LogDeath("accident", deathtype, targ, targ);
                }
  
-               targ.death_origin = targ.origin;
-               if(targ != attacker)
-                       targ.killer_origin = attacker.origin;
+               LogDeath("accident", deathtype, targ, targ);
+               GiveFrags(targ, targ, -1, deathtype);
  
-               // FIXME: this should go in PutClientInServer
-               if (targ.killcount)
-                       targ.killcount = 0;
+               if(PlayerScore_Add(targ, SP_SCORE, 0) == -5)
+               {
+                       Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACHIEVEMENT_BOTLIKE);
+                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
+               }
        }
+       // reset target kill count
+       if(targ.killcount) { targ.killcount = 0; }
  }
  
  // these are updated by each Damage call for use in button triggering and such
@@@ -543,7 -587,7 +587,7 @@@ void Damage (entity targ, entity inflic
          damage_attacker = attacker;
                attacker_save = attacker;
  
 -      if(targ.classname == "player")
 +      if(IS_PLAYER(targ))
                if(targ.hook)
                        if(targ.hook.aiment)
                                if(targ.hook.aiment == attacker)
        // special rule: gravity bomb does not hit team mates (other than for disconnecting the hook)
        if(DEATH_ISWEAPON(deathtype, WEP_HOOK) || DEATH_ISWEAPON(deathtype, WEP_TUBA))
        {
 -              if(targ.classname == "player")
 +              if(IS_PLAYER(targ))
                        if not(IsDifferentTeam(targ, attacker))
                        {
                                self = oldself;
                        }
        }
  
-       if(deathtype == DEATH_KILL || deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE || deathtype == DEATH_QUIET)
+       if(deathtype == DEATH_KILL || deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE)
        {
                // These are ALWAYS lethal
                // No damage modification here
        }
        else
        {
 -              /*
 -              skill based bot damage? gtfo. (tZork)
 -              if (targ.classname == "player")
 -              if (attacker.classname == "player")
 -              if (!targ.isbot)
 -              if (attacker.isbot)
 -                      damage = damage * bound(0.1, (skill + 5) * 0.1, 1);
 -        */
 -        
                // nullify damage if teamplay is on
                if(deathtype != DEATH_TELEFRAG)
 -              if(attacker.classname == "player")
 +              if(IS_PLAYER(attacker))
                {
 -                      if(targ.classname == "player" && targ != attacker && (IS_INDEPENDENT_PLAYER(attacker) || IS_INDEPENDENT_PLAYER(targ)))
 +                      if(IS_PLAYER(targ) && targ != attacker && (IS_INDEPENDENT_PLAYER(attacker) || IS_INDEPENDENT_PLAYER(targ)))
                        {
                                damage = 0;
                                force = '0 0 0';
                                                damage = 0;
                                        else if(autocvar_teamplay_mode == 4)
                                        {
 -                                              if(targ.classname == "player" && targ.deadflag == DEAD_NO)
 +                                              if(IS_PLAYER(targ) && targ.deadflag == DEAD_NO)
                                                {
                                                        attacker.dmg_team = attacker.dmg_team + damage;
                                                        complainteamdamage = attacker.dmg_team - autocvar_g_teamdamage_threshold;
                        }
                }
  
 -              if(targ.classname == "player")
 -              if(attacker.classname == "player")
 +              if(IS_PLAYER(targ))
 +              if(IS_PLAYER(attacker))
                if(attacker != targ)
                {
                        targ.lms_traveled_distance = autocvar_g_lms_campcheck_distance;
                        attacker.lms_traveled_distance = autocvar_g_lms_campcheck_distance;
                }
  
 -              if(targ.classname == "player")
 +              if(IS_PLAYER(targ))
                if (g_minstagib)
                {
                        if ((deathtype == DEATH_FALL)  ||
                                complainteamdamage = 0;
                                if (targ != attacker)
                                {
 -                                      if ((targ.health >= 1) && (targ.classname == "player"))
 +                                      if ((targ.health >= 1) && (IS_PLAYER(targ)))
                                                centerprint(attacker, "Secondary fire inflicts no damage!");
                                        force = '0 0 0';
                                        // keep mirrorforce
                                damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself
                }
  
-               if(g_runematch)
-               {
-                       // apply strength rune
-                       if (attacker.runes & RUNE_STRENGTH)
-                       {
-                               if(attacker.runes & CURSE_WEAK) // have both curse & rune
-                               {
-                                       damage = damage * autocvar_g_balance_rune_strength_combo_damage;
-                                       force = force * autocvar_g_balance_rune_strength_combo_force;
-                               }
-                               else
-                               {
-                                       damage = damage * autocvar_g_balance_rune_strength_damage;
-                                       force = force * autocvar_g_balance_rune_strength_force;
-                               }
-                       }
-                       else if (attacker.runes & CURSE_WEAK)
-                       {
-                               damage = damage * autocvar_g_balance_curse_weak_damage;
-                               force = force * autocvar_g_balance_curse_weak_force;
-                       }
-                       // apply defense rune
-                       if (targ.runes & RUNE_DEFENSE)
-                       {
-                               if (targ.runes & CURSE_VULNER) // have both curse & rune
-                                       damage = damage * autocvar_g_balance_rune_defense_combo_takedamage;
-                               else
-                                       damage = damage * autocvar_g_balance_rune_defense_takedamage;
-                       }
-                       else if (targ.runes & CURSE_VULNER)
-                               damage = damage * autocvar_g_balance_curse_vulner_takedamage;
-               }
                // count the damage
                if(attacker)
                if(!targ.deadflag)
                        else
                                victim = targ;
  
 -                      if(victim.classname == "player" || victim.turrcaps_flags & TFL_TURRCAPS_ISTURRET)
 +                      if(IS_PLAYER(victim) || victim.turrcaps_flags & TFL_TURRCAPS_ISTURRET)
                        {
                                if(IsDifferentTeam(victim, attacker))
                                {
  
                                                if not(DEATH_ISSPECIAL(deathtype))
                                                {
 -                                                      if(targ.classname == "player") // don't do this for vehicles
 +                                                      if(IS_PLAYER(targ)) // don't do this for vehicles
                                                        if(!g_minstagib)
                                                        if(IsFlying(victim))
                                                                yoda = 1;
        // apply push
        if (self.damageforcescale)
        if (vlen(force))
 -      if (self.classname != "player" || time >= self.spawnshieldtime || g_midair)
 +      if (!IS_PLAYER(self) || time >= self.spawnshieldtime || g_midair)
        {
                vector farce = damage_explosion_calcpush(self.damageforcescale * force, self.velocity, autocvar_g_balance_damagepush_speedfactor);
                if(self.movetype == MOVETYPE_PHYSICS)
                self.event_damage (inflictor, attacker, damage, deathtype, hitloc, force);
        self = oldself;
  
-       if(IS_PLAYER(targ) && IS_PLAYER(attacker) && attacker != targ && attacker.health > 2)
-       {
-               if(g_runematch)
-               {
-                       if (attacker.runes & RUNE_VAMPIRE)
-                       {
-                       // apply vampire rune
-                               if (attacker.runes & CURSE_EMPATHY) // have the curse too
-                               {
-                                       //attacker.health = attacker.health + damage * autocvar_g_balance_rune_vampire_combo_absorb;
-                                       attacker.health = bound(
-                                               autocvar_g_balance_curse_empathy_minhealth, // LA: was 3, now 40
-                                               attacker.health + damage * autocvar_g_balance_rune_vampire_combo_absorb,
-                                               autocvar_g_balance_rune_vampire_maxhealth);     // LA: was 1000, now 500
-                               }
-                               else
-                               {
-                                       //attacker.health = attacker.health + damage * autocvar_g_balance_rune_vampire_absorb;
-                                       attacker.health = bound(
-                                               attacker.health,        // LA: was 3, but changed so that you can't lose health
-                                                                                       // empathy won't let you gain health in the same way...
-                                               attacker.health + damage * autocvar_g_balance_rune_vampire_absorb,
-                                               autocvar_g_balance_rune_vampire_maxhealth);     // LA: was 1000, now 500
-                                       }
-                       }
-                       // apply empathy curse
-                       else if (attacker.runes & CURSE_EMPATHY)
-                       {
-                               attacker.health = bound(
-                                       autocvar_g_balance_curse_empathy_minhealth, // LA: was 3, now 20
-                                       attacker.health + damage * autocvar_g_balance_curse_empathy_takedamage,
-                                       attacker.health);
-                       }
-               }
-       }
        // apply mirror damage if any
        if(mirrordamage > 0 || mirrorforce > 0)
        {
@@@ -1032,7 -1015,7 +1006,7 @@@ float RadiusDamage (entity inflictor, e
                                                        if(autocvar_g_throughfloor_debug)
                                                                print(sprintf(" steps=%f", total));
  
 -                                                      if (targ.classname == "player")
 +                                                      if (IS_PLAYER(targ))
                                                                total = ceil(bound(autocvar_g_throughfloor_min_steps_player, total, autocvar_g_throughfloor_max_steps_player));
                                                        else
                                                                total = ceil(bound(autocvar_g_throughfloor_min_steps_other, total, autocvar_g_throughfloor_max_steps_other));
@@@ -1168,7 -1151,7 +1142,7 @@@ float Fire_AddDamage(entity e, entity o
        float dps;
        float maxtime, mintime, maxdamage, mindamage, maxdps, mindps, totaldamage, totaltime;
  
 -      if(e.classname == "player")
 +      if(IS_PLAYER(e))
        {
                if(e.deadflag)
                        return -1;
@@@ -1292,7 -1275,7 +1266,7 @@@ void Fire_ApplyDamage(entity e
                return;
  
        for(t = 0, o = e.owner; o.owner && t < 16; o = o.owner, ++t);
 -      if(clienttype(o) == CLIENTTYPE_NOTACLIENT)
 +      if(IS_NOT_A_CLIENT(o))
                o = e.fire_owner;
  
        // water and slime stop fire
        if not(IS_INDEPENDENT_PLAYER(e))
        FOR_EACH_PLAYER(other) if(e != other)
        {
 -              if(other.classname == "player")
 +              if(IS_PLAYER(other))
                if(other.deadflag == DEAD_NO)
                if not(IS_INDEPENDENT_PLAYER(other))
                if(boxesoverlap(e.absmin, e.absmax, other.absmin, other.absmax))
index 7defd351cdffe61e50f39931779e5bc8393bc0a4,12c75ae9e57199fb5499b0a910c5ecda94d3ed42..65846f5e38ba332e8f6e226c8f29831f18474260
@@@ -61,9 -61,9 +61,9 @@@ void SUB_UseTargets(
  //
  // print the message
  //
 -      if (activator.classname == "player" && self.message != "")
 +      if (IS_PLAYER(activator) && self.message != "")
        {
 -              if(clienttype(activator) == CLIENTTYPE_REAL)
 +              if(IS_REAL_CLIENT(activator))
                {
                        centerprint (activator, self.message);
                        if (self.noise == "")
@@@ -164,7 -164,7 +164,7 @@@ void multi_trigger(
  
        if (self.classname == "trigger_secret")
        {
 -              if (self.enemy.classname != "player")
 +              if not(IS_PLAYER(self.enemy))
                        return;
                found_secrets = found_secrets + 1;
                WriteByte (MSG_ALL, SVC_FOUNDSECRET);
@@@ -384,7 -384,7 +384,7 @@@ void counter_use(
  
        if (self.count != 0)
        {
 -              if (activator.classname == "player"
 +              if (IS_PLAYER(activator)
                && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
                {
                        if (self.count >= 4)
                return;
        }
  
 -      if (activator.classname == "player"
 +      if (IS_PLAYER(activator)
        && (self.spawnflags & SPAWNFLAG_NOMESSAGE) == 0)
                centerprint(activator, "Sequence completed!");
        self.enemy = activator;
@@@ -432,7 -432,7 +432,7 @@@ void spawnfunc_trigger_counter(
  
  void trigger_hurt_use()
  {
 -      if(activator.classname == "player")
 +      if(IS_PLAYER(activator))
                self.enemy = activator;
        else
                self.enemy = world; // let's just destroy it, if taking over is too much work
@@@ -459,7 -459,7 +459,7 @@@ void trigger_hurt_touch(
  
                        entity own;
                        own = self.enemy;
 -                      if(own.classname != "player")
 +                      if not(IS_PLAYER(own))
                        {
                                own = self;
                                self.enemy = world; // I still hate you all
                        Damage(other, self, self, self.dmg, DEATH_HURTTRIGGER, other.origin, '0 0 0');
                }
        }
-       else
-       {
-               if (!other.owner)
-               {
-                       if (other.classname == "rune")                  // reset runes
-                       {
-                               EXACTTRIGGER_TOUCH;
-                               other.nextthink = min(other.nextthink, time + 1);
-                       }
-               }
-       }
  
        return;
  }
@@@ -702,7 -691,7 +691,7 @@@ void spawnfunc_trigger_gravity(
  void target_speaker_use_off();
  void target_speaker_use_activator()
  {
 -      if(clienttype(activator) != CLIENTTYPE_REAL)
 +      if not(IS_REAL_CLIENT(activator))
                return;
        string snd;
        if(substring(self.noise, 0, 1) == "*")
@@@ -1777,7 -1766,7 +1766,7 @@@ void target_voicescript_next(entity pl
                return;
        if(vs.message == "")
                return;
 -      if(pl.classname != "player")
 +      if not(IS_PLAYER(pl))
                return;
        if(gameover)
                return;
@@@ -1926,7 -1915,7 +1915,7 @@@ string trigger_magicear_processmessage(
  
        magicear_matched = FALSE;
  
 -      dotrigger = ((source.classname == "player") && (source.deadflag == DEAD_NO) && ((ear.radius == 0) || (vlen(source.origin - ear.origin) <= ear.radius)));
 +      dotrigger = ((IS_PLAYER(source)) && (source.deadflag == DEAD_NO) && ((ear.radius == 0) || (vlen(source.origin - ear.origin) <= ear.radius)));
        domatch = ((ear.spawnflags & 32) || dotrigger);
  
        if not(domatch)
diff --combined qcsrc/server/g_world.qc
index 91f8caf39cad6056978c5333d4dcf7f081137a48,d8ce88cf3ce082f631dde1a28b08e76e75e5d28b..e5106bbcd437898d2d780531aa204c39ef234524
@@@ -14,7 -14,7 +14,7 @@@ void PingPLReport_Think(
        self.nextthink = time + delta;
  
        e = edict_num(self.cnt + 1);
 -      if(clienttype(e) == CLIENTTYPE_REAL)
 +      if(IS_REAL_CLIENT(e))
        {
                WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
                WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
@@@ -256,22 -256,22 +256,22 @@@ void cvar_changes_init(
                BADCVAR("g_arena");
                BADCVAR("g_assault");
                BADCVAR("g_ca");
+               BADCVAR("g_ca_teams");
                BADCVAR("g_ctf");
                BADCVAR("g_cts");
                BADCVAR("g_dm");
                BADCVAR("g_domination");
                BADCVAR("g_domination_default_teams");
                BADCVAR("g_freezetag");
+               BADCVAR("g_freezetag_teams");
                BADCVAR("g_keepaway");
                BADCVAR("g_keyhunt");
                BADCVAR("g_keyhunt_teams");
-               BADCVAR("g_keyhunt_teams");
                BADCVAR("g_lms");
                BADCVAR("g_nexball");
                BADCVAR("g_onslaught");
                BADCVAR("g_race");
                BADCVAR("g_race_qualifying_timelimit");
-               BADCVAR("g_runematch");
                BADCVAR("g_tdm");
                BADCVAR("g_tdm_teams");
                BADCVAR("leadlimit");
                BADCVAR("g_keyhunt_point_leadlimit");
                BADPREFIX("g_mod_");
                BADCVAR("g_nexball_goalleadlimit");
-               BADCVAR("g_runematch_point_leadlimit");
                BADCVAR("leadlimit_and_fraglimit");
                BADCVAR("leadlimit_override");
                BADCVAR("pausable");
                BADCVAR("g_balance_teams_scorefactor");
                BADCVAR("g_ban_sync_trusted_servers");
                BADCVAR("g_ban_sync_uri");
+               BADCVAR("g_ca_teams_override");
                BADCVAR("g_ctf_ignore_frags");
                BADCVAR("g_domination_point_limit");
+               BADCVAR("g_freezetag_teams_override");
                BADCVAR("g_friendlyfire");
                BADCVAR("g_fullbrightitems");
                BADCVAR("g_fullbrightplayers");
                BADCVAR("g_mirrordamage");
                BADCVAR("g_nexball_goallimit");
                BADCVAR("g_powerups");
-               BADCVAR("g_runematch_point_limit");
                BADCVAR("g_start_delay");
                BADCVAR("g_warmup");
                BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay");
@@@ -550,6 -550,8 +550,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);
@@@ -582,8 -584,6 +584,6 @@@ void spawnfunc_worldspawn (void
  
        compressShortVector_init();
  
-       allowed_to_spawn = TRUE;
        entity head;
        head = nextent(world);
        maxclients = 0;
                head = nextent(head);
        }
  
+       server_is_dedicated = (stof(cvar_defstring("is_dedicated")) ? TRUE : FALSE);
        // 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));
  
        addstat(STAT_SWITCHWEAPON, AS_INT, switchweapon);
        addstat(STAT_SWITCHINGWEAPON, AS_INT, switchingweapon);
        addstat(STAT_GAMESTARTTIME, AS_FLOAT, stat_game_starttime);
+       addstat(STAT_ROUNDSTARTTIME, AS_FLOAT, stat_round_starttime);
        addstat(STAT_ALLOW_OLDNEXBEAM, AS_INT, stat_allow_oldnexbeam);
        Nagger_Init();
  
  
        addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
  
-       if(g_ca || g_freezetag)
-       {
-               addstat(STAT_REDALIVE, AS_INT, redalive_stat);
-               addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
-               addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
-               addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
-       }
-       if(g_freezetag)
-       {
-               addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
-               addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
-       }
        // g_movementspeed hack
        addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw);
        addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed);
@@@ -1347,7 -1339,7 +1339,7 @@@ void IntermissionThink(
                && ((self.autoscreenshot > 0) && (time > self.autoscreenshot)) )
        {
                self.autoscreenshot = -1;
-               if(IS_REAL_CLIENT(self)) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"", GetMapname(), strftime(FALSE, "%s"))); }
 -              if(clienttype(self) == CLIENTTYPE_REAL) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"\n", GetMapname(), strftime(FALSE, "%s"))); }
++              if(IS_REAL_CLIENT(self)) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"\n", GetMapname(), strftime(FALSE, "%s"))); }
                return;
        }
  
@@@ -1471,11 -1463,11 +1463,11 @@@ void DumpStats(float final
  
        FOR_EACH_CLIENT(other)
        {
 -              if ((clienttype(other) == CLIENTTYPE_REAL) || (clienttype(other) == CLIENTTYPE_BOT && autocvar_sv_logscores_bots))
 +              if ((IS_REAL_CLIENT(other)) || (IS_BOT_CLIENT(other) && autocvar_sv_logscores_bots))
                {
                        s = strcat(":player:see-labels:", GetPlayerScoreString(other, 0), ":");
                        s = strcat(s, ftos(rint(time - other.jointime)), ":");
-                       if(IS_PLAYER(other) || g_arena || g_ca || g_lms)
 -                      if(other.classname == "player" || g_arena || other.caplayer == 1 || g_lms)
++                      if(IS_PLAYER(other) || g_arena || other.caplayer == 1 || g_lms)
                                s = strcat(s, ftos(other.team), ":");
                        else
                                s = strcat(s, "spectator:");
@@@ -1540,7 -1532,7 +1532,7 @@@ void FixIntermissionClient(entity e
                        if (e.weaponentity.weaponentity)
                                e.weaponentity.weaponentity.effects = EF_NODRAW;
                }
 -              if(clienttype(e) == CLIENTTYPE_REAL)
 +              if(IS_REAL_CLIENT(e))
                {
                        stuffcmd(e, "\nscr_printspeed 1000000\n");
                        s = autocvar_sv_intermission_cdtrack;
@@@ -1589,6 -1581,8 +1581,8 @@@ void NextLevel(
                PlayerStats_AddGlobalInfo(e);
        PlayerStats_Shutdown();
        WeaponStats_Shutdown();
+       
+       Kill_Notification(NOTIF_ALL, world, MSG_CENTER, 0); // kill all centerprints now
  
        if(autocvar_sv_eventlog)
                GameLogEcho(":gameover");
@@@ -1672,20 -1666,8 +1666,8 @@@ void InitiateOvertime() // ONLY call th
        tl = autocvar_timelimit;
        tl += autocvar_timelimit_overtime;
        cvar_set("timelimit", ftos(tl));
-       string minutesPlural;
-       if (autocvar_timelimit_overtime == 1)
-               minutesPlural = " ^3minute";
-       else
-               minutesPlural = " ^3minutes";
-       bcenterprint(
-               strcat(
-                       "^3Now playing ^1OVERTIME^3!\n\n^3Added ^1",
-                       ftos(autocvar_timelimit_overtime),
-                       minutesPlural,
-                       " to the game!"
-               )
-       );
+       Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60);
  }
  
  float GetWinningCode(float fraglimitreached, float equality)
@@@ -1753,10 -1735,10 +1735,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 == NUM_TEAM_1) t1 = 1;
+                       if (head.team == NUM_TEAM_2) t2 = 1;
+                       if (head.team == NUM_TEAM_3) t3 = 1;
+                       if (head.team == NUM_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, NUM_TEAM_1);
+               if (t2) SetWinners(team, NUM_TEAM_2);
+               if (t3) SetWinners(team, NUM_TEAM_3);
+               if (t4) SetWinners(team, NUM_TEAM_4);
                dprint("Have a winner, ending game.\n");
                return WINNING_YES;
        }
@@@ -1805,13 -1787,13 +1787,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 == NUM_TEAM_1)
        {
-               SetWinners(team, COLOR_TEAM2);
+               SetWinners(team, NUM_TEAM_2);
        }
        else
        {
-               SetWinners(team, COLOR_TEAM1);
+               SetWinners(team, NUM_TEAM_1);
        }
  
        entity ent;
@@@ -1937,10 -1919,10 +1919,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(NUM_TEAM_1);
+               team2_score = TeamScore_GetCompareValue(NUM_TEAM_2);
+               team3_score = TeamScore_GetCompareValue(NUM_TEAM_3);
+               team4_score = TeamScore_GetCompareValue(NUM_TEAM_4);
        }
  
        ClearWinners();
  
                        if (limit)
                        if (leaderfrags == limit - 1)
-                               Announce("1fragleft");
+                               Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_1);
                        else if (leaderfrags == limit - 2)
-                               Announce("2fragsleft");
+                               Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_2);
                        else if (leaderfrags == limit - 3)
-                               Announce("3fragsleft");
+                               Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_3);
                }
        }
  
@@@ -2056,25 -2038,25 +2038,25 @@@ float WinningCondition_RanOutOfSpawns(
  
        FOR_EACH_PLAYER(head) if(head.deadflag == DEAD_NO)
        {
-               if(head.team == COLOR_TEAM1)
+               if(head.team == NUM_TEAM_1)
                        team1_score = 1;
-               else if(head.team == COLOR_TEAM2)
+               else if(head.team == NUM_TEAM_2)
                        team2_score = 1;
-               else if(head.team == COLOR_TEAM3)
+               else if(head.team == NUM_TEAM_3)
                        team3_score = 1;
-               else if(head.team == COLOR_TEAM4)
+               else if(head.team == NUM_TEAM_4)
                        team4_score = 1;
        }
  
        for(head = world; (head = find(head, classname, "info_player_deathmatch")) != world; )
        {
-               if(head.team == COLOR_TEAM1)
+               if(head.team == NUM_TEAM_1)
                        team1_score = 1;
-               else if(head.team == COLOR_TEAM2)
+               else if(head.team == NUM_TEAM_2)
                        team2_score = 1;
-               else if(head.team == COLOR_TEAM3)
+               else if(head.team == NUM_TEAM_3)
                        team3_score = 1;
-               else if(head.team == COLOR_TEAM4)
+               else if(head.team == NUM_TEAM_4)
                        team4_score = 1;
        }
  
        {
                float t, i;
                if(team1_score)
-                       t = COLOR_TEAM1;
+                       t = NUM_TEAM_1;
                else if(team2_score)
-                       t = COLOR_TEAM2;
+                       t = NUM_TEAM_2;
                else if(team3_score)
-                       t = COLOR_TEAM3;
+                       t = NUM_TEAM_3;
                else // if(team4_score)
-                       t = COLOR_TEAM4;
+                       t = NUM_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 != NUM_TEAM_1) if(c1 >= 0) TeamScore_AddToTeam(NUM_TEAM_1, i, -1000);
+                       if(t != NUM_TEAM_2) if(c2 >= 0) TeamScore_AddToTeam(NUM_TEAM_2, i, -1000);
+                       if(t != NUM_TEAM_3) if(c3 >= 0) TeamScore_AddToTeam(NUM_TEAM_3, i, -1000);
+                       if(t != NUM_TEAM_4) if(c4 >= 0) TeamScore_AddToTeam(NUM_TEAM_4, i, -1000);
                }
  
                AddWinners(team, t);
@@@ -2191,9 -2173,9 +2173,9 @@@ void CheckRules_World(
                {
                        checkrules_suddendeathwarning = TRUE;
                        if(g_race && !g_race_qualifying)
-                               bcenterprint("^3Everyone, finish your lap! The race is over!");
+                               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_RACE_FINISHLAP);
                        else
-                               bcenterprint("^3Now playing ^1OVERTIME^3!\n\n^3Keep fragging until we have a ^1winner^3!");
+                               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_FRAG);
                }
        }
        else
@@@ -2720,7 -2702,7 +2702,7 @@@ void MapVote_Tick(
                {
                        other.health = 2342;
                        other.impulse = 0;
 -                      if(clienttype(other) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(other))
                        {
                                msg_entity = other;
                                WriteByte(MSG_ONE, SVC_FINALE);
@@@ -2832,7 -2814,7 +2814,7 @@@ void EndFrame(
        float altime;
        FOR_EACH_REALCLIENT(self)
        {
 -              if(self.classname == "spectator")
 +              if(IS_SPEC(self))
                {
                        if(self.enemy.typehitsound)
                                self.typehit_time = time;
index 6f76df693021695ef88edb597e790ed7c06ca331,fa8be67fe04bdcae11117eec41683166b2a74ae0..87d4d76bc2681751b3ae882b3e33a4b103067e7b
@@@ -32,7 -32,6 +32,6 @@@ void WarpZone_crosshair_trace(entity pl
  void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
  void() spawnpoint_use;
  string GetMapname();
- string ColoredTeamName(float t);
  
  string admin_name(void)
  {
@@@ -80,7 -79,6 +79,6 @@@ float DistributeEvenly_GetRandomized(fl
  
  #define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
  
  string STR_PLAYER = "player";
  string STR_SPECTATOR = "spectator";
  string STR_OBSERVER = "observer";
@@@ -109,15 -107,6 +107,6 @@@ string strcat1(string s) = #115; // FRI
  float logfile_open;
  float logfile;
  
- void bcenterprint(string s)
- {
-     // TODO replace by MSG_ALL (would show it to spectators too, though)?
-     entity head;
-     FOR_EACH_PLAYER(head)
-     if (IS_REAL_CLIENT(head))
-         centerprint(head, s);
- }
  void GameLogEcho(string s)
  {
      string fn;
@@@ -548,7 -537,11 +537,11 @@@ void GetCvars(float f
  
        get_cvars_f = f;
        get_cvars_s = s;
        MUTATOR_CALLHOOK(GetCvars);
+       Notification_GetCvars();
        GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
        GetCvars_handleFloat(s, f, cvar_cl_autoscreenshot, "cl_autoscreenshot");
        GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
        }
  }
  
- void backtrace(string msg)
- {
-     float dev, war;
-     dev = autocvar_developer;
-     war = autocvar_prvm_backtraceforwarnings;
-     cvar_set("developer", "1");
-     cvar_set("prvm_backtraceforwarnings", "1");
-     print("\n");
-     print("--- CUT HERE ---\nWARNING: ");
-     print(msg);
-     print("\n");
-     remove(world); // isn't there any better way to cause a backtrace?
-     print("\n--- CUT UNTIL HERE ---\n");
-     cvar_set("developer", ftos(dev));
-     cvar_set("prvm_backtraceforwarnings", ftos(war));
- }
- string Team_ColorCode(float teamid)
- {
-     if (teamid == COLOR_TEAM1)
-         return "^1";
-     else if (teamid == COLOR_TEAM2)
-         return "^4";
-     else if (teamid == COLOR_TEAM3)
-         return "^3";
-     else if (teamid == COLOR_TEAM4)
-         return "^6";
-     else
-         return "^7";
- }
- string Team_ColorName(float t)
- {
-     // fixme: Search for team entities and get their .netname's!
-     if (t == COLOR_TEAM1)
-         return "Red";
-     if (t == COLOR_TEAM2)
-         return "Blue";
-     if (t == COLOR_TEAM3)
-         return "Yellow";
-     if (t == COLOR_TEAM4)
-         return "Pink";
-     return "Neutral";
- }
- string Team_ColorNameLowerCase(float t)
- {
-     // fixme: Search for team entities and get their .netname's!
-     if (t == COLOR_TEAM1)
-         return "red";
-     if (t == COLOR_TEAM2)
-         return "blue";
-     if (t == COLOR_TEAM3)
-         return "yellow";
-     if (t == COLOR_TEAM4)
-         return "pink";
-     return "neutral";
- }
- float ColourToNumber(string team_colour)
- {
-       if (team_colour == "red")
-               return COLOR_TEAM1;
-       if (team_colour == "blue")
-               return COLOR_TEAM2;
-       if (team_colour == "yellow")
-               return COLOR_TEAM3;
-       if (team_colour == "pink")
-               return COLOR_TEAM4;
-       if (team_colour == "auto")
-               return 0;
-       return -1;
- }
- float NumberToTeamNumber(float number)
- {
-       if (number == 1)
-               return COLOR_TEAM1;
-       if (number == 2)
-               return COLOR_TEAM2;
-       if (number == 3)
-               return COLOR_TEAM3;
-       if (number == 4)
-               return COLOR_TEAM4;
-       return -1;
- }
  // decolorizes and team colors the player name when needed
  string playername(entity p)
  {
      string t;
 -    if (teamplay && !intermission_running && p.classname == "player")
 +    if (teamplay && !intermission_running && IS_PLAYER(p))
      {
          t = Team_ColorCode(p.team);
          return strcat(t, strdecolorize(p.netname));
@@@ -1096,12 -993,6 +993,6 @@@ float g_bugrigs_speed_ref
  float g_bugrigs_speed_pow;
  float g_bugrigs_steer;
  
- float g_touchexplode;
- float g_touchexplode_radius;
- float g_touchexplode_damage;
- float g_touchexplode_edgedamage;
- float g_touchexplode_force;
  float sv_autotaunt;
  float sv_taunt;
  
@@@ -1117,6 -1008,8 +1008,8 @@@ void readlevelcvars(void
                MUTATOR_ADD(mutator_spawn_near_teammate);
        if(cvar("g_physical_items"))
                MUTATOR_ADD(mutator_physical_items);
+       if(cvar("g_touchexplode"))
+               MUTATOR_ADD(mutator_touchexplode);
        if(!g_minstagib)
        {
                if(cvar("g_invincible_projectiles"))
      g_bugrigs_speed_pow = cvar("g_bugrigs_speed_pow");
      g_bugrigs_steer = cvar("g_bugrigs_steer");
  
-     g_touchexplode = cvar("g_touchexplode");
-     g_touchexplode_radius = cvar("g_touchexplode_radius");
-     g_touchexplode_damage = cvar("g_touchexplode_damage");
-     g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
-     g_touchexplode_force = cvar("g_touchexplode_force");
        sv_clones = cvar("sv_clones");
-       sv_gentle = cvar("sv_gentle");
        sv_foginterval = cvar("sv_foginterval");
        g_cloaked = cvar("g_cloaked");
      if(g_cts)
        g_warmup_allguns = cvar("g_warmup_allguns");
        g_warmup_allow_timeout = cvar("g_warmup_allow_timeout");
  
-       if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign"))
+       if ((g_race && g_race_qualifying == 2) || g_arena || g_assault || cvar("g_campaign"))
                inWarmupStage = 0; // these modes cannot work together, sorry
  
        g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
      if(!g_weapon_stay)
          g_weapon_stay = cvar("g_weapon_stay");
  
-       if not(inWarmupStage && !g_ca)
-               game_starttime = cvar("g_start_delay");
+       if not(inWarmupStage)
+               game_starttime = time + cvar("g_start_delay");
  
        readplayerstartcvars();
  }
@@@ -1291,7 -1177,7 +1177,7 @@@ float sound_allowed(float dest, entity 
              return TRUE;
      // sounds by players can be removed
      if (autocvar_bot_sound_monopoly)
 -        if (clienttype(e) == CLIENTTYPE_REAL)
 +        if (IS_REAL_CLIENT(e))
              return FALSE;
      // anything else may pass
      return TRUE;
@@@ -1518,11 -1404,6 +1404,6 @@@ void precache(
  {
      // gamemode related things
      precache_model ("models/misc/chatbubble.spr");
-     if (g_runematch)
-     {
-         precache_model ("models/runematch/curse.mdl");
-         precache_model ("models/runematch/rune.mdl");
-     }
  
  #ifdef TTURRETS_ENABLED
      if (autocvar_g_turrets)
  #endif
  }
  
- // sorry, but using \ in macros breaks line numbers
- #define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (IS_SPEC(msg_entity) && msg_entity.enemy == varname)) statement msg_entity = varname
- #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
- #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
- void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
- {
-       if (IS_REAL_CLIENT(e) && IS_CLIENT(e))
-       {
-               msg_entity = e;
-               WRITESPECTATABLE_MSG_ONE({
-                       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                       WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
-                       WriteByte(MSG_ONE, id);
-                       WriteString(MSG_ONE, s);
-                       if (id != 0 && s != "")
-                       {
-                               WriteByte(MSG_ONE, duration);
-                               WriteByte(MSG_ONE, countdown_num);
-                       }
-               });
-       }
- }
- void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
- {
-       Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
- }
  // WARNING: this kills the trace globals
  #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
  #define EXACTTRIGGER_INIT  WarpZoneLib_ExactTrigger_Init()
@@@ -2148,22 -2001,6 +2001,6 @@@ string race_readName(string map, float 
        return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
  }
  
- string race_placeName(float pos) {
-       if(floor((mod(pos, 100))/10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block
-       {
-               if(mod(pos, 10) == 1)
-                       return strcat(ftos(pos), "st");
-               else if(mod(pos, 10) == 2)
-                       return strcat(ftos(pos), "nd");
-               else if(mod(pos, 10) == 3)
-                       return strcat(ftos(pos), "rd");
-               else
-                       return strcat(ftos(pos), "th");
-       }
-       else
-               return strcat(ftos(pos), "th");
- }
  float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
  {
      float m, i;
index 5ca20ec7b55a0177981f03a4cbcddaa2909ea675,8f0bc931efd540c587ea0f1ea5f3371fb04bdd0d..bc19d88ebb7bc1899ce203c1f6c462e3bc96c46c
@@@ -20,36 -20,45 +20,45 @@@ void ctf_EventLog(string mode, float fl
                GameLogEcho(strcat(":ctf:", mode, ":", ftos(flagteam), ((actor != world) ? (strcat(":", ftos(actor.playerid))) : "")));
  }
  
string ctf_CaptureRecord(entity flag, entity player)
void ctf_CaptureRecord(entity flag, entity player)
  {
-       float cap_time, cap_record, success;
-       string cap_message = string_null, refername;
+       entity tmp_entity;
+       float cap_record = ctf_captimerecord;
+       float cap_time = (time - flag.ctf_pickuptime);
+       string refername = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"));
        
-       if((autocvar_g_ctf_captimerecord_always) || (player_count - currentbots)) 
+       // notify about shit
+       FOR_EACH_REALCLIENT(tmp_entity)
        {
-               cap_record = ctf_captimerecord;
-               cap_time = (time - flag.ctf_pickuptime);
-               refername = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"));
-               refername = ((refername == player.netname) ? "their" : strcat(refername, "^7's"));
-               if(!ctf_captimerecord) 
-                       { cap_message = strcat(" in ", ftos_decimals(cap_time, 2), " seconds"); success = TRUE; }
-               else if(cap_time < cap_record) 
-                       { cap_message = strcat(" in ", ftos_decimals(cap_time, 2), " seconds, breaking ", refername, " previous record of ", ftos_decimals(cap_record, 2), " seconds"); success = TRUE; }
-               else
-                       { cap_message = strcat(" in ", ftos_decimals(cap_time, 2), " seconds, failing to break ", refername, " record of ", ftos_decimals(cap_record, 2), " seconds"); success = FALSE; }
+               if(tmp_entity.CAPTURE_VERBOSE)
+               {
+                       if(!ctf_captimerecord) { Send_Notification(NOTIF_ONE_ONLY, tmp_entity, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_TIME_), player.netname, (cap_time * 100)); }
+                       else if(cap_time < cap_record) { Send_Notification(NOTIF_ONE_ONLY, tmp_entity, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_BROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
+                       else { Send_Notification(NOTIF_ONE_ONLY, tmp_entity, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_UNBROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
+               }
+               else { Send_Notification(NOTIF_ONE_ONLY, tmp_entity, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_), player.netname); }
+       }
  
-               if(success) 
+       // the previous notification broadcast is only sent to real clients, this will notify server log too
+       if(server_is_dedicated)
+       {
+               if(autocvar_notification_ctf_capture_verbose)
                {
-                       ctf_captimerecord = cap_time;
-                       db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time"), ftos(cap_time));
-                       db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), player.netname);
-                       write_recordmarker(player, (time - cap_time), cap_time); 
-               } 
+                       if(!ctf_captimerecord) { Local_Notification(MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_TIME_), player.netname, (cap_time * 100)); }
+                       else if(cap_time < cap_record) { Local_Notification(MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_BROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
+                       else { Local_Notification(MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_UNBROKEN_), player.netname, refername, (cap_time * 100), (cap_record * 100)); }
+               }
+               else { Local_Notification(MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_CAPTURE_), player.netname); }
        }
        
-       return cap_message;
+       // write that shit in the database
+       if((!ctf_captimerecord) || (cap_time < cap_record))
+       {
+               ctf_captimerecord = cap_time;
+               db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time"), ftos(cap_time));
+               db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), player.netname);
+               write_recordmarker(player, (time - cap_time), cap_time); 
+       } 
  }
  
  void ctf_FlagcarrierWaypoints(entity player)
@@@ -165,11 -174,7 +174,7 @@@ void ctf_CaptureShield_Update(entity pl
        float updated_status = ctf_CaptureShield_CheckStatus(player);
        if((wanted_status == player.ctf_captureshielded) && (updated_status != wanted_status)) // 0: shield only, 1: unshield only
        {
-               if(updated_status) // TODO csqc notifier for this // Samual: How?
-                       Send_CSQC_Centerprint_Generic(player, CPID_CTF_CAPTURESHIELD, "^3You are now ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Make some defensive scores before trying again.", 5, 0);
-               else
-                       Send_CSQC_Centerprint_Generic(player, CPID_CTF_CAPTURESHIELD, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed.", 5, 0);
-                       
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((updated_status) ? CENTER_CTF_CAPTURESHIELD_SHIELDED : CENTER_CTF_CAPTURESHIELD_FREE));
                player.ctf_captureshielded = updated_status;
        }
  }
@@@ -191,7 -196,7 +196,7 @@@ void ctf_CaptureShield_Touch(
        vector othermid = (other.absmin + other.absmax) * 0.5;
  
        Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * ctf_captureshield_force);
-       Send_CSQC_Centerprint_Generic(other, CPID_CTF_CAPTURESHIELD, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.", 5, 0);
+       Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED);
  }
  
  void ctf_CaptureShield_Spawn(entity flag)
@@@ -234,7 -239,7 +239,7 @@@ void ctf_Handle_Drop(entity flag, entit
        flag.ctf_status = FLAG_DROPPED;
        
        // messages and sounds
-       Send_KillNotification(player.netname, flag.netname, "", INFO_LOSTFLAG, MSG_INFO);
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_LOST_), player.netname);
        sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTN_NONE);
        ctf_EventLog("dropped", player.team, player);
  
@@@ -287,11 -292,11 +292,11 @@@ void ctf_Handle_Retrieve(entity flag, e
        FOR_EACH_REALPLAYER(tmp_player)
        {
                if(tmp_player == sender)
-                       centerprint(tmp_player, strcat("You passed the ", flag.netname, " to ", player.netname));
+                       Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PASS_SENT_), player.netname);
                else if(tmp_player == player)
-                       centerprint(tmp_player, strcat("You received the ", flag.netname, " from ", sender.netname));
+                       Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PASS_RECEIVED_), sender.netname);
                else if(!IsDifferentTeam(tmp_player, sender))
-                       centerprint(tmp_player, strcat(sender.netname, " passed the ", flag.netname, " to ", player.netname));
+                       Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PASS_OTHER_), sender.netname, player.netname);
        }
        
        // create new waypoint
@@@ -404,7 -409,8 +409,8 @@@ void ctf_Handle_Capture(entity flag, en
        if not(player) { return; } // without someone to give the reward to, we can't possibly cap
        
        // messages and sounds
-       Send_KillNotification(player.netname, enemy_flag.netname, ctf_CaptureRecord(enemy_flag, player), INFO_CAPTUREFLAG, MSG_INFO);
+       Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_2(enemy_flag, CENTER_CTF_CAPTURE_));
+       ctf_CaptureRecord(enemy_flag, player);
        sound(player, CH_TRIGGER, flag.snd_flag_capture, VOL_BASE, ATTN_NONE);
        
        switch(capturetype)
  void ctf_Handle_Return(entity flag, entity player)
  {
        // messages and sounds
-       //centerprint(player, strcat("You returned the ", flag.netname));
-       Send_KillNotification(player.netname, flag.netname, "", INFO_RETURNFLAG, MSG_INFO);
+       Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_RETURN_));
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_RETURN_), player.netname);
        sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTN_NONE);
        ctf_EventLog("return", flag.team, player);
  
@@@ -471,7 -477,6 +477,6 @@@ void ctf_Handle_Pickup(entity flag, ent
  {
        // declarations
        entity tmp_player; // temporary entity which the FOR_EACH_PLAYER loop uses to scan players
-       string verbosename; // holds the name of the player OR no name at all for printing in the centerprints
        float pickup_dropped_score; // used to calculate dropped pickup score
        
        // attach the flag to the player
        }
  
        // messages and sounds
-       Send_KillNotification (player.netname, flag.netname, "", INFO_GOTFLAG, MSG_INFO);
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_PICKUP_), player.netname);
        sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTN_NONE);
-       verbosename = ((autocvar_g_ctf_flag_pickup_verbosename) ? strcat(Team_ColorCode(player.team), "(^7", player.netname, Team_ColorCode(player.team), ") ") : "");
-       
        FOR_EACH_REALPLAYER(tmp_player)
        {
                if(tmp_player == player)
                {
-                       centerprint(tmp_player, strcat("You got the ", flag.netname, "!"));
-                       //if(ctf_stalemate) { centerprint(tmp_player, "Stalemate! Enemies can see you on radar!"); }
+                       Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, APP_TEAM_ENT_2(flag, CENTER_CTF_PICKUP_));
+                       if(ctf_stalemate) { Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER); }
+               }
+               else if(!IsDifferentTeam(tmp_player, player) && tmp_player != player)
+               {
+                       if(tmp_player.PICKUP_TEAM_VERBOSE)
+                               Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, CENTER_CTF_PICKUP_TEAM_VERBOSE, Team_ColorCode(player.team), player.netname);
+                       else
+                               Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, CENTER_CTF_PICKUP_TEAM, Team_ColorCode(player.team));
+               }
+               else if(IsDifferentTeam(tmp_player, player))
+               {
+                       if(tmp_player.PICKUP_ENEMY_VERBOSE)
+                               Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, CENTER_CTF_PICKUP_ENEMY_VERBOSE, Team_ColorCode(player.team), player.netname);
+                       else
+                               Send_Notification(NOTIF_ONE, tmp_player, MSG_CENTER, CENTER_CTF_PICKUP_ENEMY, Team_ColorCode(player.team));
                }
-               //else if(!IsDifferentTeam(tmp_player, player))
-               //      centerprint(tmp_player, strcat("Your ", Team_ColorCode(player.team), "team mate ", verbosename, "^7got the flag! Protect them!"));
-               else if(!IsDifferentTeam(tmp_player, flag))
-                       centerprint(tmp_player, strcat("The ", Team_ColorCode(player.team), "enemy ", verbosename, "^7got your flag! Retrieve it!"));
        }
        
        // scoring
@@@ -568,14 -582,14 +582,14 @@@ void ctf_CheckFlagReturn(entity flag, f
                {
                        switch(returntype)
                        {
-                               case RETURN_DROPPED: bprint("The ", flag.netname, " was dropped in the base and returned itself\n"); break;
-                               case RETURN_DAMAGE: bprint("The ", flag.netname, " was destroyed and returned to base\n"); break;
-                               case RETURN_SPEEDRUN: bprint("The ", flag.netname, " became impatient after ", ftos_decimals(ctf_captimerecord, 2), " seconds and returned itself\n"); break;
-                               case RETURN_NEEDKILL: bprint("The ", flag.netname, " fell somewhere it couldn't be reached and returned to base\n"); break;
+                               case RETURN_DROPPED: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_DROPPED_)); break;
+                               case RETURN_DAMAGE: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_DAMAGED_)); break;
+                               case RETURN_SPEEDRUN: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_SPEEDRUN_), ctf_captimerecord); break;
+                               case RETURN_NEEDKILL: Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_NEEDKILL_)); break;
                                
                                default:
                                case RETURN_TIMEOUT:
-                                       { bprint("The ", flag.netname, " has returned to base\n"); break; }
+                                       { Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(flag, INFO_CTF_FLAGRETURN_TIMEOUT_)); break; }
                        }
                        sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTN_NONE);
                        ctf_EventLog("returned", flag.team, world);
@@@ -604,8 -618,8 +618,8 @@@ void ctf_CheckStalemate(void
                        
                        switch(tmp_entity.team)
                        {
-                               case COLOR_TEAM1: ++stale_red_flags; break;
-                               case COLOR_TEAM2: ++stale_blue_flags; break;
+                               case NUM_TEAM_1: ++stale_red_flags; break;
+                               case NUM_TEAM_2: ++stale_blue_flags; break;
                        }
                }
        }
                if not(wpforenemy_announced)
                {
                        FOR_EACH_REALPLAYER(tmp_entity)
-                               if(tmp_entity.flagcarried)
-                                       centerprint(tmp_entity, "Stalemate! Enemies can now see you on radar!");
-                               else
-                                       centerprint(tmp_entity, "Stalemate! Flag carriers can now be seen by enemies on radar!");
+                               Send_Notification(NOTIF_ONE, tmp_entity, MSG_CENTER, ((tmp_entity.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER));
                        
                        wpforenemy_announced = TRUE;
                }
@@@ -814,7 -825,7 +825,7 @@@ void ctf_FlagTouch(
                else
                        return; // do nothing
        }
 -      else if(toucher.classname != "player") // The flag just touched an object, most likely the world
 +      else if not(IS_PLAYER(toucher)) // The flag just touched an object, most likely the world
        {
                if(time > self.wait) // if we haven't in a while, play a sound/effect
                {
                
                case FLAG_PASSING:
                {
 -                      if((toucher.classname == "player") && (toucher.deadflag == DEAD_NO) && (toucher != self.pass_sender))
 +                      if((IS_PLAYER(toucher)) && (toucher.deadflag == DEAD_NO) && (toucher != self.pass_sender))
                        {
                                if(IsDifferentTeam(toucher, self.pass_sender))
                                        ctf_Handle_Return(self, toucher);
@@@ -917,7 -928,7 +928,7 @@@ void ctf_RespawnFlag(entity flag
  void ctf_Reset()
  {
        if(self.owner)
 -              if(self.owner.classname == "player")
 +              if(IS_PLAYER(self.owner))
                        ctf_Handle_Throw(self.owner, world, DROP_RESET);
                        
        ctf_RespawnFlag(self);
@@@ -931,7 -942,7 +942,7 @@@ void ctf_DelayedFlagSetup(void) // call
        self.bot_basewaypoint = self.nearestwaypoint;
  
        // waypointsprites
-       WaypointSprite_SpawnFixed(((self.team == COLOR_TEAM1) ? "redbase" : "bluebase"), self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE));
+       WaypointSprite_SpawnFixed(((self.team == NUM_TEAM_1) ? "redbase" : "bluebase"), self.origin + FLAG_WAYPOINT_OFFSET, self, wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE));
        WaypointSprite_UpdateTeamRadar(self.wps_flagbase, RADARICON_FLAG, colormapPaletteColor(self.team - 1, FALSE));
  
        // captureshield setup
@@@ -948,10 -959,10 +959,10 @@@ void ctf_FlagSetup(float teamnumber, en
        flag.ctf_worldflagnext = ctf_worldflaglist; // link flag into ctf_worldflaglist
        ctf_worldflaglist = flag;
  
-       setattachment(flag, world, ""); 
+       setattachment(flag, world, "");
  
-       flag.netname = ((teamnumber) ? "^1RED^7 flag" : "^4BLUE^7 flag");
-       flag.team = ((teamnumber) ? COLOR_TEAM1 : COLOR_TEAM2); // COLOR_TEAM1: color 4 team (red) - COLOR_TEAM2: color 13 team (blue)
+       flag.netname = ((teamnumber) ? "^1REPLACETHIS^7" : "^4REPLACETHIS^7"); // ((teamnumber) ? "^1RED^7 flag" : "^4BLUE^7 flag");
+       flag.team = ((teamnumber) ? NUM_TEAM_1 : NUM_TEAM_2); // NUM_TEAM_1: color 4 team (red) - NUM_TEAM_2: color 13 team (blue)
        flag.items = ((teamnumber) ? IT_KEY2 : IT_KEY1); // IT_KEY2: gold key (redish enough) - IT_KEY1: silver key (bluish enough)
        flag.classname = "item_flag_team";
        flag.target = "###item###"; // wut?
@@@ -1762,13 -1773,14 +1773,14 @@@ MUTATOR_HOOKFUNCTION(ctf_PlayerDamage) 
                        frag_target.wps_helpme_time = time;
                        WaypointSprite_HelpMePing(frag_target.wps_flagcarrier);
                }
+               // todo: add notification for when flag carrier needs help?
        }
        return FALSE;
  }
  
  MUTATOR_HOOKFUNCTION(ctf_PlayerDies)
  {
 -      if((frag_attacker != frag_target) && (frag_attacker.classname == "player") && (frag_target.flagcarried))
 +      if((frag_attacker != frag_target) && (IS_PLAYER(frag_target)) && (frag_target.flagcarried))
        {
                PlayerTeamScore_AddScore(frag_attacker, autocvar_g_ctf_score_kill);
                PlayerScore_Add(frag_attacker, SP_CTF_FCKILLS, 1);
@@@ -1828,7 -1840,7 +1840,7 @@@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey
                        
                        while(head) // find the closest acceptable target to pass to
                        {
 -                              if(head.classname == "player" && head.deadflag == DEAD_NO)
 +                              if(IS_PLAYER(head) && head.deadflag == DEAD_NO)
                                if(head != player && !IsDifferentTeam(head, player))
                                if(!head.speedrunning && !head.vehicle)
                                {
                                        {
                                                if(autocvar_g_ctf_pass_request && !player.flagcarried && head.flagcarried) 
                                                { 
 -                                                      if(clienttype(head) == CLIENTTYPE_BOT)
 +                                                      if(IS_BOT_CLIENT(head))
                                                        {
-                                                               centerprint(player, strcat("Requesting ", head.netname, " to pass you the ", head.flagcarried.netname)); 
+                                                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
                                                                ctf_Handle_Throw(head, player, DROP_PASS);
                                                        }
                                                        else
                                                        {
-                                                               centerprint(head, strcat(player.netname, " requests you to pass the ", head.flagcarried.netname)); 
-                                                               centerprint(player, strcat("Requesting ", head.netname, " to pass you the ", head.flagcarried.netname)); 
+                                                               Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_CTF_PASS_REQUESTED, player.netname);
+                                                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
                                                        }
                                                        player.throw_antispam = time + autocvar_g_ctf_pass_wait; 
                                                        return TRUE; 
                                }
                                else
                                {
-                                       centerprint(player, strcat("Too many flag throws, throwing disabled for ", ftos(rint((player.throw_prevtime + autocvar_g_ctf_throw_punish_delay) - time)), " seconds."));
+                                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_FLAG_THROW_PUNISH, rint((player.throw_prevtime + autocvar_g_ctf_throw_punish_delay) - time));
                                        return FALSE;
                                }
                        }
@@@ -1960,8 -1972,8 +1972,8 @@@ MUTATOR_HOOKFUNCTION(ctf_AbortSpeedrun
  {
        if(self.flagcarried)
        {
-               bprint("The ", self.flagcarried.netname, " was returned to base by its carrier\n");
-               ctf_RespawnFlag(self);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_2(self.flagcarried, INFO_CTF_FLAGRETURN_ABORTRUN_));
+               ctf_RespawnFlag(self.flagcarried);
                return TRUE;
        }
        
@@@ -2008,6 -2020,14 +2020,14 @@@ MUTATOR_HOOKFUNCTION(ctf_BotRoles
        return TRUE;
  }
  
+ MUTATOR_HOOKFUNCTION(ctf_GetCvars)
+ {
+       GetCvars_handleFloat(get_cvars_s, get_cvars_f, CAPTURE_VERBOSE, "notification_ctf_capture_verbose");
+       GetCvars_handleFloat(get_cvars_s, get_cvars_f, PICKUP_TEAM_VERBOSE, "notification_ctf_pickup_team_verbose");
+       GetCvars_handleFloat(get_cvars_s, get_cvars_f, PICKUP_ENEMY_VERBOSE, "notification_ctf_pickup_enemy_verbose");
+       return TRUE;
+ }
  
  // ==========
  // Spawnfuncs
@@@ -2020,7 -2040,7 +2040,7 @@@ void spawnfunc_info_player_team1(
  {
        if(g_assault) { remove(self); return; }
        
-       self.team = COLOR_TEAM1; // red
+       self.team = NUM_TEAM_1; // red
        spawnfunc_info_player_deathmatch();
  }
  
@@@ -2032,7 -2052,7 +2052,7 @@@ void spawnfunc_info_player_team2(
  {
        if(g_assault) { remove(self); return; }
        
-       self.team = COLOR_TEAM2; // blue
+       self.team = NUM_TEAM_2; // blue
        spawnfunc_info_player_deathmatch();
  }
  
@@@ -2043,7 -2063,7 +2063,7 @@@ void spawnfunc_info_player_team3(
  {
        if(g_assault) { remove(self); return; }
        
-       self.team = COLOR_TEAM3; // yellow
+       self.team = NUM_TEAM_3; // yellow
        spawnfunc_info_player_deathmatch();
  }
  
@@@ -2055,7 -2075,7 +2075,7 @@@ void spawnfunc_info_player_team4(
  {
        if(g_assault) { remove(self); return; }
        
-       self.team = COLOR_TEAM4; // purple
+       self.team = NUM_TEAM_4; // purple
        spawnfunc_info_player_deathmatch();
  }
  
@@@ -2157,8 -2177,8 +2177,8 @@@ void ctf_DelayedInit() // Do this chec
        if(find(world, classname, "ctf_team") == world)
        {
                print("No ""ctf_team"" entities found on this map, creating them anyway.\n");
-               ctf_SpawnTeam("Red", COLOR_TEAM1 - 1);
-               ctf_SpawnTeam("Blue", COLOR_TEAM2 - 1);
+               ctf_SpawnTeam("Red", NUM_TEAM_1 - 1);
+               ctf_SpawnTeam("Blue", NUM_TEAM_2 - 1);
        }
        
        ctf_ScoreRules();
@@@ -2192,6 -2212,7 +2212,7 @@@ MUTATOR_DEFINITION(gamemode_ctf
        MUTATOR_HOOK(VehicleExit, ctf_VehicleExit, CBC_ORDER_ANY);
        MUTATOR_HOOK(AbortSpeedrun, ctf_AbortSpeedrun, CBC_ORDER_ANY);
        MUTATOR_HOOK(HavocBot_ChooseRule, ctf_BotRoles, CBC_ORDER_ANY);
+       MUTATOR_HOOK(GetCvars, ctf_GetCvars, CBC_ORDER_ANY);
        
        MUTATOR_ONADD
        {
index 2f86092b7960f6f34a3e7bdd9cf38c4d703fc5aa,98b9b40dd857c5052395bd0d7b09e8d8bfb7a0df..4a3b3b818e597b20bbd29231af5760683888f02e
@@@ -19,6 -19,7 +19,7 @@@ void dompoint_captured (
  {
        entity head;
        float old_delay, old_team, real_team;
+       string msg = "dom-neut";
  
        // now that the delay has expired, switch to the latest team to lay claim to this point
        head = self.owner;
        SUB_UseTargets ();
        self.delay = old_delay;
        self.team = old_team;
-       switch(self.goalentity.team)
+       
+       switch(self.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", "", "");
+               case NUM_TEAM_1: msg = "dom-red"; break;
+               case NUM_TEAM_2: msg = "dom-blue"; break;
+               case NUM_TEAM_3: msg = "dom-yellow"; break;
+               case NUM_TEAM_4: msg = "dom-pink"; break;
        }
  
+       WaypointSprite_UpdateSprites(self.sprite, msg, "", "");
+       
        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; )
        {
                        wait_time = head.wait;
                switch(head.goalentity.team)
                {
-                       case COLOR_TEAM1:
+                       case NUM_TEAM_1:
                                pps_red += points/wait_time;
                                break;
-                       case COLOR_TEAM2:
+                       case NUM_TEAM_2:
                                pps_blue += points/wait_time;
                                break;
-                       case COLOR_TEAM3:
+                       case NUM_TEAM_3:
                                pps_yellow += points/wait_time;
                                break;
-                       case COLOR_TEAM4:
+                       case NUM_TEAM_4:
                                pps_pink += points/wait_time;
                }
                total_pps += points/wait_time;
@@@ -186,7 -182,7 +182,7 @@@ void dompointthink(
  void dompointtouch()
  {
        entity head;
 -      if (other.classname != "player")
 +      if not(IS_PLAYER(other))
                return;
        if (other.health < 1)
                return;
@@@ -454,12 -450,12 +450,12 @@@ void dom_spawnteams(
  {
        float numteams = ((autocvar_g_domination_teams_override < 2) ? autocvar_g_domination_default_teams : autocvar_g_domination_teams_override);
  
-       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");
+       dom_spawnteam("Red", NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, "domination/claim.wav", "", "Red team has captured a control point");
+       dom_spawnteam("Blue", NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, "domination/claim.wav", "", "Blue team has captured a control point");
        if(numteams > 2)
-               dom_spawnteam("Yellow", COLOR_TEAM3-1, "models/domination/dom_yellow.md3", 0, "domination/claim.wav", "", "Yellow team has captured a control point");
+               dom_spawnteam("Yellow", NUM_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", COLOR_TEAM4-1, "models/domination/dom_pink.md3", 0, "domination/claim.wav", "", "Pink team has captured a control point");
+               dom_spawnteam("Pink", NUM_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, "", "", "");
  }
  
index 4014b140395fdf4ca4915e49759b9dddea3c292c,980a9b20d9aff6c37ac55d344404a4bf9c821b5e..79ce5e2e14f47dfa67283af4980df1da83837c55
- void freezetag_Initialize()
+ .float freezetag_frozen_time;
+ .float freezetag_frozen_timeout;
+ .float freezetag_revive_progress;
+ .entity freezetag_ice;
+ #define ICE_MAX_ALPHA 1
+ #define ICE_MIN_ALPHA 0.1
+ float freezetag_teams;
+ void freezetag_count_alive_players()
  {
-       precache_model("models/ice/ice.md3");
-       warmup = time + autocvar_g_start_delay + autocvar_g_freezetag_warmup;
-       ScoreRules_freezetag();
+       entity e;
+       total_players = redalive = bluealive = yellowalive = pinkalive = 0;
+       FOR_EACH_PLAYER(e) {
+               if(e.team == NUM_TEAM_1 && e.health >= 1)
+               {
+                       ++total_players;
+                       if (!e.freezetag_frozen) ++redalive;
+               }
+               else if(e.team == NUM_TEAM_2 && e.health >= 1)
+               {
+                       ++total_players;
+                       if (!e.freezetag_frozen) ++bluealive;
+               }
+               else if(e.team == NUM_TEAM_3 && e.health >= 1)
+               {
+                       ++total_players;
+                       if (!e.freezetag_frozen) ++yellowalive;
+               }
+               else if(e.team == NUM_TEAM_4 && e.health >= 1)
+               {
+                       ++total_players;
+                       if (!e.freezetag_frozen) ++pinkalive;
+               }
+       }
+       FOR_EACH_REALCLIENT(e) {
+               e.redalive_stat = redalive;
+               e.bluealive_stat = bluealive;
+               e.yellowalive_stat = yellowalive;
+               e.pinkalive_stat = pinkalive;
+       }
  }
+ #define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
+ #define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == freezetag_teams)
  
- void freezetag_CheckWinner()
+ float prev_total_players;
+ float freezetag_CheckTeams()
  {
-       if(time <= game_starttime) // game didn't even start yet! nobody can win in that case.
-               return;
+       if(FREEZETAG_ALIVE_TEAMS_OK())
+       {
+               if(prev_total_players > 0)
+                       Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS);
+               prev_total_players = -1;
+               return 1;
+       }
+       if(prev_total_players != total_players)
+       {
+               float p1 = 0, p2 = 0, p3 = 0, p4 = 0;
+               if(!redalive) p1 = NUM_TEAM_1;
+               if(!bluealive) p2 = NUM_TEAM_2;
+               if(freezetag_teams >= 3)
+               if(!yellowalive) p3 = NUM_TEAM_3;
+               if(freezetag_teams >= 4)
+               if(!pinkalive) p4 = NUM_TEAM_4;
+               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_TEAMS, p1, p2, p3, p4);
+               prev_total_players = total_players;
+       }
+       return 0;
+ }
  
-       if(next_round || (time > warmup - autocvar_g_freezetag_warmup && time < warmup))
-               return; // already waiting for next round to start
+ float freezetag_getWinnerTeam()
+ {
+       float winner_team = 0;
+       if(redalive >= 1)
+               winner_team = NUM_TEAM_1;
+       if(bluealive >= 1)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_2;
+       }
+       if(yellowalive >= 1)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_3;
+       }
+       if(pinkalive >= 1)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_4;
+       }
+       if(winner_team)
+               return winner_team;
+       return -1; // no player left
+ }
  
-       if((redalive >= 1 && bluealive >= 1)
-               || (redalive >= 1 && yellowalive >= 1)
-               || (redalive >= 1 && pinkalive >= 1)
-               || (bluealive >= 1 && yellowalive >= 1)
-               || (bluealive >= 1 && pinkalive >= 1)
-               || (yellowalive >= 1 && pinkalive >= 1))
-               return; // we still have active players on two or more teams, nobody won yet
+ float freezetag_CheckWinner()
+ {
+       entity e;
+       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+       {
+               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER);
+               FOR_EACH_PLAYER(e)
+                       e.freezetag_frozen_timeout = 0;
+               round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+               return 1;
+       }
  
-       entity e, winner;
-       string teamname;
-       winner = world;
+       if(FREEZETAG_ALIVE_TEAMS() > 1)
+               return 0;
  
-       FOR_EACH_PLAYER(e)
+       float winner_team;
+       winner_team = freezetag_getWinnerTeam();
+       if(winner_team > 0)
        {
-               if(e.freezetag_frozen == 0 && e.health >= 1) // here's one player from the winning team... good
-               {
-                       winner = e;
-                       break; // break, we found the winner
-               }
+               Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner_team, CENTER_ROUND_TEAM_WIN_));
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner_team, INFO_ROUND_TEAM_WIN_));
+               TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
        }
-       if(winner != world) // just in case a winner wasn't found
+       else if(winner_team == -1)
        {
-               if(winner.team == COLOR_TEAM1)
-                       teamname = "^1Red Team";
-               else if(winner.team == COLOR_TEAM2)
-                       teamname = "^4Blue Team";
-               else if(winner.team == COLOR_TEAM3)
-                       teamname = "^3Yellow Team";
-               else
-                       teamname = "^6Pink Team";
-               FOR_EACH_PLAYER(e) {
-                       centerprint(e, strcat(teamname, "^5 wins the round, all other teams were frozen.\n"));
-               }
-               bprint(teamname, "^5 wins the round since all the other teams were frozen.\n");
-               TeamScore_AddToTeam(winner.team, ST_SCORE, +1);
+               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
        }
  
-       next_round = time + 5;
+       FOR_EACH_PLAYER(e)
+               e.freezetag_frozen_timeout = 0;
+       round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+       return 1;
  }
  
  // this is needed to allow the player to turn his view around (fixangle can't
@@@ -63,13 -137,36 +137,36 @@@ void freezetag_Ice_Think(
        self.nextthink = time;
  }
  
+ void freezetag_Add_Score(entity attacker)
+ {
+       if(attacker == self)
+       {
+               // you froze your own dumb self
+               // counted as "suicide" already
+               PlayerScore_Add(self, SP_SCORE, -1);
+       }
+       else if(IS_PLAYER(attacker))
+       {
+               // got frozen by an enemy
+               // counted as "kill" and "death" already
+               PlayerScore_Add(self, SP_SCORE, -1);
+               PlayerScore_Add(attacker, SP_SCORE, +1);
+       }
+       // else nothing - got frozen by the game type rules themselves
+ }
  void freezetag_Freeze(entity attacker)
  {
        if(self.freezetag_frozen)
                return;
        self.freezetag_frozen = 1;
+       self.freezetag_frozen_time = time;
        self.freezetag_revive_progress = 0;
        self.health = 1;
+       if(autocvar_g_freezetag_frozen_maxtime > 0)
+               self.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
+       freezetag_count_alive_players();
  
        entity ice;
        ice = spawn();
        ice.think = freezetag_Ice_Think;
        ice.nextthink = time;
        ice.frame = floor(random() * 21); // ice model has 20 different looking frames
+       ice.alpha = ICE_MAX_ALPHA;
+       ice.colormod = Team_ColorRGB(self.team);
+       ice.glowmod = ice.colormod;
        setmodel(ice, "models/ice/ice.md3");
  
-       entity oldself;
-       oldself = self;
-       self = ice;
-       freezetag_Ice_Think();
-       self = oldself;
+       self.freezetag_ice = ice;
  
        RemoveGrapplingHook(self);
  
        // add waypoint
        WaypointSprite_Spawn("freezetag_frozen", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1');
  
-       if(attacker == self)
-       {
-               // you froze your own dumb self
-               // counted as "suicide" already
-               PlayerScore_Add(self, SP_SCORE, -1);
-       }
-       else if(IS_PLAYER(attacker))
-       {
-               // got frozen by an enemy
-               // counted as "kill" and "death" already
-               PlayerScore_Add(self, SP_SCORE, -1);
-               PlayerScore_Add(attacker, SP_SCORE, +1);
-       }
-       else
-       {
-               // nothing - got frozen by the game type rules themselves
-       }
+       freezetag_Add_Score(attacker);
  }
  
  void freezetag_Unfreeze(entity attacker)
  {
        self.freezetag_frozen = 0;
+       self.freezetag_frozen_time = 0;
+       self.freezetag_frozen_timeout = 0;
        self.freezetag_revive_progress = 0;
-       self.health = autocvar_g_balance_health_start;
  
-       // remove the ice block
-       entity ice;
-       for(ice = world; (ice = find(ice, classname, "freezetag_ice")); ) if(ice.owner == self)
-       {
-               remove(ice);
-               break;
-       }
+       remove(self.freezetag_ice);
+       self.freezetag_ice = world;
  
-       // remove waypoint
        if(self.waypointsprite_attached)
                WaypointSprite_Kill(self.waypointsprite_attached);
  }
@@@ -240,112 -315,151 +315,151 @@@ void havocbot_role_ft_freeing(
  
  MUTATOR_HOOKFUNCTION(freezetag_RemovePlayer)
  {
-       if(self.freezetag_frozen == 0 && self.health >= 1)
-       {
-               if(self.team == COLOR_TEAM1)
-                       --redalive;
-               else if(self.team == COLOR_TEAM2)
-                       --bluealive;
-               else if(self.team == COLOR_TEAM3)
-                       --yellowalive;
-               else if(self.team == COLOR_TEAM4)
-                       --pinkalive;
-               --totalalive;
-       }
-       if(total_players > 2) // only check for winners if we had more than two players (one of them left, don't let the other player win just because of that)
-               freezetag_CheckWinner();
+       self.health = 0; // neccessary to update correctly alive stats
        freezetag_Unfreeze(world);
+       freezetag_count_alive_players();
        return 1;
  }
  
  MUTATOR_HOOKFUNCTION(freezetag_PlayerDies)
  {
-       if(self.freezetag_frozen == 0)
+       if(round_handler_IsActive())
+       if(round_handler_CountdownRunning())
        {
-               if(self.team == COLOR_TEAM1)
-                       --redalive;
-               else if(self.team == COLOR_TEAM2)
-                       --bluealive;
-               else if(self.team == COLOR_TEAM3)
-                       --yellowalive;
-               else if(self.team == COLOR_TEAM4)
-                       --pinkalive;
-               --totalalive;
+               if(self.freezetag_frozen)
+                       freezetag_Unfreeze(world);
+               freezetag_count_alive_players();
+               return 1; // let the player die so that he can respawn whenever he wants
+       }
  
-               freezetag_Freeze(frag_attacker);
+       // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
+       // you succeed changing team through the menu: you both really die (gibbing) and get frozen
+       if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
+               || frag_deathtype == DEATH_TEAMCHANGE || frag_deathtype == DEATH_AUTOTEAMCHANGE)
+       {
+               // let the player die, he will be automatically frozen when he respawns
+               if(!self.freezetag_frozen)
+               {
+                       freezetag_Add_Score(frag_attacker);
+                       freezetag_count_alive_players();
+               }
+               else
+                       freezetag_Unfreeze(world); // remove ice
+               self.freezetag_frozen_timeout = -2; // freeze on respawn
+               return 1;
        }
  
+       if(self.freezetag_frozen)
+               return 1;
+       freezetag_Freeze(frag_attacker);
        if(frag_attacker == frag_target || frag_attacker == world)
        {
 -              if(frag_target.classname == STR_PLAYER)
 +              if(IS_PLAYER(frag_target))
-                       centerprint(frag_target, "^1You froze yourself.\n");
-               bprint("^7", frag_target.netname, "^1 froze himself.\n");
+                       Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_SELF);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_SELF, frag_target.netname);
        }
        else
        {
 -              if(frag_target.classname == STR_PLAYER)
 +              if(IS_PLAYER(frag_target))
-                       centerprint(frag_target, strcat("^1You were frozen by ^7", frag_attacker.netname, ".\n"));
+                       Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_FROZEN, frag_attacker.netname);
 -              if(frag_attacker.classname == STR_PLAYER)
 +              if(IS_PLAYER(frag_attacker))
-                       centerprint(frag_attacker, strcat("^2You froze ^7", frag_target.netname, ".\n"));
-               bprint("^7", frag_target.netname, "^1 was frozen by ^7", frag_attacker.netname, ".\n");
+                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_FREEZETAG_FREEZE, frag_target.netname);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname);
        }
  
        frag_target.health = 1; // "respawn" the player :P
  
-       freezetag_CheckWinner();
        return 1;
  }
  
  MUTATOR_HOOKFUNCTION(freezetag_PlayerSpawn)
  {
-       freezetag_Unfreeze(world); // start by making sure that all ice blocks are removed
+       if(self.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
+               return 1; // do nothing, round is starting right now
  
-       if(total_players == 1 && time > game_starttime) // only one player active on server, start a new match immediately
-       if(!next_round && warmup && (time < warmup - autocvar_g_freezetag_warmup || time > warmup)) // not awaiting next round
+       if(self.freezetag_frozen_timeout == -2) // player was dead
        {
-               next_round = time;
+               freezetag_Freeze(world);
                return 1;
        }
-       if(warmup && time > warmup) // spawn too late, freeze player
+       freezetag_count_alive_players();
+       if(round_handler_IsActive())
+       if(round_handler_IsRoundStarted())
        {
-               centerprint(self, "^1You spawned after the round started, you'll spawn as frozen.\n");
+               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_SPAWN_LATE);
                freezetag_Freeze(world);
        }
  
        return 1;
  }
  
+ MUTATOR_HOOKFUNCTION(freezetag_reset_map_players)
+ {
+       FOR_EACH_PLAYER(self)
+       {
+               if (self.freezetag_frozen)
+                       freezetag_Unfreeze(world);
+               self.freezetag_frozen_timeout = -1;
+               PutClientInServer();
+               self.freezetag_frozen_timeout = 0;
+       }
+       freezetag_count_alive_players();
+       return 1;
+ }
  MUTATOR_HOOKFUNCTION(freezetag_GiveFragsForKill)
  {
        frag_score = 0; // no frags counted in Freeze Tag
        return 1;
  }
  
+ .float reviving; // temp var
  MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink)
  {
        float n;
-       vector revive_extra_size;
  
-       revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
+       if(gameover)
+               return 1;
+       if(self.freezetag_frozen)
+       {
+               // keep health = 1
+               self.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
+       }
+       if(round_handler_IsActive())
+       if(!round_handler_IsRoundStarted())
+               return 1;
  
        entity o;
        o = world;
-       n = 0;
-       FOR_EACH_PLAYER(other) if(self != other)
+       if(self.freezetag_frozen_timeout > 0 && time < self.freezetag_frozen_timeout)
+               self.freezetag_ice.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (self.freezetag_frozen_timeout - time) / (self.freezetag_frozen_timeout - self.freezetag_frozen_time);
+       if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
+               n = -1;
+       else
        {
-               if(other.freezetag_frozen == 0)
+               vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
+               n = 0;
+               FOR_EACH_PLAYER(other) if(self != other)
                {
-                       if(other.team == self.team)
+                       if(other.freezetag_frozen == 0)
                        {
-                               if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
+                               if(other.team == self.team)
                                {
-                                       if(!o)
-                                               o = other;
-                                       ++n;
+                                       if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
+                                       {
+                                               if(!o)
+                                                       o = other;
+                                               if(self.freezetag_frozen)
+                                                       other.reviving = TRUE;
+                                               ++n;
+                                       }
                                }
                        }
                }
  
        if(n && self.freezetag_frozen) // OK, there is at least one teammate reviving us
        {
-               self.freezetag_revive_progress = bound(0, self.freezetag_revive_progress + frametime * autocvar_g_freezetag_revive_speed, 1);
+               self.freezetag_revive_progress = bound(0, self.freezetag_revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
                self.health = max(1, self.freezetag_revive_progress * autocvar_g_balance_health_start);
  
                if(self.freezetag_revive_progress >= 1)
                {
                        freezetag_Unfreeze(self);
+                       freezetag_count_alive_players();
+                       if(n == -1)
+                       {
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, autocvar_g_freezetag_frozen_maxtime);
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, self.netname, autocvar_g_freezetag_frozen_maxtime);
+                               return 1;
+                       }
  
                        // EVERY team mate nearby gets a point (even if multiple!)
-                       FOR_EACH_PLAYER(other) if(self != other)
+                       FOR_EACH_PLAYER(other)
                        {
-                               if(other.freezetag_frozen == 0)
+                               if(other.reviving)
                                {
-                                       if(other.team == self.team)
-                                       {
-                                               if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
-                                               {
-                                                       PlayerScore_Add(other, SP_FREEZETAG_REVIVALS, +1);
-                                                       PlayerScore_Add(other, SP_SCORE, +1);
-                                               }
-                                       }
+                                       PlayerScore_Add(other, SP_FREEZETAG_REVIVALS, +1);
+                                       PlayerScore_Add(other, SP_SCORE, +1);
                                }
                        }
  
-                       if(n > 1)
-                               centerprint(self, strcat("^5You were revived by ^7", o.netname, "^5 et al.\n"));
-                       else
-                               centerprint(self, strcat("^5You were revived by ^7", o.netname, "^5.\n"));
-                       centerprint(o, strcat("^5You revived ^7", self.netname, "^5.\n"));
-                       if(n > 1)
-                               bprint("^7", o.netname, "^5 et al revived ^7", self.netname, "^5.\n");
-                       else
-                               bprint("^7", o.netname, "^5 revived ^7", self.netname, "^5.\n");
+                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
+                       Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname);
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED, self.netname, o.netname);
                }
  
-               // now find EVERY teammate within reviving radius, set their revive_progress values correct
-               FOR_EACH_PLAYER(other) if(self != other)
+               FOR_EACH_PLAYER(other)
                {
-                       if(other.freezetag_frozen == 0)
+                       if(other.reviving)
                        {
-                               if(other.team == self.team)
-                               {
-                                       if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
-                                               other.freezetag_revive_progress = self.freezetag_revive_progress;
-                               }
+                               other.freezetag_revive_progress = self.freezetag_revive_progress;
+                               other.reviving = FALSE;
                        }
                }
        }
@@@ -425,15 -531,12 +531,12 @@@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPh
  
  MUTATOR_HOOKFUNCTION(freezetag_PlayerDamage_Calculate)
  {
-     if(g_freezetag)
-     {
-         if(frag_target.freezetag_frozen == 1 && frag_deathtype != DEATH_HURTTRIGGER)
-         {
-             frag_damage = 0;
-             frag_force = frag_force * autocvar_g_freezetag_frozen_force;
-         }
-     }
-     return 1;
+       if(frag_target.freezetag_frozen && frag_deathtype != DEATH_HURTTRIGGER)
+       {
+               frag_damage = 0;
+               frag_force = frag_force * autocvar_g_freezetag_frozen_force;
+       }
+       return 1;
  }
  
  MUTATOR_HOOKFUNCTION(freezetag_ForbidThrowCurrentWeapon)
        return 0;
  }
  
+ MUTATOR_HOOKFUNCTION(freezetag_ItemTouch)
+ {
+       if (other.freezetag_frozen)
+               return 1;
+       return 0;
+ }
  MUTATOR_HOOKFUNCTION(freezetag_BotRoles)
  {
        if not(self.deadflag)
                else
                        self.havocbot_role = havocbot_role_ft_offense;
        }
-       
        return TRUE;
  }
  
+ MUTATOR_HOOKFUNCTION(freezetag_SpectateCopy)
+ {
+       self.freezetag_frozen = other.freezetag_frozen;
+       self.freezetag_revive_progress = other.freezetag_revive_progress;
+       return 0;
+ }
+ MUTATOR_HOOKFUNCTION(freezetag_GetTeamCount)
+ {
+       freezetag_teams = autocvar_g_freezetag_teams_override;
+       if(freezetag_teams < 2)
+               freezetag_teams = autocvar_g_freezetag_teams;
+       freezetag_teams = bound(2, freezetag_teams, 4);
+       ret_float = freezetag_teams;
+       return 0;
+ }
+ void freezetag_Initialize()
+ {
+       precache_model("models/ice/ice.md3");
+       ScoreRules_freezetag();
+       round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
+       round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+       addstat(STAT_REDALIVE, AS_INT, redalive_stat);
+       addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
+       addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
+       addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
+       addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
+       addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
+ }
  MUTATOR_DEFINITION(gamemode_freezetag)
  {
        MUTATOR_HOOK(MakePlayerObserver, freezetag_RemovePlayer, CBC_ORDER_ANY);
        MUTATOR_HOOK(ClientDisconnect, freezetag_RemovePlayer, CBC_ORDER_ANY);
        MUTATOR_HOOK(PlayerDies, freezetag_PlayerDies, CBC_ORDER_ANY);
        MUTATOR_HOOK(PlayerSpawn, freezetag_PlayerSpawn, CBC_ORDER_ANY);
+       MUTATOR_HOOK(reset_map_players, freezetag_reset_map_players, CBC_ORDER_ANY);
        MUTATOR_HOOK(GiveFragsForKill, freezetag_GiveFragsForKill, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerPreThink, freezetag_PlayerPreThink, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerPhysics, freezetag_PlayerPhysics, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerDamage_Calculate, freezetag_PlayerDamage_Calculate, CBC_ORDER_ANY);
-       MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_FIRST); //first, last or any? dunno.
+       MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_ANY);
+       MUTATOR_HOOK(ItemTouch, freezetag_ItemTouch, CBC_ORDER_ANY);
        MUTATOR_HOOK(HavocBot_ChooseRule, freezetag_BotRoles, CBC_ORDER_ANY);
+       MUTATOR_HOOK(SpectateCopy, freezetag_SpectateCopy, CBC_ORDER_ANY);
+       MUTATOR_HOOK(GetTeamCount, freezetag_GetTeamCount, CBC_ORDER_EXCLUSIVE);
  
        MUTATOR_ONADD
        {
index 4611c60fe1ae768c404df2ff9f5446084a10eb67,7a16cd62b2716f62d0115916ff4a3f09cee06350..f92afab658a81d0eee8d51ce55e2cfdf6bc64947
@@@ -6,7 -6,7 +6,7 @@@
  float ka_ballcarrier_waypointsprite_visible_for_player(entity e) // runs on waypoints which are attached to ballcarriers, updates once per frame 
  {
        if(e.ballcarried)
 -              if(other.classname == "spectator"
 +              if(IS_SPEC(other)
                        return FALSE; // we don't want spectators of the ballcarrier to see the attached waypoint on the top of their screen
                
        // TODO: Make the ballcarrier lack a waypointsprite whenever they have the invisibility powerup
@@@ -71,7 -71,7 +71,7 @@@ void ka_TouchEvent() // runs any time t
                return;
        }
        if(other.deadflag != DEAD_NO) { return; }
 -      if(other.classname != "player"
 +      if not(IS_PLAYER(other)
        {  // The ball just touched an object, most likely the world
                pointparticles(particleeffectnum("kaball_sparks"), self.origin, '0 0 0', 1);
                sound(self, CH_TRIGGER, "keepaway/touch.wav", VOL_BASE, ATTN_NORM);
        
        // messages and sounds
        ka_EventLog("pickup", other);
-       Send_KillNotification(other.netname, "", "", KA_PICKUPBALL, MSG_KA);
-       WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
-       WriteString(MSG_BROADCAST, strcat(other.netname, "^7 has picked up the ball!"));
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_KEEPAWAY_PICKUP, other.netname);
+       Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEEPAWAY_PICKUP, other.netname);
        sound(self.owner, CH_TRIGGER, "keepaway/pickedup.wav", VOL_BASE, ATTN_NONE); // ATTN_NONE (it's a sound intended to be heard anywhere) 
        
        // scoring
@@@ -144,9 -143,8 +143,8 @@@ void ka_DropEvent(entity plyr) // runs 
  
        // messages and sounds
        ka_EventLog("dropped", plyr);
-       Send_KillNotification(plyr.netname, "", "", KA_DROPBALL, MSG_KA);
-       WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
-       WriteString(MSG_BROADCAST, strcat(plyr.netname, "^7 has dropped the ball!"));
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_KEEPAWAY_DROPPED, plyr.netname);
+       Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEEPAWAY_DROPPED, plyr.netname);
        sound(other, CH_TRIGGER, "keepaway/dropped.wav", VOL_BASE, ATTN_NONE);  // ATTN_NONE (it's a sound intended to be heard anywhere) 
        
        // scoring
  
  void ka_Reset() // used to clear the ballcarrier whenever the match switches from warmup to normal
  {
 -      if((self.owner) && (self.owner.classname == "player"))
 +      if((self.owner) && (IS_PLAYER(self.owner)))
                ka_DropEvent(self.owner);
  
        ka_RespawnBall();
@@@ -245,7 -243,7 +243,7 @@@ void havocbot_role_ka_collector(
  
  MUTATOR_HOOKFUNCTION(ka_Scoring)
  {
 -      if((frag_attacker != frag_target) && (frag_attacker.classname == "player"))
 +      if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)))
        {
                if(frag_target.ballcarried) { // add to amount of times killing carrier
                        PlayerScore_Add(frag_attacker, SP_KEEPAWAY_CARRIERKILLS, 1);
                }
                else if(!frag_attacker.ballcarried)
                        if(autocvar_g_keepaway_noncarrier_warn)
-                               centerprint(frag_attacker, "Killing people while you don't have the ball gives no points!");
+                               Send_Notification(NOTIF_ONE_ONLY, frag_attacker, MSG_CENTER, CENTER_KEEPAWAY_WARN);
  
                if(frag_attacker.ballcarried) // add to amount of kills while ballcarrier
                        PlayerScore_Add(frag_attacker, SP_SCORE, autocvar_g_keepaway_score_killac);
index 6724cd8f16152d6bee55bd09fe23469a008b95e0,13a06c367c72ca7084bb4d5d7301fa8affe73f58..99e7a3eae1cfd5666505e32237180d6d08549bf0
@@@ -20,7 -20,6 +20,6 @@@ vector KH_KEY_MIN = '-10 -10 -46'
  vector KH_KEY_MAX = '10 10 3';
  float KH_KEY_BRIGHTNESS = 2;
  
- string kh_Controller_Waitmsg;
  float kh_no_radar_circles;
  
  // kh_state
@@@ -40,10 -39,10 +39,10 @@@ float kh_keystatus[17]
  
  float kh_Team_ByID(float t)
  {
-       if(t == 0) return COLOR_TEAM1;
-       if(t == 1) return COLOR_TEAM2;
-       if(t == 2) return COLOR_TEAM3;
-       if(t == 3) return COLOR_TEAM4;
+       if(t == 0) return NUM_TEAM_1;
+       if(t == 1) return NUM_TEAM_2;
+       if(t == 2) return NUM_TEAM_3;
+       if(t == 3) return NUM_TEAM_4;
        return 0;
  }
  
@@@ -70,7 -69,7 +69,7 @@@ float kh_key_dropped, kh_key_carried
  
  float kh_KeyCarrier_waypointsprite_visible_for_player(entity e)  // runs all the time
  {
 -      if(e.classname != "player" || self.team != e.team)
 +      if(!IS_PLAYER(e) || self.team != e.team)
                if(!kh_tracking_enabled)
                        return FALSE;
  
@@@ -122,50 -121,20 +121,20 @@@ void kh_update_state(
  
  
  var kh_Think_t kh_Controller_Thinkfunc;
- void kh_Controller_SetThink(float t, string msg, float centerprint_duration, kh_Think_t func)  // runs occasionaly
+ void kh_Controller_SetThink(float t, kh_Think_t func)  // runs occasionaly
  {
        kh_Controller_Thinkfunc = func;
        kh_controller.cnt = ceil(t);
-       if(kh_Controller_Waitmsg != "")
-               strunzone(kh_Controller_Waitmsg);
-       if(msg == "")
-               kh_Controller_Waitmsg = "";
-       else
-       {
-               kh_controller.kh_cp_duration = centerprint_duration;
-               kh_Controller_Waitmsg = strzone(msg);
-       }
        if(t == 0)
                kh_controller.nextthink = time; // force
  }
- void kh_Controller_SetThink_NoMsg(float t, kh_Think_t func)  // runs occasionaly
- {
-       kh_Controller_SetThink(t, "", 0, func);
- }
+ void kh_WaitForPlayers();
  void kh_Controller_Think()  // called a lot
  {
-       entity e;
        if(intermission_running)
                return;
        if(self.cnt > 0)
-       {
-               if(kh_Controller_Waitmsg != "")
-               {
-                       string s;
-                       if(substring(kh_Controller_Waitmsg, strlen(kh_Controller_Waitmsg)-1, 1) == " ")
-                               s = strcat(kh_Controller_Waitmsg, ftos(self.cnt));
-                       else
-                               s = kh_Controller_Waitmsg;
-                       //dprint(s, "\n");
-                       FOR_EACH_PLAYER(e)
-                               if(IS_REAL_CLIENT(e))
-                                       Send_CSQC_Centerprint_Generic(e, CPID_KH_MSG, s, self.kh_cp_duration, 0);
-               }
-               self.cnt -= 1;
-       }
+       { if(self.think != kh_WaitForPlayers) { self.cnt -= 1; } }
        else if(self.cnt == 0)
        {
                self.cnt -= 1;
@@@ -361,13 -330,13 +330,13 @@@ void kh_Key_AssignTo(entity key, entit
                        WaypointSprite_AttachCarrier("", player, RADARICON_FLAGCARRIER, colormapPaletteColor(player.team - 1, 0));
                        player.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = kh_KeyCarrier_waypointsprite_visible_for_player;
                        WaypointSprite_UpdateRule(player.waypointsprite_attachedforcarrier, player.team, SPRITERULE_TEAMPLAY);
-                       if(player.team == COLOR_TEAM1)
+                       if(player.team == NUM_TEAM_1)
                                WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, "keycarrier-red", "keycarrier-friend", "keycarrier-red");
-                       else if(player.team == COLOR_TEAM2)
+                       else if(player.team == NUM_TEAM_2)
                                WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, "keycarrier-blue", "keycarrier-friend", "keycarrier-blue");
-                       else if(player.team == COLOR_TEAM3)
+                       else if(player.team == NUM_TEAM_3)
                                WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, "keycarrier-yellow", "keycarrier-friend", "keycarrier-yellow");
-                       else if(player.team == COLOR_TEAM4)
+                       else if(player.team == NUM_TEAM_4)
                                WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, "keycarrier-pink", "keycarrier-friend", "keycarrier-pink");
                        if(!kh_no_radar_circles)
                                WaypointSprite_Ping(player.waypointsprite_attachedforcarrier);
@@@ -422,7 -391,7 +391,7 @@@ void kh_Key_Damage(entity inflictor, en
        if(vlen(force) <= 0)
                return;
        if(time > self.pushltime)
 -              if(attacker.classname == "player")
 +              if(IS_PLAYER(attacker))
                        self.team = attacker.team;
  }
  
@@@ -436,7 -405,7 +405,7 @@@ void kh_Key_Collect(entity key, entity 
                PlayerScore_Add(player, SP_KH_PICKUPS, 1);
        }
        key.kh_dropperteam = 0;
-       bprint(player.netname, "^7 picked up the ", key.netname, "\n");
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(key, INFO_KEYHUNT_PICKUP_), player.netname);
  
        kh_Key_AssignTo(key, player); // this also updates .kh_state
  }
@@@ -457,7 -426,7 +426,7 @@@ void kh_Key_Touch()  // runs many, man
                // maybe start a shorter countdown?
        }
  
 -      if(other.classname != "player")
 +      if not(IS_PLAYER(other))
                return;
        if(other.deadflag != DEAD_NO)
                return;
@@@ -510,10 -479,11 +479,11 @@@ void kh_FinishRound()  // runs when a t
                kh_Key_Remove(key);
        kh_no_radar_circles = FALSE;
  
-       kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, "Round starts in ", 1, kh_StartRound);
+       Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEYHUNT_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round);
+       kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, kh_StartRound);
  }
  
- void kh_WinnerTeam(float teem)  // runs when a team wins
+ void kh_WinnerTeam(float teem)  // runs when a team wins // Samual: Teem?.... TEEM?!?! what the fuck is wrong with you people
  {
        // all key carriers get some points
        vector firstorigin, lastorigin, midpoint;
        }
  
        first = TRUE;
+       string keyowner = "";
        FOR_EACH_KH_KEY(key)
                if(key.owner.kh_next == key)
                {
                        if(!first)
-                               bprint("^7, ");
-                       bprint(key.owner.netname);
+                               keyowner = strcat(keyowner, ", ");
+                       keyowner = key.owner.netname;
                        first = FALSE;
                }
-       bprint("^7 captured the keys for the ", ColoredTeamName(teem), "\n");
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(teem, INFO_KEYHUNT_CAPTURE_), keyowner);
  
        first = TRUE;
        midpoint = '0 0 0';
                te_lightning2(world, lastorigin, firstorigin);
        }
        midpoint = midpoint * (1 / kh_teams);
-       te_customflash(midpoint, 1000, 1, TeamColor(teem) * 0.5 + '0.5 0.5 0.5');  // make the color >=0.5 in each component
+       te_customflash(midpoint, 1000, 1, Team_ColorRGB(teem) * 0.5 + '0.5 0.5 0.5');  // make the color >=0.5 in each component
  
        play2all(kh_sound_capture);
        kh_FinishRound();
@@@ -583,7 -555,7 +555,7 @@@ void kh_LoserTeam(float teem, entity lo
        attacker = world;
        if(lostkey.pusher)
                if(lostkey.pusher.team != teem)
 -                      if(lostkey.pusher.classname == "player")
 +                      if(IS_PLAYER(lostkey.pusher))
                                attacker = lostkey.pusher;
  
        players = keys = 0;
                        // don't actually GIVE him the -nn points, just log
                kh_Scores_Event(attacker, world, "push", autocvar_g_balance_keyhunt_score_push, 0);
                PlayerScore_Add(attacker, SP_KH_PUSHES, 1);
-               centerprint(attacker, "Your push is the best!");
-               bprint("The ", ColoredTeamName(teem), "^7 could not take care of the ", lostkey.netname, "^7 when ", attacker.netname, "^7 came\n");
+               //centerprint(attacker, "Your push is the best!"); // does this really need to exist?
        }
        else
        {
  
                        --j;
                }
-               bprint("The ", ColoredTeamName(teem), "^7 could not take care of the ", lostkey.netname, "\n");
        }
+       
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(lostkey, INFO_KEYHUNT_LOST_), lostkey.kh_previous_owner.netname);
+       
        play2all(kh_sound_destroy);
        te_tarexplosion(lostkey.origin);
  
@@@ -711,11 -683,11 +683,11 @@@ void kh_Key_Think()  // runs all the ti
                {
                        if(head.team == kh_interferemsg_team)
                                if(head.kh_next)
-                                       Send_CSQC_Centerprint_Generic(head, CPID_KH_MSG, "All keys are in your team's hands!\n\nMeet the other key carriers ^1NOW^7!", 0, 0);
+                                       Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_KEYHUNT_MEET);
                                else
-                                       Send_CSQC_Centerprint_Generic(head, CPID_KH_MSG, "All keys are in your team's hands!\n\nHelp the key carriers to meet!", 0, 0);
+                                       Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_KEYHUNT_HELP);
                        else
-                               Send_CSQC_Centerprint_Generic(head, CPID_KH_MSG, strcat("All keys are in the ", ColoredTeamName(kh_interferemsg_team), "^7's hands!\n\nInterfere ^1NOW^7!"), 0, 0);
+                               Send_Notification(NOTIF_ONE, head, MSG_CENTER, APP_TEAM_NUM_4(kh_interferemsg_team, CENTER_KEYHUNT_INTERFERE_));
                }
        }
  
@@@ -748,21 -720,21 +720,21 @@@ void kh_Key_Spawn(entity initial_owner
        key.kh_dropperteam = 0;
        key.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
        setsize(key, KH_KEY_MIN, KH_KEY_MAX);
-       key.colormod = TeamColor(initial_owner.team) * KH_KEY_BRIGHTNESS;
+       key.colormod = Team_ColorRGB(initial_owner.team) * KH_KEY_BRIGHTNESS;
        key.reset = key_reset;
  
        switch(initial_owner.team)
        {
-               case COLOR_TEAM1:
+               case NUM_TEAM_1:
                        key.netname = "^1red key";
                        break;
-               case COLOR_TEAM2:
+               case NUM_TEAM_2:
                        key.netname = "^4blue key";
                        break;
-               case COLOR_TEAM3:
+               case NUM_TEAM_3:
                        key.netname = "^3yellow key";
                        break;
-               case COLOR_TEAM4:
+               case NUM_TEAM_4:
                        key.netname = "^6pink key";
                        break;
                default:
        key.kh_worldkeynext = kh_worldkeylist;
        kh_worldkeylist = key;
  
-       centerprint(initial_owner, strcat("You are starting with the ", key.netname, "\n"));  // message to player at start of round
+       Send_Notification(NOTIF_ONE, initial_owner, MSG_CENTER, APP_TEAM_NUM_4(initial_owner.team, CENTER_KEYHUNT_START_));
  
        WaypointSprite_Spawn("key-dropped", 0, 0, key, '0 0 1' * KH_KEY_WP_ZSHIFT, world, key.team, key, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAG, '0 1 1');
        key.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = kh_Key_waypointsprite_visible_for_player;
@@@ -817,7 -789,8 +789,8 @@@ void kh_Key_DropOne(entity key
  
        kh_Scores_Event(player, key, "dropkey", 0, 0);
        PlayerScore_Add(player, SP_KH_LOSSES, 1);
-       bprint(player.netname, "^7 dropped the ", key.netname, "\n");
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(key, INFO_KEYHUNT_DROP_), player.netname);
+       
        kh_Key_AssignTo(key, world);
        makevectors(player.v_angle);
        key.velocity = W_CalculateProjectileVelocity(player.velocity, autocvar_g_balance_keyhunt_throwvelocity * v_forward, FALSE);
@@@ -842,7 -815,7 +815,7 @@@ void kh_Key_DropAll(entity player, floa
                {
                        kh_Scores_Event(player, key, "losekey", 0, 0);
                        PlayerScore_Add(player, SP_KH_LOSSES, 1);
-                       bprint(player.netname, "^7 died and lost the ", key.netname, "\n");
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(key, INFO_KEYHUNT_LOST_), player.netname);
                        kh_Key_AssignTo(key, world);
                        makevectors('-1 0 0' * (45 + 45 * random()) + '0 360 0' * random());
                        key.velocity = W_CalculateProjectileVelocity(player.velocity, autocvar_g_balance_keyhunt_dropvelocity * v_forward, FALSE);
        }
  }
  
- string kh_CheckEnoughPlayers()  // checks enough player are present, runs after every completed round
+ float kh_CheckPlayers(float num)
  {
-       float i, players, teem;
-       entity player;
-       string result;
-       result = "";
-       // find a random player per team
-       for(i = 0; i < kh_teams; ++i)
-       {
-               teem = kh_Team_ByID(i);
-               players = 0;
-               FOR_EACH_PLAYER(player)
-                       if(player.deadflag == DEAD_NO)
-                               if(!player.BUTTON_CHAT)
-                                       if(player.team == teem)
+       if(num < kh_teams)
+       {
+               float t_team = kh_Team_ByID(num);
+               float players = 0;
+               entity tmp_player;
+               FOR_EACH_PLAYER(tmp_player)
+                       if(tmp_player.deadflag == DEAD_NO)
+                               if(!tmp_player.BUTTON_CHAT)
+                                       if(tmp_player.team == t_team)
                                                ++players;
-               if(players == 0)
-               {
-                       if(result != "")
-                               result = strcat(result, ", ");
-                       result = strcat(result, ColoredTeamName(teem));
-               }
+               
+               if not(players) { return t_team; }
        }
-       return result;
+       return 0;
  }
  
  void kh_WaitForPlayers()  // delay start of the round until enough players are present
  {
-       string teams_missing;
        if(time < game_starttime)
        {
-               kh_Controller_SetThink_NoMsg(game_starttime - time + 0.1, kh_WaitForPlayers);
+               kh_Controller_SetThink(game_starttime - time + 0.1, kh_WaitForPlayers);
                return;
        }
  
-       teams_missing = kh_CheckEnoughPlayers();
-       if(teams_missing == "")
-               kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, "Round starts in ", 1, kh_StartRound);
+       float p1 = kh_CheckPlayers(0), p2 = kh_CheckPlayers(1), p3 = kh_CheckPlayers(2), p4 = kh_CheckPlayers(3);
+       if not(p1 || p2 || p3 || p4)
+       {
+               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEYHUNT_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round);
+               kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, kh_StartRound);
+       }
        else
-               kh_Controller_SetThink(1, strcat("Waiting for players to join...\n\nNeed active players for: ", teams_missing), -1, kh_WaitForPlayers);
+       {
+               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEYHUNT_WAIT, p1, p2, p3, p4);
+               kh_Controller_SetThink(1, kh_WaitForPlayers);
+       }
  }
  
  void kh_EnableTrackingDevice()  // runs after each round
  {
-       entity player;
-       FOR_EACH_PLAYER(player)
-               if(IS_REAL_CLIENT(player))
-                       Send_CSQC_Centerprint_Generic_Expire(player, CPID_KH_MSG);
+       Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_KEYHUNT);
+       Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_KEYHUNT_OTHER);
  
        kh_tracking_enabled = TRUE;
  }
  
  void kh_StartRound()  // runs at the start of each round
  {
-       string teams_missing;
        float i, players, teem;
        entity player;
  
        if(time < game_starttime)
        {
-               kh_Controller_SetThink_NoMsg(game_starttime - time + 0.1, kh_WaitForPlayers);
+               kh_Controller_SetThink(game_starttime - time + 0.1, kh_WaitForPlayers);
                return;
        }
  
-       teams_missing = kh_CheckEnoughPlayers();
-       if(teams_missing != "")
+       float p1 = kh_CheckPlayers(0), p2 = kh_CheckPlayers(1), p3 = kh_CheckPlayers(2), p4 = kh_CheckPlayers(3);
+       if(p1 || p2 || p3 || p4)
        {
-               kh_Controller_SetThink(1, strcat("Waiting for players to join...\n\nNeed active players for: ", teams_missing), -1, kh_WaitForPlayers);
+               kh_Controller_SetThink(1, kh_WaitForPlayers);
+               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEYHUNT_WAIT, p1, p2, p3, p4);
                return;
        }
-       FOR_EACH_PLAYER(player)
-               if(IS_REAL_CLIENT(player))
-                       Send_CSQC_Centerprint_Generic_Expire(player, CPID_KH_MSG);
+       
+       Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_KEYHUNT);
+       Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_KEYHUNT_OTHER);
  
        for(i = 0; i < kh_teams; ++i)
        {
        }
  
        kh_tracking_enabled = FALSE;
-       kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_tracking, "Scanning frequency range...", -1, kh_EnableTrackingDevice);
+       Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_KEYHUNT_SCAN, autocvar_g_balance_keyhunt_delay_tracking);
+       kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_tracking, kh_EnableTrackingDevice);
  }
  
  float kh_HandleFrags(entity attacker, entity targ, float f)  // adds to the player score
@@@ -1003,7 -968,7 +968,7 @@@ void kh_Initialize()  // sets up th KH 
        // make a KH entity for controlling the game
        kh_controller = spawn();
        kh_controller.think = kh_Controller_Think;
-       kh_Controller_SetThink_NoMsg(0, kh_WaitForPlayers);
+       kh_Controller_SetThink(0, kh_WaitForPlayers);
  
        setmodel(kh_controller, "models/keyhunt/key.md3");
        kh_key_dropped = kh_controller.modelindex;
@@@ -1047,7 -1012,7 +1012,7 @@@ MUTATOR_HOOKFUNCTION(kh_PlayerDies
  {
        if(self == other)
                kh_Key_DropAll(self, TRUE);
 -      else if(other.classname == "player")
 +      else if(IS_PLAYER(other))
                kh_Key_DropAll(self, FALSE);
        else
                kh_Key_DropAll(self, TRUE);
index 2dd1b3c2425a77684d0b8210bc7ca1b60997327d,8790162afa9804ed508c48bcecb4241930ad5319..ba70a6cda8a5e301242f978430cf2c82d31a5e95
@@@ -49,7 -49,7 +49,7 @@@ void nexball_setstatus(void
        {
                if(self.ballcarried.teamtime && (self.ballcarried.teamtime < time))
                {
-                       bprint("The ", ColoredTeamName(self.team), " held the ball for too long.\n");
+                       bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n");
                        oldself = self;
                        self = self.ballcarried;
                        DropBall(self, self.owner.origin, '0 0 0');
@@@ -204,7 -204,8 +204,8 @@@ void ResetBall(void
        if(self.cnt < 2)        // step 1
        {
                if(time == self.teamtime)
-                       bprint("The ", ColoredTeamName(self.team), " held the ball for too long.\n");
+                       bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n");
                self.touch = func_null;
                self.movetype = MOVETYPE_NOCLIP;
                self.velocity = '0 0 0'; // just in case?
@@@ -247,7 -248,7 +248,7 @@@ void football_touch(void
                        self.nextthink = time + autocvar_g_nexball_delay_idle;
                return;
        }
 -      if(other.classname != "player")
 +      if not(IS_PLAYER(other))
                return;
        if(other.health < 1)
                return;
@@@ -287,7 -288,7 +288,7 @@@ void basketball_touch(void
                football_touch();
                return;
        }
 -      if(!self.cnt && other.classname == "player" && (other != self.nb_dropper || time > self.nb_droptime + autocvar_g_nexball_delay_collect))
 +      if(!self.cnt && IS_PLAYER(other) && (other != self.nb_dropper || time > self.nb_droptime + autocvar_g_nexball_delay_collect))
        {
                if(other.health <= 0)
                        return;
@@@ -326,7 -327,7 +327,7 @@@ void GoalTouch(void
        else
                otherteam = 0;
  
 -      if((isclient = ball.pusher.flags & FL_CLIENT))
 +      if((isclient = IS_CLIENT(ball.pusher)))
                pname = ball.pusher.netname;
        else
                pname = "Someone (?)";
        {
                LogNB("fault", ball.pusher);
                if(nb_teams == 2)
-                       bprint(ColoredTeamName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
+                       bprint(Team_ColoredFullName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
                else
-                       bprint(ColoredTeamName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
+                       bprint(Team_ColoredFullName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
                pscore = -1;
        }
        else if(self.team == GOAL_OUT)
        else                                                       //score
        {
                LogNB(strcat("goal:", ftos(self.team)), ball.pusher);
-               bprint("Goaaaaal! ", pname, "^7 scored a point for the ", ColoredTeamName(ball.team), ".\n");
+               bprint("Goaaaaal! ", pname, "^7 scored a point for the ", Team_ColoredFullName(ball.team), ".\n");
                pscore = 1;
        }
  
@@@ -424,28 -425,28 +425,28 @@@ void nb_spawnteams(void
        {
                switch(e.team)
                {
-               case COLOR_TEAM1:
+               case NUM_TEAM_1:
                        if(!t_r)
                        {
                                nb_spawnteam("Red", e.team-1)   ;
                                t_r = 1;
                        }
                        break;
-               case COLOR_TEAM2:
+               case NUM_TEAM_2:
                        if(!t_b)
                        {
                                nb_spawnteam("Blue", e.team-1)  ;
                                t_b = 1;
                        }
                        break;
-               case COLOR_TEAM3:
+               case NUM_TEAM_3:
                        if(!t_y)
                        {
                                nb_spawnteam("Yellow", e.team-1);
                                t_y = 1;
                        }
                        break;
-               case COLOR_TEAM4:
+               case NUM_TEAM_4:
                        if(!t_p)
                        {
                                nb_spawnteam("Pink", e.team-1)  ;
@@@ -575,22 -576,22 +576,22 @@@ void SpawnGoal(void
  
  void spawnfunc_nexball_redgoal(void)
  {
-       self.team = COLOR_TEAM1;
+       self.team = NUM_TEAM_1;
        SpawnGoal();
  }
  void spawnfunc_nexball_bluegoal(void)
  {
-       self.team = COLOR_TEAM2;
+       self.team = NUM_TEAM_2;
        SpawnGoal();
  }
  void spawnfunc_nexball_yellowgoal(void)
  {
-       self.team = COLOR_TEAM3;
+       self.team = NUM_TEAM_3;
        SpawnGoal();
  }
  void spawnfunc_nexball_pinkgoal(void)
  {
-       self.team = COLOR_TEAM4;
+       self.team = NUM_TEAM_4;
        SpawnGoal();
  }
  
@@@ -673,7 -674,7 +674,7 @@@ void W_Nexball_Touch(void
        
        PROJECTILE_TOUCH;
        if(attacker.team != other.team || autocvar_g_nexball_basketball_teamsteal)
 -              if((ball = other.ballcarried) && (attacker.classname == "player"))
 +              if((ball = other.ballcarried) && (IS_PLAYER(attacker)))
                {
                        other.velocity = other.velocity + normalize(self.velocity) * other.damageforcescale * autocvar_g_balance_nexball_secondary_force;
                        other.flags &~= FL_ONGROUND;
@@@ -843,14 -844,8 +844,8 @@@ float w_nexball_weapon(float req
                precache_sound("misc/typehit.wav");
        }
        else if(req == WR_SETUP)
-               weapon_setup(WEP_PORTO);
-       else if(req == WR_SUICIDEMESSAGE)
        {
-               w_deathtypestring = "is a weirdo";
-       }
-       else if(req == WR_KILLMESSAGE)
-       {
-               w_deathtypestring = "got killed by #'s black magic";
+               weapon_setup(WEP_PORTO);
        }
        // No need to check WR_CHECKAMMO* or WR_AIM, it should always return TRUE
        return TRUE;
@@@ -905,7 -900,7 +900,7 @@@ MUTATOR_HOOKFUNCTION(nexball_PlayerPreT
                                //tracebox(self.origin + self.view_ofs, '-2 -2 -2', '2 2 2', self.origin + self.view_ofs + v_forward * autocvar_g_nexball_safepass_maxdist);
                                crosshair_trace(self);
                                if( trace_ent && 
 -                                      trace_ent.flags & FL_CLIENT &&
 +                                      IS_CLIENT(trace_ent) &&
                                        trace_ent.deadflag == DEAD_NO &&
                                        trace_ent.team == self.team &&
                                        vlen(trace_ent.origin - self.origin) <= autocvar_g_nexball_safepass_maxdist )
index 21a95d0f7601bd310917e1122d876b94e4c00e51,3801de302d9c80fa2ab8cb0e7e3215d01dbf0ff4..e4be2d7ab4ce2ea2b9422456b2affc7fbec3f2fd
@@@ -1,8 -1,8 +1,8 @@@
  float autocvar_g_onslaught_spawn_at_controlpoints;
  float autocvar_g_onslaught_spawn_at_generator;
- float autocvar_g_onslaught_controlpoints_proxycap;
float autocvar_g_onslaught_controlpoints_proxycap_distance = 512;
float autocvar_g_onslaught_controlpoints_proxycap_dps = 100;
+ float autocvar_g_onslaught_cp_proxydecap;
var float autocvar_g_onslaught_cp_proxydecap_distance = 512;
var float autocvar_g_onslaught_cp_proxydecap_dps = 100;
  
  void onslaught_generator_updatesprite(entity e);
  void onslaught_controlpoint_updatesprite(entity e);
@@@ -22,8 -22,6 +22,6 @@@ void onslaught_link_checkupdate()
  .float lastshielded;
  .float lastcaptured;
  
- .string model1, model2, model3;
  entity ons_red_generator;
  entity ons_blue_generator;
  
@@@ -163,16 -161,16 +161,16 @@@ void onslaught_updatelinks(
                        }
                        if(l.goalentity.classname == "onslaught_generator")
                        {
-                               if(l.goalentity.team == COLOR_TEAM1)
+                               if(l.goalentity.team == NUM_TEAM_1)
                                        l.enemy.isgenneighbor_red = TRUE;
-                               else if(l.goalentity.team == COLOR_TEAM2)
+                               else if(l.goalentity.team == NUM_TEAM_2)
                                        l.enemy.isgenneighbor_blue = TRUE;
                        }
                        else
                        {
-                               if(l.goalentity.team == COLOR_TEAM1)
+                               if(l.goalentity.team == NUM_TEAM_1)
                                        l.enemy.iscpneighbor_red = TRUE;
-                               else if(l.goalentity.team == COLOR_TEAM2)
+                               else if(l.goalentity.team == NUM_TEAM_2)
                                        l.enemy.iscpneighbor_blue = TRUE;
                        }
                }
                        }
                        if(l.enemy.classname == "onslaught_generator")
                        {
-                               if(l.enemy.team == COLOR_TEAM1)
+                               if(l.enemy.team == NUM_TEAM_1)
                                        l.goalentity.isgenneighbor_red = TRUE;
-                               else if(l.enemy.team == COLOR_TEAM2)
+                               else if(l.enemy.team == NUM_TEAM_2)
                                        l.goalentity.isgenneighbor_blue = TRUE;
                        }
                        else
                        {
-                               if(l.enemy.team == COLOR_TEAM1)
+                               if(l.enemy.team == NUM_TEAM_1)
                                        l.goalentity.iscpneighbor_red = TRUE;
-                               else if(l.enemy.team == COLOR_TEAM2)
+                               else if(l.enemy.team == NUM_TEAM_2)
                                        l.goalentity.iscpneighbor_blue = TRUE;
                        }
                }
        {
                if (l.iscaptured)
                {
-                       if (l.team == COLOR_TEAM1) t1 = 1;
-                       if (l.team == COLOR_TEAM2) t2 = 1;
-                       if (l.team == COLOR_TEAM3) t3 = 1;
-                       if (l.team == COLOR_TEAM4) t4 = 1;
+                       if (l.team == NUM_TEAM_1) t1 = 1;
+                       if (l.team == NUM_TEAM_2) t2 = 1;
+                       if (l.team == NUM_TEAM_3) t3 = 1;
+                       if (l.team == NUM_TEAM_4) t4 = 1;
                }
                onslaught_generator_updatesprite(l);
                l = l.chain;
  
  float onslaught_controlpoint_can_be_linked(entity cp, float t)
  {
-       if(t == COLOR_TEAM1)
+       if(t == NUM_TEAM_1)
        {
                if(cp.isgenneighbor_red)
                        return 2;
                if(cp.iscpneighbor_red)
                        return 1;
        }
-       else if(t == COLOR_TEAM2)
+       else if(t == NUM_TEAM_2)
        {
                if(cp.isgenneighbor_blue)
                        return 2;
@@@ -354,7 -352,7 +352,7 @@@ float onslaught_controlpoint_attackable
                // if there's already an icon built, nothing happens
                if(cp.team == t)
                {
-                       a = onslaught_controlpoint_can_be_linked(cp, COLOR_TEAM1 + COLOR_TEAM2 - t);
+                       a = onslaught_controlpoint_can_be_linked(cp, NUM_TEAM_1 + NUM_TEAM_2 - t);
                        if(a) // attackable by enemy?
                                return -2; // EMERGENCY!
                        return -1;
                // free point
                if(onslaught_controlpoint_can_be_linked(cp, t))
                {
-                       a = onslaught_controlpoint_can_be_linked(cp, COLOR_TEAM1 + COLOR_TEAM2 - t);
+                       a = onslaught_controlpoint_can_be_linked(cp, NUM_TEAM_1 + NUM_TEAM_2 - t);
                        if(a == 2)
                                return 4; // GET THIS ONE NOW!
                        else
@@@ -419,19 -417,19 +417,19 @@@ void onslaught_generator_think(
                }
                else if (overtime_msg_time)
                        overtime_msg_time = 0;
-         
          if(!self.isshielded && self.wait < time)
          {
              self.wait = time + 5;
-             FOR_EACH_PLAYER(e)
+             FOR_EACH_REALPLAYER(e)
              {
                  if(e.team == self.team)
                  {
                      centerprint(e, "^1Your generator is NOT shielded!\n^7Re-capture controlpoints to shield it!");
                      soundto(MSG_ONE, e, CHAN_AUTO, "kh/alarm.wav", VOL_BASE, ATTN_NONE);    // FIXME: Uniqe sound?
-                 }                                 
-             }                                             
-         }    
+                 }
+             }
+         }
        }
  }
  
@@@ -586,7 -584,7 +584,7 @@@ void onslaught_generator_damage(entity 
                {
                        // this is protected by a shield, so ignore the damage
                        if (time > self.pain_finished)
 -                              if (attacker.classname == "player")
 +                              if (IS_PLAYER(attacker))
                                {
                                        play2(attacker, "onslaught/damageblockedbyshield.wav");
                                        self.pain_finished = time + 1;
                if (time > self.pain_finished)
                {
                        self.pain_finished = time + 10;
-                       bprint(ColoredTeamName(self.team), " generator under attack!\n");
+                       bprint(Team_ColoredFullName(self.team), " generator under attack!\n");
                        play2team(self.team, "onslaught/generator_underattack.wav");
                }
        }
                lh = ceil(self.lasthealth / 100) * 100;
                h = ceil(self.health / 100) * 100;
                if(lh != h)
-                       bprint(ColoredTeamName(self.team), " generator has less than ", ftos(h), " health remaining\n");
+                       bprint(Team_ColoredFullName(self.team), " generator has less than ", ftos(h), " health remaining\n");
  #endif
                self.lasthealth = self.health;
        }
        else if not(inWarmupStage)
        {
                if (attacker == self)
-                       bprint(ColoredTeamName(self.team), " generator spontaneously exploded due to overtime!\n");
+                       bprint(Team_ColoredFullName(self.team), " generator spontaneously exploded due to overtime!\n");
                else
                {
                        string t;
-                       t = ColoredTeamName(attacker.team);
-                       bprint(ColoredTeamName(self.team), " generator destroyed by ", t, "!\n");
+                       t = Team_ColoredFullName(attacker.team);
+                       bprint(Team_ColoredFullName(self.team), " generator destroyed by ", t, "!\n");
                }
                self.iscaptured = FALSE;
                self.islinked = FALSE;
@@@ -706,16 -704,16 +704,16 @@@ string onslaught_generator_waypointspri
  {
        if(t == e.team)
        {
-               if(e.team == COLOR_TEAM1)
+               if(e.team == NUM_TEAM_1)
                        return "ons-gen-red";
-               else if(e.team == COLOR_TEAM2)
+               else if(e.team == NUM_TEAM_2)
                        return "ons-gen-blue";
        }
        if(e.isshielded)
                return "ons-gen-shielded";
-       if(e.team == COLOR_TEAM1)
+       if(e.team == NUM_TEAM_1)
                return "ons-gen-red";
-       else if(e.team == COLOR_TEAM2)
+       else if(e.team == NUM_TEAM_2)
                return "ons-gen-blue";
        return "";
  }
  void onslaught_generator_updatesprite(entity e)
  {
        string s1, s2, s3;
-       s1 = onslaught_generator_waypointsprite_for_team(e, COLOR_TEAM1);
-       s2 = onslaught_generator_waypointsprite_for_team(e, COLOR_TEAM2);
+       s1 = onslaught_generator_waypointsprite_for_team(e, NUM_TEAM_1);
+       s2 = onslaught_generator_waypointsprite_for_team(e, NUM_TEAM_2);
        s3 = onslaught_generator_waypointsprite_for_team(e, -1);
        WaypointSprite_UpdateSprites(e.sprite, s1, s2, s3);
  
                e.lastshielded = e.isshielded;
                if(e.lastshielded)
                {
-                       if(e.team == COLOR_TEAM1 || e.team == COLOR_TEAM2)
+                       if(e.team == NUM_TEAM_1 || e.team == NUM_TEAM_2)
                                WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, 0.5 * colormapPaletteColor(e.team - 1, FALSE));
                        else
                                WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.5 0.5 0.5');
                }
                else
                {
-                       if(e.team == COLOR_TEAM1 || e.team == COLOR_TEAM2)
+                       if(e.team == NUM_TEAM_1 || e.team == NUM_TEAM_2)
                                WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, colormapPaletteColor(e.team - 1, FALSE));
                        else
                                WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_GENERATOR, '0.75 0.75 0.75');
@@@ -758,25 -756,25 +756,25 @@@ string onslaught_controlpoint_waypoints
                a = onslaught_controlpoint_attackable(e, t);
                if(a == 3 || a == 4) // ATTACK/TOUCH THIS ONE NOW
                {
-                       if(e.team == COLOR_TEAM1)
+                       if(e.team == NUM_TEAM_1)
                                return "ons-cp-atck-red";
-                       else if(e.team == COLOR_TEAM2)
+                       else if(e.team == NUM_TEAM_2)
                                return "ons-cp-atck-blue";
                        else
                                return "ons-cp-atck-neut";
                }
                else if(a == -2) // DEFEND THIS ONE NOW
                {
-                       if(e.team == COLOR_TEAM1)
+                       if(e.team == NUM_TEAM_1)
                                return "ons-cp-dfnd-red";
-                       else if(e.team == COLOR_TEAM2)
+                       else if(e.team == NUM_TEAM_2)
                                return "ons-cp-dfnd-blue";
                }
                else if(e.team == t || a == -1 || a == 1) // own point, or fire at it
                {
-                       if(e.team == COLOR_TEAM1)
+                       if(e.team == NUM_TEAM_1)
                                return "ons-cp-red";
-                       else if(e.team == COLOR_TEAM2)
+                       else if(e.team == NUM_TEAM_2)
                                return "ons-cp-blue";
                }
                else if(a == 2) // touch it
        }
        else
        {
-               if(e.team == COLOR_TEAM1)
+               if(e.team == NUM_TEAM_1)
                        return "ons-cp-red";
-               else if(e.team == COLOR_TEAM2)
+               else if(e.team == NUM_TEAM_2)
                        return "ons-cp-blue";
                else
                        return "ons-cp-neut";
  void onslaught_controlpoint_updatesprite(entity e)
  {
        string s1, s2, s3;
-       s1 = onslaught_controlpoint_waypointsprite_for_team(e, COLOR_TEAM1);
-       s2 = onslaught_controlpoint_waypointsprite_for_team(e, COLOR_TEAM2);
+       s1 = onslaught_controlpoint_waypointsprite_for_team(e, NUM_TEAM_1);
+       s2 = onslaught_controlpoint_waypointsprite_for_team(e, NUM_TEAM_2);
        s3 = onslaught_controlpoint_waypointsprite_for_team(e, -1);
        WaypointSprite_UpdateSprites(e.sprite, s1, s2, s3);
  
        float sh;
-       sh = !(onslaught_controlpoint_can_be_linked(e, COLOR_TEAM1) || onslaught_controlpoint_can_be_linked(e, COLOR_TEAM2));
+       sh = !(onslaught_controlpoint_can_be_linked(e, NUM_TEAM_1) || onslaught_controlpoint_can_be_linked(e, NUM_TEAM_2));
  
        if(e.lastteam != e.team + 2 || e.lastshielded != sh || e.iscaptured != e.lastcaptured)
        {
                }
                if(e.lastshielded)
                {
-                       if(e.team == COLOR_TEAM1 || e.team == COLOR_TEAM2)
+                       if(e.team == NUM_TEAM_1 || e.team == NUM_TEAM_2)
                                WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, 0.5 * colormapPaletteColor(e.team - 1, FALSE));
                        else
                                WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.5 0.5 0.5');
                }
                else
                {
-                       if(e.team == COLOR_TEAM1 || e.team == COLOR_TEAM2)
+                       if(e.team == NUM_TEAM_1 || e.team == NUM_TEAM_2)
                                WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, colormapPaletteColor(e.team - 1, FALSE));
                        else
                                WaypointSprite_UpdateTeamRadar(e.sprite, RADARICON_CONTROLPOINT, '0.75 0.75 0.75');
@@@ -856,8 -854,11 +854,11 @@@ void onslaught_generator_reset(
        setmodel(self, "models/onslaught/generator.md3");
        setsize(self, '-52 -52 -14', '52 52 75');
  
-       if (!self.noalign)
-         droptofloor();
+       if(!self.noalign)
+       {
+               setorigin(self, self.origin + '0 0 20');
+               droptofloor();
+       }
  
        WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
        WaypointSprite_UpdateHealth(self.sprite, self.health);
@@@ -910,10 -911,10 +911,10 @@@ void spawnfunc_onslaught_generator(
        if (!self.team)
                objerror("team must be set");
        
-       if(self.team == COLOR_TEAM1)
+       if(self.team == NUM_TEAM_1)
          ons_red_generator = self;
  
-       if(self.team == COLOR_TEAM2)
+       if(self.team == NUM_TEAM_2)
          ons_blue_generator = self;
          
        self.team_saved = self.team;
        InitializeEntity(self, onslaught_generator_delayed, INITPRIO_LAST);
  
        WaypointSprite_SpawnFixed(string_null, self.origin + '0 0 128', self, sprite, RADARICON_NONE, '0 0 0');
-       WaypointSprite_UpdateRule(self.sprite, COLOR_TEAM2, SPRITERULE_TEAMPLAY);
+       WaypointSprite_UpdateRule(self.sprite, NUM_TEAM_2, SPRITERULE_TEAMPLAY);
        WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
        WaypointSprite_UpdateHealth(self.sprite, self.health);
  
@@@ -977,7 -978,7 +978,7 @@@ void onslaught_controlpoint_icon_damage
        {
                // this is protected by a shield, so ignore the damage
                if (time > self.pain_finished)
 -                      if (attacker.classname == "player")
 +                      if (IS_PLAYER(attacker))
                        {
                                play2(attacker, "onslaught/damageblockedbyshield.wav");
                                self.pain_finished = time + 1;
                return;
        }
  
 -      if (attacker.classname == "player")
 +      if (IS_PLAYER(attacker))
        {
                nag = FALSE;
-               if(self.team == COLOR_TEAM1)
+               if(self.team == NUM_TEAM_1)
                {
                        if(time - ons_notification_time_team1 > 10)
                        {
                                ons_notification_time_team1 = time;
                        }
                }
-               else if(self.team == COLOR_TEAM2)
+               else if(self.team == NUM_TEAM_2)
                {
                        if(time - ons_notification_time_team2 > 10)
                        {
                pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1);
                {
                        string t;
-                       t = ColoredTeamName(attacker.team);
-                       bprint(ColoredTeamName(self.team), " ", self.message, " control point destroyed by ", t, "\n");
+                       t = Team_ColoredFullName(attacker.team);
+                       bprint(Team_ColoredFullName(self.team), " ", self.message, " control point destroyed by ", t, "\n");
                        ons_throwgib(self.origin, (2 * randomvec() - '1 1 1') * 25, "models/onslaught/controlpoint_icon_gib1.md3", 3, FALSE);
                        ons_throwgib(self.origin, (2 * randomvec() - '1 1 1') * 45, "models/onslaught/controlpoint_icon_gib2.md3", 3, FALSE);
                        ons_throwgib(self.origin, (2 * randomvec() - '1 1 1') * 45, "models/onslaught/controlpoint_icon_gib2.md3", 3, FALSE);
@@@ -1076,9 -1077,9 +1077,9 @@@ void onslaught_controlpoint_icon_think(
  {
        entity oself;
        self.nextthink = time + sys_frametime;
-       
-       if(autocvar_g_onslaught_controlpoints_proxycap)
-       {        
+       if(autocvar_g_onslaught_cp_proxydecap)
+       {
          float _enemy_count = 0;
          float _friendly_count = 0;
          float _dist;
              if(!_player.deadflag)
              {
                  _dist = vlen(_player.origin - self.origin);
-                 if(_dist < autocvar_g_onslaught_controlpoints_proxycap_distance)
+                 if(_dist < autocvar_g_onslaught_cp_proxydecap_distance)
                  {
                      if(_player.team == self.team)
                          ++_friendly_count;
              }
          }
  
-         _friendly_count = _friendly_count * (autocvar_g_onslaught_controlpoints_proxycap_dps * sys_frametime);
-         _enemy_count = _enemy_count * (autocvar_g_onslaught_controlpoints_proxycap_dps * sys_frametime);
-         
+         _friendly_count = _friendly_count * (autocvar_g_onslaught_cp_proxydecap_dps * sys_frametime);
+         _enemy_count = _enemy_count * (autocvar_g_onslaught_cp_proxydecap_dps * sys_frametime);
          self.health = bound(0, self.health + (_friendly_count - _enemy_count), self.max_health);
          if(self.health <= 0)
          {
              return;
          }
      }
-     
        if (time > self.pain_finished + 5)
        {
                if(self.health < self.max_health)
@@@ -1234,7 -1235,7 +1235,7 @@@ void onslaught_controlpoint_icon_buildt
                self.count = autocvar_g_onslaught_cp_regen * sys_frametime; // slow repair rate from now on
                self.think = onslaught_controlpoint_icon_think;
                sound(self, CH_TRIGGER, "onslaught/controlpoint_built.wav", VOL_BASE, ATTN_NORM);
-               bprint(ColoredTeamName(self.team), " captured ", self.owner.message, " control point\n");
+               bprint(Team_ColoredFullName(self.team), " captured ", self.owner.message, " control point\n");
                self.owner.iscaptured = TRUE;
  
                WaypointSprite_UpdateMaxHealth(self.owner.sprite, self.max_health);
@@@ -1270,7 -1271,7 +1271,7 @@@ void onslaught_controlpoint_touch(
  {
        entity e;
        float a;
 -      if (other.classname != "player")
 +      if not(IS_PLAYER(other))
                return;
        a = onslaught_controlpoint_attackable(self, other.team);
        if(a != 2 && a != 4)
@@@ -1338,49 -1339,6 +1339,6 @@@ keys
  "target" - target any entities that are tied to this control point, such as vehicles and buildable structure entities.
  "message" - name of this control point (should reflect the location in the map, such as "center bridge", "north tower", etc)
   */
-  
-  /*
- void onslaught_controlpoint_think()
- {
-     self.nextthink = time;
-       //if(autocvar_g_onslaught_controlpoints_proxycap)
-                   
-     float _enemy_count;
-     float _friendly_count;
-     float _dist;
-     entity _player;
-     
-     FOR_EACH_PLAYER(_player)
-     {
-         if(!_player.deadflag)
-         {
-             _dist = vlen(_player.origin - self.origin);
-             if(_dist < autocvar_g_onslaught_controlpoints_proxycap_distance)
-             {
-                 if(_player.team == self.team)
-                     ++_friendly_count;
-                 else
-                     ++_enemy_count;
-             }
-         }
-     }
-     _friendly_count = _friendly_count * (autocvar_g_onslaught_controlpoints_proxycap_dps * sys_frametime);
-     _enemy_count = _enemy_count * (autocvar_g_onslaught_controlpoints_proxycap_dps * sys_frametime);
-     
-     self.health = bound(0, self.health + (_friendly_count - _enemy_count), self.max_health);
-     if(self.health <= 0)
-     {
-         onslaught_controlpoint_icon_damage(self, self, 1, 0, self.origin, '0 0 0');
-         return;
-     }
-     
-     if(self.health == max_health)
-       {
-           
-       }
- }
- */
  
  void spawnfunc_onslaught_controlpoint()
  {
        precache_sound("onslaught/controlpoint_underattack.wav");
        precache_sound("onslaught/ons_spark1.wav");
        precache_sound("onslaught/ons_spark2.wav");
        self.solid = SOLID_BBOX;
        self.movetype = MOVETYPE_NONE;
        setmodel(self, "models/onslaught/controlpoint_pad.md3");
        //setsize(self, '-32 -32 0', '32 32 8');
-       if (!self.noalign)
-         droptofloor();
-       
-       setorigin(self, self.origin);
+       if(!self.noalign)
+       {
+               setorigin(self, self.origin + '0 0 20');
+               droptofloor();
+       }
        self.touch = onslaught_controlpoint_touch;
        self.team = 0;
        self.colormap = 1024;
        self.iscaptured = FALSE;
        self.islinked = FALSE;
        self.isshielded = TRUE;
        // spawn shield model which indicates whether this can be damaged
        self.enemy = spawn();
        self.enemy.classname = "onslaught_controlpoint_shield";
        self.enemy.movetype = MOVETYPE_NONE;
        self.enemy.effects = EF_ADDITIVE;
        setmodel(self.enemy , "models/onslaught/controlpoint_shield.md3");
-       
        setattachment(self.enemy , self, "");
        //setsize(e, '-32 -32 0', '32 32 128');
  
        waypoint_spawnforitem(self);
  
        WaypointSprite_SpawnFixed(string_null, self.origin + '0 0 128', self, sprite, RADARICON_NONE, '0 0 0');
-       WaypointSprite_UpdateRule(self.sprite, COLOR_TEAM2, SPRITERULE_TEAMPLAY);
+       WaypointSprite_UpdateRule(self.sprite, NUM_TEAM_2, SPRITERULE_TEAMPLAY);
  
        onslaught_updatelinks();
-       
        self.reset = onslaught_controlpoint_reset;
  }
  
@@@ -1476,28 -1437,28 +1437,28 @@@ void onslaught_link_checkupdate(
        redpower = bluepower = 0;
        if(self.goalentity.islinked)
        {
-               if(self.goalentity.team == COLOR_TEAM1)
+               if(self.goalentity.team == NUM_TEAM_1)
                        redpower = 1;
-               else if(self.goalentity.team == COLOR_TEAM2)
+               else if(self.goalentity.team == NUM_TEAM_2)
                        bluepower = 1;
        }
        if(self.enemy.islinked)
        {
-               if(self.enemy.team == COLOR_TEAM1)
+               if(self.enemy.team == NUM_TEAM_1)
                        redpower = 2;
-               else if(self.enemy.team == COLOR_TEAM2)
+               else if(self.enemy.team == NUM_TEAM_2)
                        bluepower = 2;
        }
  
        float cc;
        if(redpower == 1 && bluepower == 2)
-               cc = (COLOR_TEAM1 - 1) * 0x01 + (COLOR_TEAM2 - 1) * 0x10;
+               cc = (NUM_TEAM_1 - 1) * 0x01 + (NUM_TEAM_2 - 1) * 0x10;
        else if(redpower == 2 && bluepower == 1)
-               cc = (COLOR_TEAM1 - 1) * 0x10 + (COLOR_TEAM2 - 1) * 0x01;
+               cc = (NUM_TEAM_1 - 1) * 0x10 + (NUM_TEAM_2 - 1) * 0x01;
        else if(redpower)
-               cc = (COLOR_TEAM1 - 1) * 0x11;
+               cc = (NUM_TEAM_1 - 1) * 0x11;
        else if(bluepower)
-               cc = (COLOR_TEAM2 - 1) * 0x11;
+               cc = (NUM_TEAM_2 - 1) * 0x11;
        else
                cc = 0;
  
@@@ -1557,7 -1518,7 +1518,7 @@@ MUTATOR_HOOKFUNCTION(ons_BuildMutatorsS
  
  MUTATOR_HOOKFUNCTION(ons_BuildMutatorsPrettyString)
  {
-       ret_string = strcat(ret_string, ", Onslught");
+       ret_string = strcat(ret_string, ", Onslaught");
        return 0;
  }
  
@@@ -1569,10 -1530,10 +1530,10 @@@ MUTATOR_HOOKFUNCTION(ons_Spawn_Score
      
        RandomSelection_Init();
        
-       if(self.team == COLOR_TEAM1)
+       if(self.team == NUM_TEAM_1)
          RandomSelection_Add(ons_red_generator, 0, string_null, 1, 1);
        
-       if(self.team == COLOR_TEAM2)
+       if(self.team == NUM_TEAM_2)
          RandomSelection_Add(ons_blue_generator, 0, string_null, 1, 1);
        
        entity _cp = findchain(classname, "onslaught_controlpoint"):
@@@ -1611,7 -1572,7 +1572,7 @@@ MUTATOR_HOOKFUNCTION(ons_PlayerSpawn
      
        RandomSelection_Init();
      
-       if(self.team == COLOR_TEAM1)
+       if(self.team == NUM_TEAM_1)
        {
            if(!_close_to_home)
              _trg_gen = ons_blue_generator;
              _trg_gen  = ons_red_generator;        
        }
        
-       if(self.team == COLOR_TEAM2)
+       if(self.team == NUM_TEAM_2)
        {
            if(_close_to_home)
              _trg_gen = ons_blue_generator;
          if(!autocvar_g_onslaught_spawn_at_generator)
              return 0;
          
-         _trg_gen = ((self.team == COLOR_TEAM1) ? ons_red_generator : ons_blue_generator);
+         _trg_gen = ((self.team == NUM_TEAM_1) ? ons_red_generator : ons_blue_generator);
          
          for(i = 0; i < 10; ++i)
          {
  
  MUTATOR_DEFINITION(gamemode_onslaught)
  {
-       //MUTATOR_HOOK(PlayerDies, nexball_BallDrop, CBC_ORDER_ANY);
-       //MUTATOR_HOOK(MakePlayerObserver, nexball_BallDrop, CBC_ORDER_ANY);
-       //MUTATOR_HOOK(ClientDisconnect, nexball_BallDrop, CBC_ORDER_ANY);
-       //MUTATOR_HOOK(PlayerPreThink, nexball_PlayerPreThink, CBC_ORDER_ANY);
        MUTATOR_HOOK(BuildMutatorsPrettyString, ons_BuildMutatorsPrettyString, CBC_ORDER_ANY);
        MUTATOR_HOOK(BuildMutatorsString, ons_BuildMutatorsString, CBC_ORDER_ANY);
        MUTATOR_HOOK(PlayerSpawn, ons_PlayerSpawn, CBC_ORDER_ANY);
        //MUTATOR_HOOK(Spawn_Score, ons_Spawn_Score, CBC_ORDER_ANY);
-       
        MUTATOR_ONADD
        {
                if(time > 1) // game loads at time 1
index 151428e8685b7a5730c61b3e7400d7eb95b88b5d,d5f95bd3039465f4df277b7ec389f6909a37c549..21285b53a0b62c627065d2d6144ede7f5b2dae2f
@@@ -96,7 -96,7 +96,7 @@@ void NIX_GiveCurrentWeapon(
                if(dt >= 1 && dt <= 5)
                        self.nix_lastinfotime = -42;
                else
-                       Send_CSQC_Centerprint_Generic(self, CPID_NIX_WPNCHANGE, strcat("^2Active weapon: ^3", W_Name(nix_weapon)), 0, 0);
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
  
                weapon_action(nix_weapon, WR_RESETPLAYER);
  
        {
                self.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
                if(dt >= 1 && dt <= 5)
-                       Send_CSQC_Centerprint_Generic(self, CPID_NIX_WPNCHANGE, strcat("^3%d^2 seconds until weapon change...\n\nNext weapon: ^3", W_Name(nix_nextweapon)), 1, dt);
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
        }
  
        if(!(self.items & IT_UNLIMITED_WEAPON_AMMO) && time > self.nix_nextincr)
@@@ -205,7 -205,7 +205,7 @@@ MUTATOR_HOOKFUNCTION(nix_PlayerPreThink
  {
        if(!intermission_running)
        if(self.deadflag == DEAD_NO)
 -      if(self.classname == "player")
 +      if(IS_PLAYER(self))
                NIX_GiveCurrentWeapon();
        return 0;
  }
index f66c9657e26540a26564d8cdc3f60468fa15932b,5a050356de617f251898f27648ca1736a91065f8..0b70890141f2d4fc5e77e004a3433d18e45ac829
@@@ -129,9 -129,9 +129,9 @@@ MUTATOR_HOOKFUNCTION(superspec_ItemTouc
                                (self.autospec_flags& ASF_FLAG_GRAB && _item.classname == "item_flag_team"))
                {
  
 -                      if((self.enemy != other) || self.classname == "observer")
 +                      if((self.enemy != other) || IS_OBSERVER(self))
                        {
 -                              if(self.autospec_flags & ASF_OBSERVER_ONLY && self.classname != "observer")
 +                              if(self.autospec_flags & ASF_OBSERVER_ONLY && !IS_OBSERVER(self))
                                {
                                        if(self.superspec_flags & SSF_VERBOSE)
                                                superspec_msg("", "", self, sprintf("^8Ignored that %s^8 grabbed %s^8 since the observer_only option is ON\n", other.netname, _item.netname), 2);
@@@ -161,7 -161,7 +161,7 @@@ MUTATOR_HOOKFUNCTION(superspec_SV_Parse
        if(MUTATOR_RETURNVALUE) // command was already handled?
                return FALSE;
  
 -      if(self.classname == "player")
 +      if(IS_PLAYER(self))
                return FALSE;
  
        if(cmd_name == "superspec_itemfilter")
                if(cmd_argc == 2)
                {
                        if(argv(1) == "red")
-                               _team = COLOR_TEAM1;
+                               _team = NUM_TEAM_1;
                        else
-                               _team = COLOR_TEAM2;
+                               _team = NUM_TEAM_2;
                }
  
                FOR_EACH_PLAYER(_player)
@@@ -443,6 -443,9 +443,9 @@@ void superspec_hello(
  
  MUTATOR_HOOKFUNCTION(superspec_ClientConnect)
  {
+       if(clienttype(self) != CLIENTTYPE_REAL)
+               return FALSE;
        string fn = "superspec-local.options";
        float fh;
  
diff --combined qcsrc/server/portals.qc
index 7fba081c4fca04b9a21d1fafc84349e253ac6bc5,f0b9c5b21861a8095913ca6fc3066a53590c4411..d5b14bcdd87cc37603383746944c2f1b2daf6eae
@@@ -146,7 -146,7 +146,7 @@@ float Portal_TeleportPlayer(entity tele
        //print(vtos(to), "\n");
  
        // ang_x stuff works around weird quake angles
 -      if(player.classname == "player")
 +      if(IS_PLAYER(player))
                ang = Portal_ApplyTransformToPlayerAngle(transform, player.v_angle);
        else
                ang = AnglesTransform_ApplyToAngles(transform, player.angles);
        {
                // telefrag within 1 second of portal creation = amazing
                if(time < teleporter.teleport_time + 1)
-                       AnnounceTo(player, "amazing");
+                       Send_Notification(NOTIF_ONE, player, MSG_ANNCE, ANNCE_ACHIEVEMENT_AMAZING);
        }
  
        if not(teleporter.enemy)
@@@ -244,7 -244,7 +244,7 @@@ void Portal_Touch(
        if(self.solid != SOLID_TRIGGER)
                return; // possibly engine bug
  
 -      if(other.classname == "player")
 +      if(IS_PLAYER(other))
                return; // handled by think
  #endif
  
                        return;
                }
        if(other != self.aiment)
 -              if(other.classname == "player")
 +              if(IS_PLAYER(other))
                        if(IS_INDEPENDENT_PLAYER(other) || IS_INDEPENDENT_PLAYER(self.aiment))
                                return; // cannot go through someone else's portal
        if(other.aiment != self.aiment)
 -              if(other.aiment.classname == "player")
 +              if(IS_PLAYER(other.aiment))
                        if(IS_INDEPENDENT_PLAYER(other.aiment) || IS_INDEPENDENT_PLAYER(self.aiment))
                                return; // cannot go through someone else's portal
        fixedmakevectors(self.mangle);
@@@ -479,7 -479,7 +479,7 @@@ void Portal_Think(
  
  float Portal_Customize()
  {
 -      if(other.classname == "spectator")
 +      if(IS_SPEC(other))
                other = other.enemy;
        if(other == self.aiment)
        {
diff --combined qcsrc/server/race.qc
index 53e91f00a85e053d70b42a4bfc4a0eca1296b5bc,6ec8a68e4935cbd9ce7f6ee35e68b90f1f8eb401..63d846f1fd03ad861dc53de314b1c155356896ec
@@@ -149,20 -149,17 +149,17 @@@ void race_setTime(string map, float t, 
        }
  
        float oldrec;
-       string recorddifference, oldrec_holder;
+       string oldrec_holder;
        if (player_prevpos && (player_prevpos < newpos || !newpos))
        {
                oldrec = race_readTime(GetMapname(), player_prevpos);
-               recorddifference = strcat(" ^1[+", TIME_ENCODED_TOSTRING(t - oldrec), "]");
-               bprint(mynetname, "^7 couldn't break their ", race_placeName(player_prevpos), " place record of ", TIME_ENCODED_TOSTRING(oldrec), recorddifference, "\n");
                race_SendStatus(0, e); // "fail"
-               Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_FAIL, MSG_RACE);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_FAIL_RANKED, mynetname, player_prevpos, t, oldrec);
                return;
        } else if (!newpos) { // no ranking, time worse than the worst ranked
-               recorddifference = strcat(" ^1[+", TIME_ENCODED_TOSTRING(t - race_readTime(GetMapname(), RANKINGS_CNT)), "]");
-               bprint(mynetname, "^7 couldn't break the ", race_placeName(RANKINGS_CNT), " place record of ", TIME_ENCODED_TOSTRING(race_readTime(GetMapname(), RANKINGS_CNT)), recorddifference, "\n");
+               oldrec = race_readTime(GetMapname(), RANKINGS_CNT);
                race_SendStatus(0, e); // "fail"
-               Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_FAIL, MSG_RACE);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_FAIL_UNRANKED, mynetname, RANKINGS_CNT, t, oldrec);
                return;
        }
  
        // if the player does not have a UID we can unfortunately not store the record, as the rankings system relies on UIDs
        if(myuid == "")
        {
-               bprint(mynetname, "^1 scored a new record with ^7", TIME_ENCODED_TOSTRING(t), "^1, but lacks a UID, so the record will unfortunately be lost.\n");
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_NEW_MISSING_UID, mynetname, t);
                return;
        }
  
        if(rankings_reply)
                strunzone(rankings_reply);
        rankings_reply = strzone(getrankings());
-       if(newpos == 1) {
-               if(newpos == player_prevpos) {
-                       recorddifference = strcat(" ^2[-", TIME_ENCODED_TOSTRING(oldrec - t), "]");
-                       bprint(mynetname, "^1 improved their 1st place record with ", TIME_ENCODED_TOSTRING(t), recorddifference, "\n");
-               } else if (oldrec == 0) {
-                       bprint(mynetname, "^1 set the 1st place record with ", TIME_ENCODED_TOSTRING(t), "\n");
-               } else {
-                       recorddifference = strcat(" ^2[-", TIME_ENCODED_TOSTRING(oldrec - t), "]");
-                       bprint(mynetname, "^1 broke ", oldrec_holder, "^1's 1st place record with ", strcat(TIME_ENCODED_TOSTRING(t), recorddifference, "\n"));
-               }
-               race_SendStatus(3, e); // "new server record"
-               Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_SERVER_RECORD, MSG_RACE);
-       } else {
-               if(newpos == player_prevpos) {
-                       recorddifference = strcat(" ^2[-", TIME_ENCODED_TOSTRING(oldrec - t), "]");
-                       bprint(mynetname, "^5 improved their ", race_placeName(newpos), " ^5place record with ", TIME_ENCODED_TOSTRING(t), recorddifference, "\n");
-                       race_SendStatus(1, e); // "new time"
-                       Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_NEW_TIME, MSG_RACE);
-               } else if (oldrec == 0) {
-                       bprint(mynetname, "^2 set the ", race_placeName(newpos), " ^2place record with ", TIME_ENCODED_TOSTRING(t), "\n");
-                       race_SendStatus(2, e); // "new rank"
-                       Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_NEW_RANK, MSG_RACE);
-               } else {
-                       recorddifference = strcat(" ^2[-", TIME_ENCODED_TOSTRING(oldrec - t), "]");
-                       bprint(mynetname, "^2 broke ", oldrec_holder, "^2's ", race_placeName(newpos), " ^2place record with ", strcat(TIME_ENCODED_TOSTRING(t), recorddifference, "\n"));
-                       race_SendStatus(2, e); // "new rank"
-                       Send_KillNotification(e.netname, TIME_ENCODED_TOSTRING(t), "", RACE_NEW_TIME, MSG_RACE);
-               }
+       
+       if(newpos == player_prevpos)
+       {
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_NEW_IMPROVED, mynetname, newpos, t, oldrec);
+               if(newpos == 1) { race_SendStatus(3, e); } // "new server record"
+               else { race_SendStatus(1, e); } // "new time"
+       }
+       else if(oldrec == 0)
+       {
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_NEW_SET, mynetname, newpos, t);
+               if(newpos == 1) { race_SendStatus(3, e); } // "new server record"
+               else { race_SendStatus(2, e); } // "new rank"
+       }
+       else
+       {
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_NEW_BROKEN, mynetname, oldrec_holder, newpos, t, oldrec);
+               if(newpos == 1) { race_SendStatus(3, e); } // "new server record"
+               else { race_SendStatus(2, e); } // "new rank"
        }
  }
  
@@@ -290,7 -277,7 +277,7 @@@ void race_SendTime(entity e, float cp, 
                        {
                                e.race_completed = 1;
                                MAKE_INDEPENDENT_PLAYER(e);
-                               bprint(e.netname, "^7 has finished the race.\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_FINISHED, e.netname);
                                ClientData_Touch(e);
                        }
                }
@@@ -470,7 -457,7 +457,7 @@@ void checkpoint_passed(
        /*
         * Trigger targets
         */
 -      if not((self.spawnflags & 2) && (other.classname == "player"))
 +      if not((self.spawnflags & 2) && (IS_PLAYER(other)))
        {
                activator = other;
                oldmsg = self.message;
                self.message = oldmsg;
        }
  
 -      if(other.classname != "player")
 +      if not(IS_PLAYER(other))
                return;
  
        /*
@@@ -907,7 -894,7 +894,7 @@@ void race_AbandonRaceCheck(entity p
        {
                p.race_completed = 1;
                MAKE_INDEPENDENT_PLAYER(p);
-               bprint(p.netname, "^7 has abandoned the race.\n");
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_RACE_ABANDONED, p.netname);
                ClientData_Touch(p);
        }
  }
diff --combined qcsrc/server/scores.qc
index 5ccc212bdcee8da9cc4a2b0b5d52dc36249eb31e,4c75c9850a510948077c5ad018336c13535ebee7..114c4f7f85aee30606fc65841c6abd5f31c392d5
@@@ -204,13 -204,13 +204,13 @@@ void ScoreInfo_Init(float teams
                Net_LinkEntity(scores_initialized, FALSE, 0, ScoreInfo_SendEntity);
        }
        if(teams >= 1)
-               TeamScore_Spawn(COLOR_TEAM1, "Red");
+               TeamScore_Spawn(NUM_TEAM_1, "Red");
        if(teams >= 2)
-               TeamScore_Spawn(COLOR_TEAM2, "Blue");
+               TeamScore_Spawn(NUM_TEAM_2, "Blue");
        if(teams >= 3)
-               TeamScore_Spawn(COLOR_TEAM3, "Yellow");
+               TeamScore_Spawn(NUM_TEAM_3, "Yellow");
        if(teams >= 4)
-               TeamScore_Spawn(COLOR_TEAM4, "Pink");
+               TeamScore_Spawn(NUM_TEAM_4, "Pink");
  }
  
  /*
@@@ -256,8 -256,8 +256,8 @@@ float PlayerScore_Clear(entity player
        if(teamscores_entities_count)
                return 0;
  
+       if(MUTATOR_CALLHOOK(ForbidPlayerScore_Clear)) return 0;
        if(g_lms) return 0;
-       if(g_arena || g_ca) return 0;
        if(g_cts) return 0; // in CTS, you don't lose score by observing
        if(g_race && g_race_qualifying) return 0; // in qualifying, you don't lose score by observing
  
@@@ -393,15 -393,15 +393,15 @@@ void WinningConditionHelper(
        // so to match pure, match for :P0:
        // to match full, match for :S0:
  
+       fullstatus = autocvar_g_full_getstatus_responses;
        s = GetGametype();
        s = strcat(s, ":", autocvar_g_xonoticversion);
        s = strcat(s, ":P", ftos(cvar_purechanges_count));
        s = strcat(s, ":S", ftos(nJoinAllowed(world)));
        s = strcat(s, ":F", ftos(serverflags));
        s = strcat(s, ":M", modname);
-       s = strcat(s, "::", GetPlayerScoreString(world, 1)); // make this 1 once we can, note: this doesn't contain any :<letter>
-       fullstatus = autocvar_g_full_getstatus_responses;
+       s = strcat(s, "::", GetPlayerScoreString(world, (fullstatus ? 1 : 2)));
  
        if(teamscores_entities_count)
        {
                if(fullstatus)
                {
                        s = GetPlayerScoreString(p, 1);
 -                      if(clienttype(p) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(p))
                                s = strcat(s, ":human");
                        else
                                s = strcat(s, ":bot");
-                       if(!IS_PLAYER(p) && !g_arena && !g_ca && !g_lms)
 -                      if(p.classname != "player" && !g_arena && p.caplayer != 1 && !g_lms)
++                      if(!IS_PLAYER(p) && !g_arena && p.caplayer != 1 && !g_lms)
                                s = strcat(s, ":spectator");
                }
                else
                {
-                       if(IS_PLAYER(p) || g_arena || g_ca || g_lms)
 -                      if(p.classname == "player" || g_arena || p.caplayer == 1 || g_lms)
++                      if(IS_PLAYER(p) || g_arena || p.caplayer == 1 || g_lms)
                                s = GetPlayerScoreString(p, 2);
                        else
                                s = "-666";
@@@ -622,7 -622,7 +622,7 @@@ string GetTeamScoreString(float tm, flo
        if(tm == 0)
        {
                // label
-               for(i = 0; i < MAX_SCORE; ++i)
+               for(i = 0; i < MAX_TEAMSCORE; ++i)
                        if(teamscores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_PRIMARY)
                        {
                                f = teamscores_flags[i];
                                out = strcat(out, GetScoreLogLabel(l, f), ",");
                        }
                if(shortString < 2)
-               for(i = 0; i < MAX_SCORE; ++i)
+               for(i = 0; i < MAX_TEAMSCORE; ++i)
                        if(teamscores_flags[i] & SFL_SORT_PRIO_MASK == SFL_SORT_PRIO_SECONDARY)
                        {
                                f = teamscores_flags[i];
                                out = strcat(out, GetScoreLogLabel(l, f), ",");
                        }
                if(shortString < 1)
-               for(i = 0; i < MAX_SCORE; ++i)
+               for(i = 0; i < MAX_TEAMSCORE; ++i)
                        if(teamscores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_PRIMARY)
                        if(teamscores_flags[i] & SFL_SORT_PRIO_MASK != SFL_SORT_PRIO_SECONDARY)
                        {
@@@ -795,7 -795,7 +795,7 @@@ void Score_NicePrint_Team(entity to, fl
        sk = teamscorekeepers[t - 1];
        if(sk)
        {
-               s = strcat(s, ColoredTeamName(t));
+               s = strcat(s, Team_ColoredFullName(t));
                for(i = 0; i < MAX_TEAMSCORE; ++i)
                        if(teamscores_label[i] != "")
                        {
@@@ -894,7 -894,7 +894,7 @@@ void Score_NicePrint(entity to
        
        t = 0;
        FOR_EACH_CLIENT(p)
 -      if(p.classname != "player")
 +      if not(IS_PLAYER(p))
        {
                if not(t)
                        Score_NicePrint_Spectators(to);
diff --combined qcsrc/server/sv_main.qc
index c532f2ede0d8c391a9d5e9a350ce4b5a08bec70b,8d81e03806267b9c5b565aa495ade4744cffa619..538dcc62c624b173caa59b1ff53686a39dd50109
@@@ -153,7 -153,6 +153,6 @@@ Called before each frame by the serve
  float game_delay;
  float game_delay_last;
  
- void RuneMatchGivePoints();
  float RedirectionThink();
  entity SelectSpawnPoint (float anypoint);
  void StartFrame (void)
                c_seen = 0;
                FOR_EACH_CLIENT(cl)
                {
 -                      if(clienttype(cl) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(cl))
                                ++c_seeing;
 -                      if(cl.classname == "player")
 +                      if(IS_PLAYER(cl))
                                ++c_seen;
                }
                print("CEFC calls per second: ", ftos(c_seeing * (c_seen - 1) / t), "; ");
  
        skill = autocvar_skill;
  
-       count_players();
-       if(g_ca || g_freezetag)
-               count_alive_players();
-       Arena_Warmup();
-       Spawnqueue_Check();
        // detect when the pre-game countdown (if any) has ended and the game has started
        game_delay = (time < game_starttime) ? TRUE : FALSE;
  
        if(game_delay_last == TRUE)
        if(game_delay == FALSE)
        if(autocvar_sv_eventlog)
-                       GameLogEcho(":startdelay_ended");
+               GameLogEcho(":startdelay_ended");
  
        game_delay_last = game_delay;
  
        CreatureFrame ();
        CheckRules_World ();
  
-       RuneMatchGivePoints();
        bot_serverframe();
  
        FOR_EACH_PLAYER(self)
diff --combined qcsrc/server/t_items.qc
index 407962ae6adbb61e0894e493dbcf6750feef779a,392c05ce14f3e9b9ac0671b662e510adf34393fd..49a1cb3b5dca6cf84629950a0be1cff54f894c29
@@@ -627,19 -627,19 +627,19 @@@ float Item_GiveTo(entity item, entity p
                        _switchweapon = TRUE;
  
                        // play some cool sounds ;)
 -                      if (clienttype(player) == CLIENTTYPE_REAL)
 +                      if (IS_REAL_CLIENT(player))
                        {
                                if(player.health <= 5)
-                                       AnnounceTo(player, "lastsecond");
+                                       Send_Notification(NOTIF_ONE, player, MSG_ANNCE, ANNCE_MINSTAGIB_LASTSECOND);
                                else if(player.health < 50)
-                                       AnnounceTo(player, "narrowly");
+                                       Send_Notification(NOTIF_ONE, player, MSG_ANNCE, ANNCE_MINSTAGIB_NARROWLY);
                        }
                        // sound not available
                        // else if(item.items == IT_CELLS)
                        //      AnnounceTo(player, "ammo");
  
                        if (WEPSET_CONTAINS_EW(item, WEP_MINSTANEX))
-                               W_GiveWeapon (player, WEP_MINSTANEX, item.netname);
+                               W_GiveWeapon (player, WEP_MINSTANEX);
                        player.health = 100;
                }
  
                                pickedup = TRUE;
                                for(i = WEP_FIRST; i <= WEP_LAST; ++i)
                                        if(WEPSET_CONTAINS_AW(it, i))
-                                               W_GiveWeapon (player, i, item.netname);
+                                               W_GiveWeapon(player, i);
                        }
                }
  
@@@ -766,7 -766,7 +766,7 @@@ void Item_Touch (void
                }
        }
  
 -      if (other.classname != "player")
 +      if not(IS_PLAYER(other))
                return;
        if (other.deadflag)
                return;
@@@ -1680,7 -1680,7 +1680,7 @@@ void target_items_use (void
                return;
        }
  
 -      if(activator.classname != "player")
 +      if not(IS_PLAYER(activator))
                return;
        if(activator.deadflag != DEAD_NO)
                return;
index e3df3a759ef38752174cfbfd9c7b53b5ff50dc63,0b6f7fc4cd9488357ccb0b0110adf3adf87a18ec..fba705c28afd229aa5676ebc329bbff1fdba7ea1
@@@ -37,6 -37,8 +37,8 @@@ vector trigger_push_calculatevelocity(v
        torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
  
        grav = autocvar_sv_gravity;
+       if(other.gravity)
+               grav *= other.gravity;
  
        zdist = torg_z - org_z;
        sdist = vlen(torg - org - zdist * '0 0 1');
@@@ -164,7 -166,7 +166,7 @@@ void trigger_push_touch(
  
        other.flags &~= FL_ONGROUND;
  
 -      if (other.classname == "player")
 +      if (IS_PLAYER(other))
        {
                // reset tracking of oldvelocity for impact damage (sudden velocity changes)
                other.oldvelocity = other.velocity;
                        sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTN_NORM);
                        self.pushltime = time + 0.2;
                }
 -              float ct;
 -              ct = clienttype(other);
 -              if( ct == CLIENTTYPE_REAL || ct == CLIENTTYPE_BOT)
 +              if(IS_REAL_CLIENT(other) || IS_BOT_CLIENT(other))
                {
                        float i;
                        float found;
                                other.jumppadcount = other.jumppadcount + 1;
                        }
  
 -                      if(ct == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(other))
                        {
                                if(self.message)
                                        centerprint(other, self.message);
diff --combined qcsrc/server/teamplay.qc
index 163f71a099c7c0cba598d7d4ccc7282ced4f91e1,e307489909d2605e5184d2f7545a68ae84bd9241..7a3c64e26f6fd785fa2a7c67ce6308156a8ab707
@@@ -13,46 -13,6 +13,6 @@@ void TeamchangeFrags(entity e
        PlayerScore_Clear(e);
  }
  
- 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();
  
@@@ -146,14 -106,6 +106,6 @@@ void InitGameplayMode(
                have_team_spawns = -1; // request team spawns
        }
  
-       if(g_runematch)
-       {
-               // ActivateTeamplay();
-               fraglimit_override = autocvar_g_runematch_point_limit;
-               leadlimit_override = autocvar_g_runematch_point_leadlimit;
-               runematch_init();
-       }
        if(g_lms)
        {
                fraglimit_override = autocvar_g_lms_lives_override;
        {
                fraglimit_override = autocvar_g_arena_point_limit;
                leadlimit_override = autocvar_g_arena_point_leadlimit;
-               maxspawned = autocvar_g_arena_maxspawned;
-               if(maxspawned < 2)
-                       maxspawned = 2;
-               arena_roundbased = autocvar_g_arena_roundbased;
+               MUTATOR_ADD(gamemode_arena);
        }
  
        if(g_ca)
                ActivateTeamplay();
                fraglimit_override = autocvar_g_ca_point_limit;
                leadlimit_override = autocvar_g_ca_point_leadlimit;
-               precache_sound("ctf/red_capture.wav");
-               precache_sound("ctf/blue_capture.wav");
+               MUTATOR_ADD(gamemode_ca);
        }
        if(g_keyhunt)
        {
                ActivateTeamplay();
@@@ -416,13 -365,13 +365,13 @@@ void SetPlayerTeam(entity pl, float t, 
        float _color;
  
        if(t == 4)
-               _color = COLOR_TEAM4 - 1;
+               _color = NUM_TEAM_4 - 1;
        else if(t == 3)
-               _color = COLOR_TEAM3 - 1;
+               _color = NUM_TEAM_3 - 1;
        else if(t == 2)
-               _color = COLOR_TEAM2 - 1;
+               _color = NUM_TEAM_2 - 1;
        else
-               _color = COLOR_TEAM1 - 1;
+               _color = NUM_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");
        }
  
  }
@@@ -452,10 -401,10 +401,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 == NUM_TEAM_1) c1 = 0;
+                       if (head.team == NUM_TEAM_2) c2 = 0;
+                       if (head.team == NUM_TEAM_3) c3 = 0;
+                       if (head.team == NUM_TEAM_4) c4 = 0;
                        head = head.chain;
                }
        }
                {
                        if(!(g_domination && head.netname == ""))
                        {
-                               if(head.team == COLOR_TEAM1)
+                               if(head.team == NUM_TEAM_1)
                                        c1 = 0;
-                               else if(head.team == COLOR_TEAM2)
+                               else if(head.team == NUM_TEAM_2)
                                        c2 = 0;
-                               else if(head.team == COLOR_TEAM3)
+                               else if(head.team == NUM_TEAM_3)
                                        c3 = 0;
-                               else if(head.team == COLOR_TEAM4)
+                               else if(head.team == NUM_TEAM_4)
                                        c4 = 0;
                        }
                        head = find(head, classname, teament_name);
                if(autocvar_bot_vs_human > 0)
                {
                        // bots are all blue
 -                      if(clienttype(for_whom) == CLIENTTYPE_BOT)
 +                      if(IS_BOT_CLIENT(for_whom))
                                c1 = c3 = c4 = -1;
                        else
                                c2 = -1;
                else
                {
                        // bots are all red
 -                      if(clienttype(for_whom) == CLIENTTYPE_BOT)
 +                      if(IS_BOT_CLIENT(for_whom))
                                c2 = c3 = c4 = -1;
                        else
                                c1 = -1;
        }
  
        // if player has a forced team, ONLY allow that one
-       if(self.team_forced == COLOR_TEAM1 && c1 >= 0)
+       if(self.team_forced == NUM_TEAM_1 && c1 >= 0)
                c2 = c3 = c4 = -1;
-       else if(self.team_forced == COLOR_TEAM2 && c2 >= 0)
+       else if(self.team_forced == NUM_TEAM_2 && c2 >= 0)
                c1 = c3 = c4 = -1;
-       else if(self.team_forced == COLOR_TEAM3 && c3 >= 0)
+       else if(self.team_forced == NUM_TEAM_3 && c3 >= 0)
                c1 = c2 = c4 = -1;
-       else if(self.team_forced == COLOR_TEAM4 && c4 >= 0)
+       else if(self.team_forced == NUM_TEAM_4 && c4 >= 0)
                c1 = c2 = c3 = -1;
  }
  
@@@ -563,7 -512,7 +512,7 @@@ void GetTeamCounts(entity ignore
        FOR_EACH_CLIENT(head)
        {
                float t;
 -              if(head.classname == "player")
 +              if(IS_PLAYER(head))
                        t = head.team;
                else if(head.team_forced > 0)
                        t = head.team_forced; // reserve the spot
                if(head != ignore)// && head.netname != "")
                {
                        value = PlayerValue(head);
 -                      if(clienttype(head) == CLIENTTYPE_BOT)
 +                      if(IS_BOT_CLIENT(head))
                                bvalue = value;
                        else
                                bvalue = 0;
-                       if(t == COLOR_TEAM1)
+                       if(t == NUM_TEAM_1)
                        {
                                if(c1 >= 0)
                                {
                                        cb1 = cb1 + bvalue;
                                }
                        }
-                       if(t == COLOR_TEAM2)
+                       if(t == NUM_TEAM_2)
                        {
                                if(c2 >= 0)
                                {
                                        cb2 = cb2 + bvalue;
                                }
                        }
-                       if(t == COLOR_TEAM3)
+                       if(t == NUM_TEAM_3)
                        {
                                if(c3 >= 0)
                                {
                                        cb3 = cb3 + bvalue;
                                }
                        }
-                       if(t == COLOR_TEAM4)
+                       if(t == NUM_TEAM_4)
                        {
                                if(c4 >= 0)
                                {
@@@ -653,7 -602,7 +602,7 @@@ float TeamSmallerEqThanTeam(float ta, f
        if(ta == tb)
                return TRUE;
  
 -      if(clienttype(e) == CLIENTTYPE_REAL)
 +      if(IS_REAL_CLIENT(e))
        {
                if(bots_would_leave)
                {
@@@ -711,7 -660,7 +660,7 @@@ float FindSmallestTeam(entity pl, floa
  
        if(totalteams <= 1)
        {
 -              if(autocvar_g_campaign && pl && clienttype(pl) == CLIENTTYPE_REAL)
 +              if(autocvar_g_campaign && pl && IS_REAL_CLIENT(pl))
                        return 1; // special case for campaign and player joining
                else if(g_domination)
                        error("Too few teams available for domination\n");
@@@ -769,13 -718,13 +718,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 == NUM_TEAM_1)
                        selectedteam = pl.team;
-               else if(c2 >= 0 && pl.team == COLOR_TEAM2)
+               else if(c2 >= 0 && pl.team == NUM_TEAM_2)
                        selectedteam = pl.team;
-               else if(c3 >= 0 && pl.team == COLOR_TEAM3)
+               else if(c3 >= 0 && pl.team == NUM_TEAM_3)
                        selectedteam = pl.team;
-               else if(c4 >= 0 && pl.team == COLOR_TEAM4)
+               else if(c4 >= 0 && pl.team == NUM_TEAM_4)
                        selectedteam = pl.team;
                else
                        selectedteam = -1;
                TeamchangeFrags(self);
                if(smallest == 1)
                {
-                       SetPlayerColors(pl, COLOR_TEAM1 - 1);
+                       SetPlayerColors(pl, NUM_TEAM_1 - 1);
                }
                else if(smallest == 2)
                {
-                       SetPlayerColors(pl, COLOR_TEAM2 - 1);
+                       SetPlayerColors(pl, NUM_TEAM_2 - 1);
                }
                else if(smallest == 3)
                {
-                       SetPlayerColors(pl, COLOR_TEAM3 - 1);
+                       SetPlayerColors(pl, NUM_TEAM_3 - 1);
                }
                else if(smallest == 4)
                {
-                       SetPlayerColors(pl, COLOR_TEAM4 - 1);
+                       SetPlayerColors(pl, NUM_TEAM_4 - 1);
                }
                else
                {
@@@ -844,21 -793,21 +793,21 @@@ void SV_ChangeTeam(float _color
        scolor = self.clientcolors & 0x0F;
        dcolor = _color & 0x0F;
  
-       if(scolor == COLOR_TEAM1 - 1)
+       if(scolor == NUM_TEAM_1 - 1)
                steam = 1;
-       else if(scolor == COLOR_TEAM2 - 1)
+       else if(scolor == NUM_TEAM_2 - 1)
                steam = 2;
-       else if(scolor == COLOR_TEAM3 - 1)
+       else if(scolor == NUM_TEAM_3 - 1)
                steam = 3;
-       else // if(scolor == COLOR_TEAM4 - 1)
+       else // if(scolor == NUM_TEAM_4 - 1)
                steam = 4;
-       if(dcolor == COLOR_TEAM1 - 1)
+       if(dcolor == NUM_TEAM_1 - 1)
                dteam = 1;
-       else if(dcolor == COLOR_TEAM2 - 1)
+       else if(dcolor == NUM_TEAM_2 - 1)
                dteam = 2;
-       else if(dcolor == COLOR_TEAM3 - 1)
+       else if(dcolor == NUM_TEAM_3 - 1)
                dteam = 3;
-       else // if(dcolor == COLOR_TEAM4 - 1)
+       else // if(dcolor == NUM_TEAM_4 - 1)
                dteam = 4;
  
        CheckAllowedTeams(self);
  
  //    bprint("allow change teams from ", ftos(steam), " to ", ftos(dteam), "\n");
  
 -      if(self.classname == "player" && steam != dteam)
 +      if(IS_PLAYER(self) && steam != dteam)
        {
                // reduce frags during a team change
                TeamchangeFrags(self);
  
        SetPlayerTeam(self, dteam, steam, FALSE);
  
 -      if(self.classname == "player" && steam != dteam)
 +      if(IS_PLAYER(self) && steam != dteam)
        {
                // kill player when changing teams
                if(self.deadflag == DEAD_NO)
@@@ -947,13 -896,13 +896,13 @@@ void ShufflePlayerOutOfTeam (float sour
        }
  
        if(source_team == 1)
-               steam = COLOR_TEAM1;
+               steam = NUM_TEAM_1;
        else if(source_team == 2)
-               steam = COLOR_TEAM2;
+               steam = NUM_TEAM_2;
        else if(source_team == 3)
-               steam = COLOR_TEAM3;
+               steam = NUM_TEAM_3;
        else // if(source_team == 4)
-               steam = COLOR_TEAM4;
+               steam = NUM_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
@@@ -1072,12 -1021,12 +1021,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", NUM_TEAM_1-1);
+       tdm_spawnteam("Blue", NUM_TEAM_2-1);
        if(numteams >= 3)
-               tdm_spawnteam("Yellow", COLOR_TEAM3-1);
+               tdm_spawnteam("Yellow", NUM_TEAM_3-1);
        if(numteams >= 4)
-               tdm_spawnteam("Pink", COLOR_TEAM4-1);
+               tdm_spawnteam("Pink", NUM_TEAM_4-1);
  }
  
  void tdm_delayedinit()
index 4c216e5a756fe038e807a04e355f9853b622714c,429b8e5f9f8c55cdf709e2e405c5481dffb74527..a530680632592cb5158e8d430b938e57fe30beb8
@@@ -86,7 -86,7 +86,7 @@@ void bumb_fire_cannon(entity _gun, stri
        vehicles_projectile("bigplasma_muzzleflash", "weapons/flacexp3.wav",
                                                v, normalize(v_forward + randomvec() * autocvar_g_vehicle_bumblebee_cannon_spread) * autocvar_g_vehicle_bumblebee_cannon_speed,
                                                autocvar_g_vehicle_bumblebee_cannon_damage, autocvar_g_vehicle_bumblebee_cannon_radius, autocvar_g_vehicle_bumblebee_cannon_force,  0,
-                                               DEATH_BUMB_GUN, PROJECTILE_BUMBLE_GUN, 0, TRUE, TRUE, _owner);
+                                               DEATH_VH_BUMB_GUN, PROJECTILE_BUMBLE_GUN, 0, TRUE, TRUE, _owner);
  }
  
  float bumb_gunner_frame()
  
  void bumb_gunner_exit(float _exitflag)
  {
 -
 -
 -      if(clienttype(self) == CLIENTTYPE_REAL)
 +      if(IS_REAL_CLIENT(self))
        {
                msg_entity = self;
                WriteByte(MSG_ONE, SVC_SETVIEWPORT);
@@@ -339,7 -341,7 +339,7 @@@ float bumb_gunner_enter(
  
  float vehicles_valid_pilot()
  {
 -      if(other.classname != "player")
 +      if not(IS_PLAYER(other))
                return FALSE;
  
        if(other.deadflag != DEAD_NO)
        if(other.vehicle != world)
                return FALSE;
  
 -      if(clienttype(other) != CLIENTTYPE_REAL)
 +      if not(IS_REAL_CLIENT(other))
                if(!autocvar_g_vehicles_allow_bots)
                        return FALSE;
  
@@@ -559,7 -561,7 +559,7 @@@ float bumb_pilot_frame(
                                                        if(autocvar_g_vehicle_bumblebee_healgun_hps)
                                                                trace_ent.vehicle_health = min(trace_ent.vehicle_health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.tur_health);
                                                }
 -                                              else if(trace_ent.flags & FL_CLIENT)
 +                                              else if(IS_CLIENT(trace_ent))
                                                {
                                                        if(trace_ent.health <= autocvar_g_vehicle_bumblebee_healgun_hmax && autocvar_g_vehicle_bumblebee_healgun_hps)
                                                                trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax);
@@@ -733,7 -735,7 +733,7 @@@ void bumb_blowup(
                                 autocvar_g_vehicle_bumblebee_blowup_edgedamage,
                                 autocvar_g_vehicle_bumblebee_blowup_radius, self,
                                 autocvar_g_vehicle_bumblebee_blowup_forceintensity,
-                                DEATH_WAKIBLOWUP, world);
+                                DEATH_VH_BUMB_DEATH, world);
  
        sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
        pointparticles(particleeffectnum("explosion_large"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1);
index 76d4aec96a2692a151ec0fc56795a5765155f902,a79fcc62a4e2df25044e7d4a55e7647ecf4273f4..db57f65a1ff94f4516a9dfe023a37b522acd8abb
@@@ -46,7 -46,7 +46,7 @@@ float SendAuxiliaryXhair(entity to, flo
  
  void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, float axh_id)
  {
 -    if (clienttype(own) != CLIENTTYPE_REAL)
 +    if not(IS_REAL_CLIENT(own))
          return;
  
      entity axh;
@@@ -101,7 -101,7 +101,7 @@@ void SendAuxiliaryXhair2(entity own, ve
  **/
  void CSQCVehicleSetup(entity own, float vehicle_id)
  {
 -    if (clienttype(own) != CLIENTTYPE_REAL)
 +    if not(IS_REAL_CLIENT(own))
          return;
        
        msg_entity = own;
@@@ -503,11 -503,11 +503,11 @@@ void vehicles_spawn(
  // Better way of determening whats crushable needed! (fl_crushable?)
  float vehicles_crushable(entity e)
  {
 -    if(e.classname == "player")
 +    if(IS_PLAYER(e))
          return TRUE;
  
 -    if(e.classname == "monster_zombie")
 -        return TRUE;
 +    if(e.flags & FL_MONSTER)
 +        return TRUE; // more bitflags for everyone!
  
      return FALSE;
  }
@@@ -544,7 -544,7 +544,7 @@@ void vehicles_touch(
          if(vehicles_crushable(other))
          {
              if(vlen(self.velocity) != 0)
-                 Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VHCRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force);
+                 Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force);
  
              return; // Dont do selfdamage when hitting "soft targets".
          }
          return;
      }
  
 -    if(other.classname != "player")
 +    if not(IS_PLAYER(other))
          return;
  
      if(other.deadflag != DEAD_NO)
@@@ -572,7 -572,7 +572,7 @@@ void vehicles_enter(
  {
     // Remove this when bots know how to use vehicles
     
 -    if (clienttype(other) == CLIENTTYPE_BOT)    
 +    if (IS_BOT_CLIENT(other))    
          if (autocvar_g_vehicles_allow_bots)
              dprint("Bot enters vehicle\n"); // This is where we need to disconnect (some, all?) normal bot AI and hand over to vehicle's _aiframe()
          else
      self.team                 = self.owner.team;
      self.flags               -= FL_NOTARGET;
      
 -    if (clienttype(other) == CLIENTTYPE_REAL)
 +    if (IS_REAL_CLIENT(other))
      {
          msg_entity = other;
          WriteByte (MSG_ONE, SVC_SETVIEWPORT);
@@@ -740,7 -740,7 +740,7 @@@ void vehicles_exit(float eject
      }
      
      vehicles_exit_running = TRUE;
 -    if(self.flags & FL_CLIENT)
 +    if(IS_CLIENT(self))
      {
          _vehicle = self.vehicle;
              
  
      if (_player)
      {
 -        if (clienttype(_player) == CLIENTTYPE_REAL)
 +        if (IS_REAL_CLIENT(_player))
          {
              msg_entity = _player;
              WriteByte (MSG_ONE, SVC_SETVIEWPORT);
@@@ -1033,7 -1033,7 +1033,7 @@@ void vehicles_showwp(
      }
  
      if(teamplay && self.team)
-           rgb = TeamColor(self.team);
+           rgb = Team_ColorRGB(self.team);
      else
            rgb = '1 1 1';
      WaypointSprite_Spawn("vehicle", 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, TRUE, RADARICON_POWERUP, rgb);
@@@ -1268,7 -1268,7 +1268,7 @@@ float vehicle_initialize(string  net_na
      self.vehicle_exit        = exitfunc;
      self.vehicle_enter       = enterproc;
      self.PlayerPhysplug      = physproc;
-     self.event_damage        = vehicles_damage;
+     self.event_damage        = func_null;
      self.touch               = vehicles_touch;
      self.think               = vehicles_spawn;
      self.nextthink           = time;
diff --combined qcsrc/server/w_common.qc
index 592fa7df35d86e9302bc6d15bae0e62a5fd6ff89,2e0c1e8f02bbcd466773894e43e3da4df52104f5..a2de5dab04be64621a6742d0c024ac05aa69e79f
@@@ -1,5 -1,5 +1,5 @@@
  
- void W_GiveWeapon (entity e, float wep, string name)
+ void W_GiveWeapon (entity e, float wep)
  {
        entity oldself;
  
        oldself = self;
        self = e;
  
--      if not(g_minstagib)
-       if (IS_PLAYER(other))
-       {
-               sprint (other, "You got the ^2");
-               sprint (other, name);
-               sprint (other, "\n");
-       }
 -      if(other.classname == "player")
++      if(IS_PLAYER(other))
+               { Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_WEAPON_GOT, wep); }
  
        self = oldself;
  }
@@@ -109,7 -105,7 +104,7 @@@ void FireRailgunBullet (vector start, v
        // Find all non-hit players the beam passed close by
        if(deathtype == WEP_MINSTANEX || deathtype == WEP_NEX)
        {
 -              FOR_EACH_REALCLIENT(msg_entity) if(msg_entity != self) if(!msg_entity.railgunhit) if not(msg_entity.classname == "spectator" && msg_entity.enemy == self) // we use realclient, so spectators can hear the whoosh too
 +              FOR_EACH_REALCLIENT(msg_entity) if(msg_entity != self) if(!msg_entity.railgunhit) if not(IS_SPEC(msg_entity) && msg_entity.enemy == self) // we use realclient, so spectators can hear the whoosh too
                {
                        // nearest point on the beam
                        beampos = start + dir * bound(0, (msg_entity.origin - start) * dir, length);
  .float dmg_force;
  .float dmg_radius;
  .float dmg_total;
+ //.float last_yoda;
  void W_BallisticBullet_Hit (void)
  {
        float f, q, g;
                g = accuracy_isgooddamage(self.realowner, other);
                Damage(other, self, self.realowner, self.dmg * f, self.projectiledeathtype, self.origin, self.dmg_force * normalize(self.velocity) * f);
  
-               if(yoda)
-                       AnnounceTo(self.realowner, "awesome");
+               /*if(yoda && (time > (self.last_yoda + 5)))
+               {
+                       Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
+                       self.last_yoda = time; 
+               }*/
  
                // calculate hits for ballistic weapons
                if(g)
@@@ -445,7 -445,7 +444,7 @@@ void fireBallisticBullet(vector start, 
                lag = ANTILAG_LATENCY(self);
                if(lag < 0.001)
                        lag = 0;
 -              if(clienttype(self) != CLIENTTYPE_REAL)
 +              if not(IS_REAL_CLIENT(self))
                        lag = 0;
                if(autocvar_g_antilag == 0 || self.cvar_cl_noantilag)
                        lag = 0; // only do hitscan, but no antilag
@@@ -618,7 -618,7 +617,7 @@@ void W_PrepareExplosionByDamage(entity 
        self.takedamage = DAMAGE_NO;
        self.event_damage = func_null;
        
 -      if((attacker.flags & FL_CLIENT) && !autocvar_g_projectiles_keep_owner)
 +      if(IS_CLIENT(attacker) && !autocvar_g_projectiles_keep_owner)
        {
                self.owner = attacker;
                self.realowner = attacker;
index 21f9d36639dcc6806cf6dd7330869aaab0e559d6,972642343b38c068317eeb1ec5b1cae944e6fdfb..29af116bc4977dbd80f7be4311761bdaff1b8b87
@@@ -29,11 -29,11 +29,11 @@@ void W_Plasma_TriggerCombo(vector org, 
  void W_Plasma_Explode (void)
  {
        if(other.takedamage == DAMAGE_AIM)
 -              if(other.classname == "player")
 +              if(IS_PLAYER(other))
                        if(IsDifferentTeam(self.realowner, other))
                                if(other.deadflag == DEAD_NO)
                                        if(IsFlying(other))
-                                               AnnounceTo(self.realowner, "electrobitch");
+                                               Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_ELECTROBITCH);
  
        self.event_damage = func_null;
        self.takedamage = DAMAGE_NO;
@@@ -543,6 -543,27 +543,27 @@@ float w_electro(float req
        {
                W_Reload(min(autocvar_g_balance_electro_primary_ammo, autocvar_g_balance_electro_secondary_ammo), autocvar_g_balance_electro_reload_ammo, autocvar_g_balance_electro_reload_time, "weapons/reload.wav");
        }
+       else if (req == WR_SUICIDEMESSAGE)
+       {
+               if(w_deathtype & HITTYPE_SECONDARY)
+                       return WEAPON_ELECTRO_SUICIDE_ORBS;
+               else
+                       return WEAPON_ELECTRO_SUICIDE_BOLT;
+       }
+       else if (req == WR_KILLMESSAGE)
+       {
+               if(w_deathtype & HITTYPE_SECONDARY)
+               {
+                       return WEAPON_ELECTRO_MURDER_ORBS;
+               }
+               else
+               {
+                       if(w_deathtype & HITTYPE_BOUNCE)
+                               return WEAPON_ELECTRO_MURDER_COMBO;
+                       else
+                               return WEAPON_ELECTRO_MURDER_BOLT;
+               }
+       }
        return TRUE;
  }
  #endif
@@@ -581,32 -602,6 +602,6 @@@ float w_electro(float req
                precache_sound("weapons/electro_impact.wav");
                precache_sound("weapons/electro_impact_combo.wav");
        }
-       else if (req == WR_SUICIDEMESSAGE)
-       {
-               if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = _("%s could not remember where they put their electro plasma");
-               else
-                       w_deathtypestring = _("%s played with electro plasma");
-       }
-       else if (req == WR_KILLMESSAGE)
-       {
-               if(w_deathtype & HITTYPE_SECONDARY)
-               {
-                       if(w_deathtype & HITTYPE_SPLASH) // unchecked: BOUNCE
-                               w_deathtypestring = _("%s just noticed %s's electro plasma");
-                       else // unchecked: BOUNCE
-                               w_deathtypestring = _("%s got in touch with %s's electro plasma");
-               }
-               else
-               {
-                       if(w_deathtype & HITTYPE_BOUNCE) // combo
-                               w_deathtypestring = _("%s felt the electrifying air of %s's electro combo");
-                       else if(w_deathtype & HITTYPE_SPLASH)
-                               w_deathtypestring = _("%s got too close to %s's blue electro bolt");
-                       else
-                               w_deathtypestring = _("%s was blasted by %s's blue electro bolt");
-               }
-       }
        return TRUE;
  }
  #endif
index ba0acc34408ad346fdd538ff0e4a7fd6fa7e2405,4d243a513575bb04ab1703521d2c981801cb8c3c..7d9ef6c04e3a39b937899414abe51c0cee345a59
@@@ -28,7 -28,7 +28,7 @@@ void W_Fireball_Explode (void
                // 2. bfg effect
                // NOTE: this cannot be made warpzone aware by design. So, better intentionally ignore warpzones here.
                for(e = findradius(self.origin, autocvar_g_balance_fireball_primary_bfgradius); e; e = e.chain)
 -              if(e != self.realowner) if(e.takedamage == DAMAGE_AIM) if(e.classname != "player" || !self.realowner || IsDifferentTeam(e, self))
 +              if(e != self.realowner) if(e.takedamage == DAMAGE_AIM) if(!IS_PLAYER(e) || !self.realowner || IsDifferentTeam(e, self))
                {
                        // can we see fireball?
                        traceline(e.origin + e.view_ofs, self.origin, MOVE_NORMAL, e);
@@@ -73,7 -73,7 +73,7 @@@ void W_Fireball_LaserPlay(float dt, flo
  
        RandomSelection_Init();
        for(e = WarpZone_FindRadius(self.origin, dist, TRUE); e; e = e.chain)
 -      if(e != self.realowner) if(e.takedamage == DAMAGE_AIM) if(e.classname != "player" || !self.realowner || IsDifferentTeam(e, self))
 +      if(e != self.realowner) if(e.takedamage == DAMAGE_AIM) if(!IS_PLAYER(e) || !self.realowner || IsDifferentTeam(e, self))
        {
                p = e.origin;
                p_x += e.mins_x + random() * (e.maxs_x - e.mins_x);
@@@ -374,6 -374,24 +374,24 @@@ float w_fireball(float req
        {
                self.fireball_primarytime = time;
        }
+       else if (req == WR_SUICIDEMESSAGE)
+       {
+               if(w_deathtype & HITTYPE_SECONDARY)
+                       return WEAPON_FIREBALL_SUICIDE_FIREMINE;
+               else
+                       return WEAPON_FIREBALL_SUICIDE_BLAST;
+       }
+       else if (req == WR_KILLMESSAGE)
+       {
+               if(w_deathtype & HITTYPE_SECONDARY)
+               {
+                       return WEAPON_FIREBALL_MURDER_FIREMINE;
+               }
+               else
+               {
+                       return WEAPON_FIREBALL_MURDER_BLAST;
+               }
+       }
        return TRUE;
  }
  #endif
@@@ -399,34 -417,7 +417,7 @@@ float w_fireball(float req
        {
                precache_sound("weapons/fireball_impact2.wav");
        }
-       else if (req == WR_SUICIDEMESSAGE)
-       {
-               if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = _("%s forgot about some firemine");
-               else
-                       w_deathtypestring = _("%s should have used a smaller gun");
-       }
-       else if (req == WR_KILLMESSAGE)
-       {
-               if(w_deathtype & HITTYPE_SECONDARY)
-               {
-                       w_deathtypestring = _("%s fatefully ignored %s's firemine");
-               }
-               else
-               {
-                       if(w_deathtype & HITTYPE_BOUNCE)
-                       {
-                               if(w_deathtype & HITTYPE_SPLASH) // BFG effect
-                                       w_deathtypestring = _("%s could not hide from %s's fireball");
-                               else // laser
-                                       w_deathtypestring = _("%s saw the pretty lights of %s's fireball");
-                       }
-                       else if(w_deathtype & HITTYPE_SPLASH)
-                               w_deathtypestring = _("%s got too close to %s's fireball");
-                       else
-                               w_deathtypestring = _("%s tasted %s's fireball");
-               }
-       }
        return TRUE;
  }
  #endif
index acde7d5c10f2d6c03bd117d2507db29bd47d3315,cdcf841e018956e11b48ddd61afe7903f76e1fca..dcf06ceaa7f168e7e76fc0a549b3ccad62724c65
@@@ -8,11 -8,11 +8,11 @@@ REGISTER_WEAPON(GRENADE_LAUNCHER, w_gla
  void W_Grenade_Explode (void)
  {
        if(other.takedamage == DAMAGE_AIM)
 -              if(other.classname == "player")
 +              if(IS_PLAYER(other))
                        if(IsDifferentTeam(self.realowner, other))
                                if(other.deadflag == DEAD_NO)
                                        if(IsFlying(other))
-                                               AnnounceTo(self.realowner, "airshot");
+                                               Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
  
        self.event_damage = func_null;
        self.takedamage = DAMAGE_NO;
  void W_Grenade_Explode2 (void)
  {
        if(other.takedamage == DAMAGE_AIM)
 -              if(other.classname == "player")
 +              if(IS_PLAYER(other))
                        if(IsDifferentTeam(self.realowner, other))
                                if(other.deadflag == DEAD_NO)
                                        if(IsFlying(other))
-                                               AnnounceTo(self.realowner, "airshot");
+                                               Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
  
        self.event_damage = func_null;
        self.takedamage = DAMAGE_NO;
@@@ -366,6 -366,20 +366,20 @@@ float w_glauncher(float req
        {
                W_Reload(min(autocvar_g_balance_grenadelauncher_primary_ammo, autocvar_g_balance_grenadelauncher_secondary_ammo), autocvar_g_balance_grenadelauncher_reload_ammo, autocvar_g_balance_grenadelauncher_reload_time, "weapons/reload.wav");
        }
+       else if (req == WR_SUICIDEMESSAGE)
+       {
+               if(w_deathtype & HITTYPE_SECONDARY)
+                       return WEAPON_MORTAR_SUICIDE_BOUNCE;
+               else
+                       return WEAPON_MORTAR_SUICIDE_EXPLODE;
+       }
+       else if (req == WR_KILLMESSAGE)
+       {
+               if(w_deathtype & HITTYPE_SECONDARY)
+                       return WEAPON_MORTAR_MURDER_BOUNCE;
+               else
+                       return WEAPON_MORTAR_MURDER_EXPLODE;
+       }
        return TRUE;
  }
  #endif
@@@ -384,23 -398,6 +398,6 @@@ float w_glauncher(float req
        {
                precache_sound("weapons/grenade_impact.wav");
        }
-       else if (req == WR_SUICIDEMESSAGE)
-       {
-               if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = _("%s didn't see their own grenade");
-               else
-                       w_deathtypestring = _("%s blew themself up with their grenadelauncher");
-       }
-       else if (req == WR_KILLMESSAGE)
-       {
-               if(w_deathtype & HITTYPE_SPLASH)
-                       if(w_deathtype & HITTYPE_BOUNCE) // (must be secondary then)
-                               w_deathtypestring = _("%s didn't see %s's grenade");
-                       else // unchecked: SECONDARY
-                               w_deathtypestring = _("%s almost dodged %s's grenade");
-               else // unchecked: SECONDARY, BOUNCE
-                       w_deathtypestring = _("%s ate %s's grenade");
-       }
        return TRUE;
  }
  #endif
index 12d0a40f9c70626ba7a8dc5c33c0f576f0862d26,40c60e827e3adc024457f462577d6a2b68b32ac0..813bcff75508c01b044c43cfef5a48ff92593863
@@@ -5,6 -5,7 +5,7 @@@ REGISTER_WEAPON(MINE_LAYER, w_minelayer
  void W_Mine_Think (void);
  .float minelayer_detonate, mine_explodeanyway;
  .float mine_time;
+ .vector mine_orientation;
  
  void spawnfunc_weapon_minelayer (void)
  {
@@@ -31,7 -32,7 +32,7 @@@ void W_Mine_Stick (entity to
        setmodel(newmine, "models/mine.md3");
        newmine.angles = vectoangles(-trace_plane_normal); // face against the surface
  
-       newmine.oldvelocity = self.velocity;
+       newmine.mine_orientation = -trace_plane_normal;
  
        newmine.takedamage = self.takedamage;
        newmine.damageforcescale = self.damageforcescale;
  void W_Mine_Explode ()
  {
        if(other.takedamage == DAMAGE_AIM)
 -              if(other.classname == "player")
 +              if(IS_PLAYER(other))
                        if(IsDifferentTeam(self.realowner, other))
                                if(other.deadflag == DEAD_NO)
                                        if(IsFlying(other))
-                                               AnnounceTo(self.realowner, "airshot");
+                                               Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
  
        self.event_damage = func_null;
        self.takedamage = DAMAGE_NO;
@@@ -95,7 -96,7 +96,7 @@@ void W_Mine_DoRemoteExplode (
        self.takedamage = DAMAGE_NO;
  
        if(self.movetype == MOVETYPE_NONE || self.movetype == MOVETYPE_FOLLOW)
-               self.velocity = self.oldvelocity;
+               self.velocity = self.mine_orientation; // particle fx and decals need .velocity
  
        RadiusDamage (self, self.realowner, autocvar_g_balance_minelayer_remote_damage, autocvar_g_balance_minelayer_remote_edgedamage, autocvar_g_balance_minelayer_remote_radius, world, autocvar_g_balance_minelayer_remote_force, self.projectiledeathtype | HITTYPE_BOUNCE, world);
  
@@@ -153,7 -154,7 +154,7 @@@ float W_Mine_Count(entity e
        entity mine;
        for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.realowner == e)
                minecount += 1;
-               
        return minecount;
  }
  
@@@ -184,7 -185,7 +185,7 @@@ void W_Mine_Think (void
  
        // a player's mines shall explode if he disconnects or dies
        // TODO: Do this on team change too -- Samual: But isn't a player killed when they switch teams?
 -      if(self.realowner.classname != "player" || self.realowner.deadflag != DEAD_NO)
 +      if(!IS_PLAYER(self.realowner) || self.realowner.deadflag != DEAD_NO)
        {
                other = world;
                self.projectiledeathtype |= HITTYPE_BOUNCE;
        head = findradius(self.origin, autocvar_g_balance_minelayer_proximityradius);
        while(head)
        {
 -              if(head.classname == "player" && head.deadflag == DEAD_NO)
 +              if(IS_PLAYER(head) && head.deadflag == DEAD_NO)
                if(head != self.realowner && IsDifferentTeam(head, self.realowner)) // don't trigger for team mates
                if(!self.mine_time)
                {
@@@ -225,9 -226,14 +226,14 @@@ void W_Mine_Touch (void
        if(self.movetype == MOVETYPE_NONE || self.movetype == MOVETYPE_FOLLOW)
                return; // we're already a stuck mine, why do we get called? TODO does this even happen?
  
-       PROJECTILE_TOUCH;
+       if(WarpZone_Projectile_Touch())
+       {
+               if(wasfreed(self))
+                       self.realowner.minelayer_mines -= 1;
+               return;
+       }
  
 -      if(other && other.classname == "player" && other.deadflag == DEAD_NO)
 +      if(other && IS_PLAYER(other) && other.deadflag == DEAD_NO)
        {
                // hit a player
                // don't stick
@@@ -263,8 -269,7 +269,7 @@@ void W_Mine_Attack (void
        // scan how many mines we placed, and return if we reached our limit
        if(autocvar_g_balance_minelayer_limit)
        {
-       
-               if(W_Mine_Count(self) >= autocvar_g_balance_minelayer_limit)
+               if(self.minelayer_mines >= autocvar_g_balance_minelayer_limit)
                {
                        // the refire delay keeps this message from being spammed
                        sprint(self, strcat("minelayer: You cannot place more than ^2", ftos(autocvar_g_balance_minelayer_limit), " ^7mines at a time\n") );
@@@ -355,7 -360,10 +360,10 @@@ float w_minelayer(float req
        if (req == WR_AIM)
        {
                // aim and decide to fire if appropriate
-               self.BUTTON_ATCK = bot_aim(autocvar_g_balance_minelayer_speed, 0, autocvar_g_balance_minelayer_lifetime, FALSE);
+               if(self.minelayer_mines >= autocvar_g_balance_minelayer_limit)
+                       self.BUTTON_ATCK = FALSE;
+               else
+                       self.BUTTON_ATCK = bot_aim(autocvar_g_balance_minelayer_speed, 0, autocvar_g_balance_minelayer_lifetime, FALSE);
                if(skill >= 2) // skill 0 and 1 bots won't detonate mines!
                {
                        // decide whether to detonate mines
                                        //As the distance gets larger, a correct detonation gets near imposible
                                        //Bots are assumed to use the mine spawnfunc_light to see if the mine gets near a player
                                        if(v_forward * normalize(mine.origin - self.enemy.origin)< 0.1)
 -                                              if(self.enemy.classname == "player")
 +                                              if(IS_PLAYER(self.enemy))
                                                        if(desirabledamage >= 0.1*coredamage)
                                                                if(random()/distance*300 > frametime*bound(0,(10-skill)*0.2,1))
                                                                        self.BUTTON_ATCK2 = TRUE;
                else
                        return FALSE;
        }
+       else if (req == WR_RESETPLAYER)
+       {
+               self.minelayer_mines = 0;
+       }
        else if (req == WR_RELOAD)
        {
                W_Reload(autocvar_g_balance_minelayer_ammo, autocvar_g_balance_minelayer_reload_ammo, autocvar_g_balance_minelayer_reload_time, "weapons/reload.wav");
        }
+       else if (req == WR_SUICIDEMESSAGE)
+       {
+               return WEAPON_MINELAYER_SUICIDE;
+       }
+       else if (req == WR_KILLMESSAGE)
+       {
+               return WEAPON_MINELAYER_MURDER;
+       }
        return TRUE;
  }
  #endif
@@@ -527,20 -547,6 +547,6 @@@ float w_minelayer(float req
        {
                precache_sound("weapons/mine_exp.wav");
        }
-       else if (req == WR_SUICIDEMESSAGE)
-               if(w_deathtype & HITTYPE_BOUNCE) // (remote detonation)
-                       w_deathtypestring = _("%s blew themself up with their minelayer");
-               else
-                       w_deathtypestring = _("%s forgot about their mine");
-       else if (req == WR_KILLMESSAGE)
-       {
-               if(w_deathtype & HITTYPE_BOUNCE) // (remote detonation)
-                       w_deathtypestring = _("%s got too close to %s's mine");
-               else if(w_deathtype & HITTYPE_SPLASH)
-                       w_deathtypestring = _("%s almost dodged %s's mine");
-               else
-                       w_deathtypestring = _("%s stepped on %s's mine");
-       }
        return TRUE;
  }
  #endif
index 456d24907986c1cb442e53a8886e6565b707607d,250fc0d3bea089ff22db74c3633f54244e38f8b4..7548de88d5cfb96ed70c727f6b264ced34c71fb7
@@@ -19,11 -19,11 +19,11 @@@ void W_Rocket_Explode (
        W_Rocket_Unregister();
  
        if(other.takedamage == DAMAGE_AIM)
 -              if(other.classname == "player")
 +              if(IS_PLAYER(other))
                        if(IsDifferentTeam(self.realowner, other))
                                if(other.deadflag == DEAD_NO)
                                        if(IsFlying(other))
-                                               AnnounceTo(self.realowner, "airshot");
+                                               Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
  
        self.event_damage = func_null;
        self.takedamage = DAMAGE_NO;
@@@ -348,7 -348,7 +348,7 @@@ float w_rlauncher(float req
                                        //As the distance gets larger, a correct detonation gets near imposible
                                        //Bots are assumed to use the rocket spawnfunc_light to see if the rocket gets near a player
                                        if(v_forward * normalize(missile.origin - self.enemy.origin)< 0.1)
 -                                              if(self.enemy.classname == "player")
 +                                              if(IS_PLAYER(self.enemy))
                                                        if(desirabledamage >= 0.1*coredamage)
                                                                if(random()/distance*300 > frametime*bound(0,(10-skill)*0.2,1))
                                                                        self.BUTTON_ATCK2 = TRUE;
        {
                W_Reload(autocvar_g_balance_rocketlauncher_ammo, autocvar_g_balance_rocketlauncher_reload_ammo, autocvar_g_balance_rocketlauncher_reload_time, "weapons/reload.wav");
        }
+       else if (req == WR_SUICIDEMESSAGE)
+       {
+               return WEAPON_ROCKETLAUNCHER_SUICIDE;
+       }
+       else if (req == WR_KILLMESSAGE)
+       {
+               if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+                       return WEAPON_ROCKETLAUNCHER_MURDER_SPLASH;
+               else
+                       return WEAPON_ROCKETLAUNCHER_MURDER_DIRECT;
+       }
        return TRUE;
  }
  #endif
@@@ -464,17 -475,6 +475,6 @@@ float w_rlauncher(float req
        {
                precache_sound("weapons/rocket_impact.wav");
        }
-       else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = _("%s blew themself up with their rocketlauncher");
-       else if (req == WR_KILLMESSAGE)
-       {
-               if(w_deathtype & HITTYPE_BOUNCE) // (remote detonation)
-                       w_deathtypestring = _("%s got too close to %s's rocket");
-               else if(w_deathtype & HITTYPE_SPLASH)
-                       w_deathtypestring = _("%s almost dodged %s's rocket");
-               else
-                       w_deathtypestring = _("%s ate %s's rocket");
-       }
        return TRUE;
  }
  #endif
index 89e94198ca33c8520574ecc7be536411792453ba,75f6a087d14256ef0b32ee3525809e847b47cf41..1fc7d8e175a3d71ce5745b3605b6b5a227638662
@@@ -91,7 -91,7 +91,7 @@@ void shotgun_meleethink (void
                //te_lightning2(world, targpos, self.realowner.origin + self.realowner.view_ofs + v_forward * 5 - v_up * 5); 
                //te_customflash(targpos, 40,  2, '1 1 1');
                
 -              is_player = (trace_ent.classname == "player" || trace_ent.classname == "body");
 +              is_player = (IS_PLAYER(trace_ent) || trace_ent.classname == "body");
  
                if((trace_fraction < 1) // if trace is good, apply the damage and remove self
                        && (trace_ent.takedamage == DAMAGE_AIM)  
@@@ -238,6 -238,17 +238,17 @@@ float w_shotgun(float req
        {
                W_Reload(autocvar_g_balance_shotgun_primary_ammo, autocvar_g_balance_shotgun_reload_ammo, autocvar_g_balance_shotgun_reload_time, "weapons/reload.wav");
        }
+       else if (req == WR_SUICIDEMESSAGE)
+       {
+               return WEAPON_THINKING_WITH_PORTALS;
+       }
+       else if (req == WR_KILLMESSAGE)
+       {
+               if(w_deathtype & HITTYPE_SECONDARY)
+                       return WEAPON_SHOTGUN_MURDER_SLAP;
+               else
+                       return WEAPON_SHOTGUN_MURDER;
+       }
        return TRUE;
  }
  #endif
@@@ -267,15 -278,6 +278,6 @@@ float w_shotgun(float req
                precache_sound("weapons/ric2.wav");
                precache_sound("weapons/ric3.wav");
        }
-       else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = _("%s is now thinking with portals");
-       else if (req == WR_KILLMESSAGE)
-       {
-               if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = _("%2$s slapped %1$s around a bit with a large shotgun");
-               else
-                       w_deathtypestring = _("%s was gunned down with a shotgun by %s");
-       }
        return TRUE;
  }
  #endif