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

index fe5fb5ef04da10914e70498abc5d8027e792ba93,7a5662c9799fb51f738b7293a3e5ce04f9a99f44..71ac7239a675a75f93a2dc33334dd4b66ed5c6c3
@@@ -361,12 -361,12 +361,12 @@@ void assault_new_round(
        entity ent;
        for(ent = world; (ent = nextent(ent)); )
        {
 -              if(clienttype(ent) == CLIENTTYPE_NOTACLIENT)
 +              if(IS_NOT_A_CLIENT(ent))
                {
-                       if(ent.team_saved == COLOR_TEAM1)
-                               ent.team_saved = COLOR_TEAM2;
-                       else if(ent.team_saved == COLOR_TEAM2)
-                               ent.team_saved = COLOR_TEAM1;
+                       if(ent.team_saved == NUM_TEAM_1)
+                               ent.team_saved = NUM_TEAM_2;
+                       else if(ent.team_saved == NUM_TEAM_2)
+                               ent.team_saved = NUM_TEAM_1;
                }
        }
  
index 0000000000000000000000000000000000000000,ba8f648c888b33e0e312cdf8774b3e1cd0169cad..1b6cc5dbb16266a3a585c0b0645edcb5c00a4afb
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,604 +1,604 @@@
 -      if(self.owner.classname != "player" || time < game_starttime)
+ float rune_numspawns;
+ float RUNE_FIRST      = 1;
+ float RUNE_STRENGTH   = 1;
+ float RUNE_DEFENSE    = 2;
+ float RUNE_REGEN      = 4;
+ float RUNE_SPEED      = 8;
+ float RUNE_VAMPIRE    = 16;
+ float RUNE_LAST       = 16;
+ float CURSE_FIRST     = 8192;
+ float CURSE_WEAK      = 8192;
+ float CURSE_VULNER    = 16384;
+ float CURSE_VENOM     = 32768;
+ float CURSE_SLOW      = 65536;
+ float CURSE_EMPATHY   = 131072;
+ float CURSE_LAST      = 131072;
+ float RUNE_COUNT = 5;
+ /* rune ideas:
+       Doom/Death
+       Rune: When you damage enemies, you have a slight chance of instant-killing them (porportional to damage dealt / their health)
+       Curse: When you are damaged, you have a chance of being instant-killed
+       Vengence/Slothful
+       Rune: The lower your health below 100, the more damage you deal (does not decrease your damage if you're above 100)
+       Curse: The higher your health (up to 100), the less damage you deal (at 100 hp deal 1/5th damage)
+ */
+ /*QUAKED spawnfunc_runematch_spawn_point (1 0 0) (-16 -16 -24) (16 16 24)
+ spawn point for runes in runematch
+ */
+ void spawnfunc_runematch_spawn_point()
+ {
+       if(!g_runematch || !autocvar_g_runematch_fixedspawns)
+       {
+               remove(self);
+               return;
+       }
+       setsize(self, '0 0 -35', '0 0 0');
+       droptofloor();
+       ++rune_numspawns;
+ }
+ // only used if using rune spawns at all
+ entity rune_find_spawnpoint()
+ {
+       entity e;
+       if(rune_numspawns < RUNE_COUNT)
+               return world;
+       RandomSelection_Init();
+       for(e = world; (e = find(e, classname, "runematch_spawn_point")); )
+               if(e.owner == world)
+                       RandomSelection_Add(e, 0, string_null, e.cnt, 0);
+       return RandomSelection_chosen_ent;
+ }
+ float rune_spawn_somewhere(entity e)
+ {
+       entity spot;
+       spot = rune_find_spawnpoint();
+       if(spot)
+       {
+               spot.owner = e;
+               setorigin(e, spot.origin);
+               e.owner = spot;
+               spot.owner = e;
+               return TRUE;
+       }
+       else
+       {
+               if(MoveToRandomMapLocation(e, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
+               {
+                       // great
+                       makevectors(self.angles),
+                       self.velocity = v_forward * 250;
+                       self.angles = '0 0 0';
+                       return TRUE;
+               }
+               else
+               {
+                       // sorry, can't spawn, better luck next frame
+                       return FALSE;
+               }
+       }
+ }
+ void rune_unmark_spot(entity e)
+ {
+       if(e.owner.classname == "runematch_spawn_point")
+       {
+               e.owner.owner = world;
+               e.owner = world;
+       }
+ }
+ string RuneName(float r)
+ {
+       if(r == RUNE_STRENGTH)
+               return "^1Strength^7";
+       if(r == RUNE_DEFENSE)
+               return "^4Defense^7";
+       if(r == RUNE_REGEN)
+               return "^2Vitality^7";
+       if(r == RUNE_SPEED)
+               return "^3Speed^7";
+       if(r == RUNE_VAMPIRE)
+               return "^6Vampire^7";
+       if(r == CURSE_WEAK)
+               return "^1Weakness^7";
+       if(r == CURSE_VULNER)
+               return "^4Vulnerability^7";
+       if(r == CURSE_VENOM)
+               return "^2Venom^7";
+       if(r == CURSE_SLOW)
+               return "^3Slow^7";
+       if(r == CURSE_EMPATHY)
+               return "^6Empathy^7";
+       return strcat("^8[unnamed", ftos(r), "]^7");
+ }
+ vector RuneColormod(float r)
+ {
+       vector _color = '255 0 255';
+       if(r == RUNE_STRENGTH)
+               _color = '255 0 0';
+       if(r == RUNE_DEFENSE)
+               _color = '0 0 255';//'0 102 255';//
+       if(r == RUNE_REGEN)
+               _color = '0 204 0';//'0 255 0';
+       if(r == RUNE_SPEED)
+               _color = 0.35*'185 185 0';//255 230 0';//'255 255 0';
+       if(r == RUNE_VAMPIRE)
+               _color = '64 0 128';//'108 0 217';//'128 0 255';//'179 0 204';//
+       if(r == CURSE_WEAK)
+               _color = '255 0 0';
+       if(r == CURSE_VULNER)
+               _color = '0 0 255';//'0 102 255';//
+       if(r == CURSE_VENOM)
+               _color = '0 204 0';//'0 255 0';
+       if(r == CURSE_SLOW)
+               _color = 0.5*'185 185 0';//'255 255 0';
+       if(r == CURSE_EMPATHY)
+               _color = '179 0 204';//'128 0 255';
+       return _color * (1 / 255) * autocvar_g_runematch_rune_color_strength;
+ }
+ void rune_respawn();
+ void RuneCarriedThink()
+ {
+       float rcount, rnum;
+       vector ang = '0 0 0';
+       entity rune;
 -      if(other.classname != "player" || other.health < 1)
++      if(!IS_PLAYER(self.owner) || time < game_starttime)
+       {
+               rune_respawn();
+               return;
+       }
+       self.nextthink = time + 0.1;
+       // count runes my owner holds
+       rcount = 0;
+       rune = find(world, classname, "rune");
+       rnum = -1;
+       while(rune)
+       {
+               if(rune.owner == self.owner)
+                       rcount = rcount + 1;
+               if(rune == self)
+                       rnum = rcount;
+               rune = find(rune, classname, "rune");
+       }
+       ang_y = rnum*(360 / rcount) + mod(time, 360)*45;//180;
+       makevectors(ang);
+       setorigin(self, v_forward*32);
+ }
+ void rune_touch()
+ {
+       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+       {
+               self.think = rune_respawn;
+               self.nextthink = time;
+               return;
+       }
 -              if(rune.owner.classname == "player")
++      if(!IS_PLAYER(other) || other.health < 1)
+               return;
+       if(self.wait > time)
+               return; // "notouch" time isn't finished
+       // detach from the spawn point you're on
+       rune_unmark_spot(self);
+       self.owner = other;
+       self.enemy.owner = other;
+       setattachment(self, other, "");
+       other.runes = other.runes | self.runes | self.enemy.runes;
+       //self.think = func_null;
+       //self.nextthink = 0;
+       self.think = RuneCarriedThink;
+       self.nextthink = time;
+       self.touch = func_null;
+       self.solid = SOLID_NOT;
+       setorigin(self, self.origin);
+       //sprint(other, strcat("^3You have picked up ",
+       //      RuneName(self.runes & (RUNE_LAST*2-1)), " and "));
+       //sprint(other, strcat(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n"));
+       bprint("^3", other.netname, "^7 has picked up ",
+               RuneName(self.runes & (RUNE_LAST*2-1)), "^7 and ");
+       bprint(RuneName(self.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n");
+ }
+ void rune_respawn()
+ {
+       rune_unmark_spot(self);
+       if(rune_spawn_somewhere(self))
+       {
+               self.solid = SOLID_TRIGGER;
+               self.touch = rune_touch;
+               self.think = rune_respawn;
+               self.nextthink = time + autocvar_g_runematch_shuffletime;//30 + random()*5; // fixme: cvar
+       }
+       else
+       {
+               // try again later
+               self.think = rune_respawn;
+               self.nextthink = time;
+       }
+ }
+ entity FindRune(entity own, string clname, float r)
+ {
+       entity rune;
+       float _count, c;
+       c = _count = 0;
+       rune = world;
+       do
+       {
+               rune = find(rune, classname, clname);
+               if(!rune)
+                       rune = find(rune, classname, clname);
+               if(!rune)
+                       break;
+               if(rune.owner == own)
+               {
+                       _count = _count + 1;
+                       if(_count >= r)
+                               return rune;
+                       if(r <= 1)
+                               return rune;
+               }
+               c = c + 1;
+       }while(c < 30);
+       return world;
+ }
+ void DropRune(entity pl, entity e)
+ {
+       //entity pl;
+       //pl = e.owner;
+       // detach from player
+       setattachment(e, world, "");
+       e.owner = world;
+       e.enemy.owner = world;
+       // don't instantly touch player again
+       e.wait = time + 1; // "notouch" time
+       e.movetype = MOVETYPE_TOSS;
+       e.solid = SOLID_TRIGGER;
+       // reposition itself if not picked up soon
+       e.think = rune_respawn;
+       e.nextthink = time + autocvar_g_runematch_respawntime;//15 + random()*5; // fixme: cvar
+       e.touch = rune_touch;
+       pl.runes = pl.runes - (pl.runes & (e.runes | e.enemy.runes));
+       // toss from player
+       setorigin(e, pl.origin + '0 0 10');
+       e.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
+       bprint("^3", pl.netname, "^7 has lost ",
+               RuneName(e.runes & (RUNE_LAST*2-1)), "^7 and ");
+       bprint(RuneName(e.enemy.runes & (CURSE_WEAK | CURSE_VULNER | CURSE_VENOM | CURSE_SLOW | CURSE_EMPATHY)), "\n");
+ }
+ float RuneMatchesCurse(float r, float c)
+ {
+       float cr;
+       if(r & RUNE_STRENGTH)
+               cr = CURSE_WEAK;
+       else if(r & RUNE_DEFENSE)
+               cr = CURSE_VULNER;
+       else if(r & RUNE_REGEN)
+               cr = CURSE_VENOM;
+       else if(r & RUNE_SPEED)
+               cr = CURSE_SLOW;
+       else if(r & RUNE_VAMPIRE)
+               cr = CURSE_EMPATHY;
+       else return FALSE; // fixme: error?
+       if(c & cr)
+               return TRUE;
+       return FALSE;
+ }
+ // player died, drop runes
+ // each rune should pair up with a random curse and then be tossed from the player
+ void DropAllRunes(entity pl)
+ {
+       entity rune, curse;
+       float rcount, ccount, r, c, rand, prevent_same, numtodrop, tries;
+       entity curse1, rune1, curse2, rune2;
+       rcount = ccount = r = c = 0;
+       rune = find(world, classname, "rune");
+       while(rune)
+       {
+               if(rune.owner == pl)
+                       rcount = rcount + 1;
+               rune = find(rune, classname, "rune");
+       }
+       curse = find(world, classname, "curse");
+       while(curse)
+       {
+               if(curse.owner == pl)
+                       ccount = ccount + 1;
+               curse = find(curse, classname, "curse");
+       }
+       numtodrop = autocvar_g_runematch_drop_runes_max;
+       prevent_same = !autocvar_g_runematch_allow_same;
+       do
+       {
+               rune = find(rune, classname, "rune");
+               if(!rune)
+                       break;
+               if(rune.owner != pl)
+                       continue;
+               // find a random curse
+               tries = 15;
+               if(ccount > 1 && prevent_same)
+               {
+                       // avoid pairing runes and curses that match each other
+                       do{
+                               rand = floor(random()*ccount) + 1;
+                               curse = FindRune(pl, "curse", rand);
+                               tries = tries - 1;
+                       }while(RuneMatchesCurse(rune.runes, curse.runes) && tries > 0);
+                       if(tries <= 0)
+                       {
+                               bprint("warning: couldn't prevent same rune\n");
+                       }
+               }
+               else
+               {
+                               rand = floor(random()*ccount) + 1;
+                               curse = FindRune(pl, "curse", rand);
+               }
+               if(!curse)
+                       error("Couldn't fine curse to bind rune to\n");
+               // pair rune and curse
+               rune1 = rune;
+               curse1 = curse;
+               rune2 = curse1.enemy;
+               curse2 = rune1.enemy;
+               if(rune1 != rune2) // not already attached to each other
+               {
+                       rune1.enemy = curse1;
+                       curse1.enemy = rune1;
+                       setattachment(curse1, rune1, "");
+                       rune2.enemy = curse2;
+                       curse2.enemy = rune2;
+                       setattachment(curse2, rune2, "");
+                       //DropRune(pl, rune2);
+                       //ccount = ccount - 1;
+                       //rcount = rcount - 1;
+               }
+               DropRune(pl, rune1);
+               if(numtodrop <=0)
+               {
+                       rune1.think = rune_respawn;
+                       rune1.nextthink = time;
+               }
+               numtodrop = numtodrop - 1;
+               ccount = ccount - 1;
+               rcount = rcount - 1;
+       }while(rune);
+ }
+ void rune_reset()
+ {
+       if(self.owner)
+               if(self.owner.classname != "runematch_spawn_point")
+                       DropAllRunes(self.owner);
+       rune_respawn();
+ }
+ void spawn_runes()
+ {
+       float rn, cs, runes_used, curses_used, prevent_same, numrunes;
+       entity e;
+       if(self)
+               remove(self);
+       // fixme: instead of placing them all now, why not
+       // simply create them all and let them call rune_respawn() as their think?
+       runes_used  = 0;
+       curses_used = 0;
+       prevent_same = !autocvar_g_runematch_allow_same;
+       numrunes = RUNE_COUNT;
+       while(numrunes > 0)
+       {
+               RandomSelection_Init();
+               for(rn = RUNE_FIRST; rn <= RUNE_LAST; rn *= 2)
+                       if not(runes_used & rn)
+                               RandomSelection_Add(world, rn, string_null, 1, 1);
+               rn = RandomSelection_chosen_float;
+               RandomSelection_Init();
+               for(cs = CURSE_FIRST; cs <= CURSE_LAST; cs *= 2)
+                       if not(curses_used & cs)
+                               if not(prevent_same && cs == RuneMatchesCurse(rn, cs))
+                                       RandomSelection_Add(world, cs, string_null, 1, 1);
+               cs = RandomSelection_chosen_float;
+               if(!rn || !cs)
+                       error("No rune/curse left");
+               runes_used |= rn;
+               curses_used |= cs;
+               e = spawn();
+               e.runes = rn;
+               e.classname = "rune";
+               e.touch = rune_touch;
+               e.think = rune_respawn;
+               e.nextthink = time;
+               e.movetype = MOVETYPE_TOSS;
+               e.solid = SOLID_TRIGGER;
+               e.flags = FL_ITEM;
+               e.reset = rune_reset;
+               setmodel(e, "models/runematch/rune.mdl"); // precision set below
+               setsize(e, '0 0 -35', '0 0 0');
+               e.enemy = spawn();
+               e.enemy.enemy = e;
+               e.enemy.classname = "curse";
+               e.enemy.runes = cs;
+               //e.enemy.avelocity = '300 500 200';
+               setmodel(e.enemy, "models/runematch/curse.mdl"); // precision set below
+               setorigin(e, '0 0 0');
+               setattachment(e.enemy, e, "");
+               e.colormod = RuneColormod(rn);
+               e.enemy.colormod = RuneColormod(cs);
+               e.alpha = e.enemy.alpha = autocvar_g_runematch_rune_alpha;//0.78;
+               e.effects = e.enemy.effects = autocvar_g_runematch_rune_effects | EF_LOWPRECISION;//EF_ADDITIVE;// | EF_FULLBRIGHT;
+               //e.glow_size = e.enemy.glow_size = cvar("g_runematch_rune_glow_size");
+               //e.glow_color = e.enemy.glow_color = cvar("g_runematch_rune_glow_color");
+               //rn = RUNE_FIRST;
+               //cs = CURSE_FIRST;
+               numrunes = numrunes - 1;
+       }
+ }
+ void runematch_init()
+ {
+       if(!g_runematch)
+               return;
+       entity e;
+       e = spawn();
+       e.think = spawn_runes;
+       e.nextthink = time + 0.1;
+ }
+ float runematch_point_time;
+ // give points to players who are holding runes
+ void RuneMatchGivePoints()
+ {
+       entity rune;
+       if(!g_runematch || !autocvar_g_runematch_pointamt)
+               return;
+       if(gameover)
+               return;
+       if(runematch_point_time > time)
+               return;
+       runematch_point_time = time + autocvar_g_runematch_pointrate;
+       rune = world;
+       do
+       {
+               rune = find(rune, classname, "rune");
+               if(!rune)
+                       return;
++              if(IS_PLAYER(rune.owner))
+               {
+                       UpdateFrags(rune.owner, autocvar_g_runematch_pointamt);
+               }
+       }while(rune);
+ }
+ float RunematchHandleFrags(entity attacker, entity targ, float f)
+ {
+       entity head;
+       float arunes, trunes, newfrags;
+       if(f <= 0)
+               return f;
+       if(attacker == targ)
+               return f;
+       arunes = trunes = 0;
+       head = find(world, classname, "rune");
+       while(head)
+       {
+               if(head.owner == attacker)
+               {
+                       arunes = arunes + 1;
+               }
+               else if(head.owner == targ)
+               {
+                       trunes = trunes + 1;
+               }
+               head = find(head, classname, "rune");
+       }
+       if(!arunes && !trunes)
+               return f - 1 + autocvar_g_runematch_frags_norune; // don't give points to players when no runes are involved.
+       newfrags = 0;
+       if(arunes)
+       {       // got a kill while holding runes
+               newfrags = newfrags + autocvar_g_runematch_frags_killedby_runeholder;//5;
+       }
+       if(trunes)
+       {       // killed an enemy holding runes
+               newfrags = newfrags + autocvar_g_runematch_frags_killed_runeholder;//5;
+       }
+       if(newfrags)
+               f = f - 1 + newfrags;
+       return f;
+ }
Simple merge
index ee4933cc464ef8f2ddcaf4fbd62c291a92999584,f6e7f6f1b6921f5745982030050f76e1f350cee4..b45f35aa8fffb0d80b2e1b700f6636f7153e25ef
@@@ -551,7 -551,7 +551,7 @@@ float bot_fixcount(
  
        FOR_EACH_REALCLIENT(head)
        {
-               if(IS_PLAYER(head) || g_lms || g_arena || g_ca)
 -              if(head.classname == "player" || g_lms || g_arena || head.caplayer == 1)
++              if(IS_PLAYER(head) || g_lms || g_arena || head.caplayer == 1)
                        ++activerealplayers;
                ++realplayers;
        }
index c8b64a175f95a88e136f1a6cc3a98a3a10180022,5d29bf7e1537e4099fba46418a467cb2bde7cb57..4f741fa4435abe5481cecf737e67e0a1ced851fb
@@@ -685,7 -627,7 +627,8 @@@ void PutClientInServer (void
        if(gameover)
                self.classname = "observer";
  
-       if(IS_PLAYER(self) && (!g_ca || (g_ca && allowed_to_spawn))) {
 -      if(self.classname == "player") {
++      if(IS_PLAYER(self))
++      {
                entity spot, oldself;
                float j;
  
@@@ -1149,10 -1082,10 +1083,10 @@@ void KillIndicator_Think(
        {
                if(self.cnt <= 10)
                        setmodel(self, strcat("models/sprites/", ftos(self.cnt), ".spr32"));
 -              if(clienttype(self.owner) == CLIENTTYPE_REAL)
 +              if(IS_REAL_CLIENT(self.owner))
                {
                        if(self.cnt <= 10)
-                               AnnounceTo(self.owner, strcat(ftos(self.cnt), ""));
+                               { Send_Notification(NOTIF_ONE, self.owner, MSG_ANNCE, Announcer_PickNumber(self.cnt)); }
                }
                self.nextthink = time + 1;
                self.cnt -= 1;
@@@ -1235,30 -1168,30 +1169,30 @@@ void ClientKill_TeamChange (float targe
                if(targetteam == 0) // just die
                {
                        self.killindicator.colormod = '0 0 0';
 -                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "^1Suicide in %d seconds", 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SUICIDE, self.killindicator.cnt);
                }
                else if(targetteam == -1) // auto
                {
                        self.killindicator.colormod = '0 1 0';
 -                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Changing team in %d seconds", 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_AUTO, self.killindicator.cnt);
                }
                else if(targetteam == -2) // spectate
                {
                        self.killindicator.colormod = '0.5 0.5 0.5';
 -                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Spectating in %d seconds", 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SPECTATE, self.killindicator.cnt);
                }
                else
                {
-                       self.killindicator.colormod = TeamColor(targetteam);
+                       self.killindicator.colormod = Team_ColorRGB(targetteam);
 -                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                      if(IS_REAL_CLIENT(self))
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, strcat("Changing to ", ColoredTeamName(targetteam), " in %d seconds"), 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, APP_TEAM_NUM_4(targetteam, CENTER_TEAMCHANGE_), self.killindicator.cnt);
                }
        }
  
  
  void ClientKill (void)
  {
-       if (gameover)
-               return;
-       if((g_arena || g_ca) && ((champion && IS_PLAYER(champion) && player_count > 1) || player_count == 1)) // don't allow a kill in this case either
-       {
-               // do nothing
-       }
-     else if(self.freezetag_frozen)
-     {
-         // do nothing
-     }
-       else
-               ClientKill_TeamChange(0);
+       if(gameover) return;
+       if(self.player_blocked) return;
+       if(self.freezetag_frozen) return;
 -
++      
+       ClientKill_TeamChange(0);
  }
  
  void CTS_ClientKill (entity e) // silent version of ClientKill, used when player finishes a CTS run. Useful to prevent cheating by running back to the start line and starting out with more speed
@@@ -1477,12 -1401,10 +1402,10 @@@ void ClientConnect (void
  
        self.netname_previous = strzone(self.netname);
  
-       bprint("^4", self.netname, "^4 connected");
-       if(!IS_OBSERVER(self) && (g_domination || g_ctf))
-               bprint(" and joined the ", ColoredTeamName(self.team));
-       bprint("\n");
 -      if((self.classname == STR_PLAYER && teamplay))
++      if(IS_PLAYER(self) && teamplay)
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(self, INFO_JOIN_CONNECT_TEAM_), self.netname);
+       else
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_CONNECT, self.netname);
  
        stuffcmd(self, strcat(clientstuff, "\n"));
        stuffcmd(self, "cl_particles_reloadeffects\n"); // TODO do we still need this?
        self.jointime = time;
        self.allowed_timeouts = autocvar_sv_timeout_number;
  
 -      if(clienttype(self) == CLIENTTYPE_REAL)
 +      if(IS_REAL_CLIENT(self))
        {
+               if(!autocvar_g_campaign)
+               {
+                       self.motd_actived_time = -1;
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
+               }
                if(autocvar_g_bugrigs || WEPSET_EQ_AW(g_weaponarena_weapons, WEP_TUBA))
                        stuffcmd(self, "cl_cmd settemp chase_active 1\n");
        }
        CSQCMODEL_AUTOINIT();
  
        self.model_randomizer = random();
-     
-     if not(IS_REAL_CLIENT(self))
-         return;
-         
-     sv_notice_join();
-     
-     MUTATOR_CALLHOOK(ClientConnect);
 -      if(clienttype(self) == CLIENTTYPE_REAL)
++      if(IS_REAL_CLIENT(self))
+               sv_notice_join();
+       MUTATOR_CALLHOOK(ClientConnect);
  }
  /*
  =============
@@@ -2392,8 -2270,9 +2271,9 @@@ float nJoinAllowed(entity ignore) 
                return maxclients - totalClients;
  
        float currentlyPlaying = 0;
-       FOR_EACH_REALPLAYER(e)
-               currentlyPlaying += 1;
+       FOR_EACH_REALCLIENT(e)
 -              if(e.classname == "player" || e.caplayer == 1)
++              if(IS_PLAYER(e) || e.caplayer == 1)
+                       currentlyPlaying += 1;
  
        if(currentlyPlaying < autocvar_g_maxplayers)
                return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
   * g_maxplayers_spectator_blocktime seconds
   */
  void checkSpectatorBlock() {
 -      if(self.classname == "spectator" || self.classname == "observer") {
 +      if(IS_SPEC(self) || IS_OBSERVER(self)) {
                if( time > (self.spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) {
-                       sprint(self, "^7You were kicked from the server because you are spectator and spectators aren't allowed at the moment.\n");
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_QUIT_KICK_SPECTATING);
                        dropclient(self);
                }
        }
  }
  
- .float motd_actived_time; // used for both motd and campaign_message
  void PrintWelcomeMessage()
  {
-       if (self.motd_actived_time == 0) { // is there already a message showing?
+       if(self.motd_actived_time == 0)
+       {
                if (autocvar_g_campaign) {
 -                      if ((self.classname == "player" && self.BUTTON_INFO) || (self.classname != "player")) {
 +                      if ((IS_PLAYER(self) && self.BUTTON_INFO) || (!IS_PLAYER(self))) {
                                self.motd_actived_time = time;
-                               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, campaign_message, -1, 0);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, campaign_message);
                        }
                } else {
-                       if ((time - self.jointime > autocvar_welcome_message_time) && self.BUTTON_INFO) {
+                       if (self.BUTTON_INFO) {
                                self.motd_actived_time = time;
-                               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), -1, 0);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
                        }
                }
-       } else { // showing MOTD or campaign message
+       }
+       else if(self.motd_actived_time > 0) // showing MOTD or campaign message
+       {
                if (autocvar_g_campaign) {
                        if (self.BUTTON_INFO)
                                self.motd_actived_time = time;
 -                      else if ((time - self.motd_actived_time > 2) && self.classname == "player") { // hide it some seconds after BUTTON_INFO has been released
 +                      else if ((time - self.motd_actived_time > 2) && IS_PLAYER(self)) { // hide it some seconds after BUTTON_INFO has been released
                                self.motd_actived_time = 0;
-                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD);
+                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                        }
                } else {
-                       if ((time - self.jointime) > autocvar_welcome_message_time) {
-                               if (self.BUTTON_INFO)
-                                       self.motd_actived_time = time;
-                               else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
-                                       self.motd_actived_time = 0;
-                                       Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD);
-                               }
+                       if (self.BUTTON_INFO)
+                               self.motd_actived_time = time;
+                       else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
+                               self.motd_actived_time = 0;
+                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                        }
                }
        }
@@@ -2639,11 -2520,10 +2521,11 @@@ void PlayerPreThink (void
                self.usekeypressed = self.BUTTON_USE;
        }
  
-       PrintWelcomeMessage();
 -      if(clienttype(self) == CLIENTTYPE_REAL)
++      if(IS_REAL_CLIENT(self))
+               PrintWelcomeMessage();
  
-       if(IS_PLAYER(self)) {
- //            if(self.netname == "Wazat")
- //                    bprint(self.classname, "\n");
 -      if(self.classname == "player") {
++      if(IS_PLAYER(self))
++      {
  
                CheckRules_Player();
  
Simple merge
index 3014b03cb3d171e05eaa4d0952a1c4d7adb5ec9f,95aeced31b308b5db10fa4ab9da332baab5151aa..aa6258468b05a78ab157949a3cd0049c96422ba4
@@@ -617,9 -598,8 +598,8 @@@ void PlayerDamage (entity inflictor, en
  
                Portal_ClearAllLater(self);
  
 -              if(clienttype(self) == CLIENTTYPE_REAL)
 +              if(IS_REAL_CLIENT(self))
                {
-                       stuffcmd(self, "-zoom\n");
                        self.fixangle = TRUE;
                        //msg_entity = self;
                        //WriteByte (MSG_ONE, SVC_SETANGLE);
                        //WriteAngle (MSG_ONE, 80);
                }
  
-               if(defer_ClientKill_Now_TeamChange) // TODO does this work with FreezeTag?
-                       ClientKill_Now_TeamChange();
-               if(g_arena)
-                       Spawnqueue_Unmark(self);
+               if(defer_ClientKill_Now_TeamChange)
+                       ClientKill_Now_TeamChange(); // can turn player into spectator
  
-               if(g_freezetag)
+               // player could have been miraculously resuscitated ;)
+               // e.g. players in freezetag get frozen, they don't really die
 -              if(self.health >= 1 || self.classname != "player")
++              if(self.health >= 1 || !IS_PLAYER(self))
                        return;
  
                // when we get here, player actually dies
@@@ -957,8 -946,8 +946,8 @@@ float Say(entity source, float teamsay
                else if(teamsay < 0) // spectator message, only sent to spectators
                {
                        sprint(source, sourcemsgstr);
-                       //print(msgstr); // send to server console too
+                       dedicated_print(msgstr); // send to server console too
 -                      FOR_EACH_REALCLIENT(head) if(head.classname != "player")
 +                      FOR_EACH_REALCLIENT(head) if not(IS_PLAYER(head))
                                if(head != source)
                                        sprint(head, msgstr);
                }
index 8d83c975e944009a90a250db74c6a8e8c03879ba,afabe1820284522acf4d4dc0211d610d277de559..405904565e187a02dfc5552a2e6f5a3adce1783f
@@@ -711,10 -696,9 +696,9 @@@ float client_hasweapon(entity cl, floa
                        if (!f)
                        {
                                if (complain)
 -                              if(clienttype(cl) == CLIENTTYPE_REAL)
 +                              if(IS_REAL_CLIENT(cl))
                                {
                                        play2(cl, "weapons/unavailable.wav");
-                                       sprint(cl, strcat("You don't have any ammo for the ^2", W_Name(wpn), "\n"));
                                        Send_WeaponComplain (cl, wpn, W_Name(wpn), 0);
                                }
                                return FALSE;
index c7fcdeacb8bc1914c7d4094e624cb37c62de0fce,e22399f4acd14ed8b42b8901d1dc2f9c056050e2..ec9c33b1987b093005f28c5df16c062d3d9e9c65
@@@ -408,12 -412,12 +412,12 @@@ void ClientCommand_spectate(float reque
                                        }
                                }
                                
 -                              if(self.classname == "player" && autocvar_sv_spectate == 1) 
 +                              if(IS_PLAYER(self) && autocvar_sv_spectate == 1) 
                                        ClientKill_TeamChange(-2); // observe
-                               
                                // in CA, allow a dead player to move to spectators (without that, caplayer!=0 will be moved back to the player list)
                                // note: if arena game mode is ever done properly, this needs to be removed.
-                               if(g_ca && self.caplayer && (IS_SPEC(self) || IS_OBSERVER(self)))
 -                              if(self.caplayer && (self.classname == "spectator" || self.classname == "observer"))
++                              if(self.caplayer && (IS_SPEC(self) || IS_OBSERVER(self)))
                                {
                                        sprint(self, "WARNING: you will spectate in the next round.\n");
                                        self.caplayer = 0;
Simple merge
index dbc09c0ee3dde52081538de63c6d3f65b321f3a2,0944f04fbbe06799f4f523d37eb243af42bddb92..4c0445f1d33a99c3313dc01eca27b44a7f25dd0f
@@@ -1109,10 -1105,10 +1105,10 @@@ void GameCommand_nospectators(float req
                        entity plr;
                        FOR_EACH_CLIENT(plr) //give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
                        {
 -                              if(plr.classname == "spectator" || plr.classname == "observer")
 +                              if(IS_SPEC(plr) || IS_OBSERVER(plr))
                                {
                                        plr.spectatortime = time;
-                                       sprint(plr, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
+                                       Send_Notification(NOTIF_ONE_ONLY, plr, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
                                }
                        }
                        bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds!\n"));
Simple merge
Simple merge
Simple merge
index 91f8caf39cad6056978c5333d4dcf7f081137a48,d8ce88cf3ce082f631dde1a28b08e76e75e5d28b..e5106bbcd437898d2d780531aa204c39ef234524
@@@ -1347,7 -1339,7 +1339,7 @@@ void IntermissionThink(
                && ((self.autoscreenshot > 0) && (time > self.autoscreenshot)) )
        {
                self.autoscreenshot = -1;
-               if(IS_REAL_CLIENT(self)) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"", GetMapname(), strftime(FALSE, "%s"))); }
 -              if(clienttype(self) == CLIENTTYPE_REAL) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"\n", GetMapname(), strftime(FALSE, "%s"))); }
++              if(IS_REAL_CLIENT(self)) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"\n", GetMapname(), strftime(FALSE, "%s"))); }
                return;
        }
  
@@@ -1475,7 -1467,7 +1467,7 @@@ void DumpStats(float final
                {
                        s = strcat(":player:see-labels:", GetPlayerScoreString(other, 0), ":");
                        s = strcat(s, ftos(rint(time - other.jointime)), ":");
-                       if(IS_PLAYER(other) || g_arena || g_ca || g_lms)
 -                      if(other.classname == "player" || g_arena || other.caplayer == 1 || g_lms)
++                      if(IS_PLAYER(other) || g_arena || other.caplayer == 1 || g_lms)
                                s = strcat(s, ftos(other.team), ":");
                        else
                                s = strcat(s, "spectator:");
Simple merge
index 5ca20ec7b55a0177981f03a4cbcddaa2909ea675,8f0bc931efd540c587ea0f1ea5f3371fb04bdd0d..bc19d88ebb7bc1899ce203c1f6c462e3bc96c46c
@@@ -1840,9 -1852,9 +1852,9 @@@ MUTATOR_HOOKFUNCTION(ctf_PlayerUseKey
                                        {
                                                if(autocvar_g_ctf_pass_request && !player.flagcarried && head.flagcarried) 
                                                { 
 -                                                      if(clienttype(head) == CLIENTTYPE_BOT)
 +                                                      if(IS_BOT_CLIENT(head))
                                                        {
-                                                               centerprint(player, strcat("Requesting ", head.netname, " to pass you the ", head.flagcarried.netname)); 
+                                                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
                                                                ctf_Handle_Throw(head, player, DROP_PASS);
                                                        }
                                                        else
index 4014b140395fdf4ca4915e49759b9dddea3c292c,980a9b20d9aff6c37ac55d344404a4bf9c821b5e..79ce5e2e14f47dfa67283af4980df1da83837c55
@@@ -263,34 -323,50 +323,50 @@@ MUTATOR_HOOKFUNCTION(freezetag_RemovePl
  
  MUTATOR_HOOKFUNCTION(freezetag_PlayerDies)
  {
-       if(self.freezetag_frozen == 0)
+       if(round_handler_IsActive())
+       if(round_handler_CountdownRunning())
        {
-               if(self.team == COLOR_TEAM1)
-                       --redalive;
-               else if(self.team == COLOR_TEAM2)
-                       --bluealive;
-               else if(self.team == COLOR_TEAM3)
-                       --yellowalive;
-               else if(self.team == COLOR_TEAM4)
-                       --pinkalive;
-               --totalalive;
+               if(self.freezetag_frozen)
+                       freezetag_Unfreeze(world);
+               freezetag_count_alive_players();
+               return 1; // let the player die so that he can respawn whenever he wants
+       }
  
-               freezetag_Freeze(frag_attacker);
+       // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
+       // you succeed changing team through the menu: you both really die (gibbing) and get frozen
+       if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
+               || frag_deathtype == DEATH_TEAMCHANGE || frag_deathtype == DEATH_AUTOTEAMCHANGE)
+       {
+               // let the player die, he will be automatically frozen when he respawns
+               if(!self.freezetag_frozen)
+               {
+                       freezetag_Add_Score(frag_attacker);
+                       freezetag_count_alive_players();
+               }
+               else
+                       freezetag_Unfreeze(world); // remove ice
+               self.freezetag_frozen_timeout = -2; // freeze on respawn
+               return 1;
        }
  
+       if(self.freezetag_frozen)
+               return 1;
+       freezetag_Freeze(frag_attacker);
        if(frag_attacker == frag_target || frag_attacker == world)
        {
 -              if(frag_target.classname == STR_PLAYER)
 +              if(IS_PLAYER(frag_target))
-                       centerprint(frag_target, "^1You froze yourself.\n");
-               bprint("^7", frag_target.netname, "^1 froze himself.\n");
+                       Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_SELF);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_SELF, frag_target.netname);
        }
        else
        {
 -              if(frag_target.classname == STR_PLAYER)
 +              if(IS_PLAYER(frag_target))
-                       centerprint(frag_target, strcat("^1You were frozen by ^7", frag_attacker.netname, ".\n"));
+                       Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_FROZEN, frag_attacker.netname);
 -              if(frag_attacker.classname == STR_PLAYER)
 +              if(IS_PLAYER(frag_attacker))
-                       centerprint(frag_attacker, strcat("^2You froze ^7", frag_target.netname, ".\n"));
-               bprint("^7", frag_target.netname, "^1 was frozen by ^7", frag_attacker.netname, ".\n");
+                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_FREEZETAG_FREEZE, frag_target.netname);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname);
        }
  
        frag_target.health = 1; // "respawn" the player :P
index 21a95d0f7601bd310917e1122d876b94e4c00e51,3801de302d9c80fa2ab8cb0e7e3215d01dbf0ff4..e4be2d7ab4ce2ea2b9422456b2affc7fbec3f2fd
@@@ -985,10 -986,10 +986,10 @@@ void onslaught_controlpoint_icon_damage
                return;
        }
  
 -      if (attacker.classname == "player")
 +      if (IS_PLAYER(attacker))
        {
                nag = FALSE;
-               if(self.team == COLOR_TEAM1)
+               if(self.team == NUM_TEAM_1)
                {
                        if(time - ons_notification_time_team1 > 10)
                        {
Simple merge
Simple merge
Simple merge
index 5ccc212bdcee8da9cc4a2b0b5d52dc36249eb31e,4c75c9850a510948077c5ad018336c13535ebee7..114c4f7f85aee30606fc65841c6abd5f31c392d5
@@@ -527,12 -527,12 +527,12 @@@ void WinningConditionHelper(
                                s = strcat(s, ":human");
                        else
                                s = strcat(s, ":bot");
-                       if(!IS_PLAYER(p) && !g_arena && !g_ca && !g_lms)
 -                      if(p.classname != "player" && !g_arena && p.caplayer != 1 && !g_lms)
++                      if(!IS_PLAYER(p) && !g_arena && p.caplayer != 1 && !g_lms)
                                s = strcat(s, ":spectator");
                }
                else
                {
-                       if(IS_PLAYER(p) || g_arena || g_ca || g_lms)
 -                      if(p.classname == "player" || g_arena || p.caplayer == 1 || g_lms)
++                      if(IS_PLAYER(p) || g_arena || p.caplayer == 1 || g_lms)
                                s = GetPlayerScoreString(p, 2);
                        else
                                s = "-666";
Simple merge
index 407962ae6adbb61e0894e493dbcf6750feef779a,392c05ce14f3e9b9ac0671b662e510adf34393fd..49a1cb3b5dca6cf84629950a0be1cff54f894c29
@@@ -627,12 -627,12 +627,12 @@@ float Item_GiveTo(entity item, entity p
                        _switchweapon = TRUE;
  
                        // play some cool sounds ;)
 -                      if (clienttype(player) == CLIENTTYPE_REAL)
 +                      if (IS_REAL_CLIENT(player))
                        {
                                if(player.health <= 5)
-                                       AnnounceTo(player, "lastsecond");
+                                       Send_Notification(NOTIF_ONE, player, MSG_ANNCE, ANNCE_MINSTAGIB_LASTSECOND);
                                else if(player.health < 50)
-                                       AnnounceTo(player, "narrowly");
+                                       Send_Notification(NOTIF_ONE, player, MSG_ANNCE, ANNCE_MINSTAGIB_NARROWLY);
                        }
                        // sound not available
                        // else if(item.items == IT_CELLS)
Simple merge
Simple merge
Simple merge
Simple merge
index 592fa7df35d86e9302bc6d15bae0e62a5fd6ff89,2e0c1e8f02bbcd466773894e43e3da4df52104f5..a2de5dab04be64621a6742d0c024ac05aa69e79f
@@@ -11,13 -11,9 +11,8 @@@ void W_GiveWeapon (entity e, float wep
        oldself = self;
        self = e;
  
--      if not(g_minstagib)
-       if (IS_PLAYER(other))
-       {
-               sprint (other, "You got the ^2");
-               sprint (other, name);
-               sprint (other, "\n");
-       }
 -      if(other.classname == "player")
++      if(IS_PLAYER(other))
+               { Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_WEAPON_GOT, wep); }
  
        self = oldself;
  }
Simple merge
Simple merge
Simple merge
index 12d0a40f9c70626ba7a8dc5c33c0f576f0862d26,40c60e827e3adc024457f462577d6a2b68b32ac0..813bcff75508c01b044c43cfef5a48ff92593863
@@@ -225,9 -226,14 +226,14 @@@ void W_Mine_Touch (void
        if(self.movetype == MOVETYPE_NONE || self.movetype == MOVETYPE_FOLLOW)
                return; // we're already a stuck mine, why do we get called? TODO does this even happen?
  
-       PROJECTILE_TOUCH;
+       if(WarpZone_Projectile_Touch())
+       {
+               if(wasfreed(self))
+                       self.realowner.minelayer_mines -= 1;
+               return;
+       }
  
 -      if(other && other.classname == "player" && other.deadflag == DEAD_NO)
 +      if(other && IS_PLAYER(other) && other.deadflag == DEAD_NO)
        {
                // hit a player
                // don't stick
Simple merge
Simple merge