]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into mario/mutator_minstagib
authorMario <mario.mario@y7mail.com>
Thu, 7 Mar 2013 06:22:48 +0000 (17:22 +1100)
committerMario <mario.mario@y7mail.com>
Thu, 7 Mar 2013 06:22:48 +0000 (17:22 +1100)
14 files changed:
1  2 
qcsrc/server/cl_client.qc
qcsrc/server/cl_physics.qc
qcsrc/server/cl_player.qc
qcsrc/server/cl_weaponsystem.qc
qcsrc/server/g_damage.qc
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/mutators.qh
qcsrc/server/progs.src
qcsrc/server/t_items.qc
qcsrc/server/teamplay.qc
qcsrc/server/w_common.qc
qcsrc/server/w_laser.qc
qcsrc/server/w_minstanex.qc

index 19588c0b34d603e9539d536e9fc48abb73d7521d,356d444c0c8a46918d573da4b036756243c6b1ef..a2ee7ece342a143758f54fb732510cb8b203943e
@@@ -404,11 -404,14 +404,12 @@@ void PutObserverInServer (void
        DropAllRunes(self);
        MUTATOR_CALLHOOK(MakePlayerObserver);
  
 -      minstagib_stop_countdown(self);
 -
        Portal_ClearAll(self);
+       
        if(self.alivetime)
        {
-               PlayerStats_Event(self, PLAYERSTATS_ALIVETIME, time - self.alivetime);
+               if(!inWarmupStage)
+                       PlayerStats_Event(self, PLAYERSTATS_ALIVETIME, time - self.alivetime);
                self.alivetime = 0;
        }
  
  
        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);
        {
                if(self.version_mismatch)
                {
+                       self.frags = FRAGS_SPECTATOR;
                        Spawnqueue_Unmark(self);
                        Spawnqueue_Remove(self);
                }
                else
                {
+                       self.frags = FRAGS_LMS_LOSER;
                        Spawnqueue_Insert(self);
                }
        }
                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;
  }
@@@ -552,7 -563,7 +561,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));
                self.skin = stof(self.playerskin);
        }
  
-       if(chmdl || oldskin != self.skin)
-               self.species = player_getspecies(); // model or skin has changed
+       if(chmdl || oldskin != self.skin) // model or skin has changed
+       {
+               self.species = player_getspecies(); // update species
+               UpdatePlayerSounds(); // update skin sounds
+       }
  
        if(!teamplay)
                if(strlen(autocvar_sv_defaultplayercolors))
@@@ -684,7 -698,7 +696,7 @@@ void PutClientInServer (void
                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
                }
  
                if(autocvar__notarget)
                        self.flags |= FL_NOTARGET;
                self.takedamage = DAMAGE_AIM;
 -              if(g_minstagib)
 -                      self.effects = EF_FULLBRIGHT;
 -              else
 -                      self.effects = 0;
 +              self.effects = 0;
                self.effects |= EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
                self.air_finished = time + 12;
                self.dmg = 2;
  
                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);
                self.weaponname = "";
                self.switchingweapon = 0;
  
-               if(!self.alivetime)
-                       self.alivetime = time;
+               if(!inWarmupStage)
+                       if(!self.alivetime)
+                               self.alivetime = time;
  
                antilag_clear(self);
  
@@@ -1067,7 -1085,7 +1080,7 @@@ void ClientKill_Now_TeamChange(
                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
@@@ -1218,28 -1236,28 +1231,28 @@@ void ClientKill_TeamChange (float targe
                        self.killindicator.colormod = '0 0 0';
                        if(clienttype(self) == CLIENTTYPE_REAL)
                        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(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(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(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);
                }
        }
  
@@@ -1281,7 -1299,7 +1294,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
@@@ -1330,7 -1348,6 +1343,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);
@@@ -1350,7 -1367,7 +1362,7 @@@ void ClientConnect (void
        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";
  
        race_PreSpawnObserver();
  
-       //if(g_domination)
-       //      dom_player_join_team(self);
        // identify the right forced team
        if(autocvar_g_campaign)
        {
                {
                        switch(autocvar_g_campaign_forceteam)
                        {
-                               case 1: self.team_forced = COLOR_TEAM1; break;
-                               case 2: self.team_forced = COLOR_TEAM2; break;
-                               case 3: self.team_forced = COLOR_TEAM3; break;
-                               case 4: self.team_forced = COLOR_TEAM4; break;
+                               case 1: self.team_forced = 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")
  
        self.netname_previous = strzone(self.netname);
  
-       bprint("^4", self.netname, "^4 connected");
-       if(self.classname != "observer" && (g_domination || g_ctf))
-               bprint(" and joined the ", ColoredTeamName(self.team));
-       bprint("\n");
+       if((self.classname == STR_PLAYER && 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?
        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;
        else if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca) // teamnagger is currently bad for ca
                send_CSQC_teamnagger();
  
-       if (g_domination)
-               set_dom_state(self);
        CheatInitClient();
  
        if(!autocvar_g_campaign)
-               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), autocvar_welcome_message_time, 0);
+               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
  
        CSQCMODEL_AUTOINIT();
  
@@@ -1625,8 -1634,8 +1629,8 @@@ void ClientDisconnect (void
  
        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);
@@@ -1785,7 -1794,55 +1789,7 @@@ void player_powerups (void
        Fire_ApplyDamage(self);
        Fire_ApplyEffect(self);
  
 -      if (g_minstagib)
 -      {
 -              self.effects |= EF_FULLBRIGHT;
 -
 -              if (self.items & IT_STRENGTH)
 -              {
 -                      play_countdown(self.strength_finished, "misc/poweroff.wav");
 -                      if (time > self.strength_finished)
 -                      {
 -                              self.alpha = default_player_alpha;
 -                              self.exteriorweaponentity.alpha = default_weapon_alpha;
 -                              self.items &~= IT_STRENGTH;
 -                              //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_INVISIBILITY, self.netname);
 -                              Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
 -                      }
 -              }
 -              else
 -              {
 -                      if (time < self.strength_finished)
 -                      {
 -                              self.alpha = g_minstagib_invis_alpha;
 -                              self.exteriorweaponentity.alpha = g_minstagib_invis_alpha;
 -                              self.items |= IT_STRENGTH;
 -                              Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname);
 -                              Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
 -                      }
 -              }
 -
 -              if (self.items & IT_INVINCIBLE)
 -              {
 -                      play_countdown(self.invincible_finished, "misc/poweroff.wav");
 -                      if (time > self.invincible_finished)
 -                      {
 -                              self.items = self.items - (self.items & IT_INVINCIBLE);
 -                              //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;
 -                              Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname);
 -                              Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED);
 -                      }
 -              }
 -      }
 -      else // if we're not in minstagib, continue. I added this else to replace the "return" which was here that broke the callhook for this function -- This code is nasty.
 +      if not(g_minstagib)
        {
                if (self.items & IT_STRENGTH)
                {
                        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
                        {
@@@ -2257,50 -2321,34 +2268,34 @@@ void ShowRespawnCountdown(
        }
  }
  
- .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(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; }
+                       else
+                               { Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD); }
  
+                       Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
+                       
                        PutClientInServer();
  
-                       if(self.classname == "player")
-                               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
-                       if (self.prevent_join_msgtime)
-                       {
-                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_PREVENT_JOIN);
-                               self.prevent_join_msgtime = 0;
-                       }
-                       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 if not(g_ca && self.caplayer) { 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_CPID, CPID_PREVENT_JOIN);
        }
  }
  
@@@ -2351,7 -2399,7 +2346,7 @@@ float nJoinAllowed(entity ignore) 
  void checkSpectatorBlock() {
        if(self.classname == "spectator" || self.classname == "observer") {
                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);
                }
        }
@@@ -2364,12 -2412,12 +2359,12 @@@ void PrintWelcomeMessage(
                if (autocvar_g_campaign) {
                        if ((self.classname == "player" && self.BUTTON_INFO) || (self.classname != "player")) {
                                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) {
                                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
                                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
                                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) {
                                        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);
+                                       Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                                }
                        }
                }
@@@ -2538,7 -2586,7 +2533,7 @@@ void PlayerPreThink (void
                                        {
                                                // 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;
        }
  
  
                if(frametime)
                {
- #ifndef NO_LEGACY_NETWORKING
-                       self.glowmod = colormapPaletteColor(self.clientcolors & 0x0F, TRUE) * 2;
- #endif
                        if(self.weapon == WEP_NEX && autocvar_g_balance_nex_charge)
                        {
                                self.weaponentity_glowmod_x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
                        player_powerups();
                }
  
 -              if (g_minstagib)
 -                      minstagib_ammocheck();
 -
                if (self.deadflag != DEAD_NO)
                {
                        float button_pressed, force_respawn;
                                //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');
  
                self.prevorigin = self.origin;
  
-               if (!self.vehicle)
-               if (((self.BUTTON_CROUCH && !self.hook.state) || self.health <= g_bloodloss) && self.animstate_startframe != self.anim_melee_x && !self.freezetag_frozen) // prevent crouching if using melee attack
+               float do_crouch = self.BUTTON_CROUCH;
+               if(self.hook.state)
+                       do_crouch = 0;
+               if(self.health <= g_bloodloss)
+                       do_crouch = 1;
+               if(self.vehicle)
+                       do_crouch = 0;
+               if(self.freezetag_frozen)
+                       do_crouch = 0;
+               if(self.weapon == WEP_SHOTGUN && self.weaponentity.wframe == WFRAME_FIRE2 && time < self.weapon_nextthink)
+                       do_crouch = 0;
+               if (do_crouch)
                {
                        if (!self.crouch)
                        {
@@@ -2897,18 -2955,6 +2899,6 @@@ Called every frame for each client afte
  =============
  */
  .float idlekick_lasttimeleft;
- .entity showheadshotbbox;
- void showheadshotbbox_think()
- {
-       if(self.owner.showheadshotbbox != self)
-       {
-               remove(self);
-               return;
-       }
-       self.nextthink = time;
-       setorigin(self, self.owner.origin);
-       setsize(self, GetHeadshotMins(self.owner), GetHeadshotMaxs(self.owner));
- }
  void PlayerPostThink (void)
  {
        // Savage: Check for nameless players
        {
                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;
                        }
        if(self.waypointsprite_attachedforcarrier)
                WaypointSprite_UpdateHealth(self.waypointsprite_attachedforcarrier, '1 0 0' * healtharmor_maxdamage(self.health, self.armorvalue, autocvar_g_balance_armor_blockpercent));
  
-       if(self.classname == "player" && self.deadflag == DEAD_NO && autocvar_r_showbboxes)
-       {
-               if(!self.showheadshotbbox)
-               {
-                       self.showheadshotbbox = spawn();
-                       self.showheadshotbbox.classname = "headshotbbox";
-                       self.showheadshotbbox.owner = self;
-                       self.showheadshotbbox.think = showheadshotbbox_think;
-                       self.showheadshotbbox.nextthink = time;
-                       self = self.showheadshotbbox;
-                       self.think();
-                       self = self.owner;
-               }
-       }
-       else
-       {
-               if(self.showheadshotbbox)
-                       if(self.showheadshotbbox && !wasfreed(self.showheadshotbbox))
-                 remove(self.showheadshotbbox);
-       }
        playerdemo_write();
  
        if((g_cts || g_race) && self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1)
index 5d0e040d2bc7a73276862a435a09f8daa2d9686c,50401604ef905313d521380d6995b0cf202d6bec..547789b44ac290751971b7d7e65a05c4835a359e
@@@ -169,10 -169,7 +169,7 @@@ void PlayerJump (void
        self.flags &~= FL_ONGROUND;
        self.flags &~= FL_JUMPRELEASED;
  
-       if (self.crouch)
-               setanim(self, self.anim_duckjump, FALSE, TRUE, TRUE);
-       else if (self.animstate_startframe != self.anim_melee_x || (self.animstate_startframe == self.anim_melee_x && time - self.animstate_starttime >= 21/20)) // jump animation shouldn't override melee until we have animation blending (or until the anim finished, 21/20 = numframes/fps)
-               setanim(self, self.anim_jump, FALSE, TRUE, TRUE);
+       animdecide_setaction(self, ANIMACTION_JUMP, TRUE);
  
        if(g_jump_grunt)
                PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
@@@ -707,6 -704,8 +704,6 @@@ void SV_PlayerPhysics(
        WarpZone_PlayerPhysics_FixVAngle();
        
        maxspd_mod = 1;
 -      if(g_minstagib && (self.items & IT_INVINCIBLE))
 -              maxspd_mod *= autocvar_g_minstagib_speed_highspeed;
        if(self.ballcarried)
                if(g_nexball)
                        maxspd_mod *= autocvar_g_nexball_basketball_carrier_highspeed;
index abbabee5366747ddae1188b0ee960f341285f13e,cb44da03fe794cada0243885dd44b53f0a974860..cfa4ca4c75608ca3c645d6e000232b3f61b3654c
@@@ -161,16 -161,20 +161,20 @@@ void CopyBody(float keepvelocity
        self.effects = oldself.effects;
        self.glowmod = oldself.glowmod;
        self.event_damage = oldself.event_damage;
-       self.animstate_startframe = oldself.animstate_startframe;
-       self.animstate_numframes = oldself.animstate_numframes;
-       self.animstate_framerate = oldself.animstate_framerate;
-       self.animstate_starttime = oldself.animstate_starttime;
-       self.animstate_endtime = oldself.animstate_endtime;
-       self.animstate_override = oldself.animstate_override;
-       self.animstate_looping = oldself.animstate_looping;
+       self.anim_state = oldself.anim_state;
+       self.anim_time = oldself.anim_time;
+       self.anim_lower_action = oldself.anim_lower_action;
+       self.anim_lower_time = oldself.anim_lower_time;
+       self.anim_upper_action = oldself.anim_upper_action;
+       self.anim_upper_time = oldself.anim_upper_time;
+       self.anim_implicit_state = oldself.anim_implicit_state;
+       self.anim_implicit_time = oldself.anim_implicit_time;
+       self.anim_lower_implicit_action = oldself.anim_lower_implicit_action;
+       self.anim_lower_implicit_time = oldself.anim_lower_implicit_time;
+       self.anim_upper_implicit_action = oldself.anim_upper_implicit_action;
+       self.anim_upper_implicit_time = oldself.anim_upper_implicit_time;
        self.dphitcontentsmask = oldself.dphitcontentsmask;
        self.death_time = oldself.death_time;
-       self.frame = oldself.frame;
        self.pain_finished = oldself.pain_finished;
        self.health = oldself.health;
        self.armorvalue = oldself.armorvalue;
        self.CopyBody_think = oldself.think;
        self.nextthink = time;
        self.think = CopyBody_Think;
+       // "bake" the current animation frame for clones (they don't get clientside animation)
+       animdecide_setframes(self, FALSE, frame, frame1time, frame2, frame2time);
  
        self = oldself;
  }
@@@ -225,136 -231,41 +231,37 @@@ float player_getspecies(
  
  void player_setupanimsformodel()
  {
-       // defaults for legacy .zym models without animinfo files
-       self.anim_die1 = animfixfps(self, '0 1 0.5'); // 2 seconds
-       self.anim_die2 = animfixfps(self, '1 1 0.5'); // 2 seconds
-       self.anim_draw = animfixfps(self, '2 1 3');
-       // self.anim_duck = '3 1 100'; // This anim is broken, use slot 3 as a new free slot in the future ;)
-       self.anim_duckwalk = animfixfps(self, '4 1 1');
-       self.anim_duckjump = '5 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it
-       self.anim_duckidle = animfixfps(self, '6 1 1');
-       self.anim_idle = animfixfps(self, '7 1 1');
-       self.anim_jump = '8 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it
-       self.anim_pain1 = animfixfps(self, '9 1 2'); // 0.5 seconds
-       self.anim_pain2 = animfixfps(self, '10 1 2'); // 0.5 seconds
-       self.anim_shoot = animfixfps(self, '11 1 5'); // analyze models and set framerate
-       self.anim_taunt = animfixfps(self, '12 1 0.33');
-       self.anim_run = animfixfps(self, '13 1 1');
-       self.anim_runbackwards = animfixfps(self, '14 1 1');
-       self.anim_strafeleft = animfixfps(self, '15 1 1');
-       self.anim_straferight = animfixfps(self, '16 1 1');
-       //self.anim_dead1 = animfixfps(self, '17 1 1');
-       //self.anim_dead2 = animfixfps(self, '18 1 1');
-       self.anim_forwardright = animfixfps(self, '19 1 1');
-       self.anim_forwardleft = animfixfps(self, '20 1 1');
-       self.anim_backright = animfixfps(self, '21 1 1');
-       self.anim_backleft  = animfixfps(self, '22 1 1');
-       self.anim_melee = animfixfps(self, '23 1 1');
-       self.anim_duckwalkbackwards = animfixfps(self, '24 1 1');
-       self.anim_duckwalkstrafeleft = animfixfps(self, '25 1 1');
-       self.anim_duckwalkstraferight = animfixfps(self, '26 1 1');
-       self.anim_duckwalkforwardright = animfixfps(self, '27 1 1');
-       self.anim_duckwalkforwardleft = animfixfps(self, '28 1 1');
-       self.anim_duckwalkbackright = animfixfps(self, '29 1 1');
-       self.anim_duckwalkbackleft  = animfixfps(self, '30 1 1');
-       // TODO introspect models for finding right "fps" value (1/duration)
-       // reset animstate now
-       setanim(self, self.anim_idle, TRUE, FALSE, TRUE);
+       // load animation info
+       animdecide_init(self);
+       animdecide_setstate(self, 0, FALSE);
  }
  
  void player_anim (void)
  {
-       updateanim(self);
-       if (self.weaponentity)
-               updateanim(self.weaponentity);
-       if (self.deadflag != DEAD_NO)
-               return;
-       if (!self.animstate_override)
-       {
-               if (self.freezetag_frozen)
-                       setanim(self, self.anim_idle, TRUE, FALSE, FALSE);
-               else if (!(self.flags & FL_ONGROUND) || self.BUTTON_JUMP)
-               {
-                       if (self.crouch)
-                       {
-                               if (self.animstate_startframe != self.anim_duckjump_x) // don't perform another trace if already playing the crouch jump anim
-                               {
-                                       traceline(self.origin + '0 0 1' * PL_CROUCH_MIN_z, self.origin + '0 0 1' * (PL_CROUCH_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self);
-                                       if(!trace_startsolid && trace_fraction == 1 || !(self.animstate_startframe == self.anim_duckwalk_x || self.animstate_startframe == self.anim_duckidle_x)) // don't get stuck on non-crouch anims
-                                       {
-                                               setanim(self, self.anim_duckjump, FALSE, TRUE, self.restart_jump);
-                                               self.restart_jump = FALSE;
-                                       }
-                               }
-                       }
-                       else
-                       {
-                 if (self.animstate_startframe != self.anim_jump_x) // don't perform another trace if already playing the jump anim
-                 {
-                     traceline(self.origin + '0 0 1' * PL_MIN_z, self.origin + '0 0 1' * (PL_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self);
-                     if(!trace_startsolid && trace_fraction == 1 || self.animstate_startframe == self.anim_idle_x || (self.animstate_startframe == self.anim_melee_x && time - self.animstate_starttime >= 21/20)) // don't get stuck on idle animation in midair, nor melee after it finished
-                     {
-                         setanim(self, self.anim_jump, FALSE, TRUE, self.restart_jump);
-                         self.restart_jump = FALSE;
-                     }
-                 }
-                       }
-               }
-               else if (self.crouch)
-               {
-                       if (self.movement_x > 0 && self.movement_y == 0)
-                               setanim(self, self.anim_duckwalk, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y == 0)
-                               setanim(self, self.anim_duckwalkbackwards, TRUE, FALSE, FALSE);
-                       else if (self.movement_x == 0 && self.movement_y > 0)
-                               setanim(self, self.anim_duckwalkstraferight, TRUE, FALSE, FALSE);
-                       else if (self.movement_x == 0 && self.movement_y < 0)
-                               setanim(self, self.anim_duckwalkstrafeleft, TRUE, FALSE, FALSE);
-                       else if (self.movement_x > 0 && self.movement_y > 0)
-                               setanim(self, self.anim_duckwalkforwardright, TRUE, FALSE, FALSE);
-                       else if (self.movement_x > 0 && self.movement_y < 0)
-                               setanim(self, self.anim_duckwalkforwardleft, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y > 0)
-                               setanim(self, self.anim_duckwalkbackright, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y < 0)
-                               setanim(self, self.anim_duckwalkbackleft, TRUE, FALSE, FALSE);
-                       else
-                               setanim(self, self.anim_duckidle, TRUE, FALSE, FALSE);
-               }
-               else if ((self.movement_x * self.movement_x + self.movement_y * self.movement_y) > 20)
-               {
-                       if (self.movement_x > 0 && self.movement_y == 0)
-                               setanim(self, self.anim_run, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y == 0)
-                               setanim(self, self.anim_runbackwards, TRUE, FALSE, FALSE);
-                       else if (self.movement_x == 0 && self.movement_y > 0)
-                               setanim(self, self.anim_straferight, TRUE, FALSE, FALSE);
-                       else if (self.movement_x == 0 && self.movement_y < 0)
-                               setanim(self, self.anim_strafeleft, TRUE, FALSE, FALSE);
-                       else if (self.movement_x > 0 && self.movement_y > 0)
-                               setanim(self, self.anim_forwardright, TRUE, FALSE, FALSE);
-                       else if (self.movement_x > 0 && self.movement_y < 0)
-                               setanim(self, self.anim_forwardleft, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y > 0)
-                               setanim(self, self.anim_backright, TRUE, FALSE, FALSE);
-                       else if (self.movement_x < 0 && self.movement_y < 0)
-                               setanim(self, self.anim_backleft, TRUE, FALSE, FALSE);
-                       else
-                               setanim(self, self.anim_run, TRUE, FALSE, FALSE);
-               }
+       float deadbits = (self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
+       if(self.deadflag && !deadbits)
+               if(random() < 0.5)
+                       deadbits = ANIMSTATE_DEAD1;
                else
-                       setanim(self, self.anim_idle, TRUE, FALSE, FALSE);
-       }
+                       deadbits = ANIMSTATE_DEAD2;
+       float animbits = deadbits;
+       if(self.freezetag_frozen)
+               animbits |= ANIMSTATE_FROZEN;
+       if(self.crouch)
+               animbits |= ANIMSTATE_DUCK;
+       animdecide_setstate(self, animbits, FALSE);
+       animdecide_setimplicitstate(self, (self.flags & FL_ONGROUND));
  
        if (self.weaponentity)
-       if (!self.weaponentity.animstate_override)
-               setanim(self.weaponentity, self.weaponentity.anim_idle, TRUE, FALSE, FALSE);
+       {
+               updateanim(self.weaponentity);
+               if (!self.weaponentity.animstate_override)
+                       setanim(self.weaponentity, self.weaponentity.anim_idle, TRUE, FALSE, FALSE);
+       }
  }
  
  void SpawnThrownWeapon (vector org, float w)
  {
 -      if(g_minstagib)
 -      if(self.ammo_cells <= 0)
 -              return;
 -
        if(g_pinata)
        {
                float j;
@@@ -480,10 -391,17 +387,10 @@@ void PlayerDamage (entity inflictor, en
        else
                Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker);
  
 -      if (!g_minstagib)
 -      {
 -              v = healtharmor_applydamage(self.armorvalue, autocvar_g_balance_armor_blockpercent, damage);
 -              take = v_x;
 -              save = v_y;
 -      }
 -      else
 -      {
 -              save = 0;
 -              take = damage;
 -      }
 +
 +      v = healtharmor_applydamage(self.armorvalue, autocvar_g_balance_armor_blockpercent, damage);
 +      take = v_x;
 +      save = v_y;
  
        if(attacker == self)
        {
                        {
                                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)
                                                {
                                                        if (random() > 0.5)
-                                                               setanim(self, self.anim_pain1, FALSE, TRUE, TRUE);
+                                                               animdecide_setaction(self, ANIMACTION_PAIN1, TRUE);
                                                        else
-                                                               setanim(self, self.anim_pain2, FALSE, TRUE, TRUE);
+                                                               animdecide_setaction(self, ANIMACTION_PAIN2, TRUE);
                                                }
                                        }
  
                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)
                        self.respawn_countdown = -1; // do not count down
                self.death_time = time;
                if (random() < 0.5)
-                       setanim(self, self.anim_die1, FALSE, TRUE, TRUE);
+                       animdecide_setstate(self, self.anim_state | ANIMSTATE_DEAD1, TRUE);
                else
-                       setanim(self, self.anim_die2, FALSE, TRUE, TRUE);
+                       animdecide_setstate(self, self.anim_state | ANIMSTATE_DEAD2, TRUE);
                if (self.maxs_z > 5)
                {
                        self.maxs_z = 5;
                // 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);
                }
@@@ -1015,17 -933,18 +922,18 @@@ float Say(entity source, float teamsay
                        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")
                                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);
@@@ -1229,7 -1148,7 +1137,7 @@@ void FakeGlobalSound(string sample, flo
                                break;
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        tauntrand = random();
                        msg_entity = self;
                case VOICETYPE_TAUNT:
                        if(self.classname == "player")
                                if(self.deadflag == DEAD_NO)
-                                       setanim(self, self.anim_taunt, FALSE, TRUE, TRUE);
+                                       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)
@@@ -1326,7 -1245,7 +1234,7 @@@ void GlobalSound(string sample, float c
                                break;
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        tauntrand = random();
                        FOR_EACH_REALCLIENT(msg_entity)
                case VOICETYPE_TAUNT:
                        if(self.classname == "player")
                                if(self.deadflag == DEAD_NO)
-                                       setanim(self, self.anim_taunt, FALSE, TRUE, TRUE);
+                                       animdecide_setaction(self, ANIMACTION_TAUNT, TRUE);
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        FOR_EACH_REALCLIENT(msg_entity)
                        {
@@@ -1392,14 -1311,8 +1300,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 07b9149cea10424892854674ede3c70ef6a1c003,c559c150db4a28adb8b41aca39b737f775277d85..cb62a44c5bfc3f5342438f82364cb5bc2961965e
@@@ -132,10 -132,8 +132,10 @@@ vector w_shotend
  .float prevstrengthsoundattempt;
  void W_PlayStrengthSound(entity player) // void W_PlayStrengthSound
  {
 -              if((!g_minstagib)
 -                      && (player.items & IT_STRENGTH)
 +      if(MUTATOR_CALLHOOK(PlayStrengthSound))
 +              return;
 +              
 +              if((player.items & IT_STRENGTH)
                        && ((time > player.prevstrengthsound + autocvar_sv_strengthsound_antispam_time) // prevent insane sound spam
                        || (time > player.prevstrengthsoundattempt + autocvar_sv_strengthsound_antispam_refire_threshold)))
                {
@@@ -345,10 -343,10 +345,10 @@@ void CL_WeaponEntity_SetModel(string na
  
                setmodel(self, strcat("models/weapons/h_", name, ".iqm")); // precision set below
                // preset some defaults that work great for renamed zym files (which don't need an animinfo)
-               self.anim_fire1  = animfixfps(self, '0 1 0.01');
-               self.anim_fire2  = animfixfps(self, '1 1 0.01');
-               self.anim_idle   = animfixfps(self, '2 1 0.01');
-               self.anim_reload = animfixfps(self, '3 1 0.01');
+               self.anim_fire1  = animfixfps(self, '0 1 0.01', '0 0 0');
+               self.anim_fire2  = animfixfps(self, '1 1 0.01', '0 0 0');
+               self.anim_idle   = animfixfps(self, '2 1 0.01', '0 0 0');
+               self.anim_reload = animfixfps(self, '3 1 0.01', '0 0 0');
  
                // if we have a "weapon" tag, let's attach the v_ model to it ("invisible hand" style model)
                // if we don't, this is a "real" animated model
@@@ -580,7 -578,6 +580,6 @@@ void CL_Weaponentity_Think(
  void CL_ExteriorWeaponentity_Think()
  {
        float tag_found;
-       vector ang;
        self.nextthink = time;
        if (self.owner.exteriorweaponentity != self)
        {
                        setattachment(self, self.owner, "bip01 r hand");
        }
        self.effects = self.owner.effects;
-       if(sv_pitch_min == sv_pitch_max)
-               self.effects |= EF_LOWPRECISION;
-       else
-               self.effects &~= EF_LOWPRECISION;
+       self.effects |= EF_LOWPRECISION;
        self.effects = self.effects & EFMASK_CHEAP; // eat performance
        if(self.owner.alpha == default_player_alpha)
                self.alpha = default_weapon_alpha;
        else
                self.alpha = 1;
  
-       if (!intermission_running)
-       {
-               ang_x = bound(sv_pitch_min, self.owner.v_angle_x, sv_pitch_max);
-               ang_y = 0;
-               ang_z = 0;
-               if(sv_pitch_fixyaw) // workaround for stupid player models that don't aim forward
-               {
-                       ang_y = self.owner.v_angle_y;
-                       makevectors(ang);
-                       var vector v = v_forward;
-                       var float t = self.tag_entity.frame1time;
-                       var float f = self.tag_entity.frame;
-                       self.tag_entity.frame1time = time;
-                       self.tag_entity.frame = self.tag_entity.anim_idle_x;
-                       gettaginfo(self.tag_entity, self.tag_index);
-                       self.tag_entity.frame1time = t;
-                       self.tag_entity.frame = f;
-                       // untransform v according to this coordinate space
-                       vector w;
-                       w_x = v_forward * v;
-                       w_y = -v_right * v;
-                       w_z = v_up * v;
-                       self.angles = vectoangles(w);
-               }
-               else
-               {
-                       ang_x = -/* don't ask */ang_x;
-                       self.angles = ang;
-               }
-               if(autocvar_g_loituma)
-               {
-                       vector modangles;
-                       float t;
-                       t = time * autocvar_g_loituma;
-                       modangles_x = t * 360;
-                       modangles_y = 90;
-                       modangles_z = 0;
-                       self.angles =
-                               AnglesTransform_ToAngles(
-                                       AnglesTransform_Multiply(
-                                               AnglesTransform_FromAngles(self.angles),
-                                               AnglesTransform_FromAngles(modangles)
-                                       )
-                               );
-               }
-       }
        self.glowmod = self.owner.weaponentity_glowmod;
        self.colormap = self.owner.colormap;
  
@@@ -772,7 -714,6 +716,6 @@@ float client_hasweapon(entity cl, floa
                                if(clienttype(cl) == CLIENTTYPE_REAL)
                                {
                                        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");
@@@ -881,14 -820,6 +822,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;
                }
@@@ -1049,25 -988,17 +990,17 @@@ void weapon_thinkf(float fr, float t, v
        self.weapon_think = func;
        //dprint("next ", ftos(self.weapon_nextthink), "\n");
  
-       // The shoot animation looks TERRIBLE without animation blending! Yay for moonwalking while shooting!
-       //anim = self.anim_shoot;
-       if (restartanim)
-       if (t)
-       if (!self.crouch) // shoot anim stands up, this looks bad
+       if((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t)
        {
-               vector anim;
-               if(self.weapon == WEP_SHOTGUN && self.BUTTON_ATCK2)
-               {
-                       anim = self.anim_melee;
-                       anim_z = anim_y / (t + sys_frametime);
-                       setanim(self, anim, FALSE, TRUE, TRUE);
-               }
-               else if (self.animstate_startframe == self.anim_idle_x) // only allow shoot anim to override idle animation until we have animation blending
-               {
-                       anim = self.anim_shoot;
-                       anim_z = anim_y / (t + sys_frametime);
-                       setanim(self, anim, FALSE, TRUE, TRUE);
-               }
+               if(self.weapon == WEP_SHOTGUN && fr == WFRAME_FIRE2)
+                       animdecide_setaction(self, ANIMACTION_MELEE, restartanim);
+               else
+                       animdecide_setaction(self, ANIMACTION_SHOOT, restartanim);
+       }
+       else
+       {
+               if(self.anim_upper_action == ANIMACTION_SHOOT || self.anim_upper_action == ANIMACTION_MELEE)
+                       self.anim_upper_action = 0;
        }
  }
  
diff --combined qcsrc/server/g_damage.qc
index f014ed3d5aecc9f61436c77da4d85b31e61b5715,e86b148bcb0b170851e4ac934ba1917d6a3353c3..859e52ae0a1614cc941455d77eefc4f9122efb27
@@@ -47,8 -47,6 +47,6 @@@ float checkrules_firstblood
  float yoda;
  float damage_goodhits;
  float damage_gooddamage;
- float headshot;
- float damage_headshotbonus; // bonus multiplier for head shots, set to 0 after use
  
  .float dmg_team;
  .float teamkill_complain;
@@@ -86,15 -84,6 +84,6 @@@ float IsFlying(entity a
        return 1;
  }
  
- vector GetHeadshotMins(entity targ)
- {
-       return '-0.5 0 0' * PL_HEAD_x + '0 -0.5 0' * PL_HEAD_y + '0 0 1' * (targ.maxs_z - PL_HEAD_z);
- }
- vector GetHeadshotMaxs(entity targ)
- {
-       return '0.5 0 0' * PL_HEAD_x + '0 0.5 0' * PL_HEAD_y + '0 0 1' * targ.maxs_z;
- }
  void UpdateFrags(entity player, float f)
  {
        PlayerTeamScore_AddScore(player, f);
@@@ -227,44 -216,6 +216,6 @@@ void GiveFrags (entity attacker, entit
                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 = ((clienttype(player) == CLIENTTYPE_BOT) ? "^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;
@@@ -297,7 -248,7 +248,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 (clienttype(e) == CLIENTTYPE_REAL)
+       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 (targ.classname == "player")
+       // 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
+       dprint(
+               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 (attacker.classname == "player")
+               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, 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: \
+                               { \
+                                       AnnounceTo(attacker, strcat(#countb, "kills")); \
+                                       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 = "";
-                               if(strstrofs(msg, "%", 0) < 0)
-                                       msg = strcat("%s ", msg, " by %s");
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG, targ.netname, kill_count_to_attacker);
  
-                               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)
+               {
+                       AnnounceTo(targ, "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
@@@ -538,7 -581,7 +581,7 @@@ void Damage (entity targ, entity inflic
  {
        float mirrordamage;
        float mirrorforce;
-       float teamdamage0;
+       float complainteamdamage = 0; 
        entity attacker_save;
        mirrordamage = 0;
        mirrorforce = 0;
                        }
        }
  
-       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
                                        {
                                                if(targ.classname == "player" && targ.deadflag == DEAD_NO)
                                                {
-                                                       teamdamage0 = max(attacker.dmg_team, autocvar_g_teamdamage_threshold);
                                                        attacker.dmg_team = attacker.dmg_team + damage;
-                                                       if(attacker.dmg_team > teamdamage0 && !g_ca)
-                                                               mirrordamage = autocvar_g_mirrordamage * (attacker.dmg_team - teamdamage0);
+                                                       complainteamdamage = attacker.dmg_team - autocvar_g_teamdamage_threshold;
+                                                       if(complainteamdamage > 0 && !g_ca) // FIXME why is g_ca ruled out here? Why not just g_mirrordamage 0 on CA servers?
+                                                               mirrordamage = autocvar_g_mirrordamage * complainteamdamage;
                                                        mirrorforce = autocvar_g_mirrordamage * vlen(force);
 -                                                      if(g_minstagib)
 -                                                      {
 -                                                              if(autocvar_g_friendlyfire == 0)
 -                                                                      damage = 0;
 -                                                      }
 -                                                      else if(g_ca)
 +                                                      if(g_ca)
                                                                damage = 0;
                                                        else
                                                                damage = autocvar_g_friendlyfire * damage;
                        attacker.lms_traveled_distance = autocvar_g_lms_campcheck_distance;
                }
  
 -              if(targ.classname == "player")
 -              if (g_minstagib)
 -              {
 -                      if ((deathtype == DEATH_FALL)  ||
 -                              (deathtype == DEATH_DROWN) ||
 -                              (deathtype == DEATH_SLIME) ||
 -                              (deathtype == DEATH_LAVA)  ||
 -                              (!DEATH_ISWEAPON(deathtype, WEP_LASER) && damage > 0 && damage < 100))
 -                      {
 -                              self = oldself;
 -                              return;
 -                      }
 -                      if(damage > 0)
 -                          damage = 10000;
 -                      if (targ.armorvalue && (deathtype == WEP_MINSTANEX) && damage)
 -                      {
 -                              targ.armorvalue -= 1;
 -                              centerprint(targ, strcat("^3Remaining extra lives: ",ftos(targ.armorvalue)));
 -                              damage = 0;
 -                              targ.hitsound += 1;
 -                              attacker.hitsound += 1; // TODO change this to a future specific hitsound for armor hit
 -                      }
 -                      if (DEATH_ISWEAPON(deathtype, WEP_LASER))
 -                      {
 -                              damage = 0;
 -                              mirrordamage = 0;
 -                              complainteamdamage = 0;
 -                              if (targ != attacker)
 -                              {
 -                                      if ((targ.health >= 1) && (targ.classname == "player"))
 -                                              centerprint(attacker, "Secondary fire inflicts no damage!");
 -                                      force = '0 0 0';
 -                                      // keep mirrorforce
 -                                      attacker = targ;
 -                              }
 -                      }
 -              }
 -
                if not(DEATH_ISSPECIAL(deathtype))
                {
                        damage *= g_weapondamagefactor;
                        mirrordamage *= g_weapondamagefactor;
+                       complainteamdamage *= g_weapondamagefactor;
                        force = force * g_weaponforcefactor;
                        mirrorforce *= g_weaponforcefactor;
                }
                frag_damage = damage;
                frag_force = force;
          frag_deathtype = deathtype;
 +              frag_mirrordamage = mirrordamage;
                MUTATOR_CALLHOOK(PlayerDamage_Calculate);
                damage = frag_damage;
 +              mirrordamage = frag_mirrordamage;
                force = frag_force;
                
 -              // apply strength multiplier
 -              if ((attacker.items & IT_STRENGTH) && !g_minstagib)
 +              if not(g_minstagib)
                {
 -                      if(targ == attacker)
 -                      {
 -                              damage = damage * autocvar_g_balance_powerup_strength_selfdamage;
 -                              force = force * autocvar_g_balance_powerup_strength_selfforce;
 -                      }
 -                      else
 +                      // apply strength multiplier
 +                      if (attacker.items & IT_STRENGTH)
                        {
 -                              damage = damage * autocvar_g_balance_powerup_strength_damage;
 -                              force = force * autocvar_g_balance_powerup_strength_force;
 +                              if(targ == attacker)
 +                              {
 +                                      damage = damage * autocvar_g_balance_powerup_strength_selfdamage;
 +                                      force = force * autocvar_g_balance_powerup_strength_selfforce;
 +                              }
 +                              else
 +                              {
 +                                      damage = damage * autocvar_g_balance_powerup_strength_damage;
 +                                      force = force * autocvar_g_balance_powerup_strength_force;
 +                              }
                        }
 -              }
  
 -              // apply invincibility multiplier
 -              if (targ.items & IT_INVINCIBLE && !g_minstagib)
 -                      damage = damage * autocvar_g_balance_powerup_invincible_takedamage;
 +                      // apply invincibility multiplier
 +                      if (targ.items & IT_INVINCIBLE)
 +                              damage = damage * autocvar_g_balance_powerup_invincible_takedamage;
 +              }
  
                if (targ == attacker)
                {
                if(targ.takedamage == DAMAGE_AIM)
                if(targ != attacker)
                {
-                       if(damage_headshotbonus)
-                       {
-                               if(targ.classname == "player")
-                               {
-                                       // HEAD SHOT:
-                                       // find height of hit on player axis
-                                       // if above view_ofs and below maxs, and also in the middle half of the bbox, it is head shot
-                                       vector headmins, headmaxs, org;
-                                       org = antilag_takebackorigin(targ, time - ANTILAG_LATENCY(attacker));
-                                       headmins = org + GetHeadshotMins(targ);
-                                       headmaxs = org + GetHeadshotMaxs(targ);
-                                       if(trace_hits_box(railgun_start, railgun_end, headmins, headmaxs))
-                                       {
-                                               deathtype |= HITTYPE_HEADSHOT;
-                                       }
-                               }
-                               else if(targ.classname == "turret_head")
-                               {
-                                       deathtype |= HITTYPE_HEADSHOT;
-                               }
-                               if(deathtype & HITTYPE_HEADSHOT)
-                                       if(damage_headshotbonus > 0)
-                                               damage *= 1 + damage_headshotbonus;
-                       }
                        entity victim;
                        if((targ.vehicle_flags & VHF_ISVEHICLE) && targ.owner)
                                victim = targ.owner;
                                                if not(DEATH_ISSPECIAL(deathtype))
                                                {
                                                        if(targ.classname == "player") // don't do this for vehicles
 -                                                      if(!g_minstagib)
                                                        if(IsFlying(victim))
                                                                yoda = 1;
  
++<<<<<<< HEAD
 +                                                      if(deathtype & HITTYPE_HEADSHOT)
 +                                                              headshot = 1;
++=======
+                                                       if(g_minstagib)
+                                                       if(victim.items & IT_STRENGTH)
+                                                               yoda = 1;
++>>>>>>> master
                                                }
                                        }
                                }
                                        {
                                                attacker.typehitsound += 1;
                                        }
-                                       if(mirrordamage > 0)
+                                       if(complainteamdamage > 0)
                                                if(time > attacker.teamkill_complain)
                                                {
                                                        attacker.teamkill_complain = time + 5;
        if(mirrordamage > 0 || mirrorforce > 0)
        {
                attacker = attacker_save;
 -              if(g_minstagib)
 -              if(mirrordamage > 0)
 -              {
 -                      // just lose extra LIVES, don't kill the player for mirror damage
 -                      if(attacker.armorvalue > 0)
 -                      {
 -                              attacker.armorvalue = attacker.armorvalue - 1;
 -                              centerprint(attacker, strcat("^3Remaining extra lives: ",ftos(attacker.armorvalue)));
 -                              attacker.hitsound += 1;
 -                      }
 -                      mirrordamage = 0;
 -              }
  
                force = normalize(attacker.origin + attacker.view_ofs - hitloc) * mirrorforce;
                Damage(attacker, inflictor, attacker, mirrordamage, DEATH_MIRRORDAMAGE, attacker.origin, force);
diff --combined qcsrc/server/g_world.qc
index 313814c3e29e86d5b30183b3467a94f1321a29c5,894ffd6158b7b347a5ed283d6f334ee3aef57988..3762e003ed2ce5c80fd9a45150bd630a5516012c
@@@ -340,9 -340,6 +340,6 @@@ void cvar_changes_init(
                BADCVAR("gameversion");
                BADPREFIX("gameversion_");
                BADCVAR("sv_namechangetimer");
- #ifndef NO_LEGACY_NETWORKING
-               BADCVAR("sv_use_csqc_players"); // transition
- #endif
  
                // allowed changes to server admins (please sync this to server.cfg)
                // vi commands:
                BADCVAR("g_minstagib");
                BADCVAR("g_new_toys");
                BADCVAR("g_nix");
 -
 -              if(autocvar_g_minstagib)
 -              {
 -                      BADCVAR("g_grappling_hook");
 -                      BADCVAR("g_jetpack");
 -              }
 +              BADCVAR("g_grappling_hook");
 +              BADCVAR("g_jetpack");
 +              
  #undef BADPREFIX
  #undef BADCVAR
  
@@@ -550,6 -550,8 +547,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);
@@@ -593,9 -595,13 +592,13 @@@ void spawnfunc_worldspawn (void
                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));
  
  
        WaypointSprite_Init();
  
-       //if (g_domination)
-       //      dom_init();
        GameLogInit(); // prepare everything
        // NOTE for matchid:
        // changing the logic generating it is okay. But:
                if(autocvar_g_midair)
                        s = strcat(s, ":midair");
  
 -              // TODO to mutator system
 -              if(autocvar_g_minstagib)
 -                      s = strcat(s, ":minstagib");
 -
                // TODO to mutator system
                if(autocvar_g_powerups == 0)
                        s = strcat(s, ":no_powerups");
        for(i = 0, j = 0; i < MapInfo_count; ++i)
        {
                if(MapInfo_Get_ByID(i))
-                       if not(MapInfo_Map_flags & (MAPINFO_FLAG_HIDDEN | MAPINFO_FLAG_FORBIDDEN))
+                       if not(MapInfo_Map_flags & MapInfo_ForbiddenFlags())
                        {
                                if(mod(i, 2))
                                        col = "^2";
                modname = cvar_string("g_mod_balance");
        if(cvar_string("g_mod_config") != cvar_defstring("g_mod_config"))
                modname = cvar_string("g_mod_config");
 -      // weird mutators that deserve to count as mod
 -      if(autocvar_g_minstagib)
 -              modname = "MinstaGib";
        // extra mutators that deserve to count as mod
        MUTATOR_CALLHOOK(SetModname);
-       // weird game types that deserve to count as mod
-       if(g_cts)
-               modname = "CTS";
        // save it for later
        modname = strzone(modname);
  
@@@ -1588,6 -1596,8 +1586,8 @@@ void NextLevel(
        PlayerStats_Shutdown();
        WeaponStats_Shutdown();
  
+       Kill_Notification(NOTIF_ALL, world, MSG_CENTER, 0); // kill all centerprints now
        if(autocvar_sv_eventlog)
                GameLogEcho(":gameover");
  
@@@ -1670,20 -1680,8 +1670,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);
  }
  
  float GetWinningCode(float fraglimitreached, float equality)
@@@ -1751,10 -1749,10 +1739,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;
        }
@@@ -1803,13 -1801,13 +1791,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;
@@@ -1935,10 -1933,10 +1923,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();
@@@ -2054,25 -2052,25 +2042,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);
@@@ -2189,9 -2187,9 +2177,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
index c303c14da8caf6a1973e7b924c66a5bd072c2b49,2b73841808bed3223c1eef10bef5c06dd384138c..23de1382984fcc66113b0bac2bf25e9f50cb640d
@@@ -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,26 -79,27 +79,27 @@@ 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";
  
- #if 0
- #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
- #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
- #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
- #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
- #else
+ #define IS_PLAYER(v)                  (v.classname == STR_PLAYER)
+ #define IS_SPEC(v)                            (v.classname == STR_SPECTATOR)
+ #define IS_OBSERVER(v)                        (v.classname == STR_OBSERVER)
+ #define IS_CLIENT(v)                  (v.flags & FL_CLIENT)
+ #define IS_BOT_CLIENT(v)              (clienttype(v) == CLIENTTYPE_BOT)
+ #define IS_REAL_CLIENT(v)             (clienttype(v) == CLIENTTYPE_REAL)
+ #define IS_NOT_A_CLIENT(v)            (clienttype(v) == CLIENTTYPE_NOTACLIENT)
  #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
- #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
- #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
- #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
- #define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if(v.classname != STR_PLAYER)
- #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
- #endif
+ #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(IS_CLIENT(v))
+ #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(IS_REAL_CLIENT(v))
+ #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(IS_PLAYER(v))
+ #define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if not(IS_PLAYER(v)) // Samual: shouldn't this be IS_SPEC(v)? and rather create a separate macro to include observers too
+ #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(IS_PLAYER(v))
  
- #define CENTER_OR_VIEWOFS(ent) (ent.origin + ((ent.classname == STR_PLAYER) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
+ #define CENTER_OR_VIEWOFS(ent) (ent.origin + (IS_PLAYER(ent) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
  
  // copies a string to a tempstring (so one can strunzone it)
  string strcat1(string s) = #115; // FRIK_FILE
  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 (clienttype(head) == CLIENTTYPE_REAL)
-         centerprint(head, s);
- }
  void GameLogEcho(string s)
  {
      string fn;
@@@ -546,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");
        self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share);
        self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive);
  
- #ifdef ALLOW_FORCEMODELS
-       GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels");
-       GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromxonotic, "cl_forceplayermodelsfromxonotic");
- #endif
        GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign");
        GetCvars_handleFloat(s, f, cvar_cl_allow_uid2name, "cl_allow_uid2name");
        GetCvars_handleFloat(s, f, cvar_cl_allow_uidtracking, "cl_allow_uidtracking");
        }
  }
  
- 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)
  {
@@@ -936,6 -831,20 +831,6 @@@ void readplayerstartcvars(
                if(!(g_lms || g_ca))
                        start_items |= IT_UNLIMITED_AMMO;
        }
 -      else if (g_minstagib)
 -      {
 -              g_pinata = 0; // incompatible
 -              g_weapon_stay = 0; // incompatible
 -              g_bloodloss = 0; // incompatible
 -              start_health = 100;
 -              start_armorvalue = 0;
 -              WEPSET_COPY_AW(start_weapons, WEP_MINSTANEX);
 -              g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha");
 -              start_items |= IT_UNLIMITED_SUPERWEAPONS;
 -
 -              if (g_minstagib_invis_alpha <= 0)
 -                      g_minstagib_invis_alpha = -1;
 -      }
        else
        {
                for (i = WEP_FIRST; i <= WEP_LAST; ++i)
        if(cvar("g_nexball"))
                start_items |= IT_UNLIMITED_SUPERWEAPONS; // FIXME BAD BAD BAD BAD HACK, NEXBALL SHOULDN'T ABUSE PORTO'S WEAPON SLOT
  
 -      if(g_minstagib)
 -      {
 -              start_ammo_cells = cvar("g_minstagib_ammo_start");
 -              start_ammo_fuel = cvar("g_start_ammo_fuel");
 -      }
 -      else if(start_items & IT_UNLIMITED_WEAPON_AMMO)
 +      if(start_items & IT_UNLIMITED_WEAPON_AMMO)
        {
                start_ammo_rockets = 999;
                start_ammo_shells = 999;
@@@ -1088,10 -1002,6 +983,6 @@@ float g_touchexplode_force
  float sv_autotaunt;
  float sv_taunt;
  
- float sv_pitch_min;
- float sv_pitch_max;
- float sv_pitch_fixyaw;
  string GetGametype(); // g_world.qc
  void readlevelcvars(void)
  {
                MUTATOR_ADD(mutator_spawn_near_teammate);
        if(cvar("g_physical_items"))
                MUTATOR_ADD(mutator_physical_items);
 +      if(cvar("g_minstagib"))
 +              MUTATOR_ADD(mutator_minstagib); 
 +
        if(!g_minstagib)
        {
                if(cvar("g_invincible_projectiles"))
      g_touchexplode_edgedamage = cvar("g_touchexplode_edgedamage");
      g_touchexplode_force = cvar("g_touchexplode_force");
  
- #ifdef ALLOW_FORCEMODELS
-       sv_clforceplayermodels = cvar("sv_clforceplayermodels");
- #endif
        sv_clones = cvar("sv_clones");
-       sv_gentle = cvar("sv_gentle");
        sv_foginterval = cvar("sv_foginterval");
        g_cloaked = cvar("g_cloaked");
      if(g_cts)
        if not(inWarmupStage && !g_ca)
                game_starttime = cvar("g_start_delay");
  
-       sv_pitch_min = cvar("sv_pitch_min");
-       sv_pitch_max = cvar("sv_pitch_max");
-       sv_pitch_fixyaw = cvar("sv_pitch_fixyaw");
        readplayerstartcvars();
  }
  
@@@ -1640,34 -1538,6 +1522,6 @@@ void precache(
  #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 || (msg_entity.classname == STR_SPECTATOR && 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 ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
-       {
-               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()
@@@ -2146,22 -2016,6 +2000,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 83c8e0143e0a6a7490b484f74c60e454bf84da6b,4bdcbb28234834629ecc13f8f52767fcd1e4ce90..14815206dea742c441cc16cf98d1fc6067f4e6c7
@@@ -4,6 -4,7 +4,7 @@@ MUTATOR_DECLARATION(gamemode_keepaway)
  MUTATOR_DECLARATION(gamemode_ctf);
  MUTATOR_DECLARATION(gamemode_nexball);
  MUTATOR_DECLARATION(gamemode_onslaught);
+ MUTATOR_DECLARATION(gamemode_domination);
  
  MUTATOR_DECLARATION(mutator_dodging);
  MUTATOR_DECLARATION(mutator_invincibleprojectiles);
@@@ -14,6 -15,5 +15,6 @@@ MUTATOR_DECLARATION(mutator_spawn_near_
  MUTATOR_DECLARATION(mutator_physical_items);
  MUTATOR_DECLARATION(mutator_vampire);
  MUTATOR_DECLARATION(mutator_superspec);
 +MUTATOR_DECLARATION(mutator_minstagib);
  
  MUTATOR_DECLARATION(sandbox);
diff --combined qcsrc/server/progs.src
index 67100fbea222f24cce4d502a3e9e028da835f32f,a00fd32c5e6f0e47a4865434dadee0ce79556034..1efa0e5650e488fb1d21594df93bea554f50decc
@@@ -13,7 -13,9 +13,9 @@@ sys-post.q
  ../warpzonelib/server.qh
  
  ../common/constants.qh
+ ../common/teams.qh
  ../common/util.qh
+ ../common/counting.qh
  ../common/items.qh
  ../common/explosion_equation.qh
  ../common/urllib.qh
  ../common/command/generic.qh
  ../common/command/shared_defs.qh
  ../common/net_notice.qh
+ ../common/animdecide.qh
  
  autocvars.qh
  constants.qh
  defs.qh               // Should rename this, it has fields and globals
  
+ ../common/notifications.qh // must be after autocvars
+ ../common/deathtypes.qh // must be after notifications
  mutators/base.qh
  mutators/mutators.qh
  mutators/gamemode_ctf.qh
+ mutators/gamemode_domination.qh
  mutators/gamemode_keyhunt.qh // TODO fix this
  mutators/gamemode_keepaway.qh
  mutators/gamemode_nexball.qh 
@@@ -141,7 -148,7 +148,7 @@@ t_plats.q
  antilag.qc
  
  //ctf.qc
- domination.qc
//domination.qc
  //mode_onslaught.qc
  //nexball.qc
  g_hook.qc
@@@ -208,6 -215,7 +215,7 @@@ playerstats.q
  
  mutators/base.qc
  mutators/gamemode_ctf.qc
+ mutators/gamemode_domination.qc
  mutators/gamemode_freezetag.qc
  mutators/gamemode_keyhunt.qc
  mutators/gamemode_keepaway.qc
@@@ -223,7 -231,6 +231,7 @@@ mutators/mutator_spawn_near_teammate.q
  mutators/mutator_physical_items.qc
  mutators/sandbox.qc
  mutators/mutator_superspec.qc
 +mutators/mutator_minstagib.qc
  
  ../warpzonelib/anglestransform.qc
  ../warpzonelib/mathlib.qc
  ../warpzonelib/util_server.qc
  ../warpzonelib/server.qc
  
+ ../common/animdecide.qc
  ../common/util.qc
+ ../common/notifications.qc
  
  ../common/if-this-file-errors-scroll-up-and-fix-the-warnings.fteqccfail
diff --combined qcsrc/server/t_items.qc
index 3a0c0d12e3a4920938d1c3c495715fa7c6293bfb,2ff925ca53d9fbf2ac2c05c103b85e4a0402e263..9e66df92be7ced5428d9bfe58c0ec029125acfa8
@@@ -271,6 -271,11 +271,6 @@@ float ItemSend(entity to, float sf
  
  float have_pickup_item(void)
  {
 -      // minstagib: only allow filtered items
 -      if(g_minstagib)
 -              if(self.classname != "minstagib")
 -                      return FALSE;
 -
        if(self.flags & FL_POWERUP)
        {
                if(autocvar_g_powerups > 0)
@@@ -439,10 -444,9 +439,10 @@@ void Item_Show (entity e, float mode
  void Item_Respawn (void)
  {
        Item_Show(self, 1);
 -      if(!g_minstagib && self.items == IT_STRENGTH)
 +      // this is ugly...
 +      if(self.items == IT_STRENGTH)
                sound (self, CH_TRIGGER, "misc/strength_respawn.wav", VOL_BASE, ATTN_NORM);     // play respawn sound
 -      else if(!g_minstagib && self.items == IT_INVINCIBLE)
 +      else if(self.items == IT_INVINCIBLE)
                sound (self, CH_TRIGGER, "misc/shield_respawn.wav", VOL_BASE, ATTN_NORM);       // play respawn sound
        else
                sound (self, CH_TRIGGER, "misc/itemrespawn.wav", VOL_BASE, ATTN_NORM);  // play respawn sound
@@@ -469,18 -473,28 +469,18 @@@ void Item_RespawnCountdown (void
                        string name;
                        vector rgb = '1 0 1';
                        name = string_null;
 -                      if(g_minstagib)
 -                      {
 -                              switch(self.items)
 -                              {
 -                                      case IT_STRENGTH:   name = "item-invis"; rgb = '0 0 1'; break;
 -                                      case IT_NAILS:      name = "item-extralife"; rgb = '1 0 0'; break;
 -                                      case IT_INVINCIBLE: name = "item-speed"; rgb = '1 0 1'; break;
 -                              }
 -                      }
 -                      else
 -                      {
 -                              switch(self.items)
 -                              {
 -                                      case IT_STRENGTH:   name = "item-strength"; rgb = '0 0 1'; break;
 -                                      case IT_INVINCIBLE: name = "item-shield"; rgb = '1 0 1'; break;
 -                              }
 -                      }
                        switch(self.items)
                        {
 -                              case IT_FUEL_REGEN:     name = "item-fuelregen"; rgb = '1 0.5 0'; break;
 -                              case IT_JETPACK:        name = "item-jetpack"; rgb = '0.5 0.5 0.5'; break;
 +                              case IT_FUEL_REGEN: name = "item-fuelregen"; rgb = '1 0.5 0'; break;
 +                              case IT_JETPACK:    name = "item-jetpack"; rgb = '0.5 0.5 0.5'; break;
 +                              case IT_STRENGTH:   name = "item-strength"; rgb = '0 0 1'; break;
 +                              case IT_INVINCIBLE: name = "item-shield"; rgb = '1 0 1'; break;
                        }
 +                      item_name = name;
 +                      item_color = rgb;
 +                      MUTATOR_CALLHOOK(Item_RespawnCountdown);
 +                      name = item_name;
 +                      rgb = item_color;
                        if(self.flags & FL_WEAPON)
                        {
                                entity wi = get_weaponinfo(self.weapon);
@@@ -600,7 -614,72 +600,7 @@@ float Item_GiveTo(entity item, entity p
        // if nothing happens to player, just return without taking the item
        pickedup = FALSE;
        _switchweapon = FALSE;
-       
 -      if (g_minstagib)
 -      {
 -              float prevcells = player.ammo_cells;
 -
 -              pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL);
 -              pickedup |= Item_GiveAmmoTo(item, player, ammo_cells, 999, ITEM_MODE_NONE);
 -
 -              if(player.ammo_cells > prevcells)
 -              {
 -                      _switchweapon = TRUE;
 -
 -                      // play some cool sounds ;)
 -                      if (clienttype(player) == CLIENTTYPE_REAL)
 -                      {
 -                              if(player.health <= 5)
 -                                      AnnounceTo(player, "lastsecond");
 -                              else if(player.health < 50)
 -                                      AnnounceTo(player, "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);
 -                      player.health = 100;
 -              }
 -
 -              if((it = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
 -              {
 -                      pickedup = TRUE;
 -                      player.items |= it;
 -                      sprint (player, strcat("You got the ^2", item.netname, "\n"));
 -              }
 -
 -              // extralife powerup
 -              if (item.max_health)
 -              {
 -                      pickedup = TRUE;
 -                      // sound not available
 -                      // AnnounceTo(player, "_lives");
 -                      player.armorvalue = bound(player.armorvalue, 999, player.armorvalue + autocvar_g_minstagib_extralives);
 -                      sprint(player, "^3You picked up some extra lives\n");
 -              }
 -
 -              // invis powerup
 -              if (item.strength_finished)
 -              {
 -                      pickedup = TRUE;
 -                      // sound not available
 -                      // AnnounceTo(player, "invisible");
 -                      player.strength_finished = max(player.strength_finished, time) + autocvar_g_balance_powerup_strength_time;
 -              }
 -
 -              // speed powerup
 -              if (item.invincible_finished)
 -              {
 -                      pickedup = TRUE;
 -                      // sound not available
 -                      // AnnounceTo(player, "speed");
 -                      player.invincible_finished = max(player.invincible_finished, time) + autocvar_g_balance_powerup_invincible_time;
 -              }
 -      }
 -      else
 -      {
                // in case the player has autoswitch enabled do the following:
                // if the player is using their best weapon before items are given, they
                // probably want to switch to an even better weapon after items are given
                                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);
                        }
                }
  
                        pickedup = TRUE;
                        player.superweapons_finished = max(player.superweapons_finished, time) + item.superweapons_finished;
                }
 -      }
  
  :skip
 +
 +      giveplayer = player;
 +      giveitem = item;
 +      player_wswitch = _switchweapon;
 +      player_pickedup = pickedup;
 +      MUTATOR_CALLHOOK(Item_GiveTo);
 +      _switchweapon = player_wswitch;
 +      pickedup = player_pickedup;
 +      
        // always eat teamed entities
        if(item.team)
                pickedup = TRUE;
@@@ -1081,9 -1152,9 +1081,9 @@@ void StartItem (string itemmodel, strin
                precache_sound (self.item_pickupsound);
  
                precache_sound ("misc/itemrespawncountdown.wav");
 -              if(!g_minstagib && itemid == IT_STRENGTH)
 +              if(itemid == IT_STRENGTH)
                        precache_sound ("misc/strength_respawn.wav");
 -              else if(!g_minstagib && itemid == IT_INVINCIBLE)
 +              else if(itemid == IT_INVINCIBLE)
                        precache_sound ("misc/shield_respawn.wav");
                else
                        precache_sound ("misc/itemrespawn.wav");
        }
  }
  
 -/* replace items in minstagib
 - * IT_STRENGTH         = invisibility
 - * IT_NAILS    = extra lives
 - * IT_INVINCIBLE = speed
 - */
 -void minstagib_items (float itemid) // will be deleted soon.
 -{
 -      float rnd;
 -      self.classname = "minstagib"; // ...?
 -
 -      // replace rocket launchers and nex guns with ammo cells
 -      if (itemid == IT_CELLS)
 -      {
 -              self.ammo_cells = autocvar_g_minstagib_ammo_drop;
 -              StartItem ("models/items/a_cells.md3",
 -                      "misc/itempickup.wav", 45, 0,
 -                      "MinstaNex Ammo", IT_CELLS, 0, 0, generic_pickupevalfunc, 100);
 -              return;
 -      }
 -
 -      // randomize
 -      rnd = random() * 3;
 -      if (rnd <= 1)
 -              itemid = IT_STRENGTH;
 -      else if (rnd <= 2)
 -              itemid = IT_NAILS;
 -      else
 -              itemid = IT_INVINCIBLE;
 -
 -      // replace with invis
 -      if (itemid == IT_STRENGTH)
 -      {
 -              if(!self.strength_finished)
 -                      self.strength_finished = autocvar_g_balance_powerup_strength_time;
 -              StartItem ("models/items/g_strength.md3",
 -                      "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
 -                      "Invisibility", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_MID);
 -      }
 -      // replace with extra lives
 -      if (itemid == IT_NAILS)
 -      {
 -              self.max_health = 1;
 -              StartItem ("models/items/g_h100.md3",
 -                      "misc/megahealth.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
 -                      "Extralife", IT_NAILS, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
 -      }
 -      // replace with speed
 -      if (itemid == IT_INVINCIBLE)
 -      {
 -              if(!self.invincible_finished)
 -                      self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
 -              StartItem ("models/items/g_invincible.md3",
 -                      "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
 -                      "Speed", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_MID);
 -      }
 -}
 -
 -float minst_no_auto_cells;
 -void minst_remove_item (void) {
 -      if(minst_no_auto_cells)
 -              remove(self);
 -}
 -
  float weaponswapping;
  float internalteam;
  
@@@ -1291,6 -1425,11 +1291,6 @@@ void weapon_defaultspawnfunc(float wpn
        if(self.team)
                f |= FL_NO_WEAPON_STAY;
  
 -      // stupid minstagib hack, don't ask
 -      if(g_minstagib)
 -              if(self.ammo_cells)
 -                      self.ammo_cells = autocvar_g_minstagib_ammo_drop;
 -
        StartItem(e.model, "weapons/weaponpickup.wav", self.respawntime, self.respawntimejitter, e.message, 0, e.weapon, f, weapon_pickupevalfunc, e.bot_pickupbasevalue);
        if (self.modelindex) // don't precache if self was removed
                weapon_action(e.weapon, WR_PRECACHE);
@@@ -1319,16 -1458,37 +1319,16 @@@ void spawnfunc_weapon_shotgun (void) 
  
  void spawnfunc_weapon_nex (void)
  {
 -      if (g_minstagib)
 -      {
 -              minstagib_items(IT_CELLS);
 -              self.think = minst_remove_item;
 -              self.nextthink = time;
 -              return;
 -      }
        weapon_defaultspawnfunc(WEP_NEX);
  }
  
  void spawnfunc_weapon_minstanex (void)
  {
 -      if (g_minstagib)
 -      {
 -              minstagib_items(IT_CELLS);
 -              self.think = minst_remove_item;
 -              self.nextthink = time;
 -              return;
 -      }
        weapon_defaultspawnfunc(WEP_MINSTANEX);
  }
  
  void spawnfunc_weapon_rocketlauncher (void)
  {
 -      if (g_minstagib)
 -      {
 -              minstagib_items(IT_CELLS); // replace rocketlauncher with cells
 -              self.think = minst_remove_item;
 -              self.nextthink = time;
 -              return;
 -      }
        weapon_defaultspawnfunc(WEP_ROCKET_LAUNCHER);
  }
  
@@@ -1456,6 -1616,9 +1456,6 @@@ void spawnfunc_item_health_large (void
  }
  
  void spawnfunc_item_health_mega (void) {
 -      if(g_minstagib) {
 -              minstagib_items(IT_NAILS);
 -      } else {
                if(!self.max_health)
                        self.max_health = g_pickup_healthmega_max;
                if(!self.health)
                if(!self.pickup_anyway)
                        self.pickup_anyway = g_pickup_healthmega_anyway;
                StartItem ("models/items/g_h100.md3", "misc/megahealth.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Health", IT_HEALTH, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
 -      }
  }
  
  // support old misnamed entities
@@@ -1473,16 -1637,34 +1473,16 @@@ void spawnfunc_item_health25() { spawnf
  void spawnfunc_item_health100() { spawnfunc_item_health_mega(); }
  
  void spawnfunc_item_strength (void) {
 -      if(g_minstagib) {
 -              minstagib_items(IT_STRENGTH);
 -      } else {
                precache_sound("weapons/strength_fire.wav");
                if(!self.strength_finished)
                        self.strength_finished = autocvar_g_balance_powerup_strength_time;
                StartItem ("models/items/g_strength.md3", "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Strength Powerup", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
 -      }
  }
  
  void spawnfunc_item_invincible (void) {
 -      if(g_minstagib) {
 -              minstagib_items(IT_INVINCIBLE);
 -      } else {
                if(!self.invincible_finished)
                        self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
                StartItem ("models/items/g_invincible.md3", "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Shield", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
 -      }
 -}
 -
 -void spawnfunc_item_minst_cells (void) {
 -      if (g_minstagib)
 -      {
 -              minst_no_auto_cells = TRUE;
 -              minstagib_items(IT_CELLS);
 -      }
 -      else
 -              remove(self);
  }
  
  // compatibility:
@@@ -1974,6 -2156,12 +1974,6 @@@ float GiveItems(entity e, float beginar
                if(WEPSET_CONTAINS_ANY_EA(self, WEPBIT_SUPERWEAPONS))
                        e.superweapons_finished = autocvar_g_balance_superweapons_time;
  
 -      if (g_minstagib)
 -      {
 -              e.health = bound(0, e.health, 100);
 -              e.armorvalue = bound(0, e.armorvalue, 999);
 -      }
 -
        if(e.strength_finished <= 0)
                e.strength_finished = 0;
        else
diff --combined qcsrc/server/teamplay.qc
index eff5f80310d8ccf26f717909b1ad1a3e3658ea03,a96726c5643f175174783c563ec77751deb70190..70966c43107a84c4f43adb2e93989f44fb3e6cb5
@@@ -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 dom_init();
  void runematch_init();
  void tdm_init();
  void entcs_init();
@@@ -134,7 -94,7 +94,7 @@@ void InitGameplayMode(
                ActivateTeamplay();
                fraglimit_override = autocvar_g_domination_point_limit;
                leadlimit_override = autocvar_g_domination_point_leadlimit;
-               dom_init();
+               MUTATOR_ADD(gamemode_domination);
                have_team_spawns = -1; // request team spawns
        }
  
@@@ -324,7 -284,9 +284,7 @@@ string getwelcomemessage(void
        ret_string = "";
        MUTATOR_CALLHOOK(BuildMutatorsPrettyString);
        modifications = ret_string;
 -      
 -      if(g_minstagib)
 -              modifications = strcat(modifications, ", MinstaGib");
 +
        if(g_weaponarena)
        {
                if(g_weaponarena_random)
@@@ -415,13 -377,13 +375,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");
        }
  
  }
@@@ -451,10 -413,10 +411,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 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;
  }
  
@@@ -575,7 -537,7 +535,7 @@@ void GetTeamCounts(entity ignore
                                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)
                                {
@@@ -768,13 -730,13 +728,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
                {
@@@ -843,21 -805,21 +803,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);
@@@ -946,13 -908,13 +906,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
@@@ -1071,12 -1033,12 +1031,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()
diff --combined qcsrc/server/w_common.qc
index 9bae1b7ba720b3c476ead7f9980627fba21bfea6,e68a417e00de6855f4bbfce117ce244b4de3a5f1..d755f68dfc7dbb182b52f7e8c970b3e84eb896f4
@@@ -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 (other.classname == "player")
-       {
-               sprint (other, "You got the ^2");
-               sprint (other, name);
-               sprint (other, "\n");
-       }
 -      if not(g_minstagib)
+       if(other.classname == "player")
+               { Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_WEAPON_GOT, wep); }
  
        self = oldself;
  }
@@@ -166,7 -163,6 +162,6 @@@ void FireRailgunBullet (vector start, v
        trace_dphitq3surfaceflags = endq3surfaceflags;
  }
  
- .float dmg_edge;
  .float dmg_force;
  .float dmg_radius;
  .float dmg_total;
@@@ -184,24 -180,14 +179,14 @@@ void W_BallisticBullet_Hit (void
        {
                endzcurveparticles();
  
-               headshot = 0;
                yoda = 0;
-               damage_headshotbonus = self.dmg_edge * f;
                railgun_start = self.origin - 2 * frametime * self.velocity;
                railgun_end = self.origin + 2 * frametime * self.velocity;
                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);
-               damage_headshotbonus = 0;
  
-               if(headshot)
-                       f *= q;
-               if(self.dmg_edge > 0)
-               {
-                       if(headshot)
-                               AnnounceTo(self.realowner, "headshot");
-                       if(yoda)
-                               AnnounceTo(self.realowner, "awesome");
-               }
+               if(yoda)
+                       AnnounceTo(self.realowner, "awesome");
  
                // calculate hits for ballistic weapons
                if(g)
@@@ -397,7 -383,7 +382,7 @@@ void fireBallisticBullet_trace_callback
        self.owner = world;
  }
  
- void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float headshotbonus, float force, float dtype, float tracereffects, float gravityfactor, float bulletconstant)
+ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float force, float dtype, float tracereffects, float gravityfactor, float bulletconstant)
  {
        float lag, dt, savetime; //, density;
        entity pl, oldself;
  
        proj.touch = W_BallisticBullet_Touch;
        proj.dmg = damage;
-       proj.dmg_edge = headshotbonus;
        proj.dmg_force = force;
        proj.projectiledeathtype = dtype;
  
diff --combined qcsrc/server/w_laser.qc
index 6af5a34f232b5dba059d8888269c8fbf7179ae25,69dcb17aa5c292d4328b539668c8dac674f76935..f2a4ba281509d6ff7df6a9f17a3d613e684a1b46
@@@ -34,11 -34,19 +34,11 @@@ void W_Laser_Attack (float issecondary
        entity missile;
        vector s_forward;
        float a;
 -      float nodamage;
 -
 -      if(issecondary == 2) // minstanex shot
 -              nodamage = g_minstagib;
 -      else
 -              nodamage = FALSE;
  
        a = autocvar_g_balance_laser_primary_shotangle;
        s_forward = v_forward * cos(a * DEG2RAD) + v_up * sin(a * DEG2RAD);
  
 -      if(nodamage)
 -              W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, 0);
 -      else if(issecondary == 1)
 +      if(issecondary == 1)
                W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, autocvar_g_balance_laser_secondary_damage);
        else
                W_SetupShot_Dir (self, s_forward, FALSE, 3, "weapons/lasergun_fire.wav", CH_WEAPON_B, autocvar_g_balance_laser_primary_damage);
        missile.owner = missile.realowner = self;
        missile.classname = "laserbolt";
        missile.dmg = 0;
 -      if(!nodamage)
 -      {
 -              missile.bot_dodge = TRUE;
 -              missile.bot_dodgerating = autocvar_g_balance_laser_primary_damage;
 -      }
 +      missile.bot_dodge = TRUE;
 +      missile.bot_dodgerating = autocvar_g_balance_laser_primary_damage;
  
        PROJECTILE_MAKETRIGGER(missile);
        missile.projectiledeathtype = WEP_LASER;
@@@ -280,6 -291,14 +280,14 @@@ float w_laser(float req
        {
                W_Reload(0, autocvar_g_balance_laser_reload_ammo, autocvar_g_balance_laser_reload_time, "weapons/reload.wav");
        }
+       else if (req == WR_SUICIDEMESSAGE)
+       {
+               return WEAPON_LASER_SUICIDE;
+       }
+       else if (req == WR_KILLMESSAGE)
+       {
+               return WEAPON_LASER_MURDER;
+       }
        return TRUE;
  }
  #endif
@@@ -298,15 -317,6 +306,6 @@@ float w_laser(float req
        {
                precache_sound("weapons/laserimpact.wav");
        }
-       else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = _("%s lasered themself to hell");
-       else if (req == WR_KILLMESSAGE)
-       {
-               if(w_deathtype & HITTYPE_SECONDARY)
-                       w_deathtypestring = _("%s was cut in half by %s's gauntlet"); // unchecked: SPLASH
-               else
-                       w_deathtypestring = _("%s was lasered to death by %s"); // unchecked: SPLASH
-       }
        return TRUE;
  }
  #endif
index 68d1291684fd001c10519fa03f0876f49d992bc4,c464af93a27c07e05ad5493efe0cfcd4b3cb60f8..041ed3caf91fb714499aedf1bf90aace4ed868e1
@@@ -14,21 -14,22 +14,21 @@@ void W_MinstaNex_Attack (void
  
        yoda = 0;
        damage_goodhits = 0;
-       headshot = 0;
-       damage_headshotbonus = -1; // no extra damage, just count
        FireRailgunBullet (w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, 10000, 800, 0, 0, 0, 0, WEP_MINSTANEX);
-       damage_headshotbonus = 0;
  
-       if(yoda && flying)
-               AnnounceTo(self, "yoda");
 -      if(g_minstagib)
 +      if(headshot)
        {
 -              if(yoda)
 -                      AnnounceTo(self, "yoda");
 +              AnnounceTo(self, "headshot");
        }
 -      else
 +      if(damage_goodhits && self.minstanex_lasthit)
        {
-               AnnounceTo(self, "impressive");
-               damage_goodhits = 0; // only every second time
+               if(yoda && flying)
+                       AnnounceTo(self, "yoda");
+               if(damage_goodhits && self.minstanex_lasthit)
+               {
+                       AnnounceTo(self, "impressive");
+                       damage_goodhits = 0; // only every second time
+               }
        }
  
        self.minstanex_lasthit = damage_goodhits;
        {
            switch(self.team)
            {
-             case COLOR_TEAM1:   // Red
+             case NUM_TEAM_1:   // Red
                  if(damage_goodhits)
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED_HIT"), w_shotorg, v);
                  else
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED"), w_shotorg, v);
                  break;
-             case COLOR_TEAM2:   // Blue
+             case NUM_TEAM_2:   // Blue
                  if(damage_goodhits)
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE_HIT"), w_shotorg, v);
                  else
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE"), w_shotorg, v);
                  break;
-             case COLOR_TEAM3:   // Yellow
+             case NUM_TEAM_3:   // Yellow
                  if(damage_goodhits)
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW_HIT"), w_shotorg, v);
                  else
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW"), w_shotorg, v);
                  break;
-             case COLOR_TEAM4:   // Pink
+             case NUM_TEAM_4:   // Pink
                  if(damage_goodhits)
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3PINK_HIT"), w_shotorg, v);
                  else
        }
        else
          WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3"), w_shotorg, v);
 -
 -      if (g_minstagib)
 -              W_DecreaseAmmo(ammo_cells, 1, autocvar_g_balance_minstanex_reload_ammo);
 -      else
 -              W_DecreaseAmmo(ammo_cells, autocvar_g_balance_minstanex_ammo, autocvar_g_balance_minstanex_reload_ammo);
 -}
 -
 -
 -.float minstagib_nextthink;
 -.float minstagib_needammo;
 -void minstagib_stop_countdown(entity e)
 -{
 -      if (!e.minstagib_needammo)
 -              return;
 -      Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_MINSTA_FINDAMMO);
 -      e.minstagib_needammo = FALSE;
 -}
 -void minstagib_ammocheck(void)
 -{
 -      if (time < self.minstagib_nextthink)
 -              return;
 -
 -      if (self.deadflag || gameover)
 -              minstagib_stop_countdown(self);
 -      else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO))
 -      {
 -              minstagib_stop_countdown(self);
 -              self.health = 100;
 -      }
 -      else
 -      {
 -              self.minstagib_needammo = TRUE;
 -              if (self.health == 5)
 -              {
 -                      Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      AnnounceTo(self, "terminated");
 -              }
 -              else if (self.health == 10)
 -              {
 -                      Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      AnnounceTo(self, "1");
 -              }
 -              else if (self.health == 20)
 -              {
 -                      Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      AnnounceTo(self, "2");
 -              }
 -              else if (self.health == 30)
 -              {
 -                      Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      AnnounceTo(self, "3");
 -              }
 -              else if (self.health == 40)
 -              {
 -                      Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      AnnounceTo(self, "4");
 -              }
 -              else if (self.health == 50)
 -              {
 -                      Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      AnnounceTo(self, "5");
 -              }
 -              else if (self.health == 60)
 -              {
 -                      Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      AnnounceTo(self, "6");
 -              }
 -              else if (self.health == 70)
 -              {
 -                      Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      AnnounceTo(self, "7");
 -              }
 -              else if (self.health == 80)
 -              {
 -                      Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      AnnounceTo(self, "8");
 -              }
 -              else if (self.health == 90)
 -              {
 -                      Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MINSTA_FINDAMMO);
 -                      Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      AnnounceTo(self, "9");
 -              }
 -              else if (self.health == 100)
 -              {
 -                      Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MINSTA_FINDAMMO_FIRST);
 -                      Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
 -                      if not(self.flags & FL_GODMODE)
 -                              AnnounceTo(self, "10");
 -              }
 -      }
 -      self.minstagib_nextthink = time + 1;
 +              
 +      W_DecreaseAmmo(ammo_cells, ((g_minstagib) ? 1 : autocvar_g_balance_minstanex_ammo), autocvar_g_balance_minstanex_reload_ammo);
  }
  
  void spawnfunc_weapon_minstanex (void); // defined in t_items.qc
@@@ -82,7 -173,10 +82,7 @@@ float w_minstanex(float req
        float minstanex_ammo;
  
        // now multiple WR_s use this
 -      if(g_minstagib)
 -              minstanex_ammo = 1;
 -      else
 -              minstanex_ammo = autocvar_g_balance_minstanex_ammo;
 +      minstanex_ammo = ((g_minstagib) ? 1 : autocvar_g_balance_minstanex_ammo);
  
        if (req == WR_AIM)
        {
  
                W_Reload(used_ammo, autocvar_g_balance_minstanex_reload_ammo, autocvar_g_balance_minstanex_reload_time, "weapons/reload.wav");
        }
+       else if (req == WR_SUICIDEMESSAGE)
+       {
+               return WEAPON_THINKING_WITH_PORTALS;
+       }
+       else if (req == WR_KILLMESSAGE)
+       {
+               return WEAPON_MINSTANEX_MURDER;
+       }
        return TRUE;
  }
  #endif
@@@ -195,10 -297,6 +203,6 @@@ float w_minstanex(float req
        {
                precache_sound("weapons/neximpact.wav");
        }
-       else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = _("%s is now thinking with portals");
-       else if (req == WR_KILLMESSAGE)
-               w_deathtypestring = _("%s has been vaporized by %s's minstanex");
        return TRUE;
  }
  #endif