]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into terencehill/gameover_stuff
authorMario <mario@smbclan.net>
Mon, 17 Oct 2016 13:43:14 +0000 (23:43 +1000)
committerMario <mario@smbclan.net>
Mon, 17 Oct 2016 13:43:14 +0000 (23:43 +1000)
# Conflicts:
# notifications.cfg

1  2 
notifications.cfg
qcsrc/common/mutators/mutator/nix/sv_nix.qc
qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
qcsrc/common/notifications/all.inc
qcsrc/common/stats.qh
qcsrc/server/bot/default/bot.qc
qcsrc/server/client.qc
qcsrc/server/defs.qh
qcsrc/server/g_world.qc

diff --combined notifications.cfg
index 4161cfca721d694cb420f326ed86a943ede62c06,8583592b9acb74d11d24b8125b9b9caac23f0177..d57a9f2beb291ea5f1ad02c1d66a81bae8d82d24
@@@ -102,7 -102,7 +102,7 @@@ seta notification_ANNCE_VOTE_ACCEPT "2
  seta notification_ANNCE_VOTE_CALL "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
  seta notification_ANNCE_VOTE_FAIL "2" "0 = disabled, 1 = enabled if gentle mode is off, 2 = always enabled"
  
- // MSG_INFO notifications (count = 316):
+ // MSG_INFO notifications (count = 320):
  seta notification_INFO_CA_JOIN_LATE "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
  seta notification_INFO_CA_LEAVE "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
  seta notification_INFO_CHAT_NOSPECTATORS "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
@@@ -311,6 -311,10 +311,10 @@@ seta notification_INFO_LMS_FORFEIT "1" 
  seta notification_INFO_LMS_NOLIVES "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
  seta notification_INFO_MINIGAME_INVITE "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
  seta notification_INFO_MONSTERS_DISABLED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+ seta notification_INFO_NEXBALL_RETURN_HELD_BLUE "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+ seta notification_INFO_NEXBALL_RETURN_HELD_PINK "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+ seta notification_INFO_NEXBALL_RETURN_HELD_RED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+ seta notification_INFO_NEXBALL_RETURN_HELD_YELLOW "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
  seta notification_INFO_ONSLAUGHT_CAPTURE "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
  seta notification_INFO_ONSLAUGHT_CPDESTROYED_BLUE "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
  seta notification_INFO_ONSLAUGHT_CPDESTROYED_PINK "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
@@@ -420,11 -424,10 +424,11 @@@ seta notification_INFO_WEAPON_TUBA_SUIC
  seta notification_INFO_WEAPON_VAPORIZER_MURDER "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
  seta notification_INFO_WEAPON_VORTEX_MURDER "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
  
 -// MSG_CENTER notifications (count = 230):
 +// MSG_CENTER notifications (count = 231):
  seta notification_CENTER_ALONE "1" "0 = off, 1 = centerprint"
  seta notification_CENTER_ASSAULT_ATTACKING "1" "0 = off, 1 = centerprint"
  seta notification_CENTER_ASSAULT_DEFENDING "1" "0 = off, 1 = centerprint"
 +seta notification_CENTER_ASSAULT_OBJ_DESTROYED "1" "0 = off, 1 = centerprint"
  seta notification_CENTER_CAMPCHECK "1" "0 = off, 1 = centerprint"
  seta notification_CENTER_COINTOSS "1" "0 = off, 1 = centerprint"
  seta notification_CENTER_COUNTDOWN_BEGIN "1" "0 = off, 1 = centerprint"
@@@ -883,4 -886,4 +887,4 @@@ seta notification_show_sprees_info "3" 
  seta notification_show_sprees_info_newline "1" "Show attacker spree information for MSG_INFO messages on a separate line than the death notification itself"
  seta notification_show_sprees_info_specialonly "1" "Don't show attacker spree information in MSG_INFO messages if it isn't an achievement"
  
- // Notification counts (total = 817): MSG_ANNCE = 89, MSG_INFO = 316, MSG_CENTER = 231, MSG_MULTI = 153, MSG_CHOICE = 28
+ // Notification counts (total = 820): MSG_ANNCE = 89, MSG_INFO = 320, MSG_CENTER = 230, MSG_MULTI = 153, MSG_CHOICE = 28
index afbc9091ddb09973462587ab24391e70b9f64bc6,39072cefc7d2ba0ab9697a9f3a104599b2a40dc9..5bb9fbc322a40b8d3b4891322a1e948b492f098d
@@@ -96,7 -96,7 +96,7 @@@ void NIX_ChooseNextWeapon(
        RandomSelection_Init();
        FOREACH(Weapons, it != WEP_Null, LAMBDA(
                if(NIX_CanChooseWeapon(it.m_id))
-                       RandomSelection_Add(NULL, it.m_id, string_null, 1, (it.m_id != nix_weapon));
+                       RandomSelection_AddFloat(it.m_id, 1, (it.m_id != nix_weapon));
        ));
        nix_nextweapon = RandomSelection_chosen_float;
  }
@@@ -267,7 -267,7 +267,7 @@@ MUTATOR_HOOKFUNCTION(nix, PlayerPreThin
  {
        entity player = M_ARGV(0, entity);
  
 -      if(!intermission_running)
 +      if(!gameover)
        if(!IS_DEAD(player))
        if(IS_PLAYER(player))
                NIX_GiveCurrentWeapon(player);
index eb40085d726dd193a6d9070a471d50827d4dcfe5,d47da6c3c38ed43c3949eed8042f94941d8beef9..74a8c40ea0b7da37f8cbc2c7a6ceb05ecc89830a
@@@ -4,15 -4,15 +4,15 @@@
  #include "rpc.qh"
  
  bool autocvar_g_overkill_powerups_replace;
- float autocvar_g_overkill_superguns_respawn_time;
- bool autocvar_g_overkill_100h_anyway;
- bool autocvar_g_overkill_100a_anyway;
  bool autocvar_g_overkill_ammo_charge;
  float autocvar_g_overkill_ammo_charge_notice;
  float autocvar_g_overkill_ammo_charge_limit;
  
- .vector ok_deathloc;
- .float ok_spawnsys_timer;
+ bool autocvar_g_overkill_filter_healthmega;
+ bool autocvar_g_overkill_filter_armormedium;
+ bool autocvar_g_overkill_filter_armorbig;
+ bool autocvar_g_overkill_filter_armorlarge;
  .float ok_lastwep;
  .float ok_item;
  
@@@ -21,8 -21,6 +21,6 @@@
  .float ok_use_ammocharge = _STAT(OK_AMMO_CHARGE);
  .float ok_ammo_charge = _STAT(OK_AMMO_CHARGEPOOL);
  
- .float ok_pauseregen_finished;
  void(entity ent, float wep) ok_DecreaseCharge;
  
  void ok_Initialize();
@@@ -109,22 -107,13 +107,13 @@@ MUTATOR_HOOKFUNCTION(ok, PlayerDamage_C
                if(!IS_DEAD(frag_target))
                {
                        Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE);
-                       M_ARGV(6, vector) = '0 0 0';
+                       M_ARGV(6, vector) = '0 0 0'; // force
                }
  
-               M_ARGV(4, float) = 0;
+               M_ARGV(4, float) = 0; // damage
        }
  }
  
- MUTATOR_HOOKFUNCTION(ok, PlayerDamage_SplitHealthArmor)
- {
-       entity frag_target = M_ARGV(2, entity);
-       float damage_take = M_ARGV(4, float);
-       if(damage_take)
-               frag_target.ok_pauseregen_finished = max(frag_target.ok_pauseregen_finished, time + 2);
- }
  void ok_DropItem(entity this, entity targ)
  {
        entity e = new(droppedweapon); // hax
@@@ -168,30 -157,6 +157,6 @@@ MUTATOR_HOOKFUNCTION(ok, MonsterDropIte
        ok_DropItem(mon, frag_attacker);
  }
  
- MUTATOR_HOOKFUNCTION(ok, PlayerRegen)
- {
-       entity player = M_ARGV(0, entity);
-       // overkill's values are different, so use custom regen
-       if(!STAT(FROZEN, player))
-       {
-               player.armorvalue = CalcRotRegen(player.armorvalue, autocvar_g_balance_armor_regenstable, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear,
-                       1 * frametime * (time > player.ok_pauseregen_finished), 0, 0, 1, 1 * frametime * (time > player.pauserotarmor_finished), autocvar_g_balance_armor_limit);
-               player.health = CalcRotRegen(player.health, autocvar_g_balance_health_regenstable, 0, 100, 1 * frametime * (time > player.ok_pauseregen_finished), 200, 0,
-                       autocvar_g_balance_health_rotlinear, 1 * frametime * (time > player.pauserothealth_finished), autocvar_g_balance_health_limit);
-               float minf, maxf, limitf;
-               maxf = autocvar_g_balance_fuel_rotstable;
-               minf = autocvar_g_balance_fuel_regenstable;
-               limitf = autocvar_g_balance_fuel_limit;
-               player.ammo_fuel = CalcRotRegen(player.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear,
-                       frametime * (time > player.pauseregen_finished) * ((player.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > player.pauserotfuel_finished), limitf);
-       }
-       return true; // return true anyway, as frozen uses no regen
- }
  MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
  {
        return true;
  
  MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
  {
 -      if(intermission_running || gameover)
 +      if(gameover)
                return;
  
        entity player = M_ARGV(0, entity);
        ok_IncreaseCharge(player, PS(player).m_weapon.m_id);
  
        if(PHYS_INPUT_BUTTON_ATCK2(player))
-       if(!forbidWeaponUse(player) || player.weapon_blocked) // allow if weapon is blocked
+       if( !forbidWeaponUse(player) || player.weapon_blocked // allow if weapon is blocked
+               || (round_handler_IsActive() && !round_handler_IsRoundStarted()) )
        if(time >= player.jump_interval)
        {
                player.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor(player);
@@@ -287,8 -253,6 +253,6 @@@ MUTATOR_HOOKFUNCTION(ok, PlayerSpawn
        // if player changed their weapon while dead, don't switch to their death weapon
        if(player.impulse)
                player.ok_lastwep = 0;
-       player.ok_pauseregen_finished = time + 2;
  }
  
  void self_spawnfunc_weapon_hmg(entity this) { spawnfunc_weapon_hmg(this); }
@@@ -310,7 -274,7 +274,7 @@@ MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpa
                        wep.noalign = ent.noalign;
                        wep.cnt = ent.cnt;
                        wep.team = ent.team;
-                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
+                       wep.respawntime = g_pickup_respawntime_superweapon;
                        wep.pickup_anyway = true;
                        wep.spawnfunc_checked = true;
                        setthink(wep, self_spawnfunc_weapon_hmg);
                        wep.noalign = ent.noalign;
                        wep.cnt = ent.cnt;
                        wep.team = ent.team;
-                       wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
+                       wep.respawntime = g_pickup_respawntime_superweapon;
                        wep.pickup_anyway = true;
                        wep.spawnfunc_checked = true;
                        setthink(wep, self_spawnfunc_weapon_rpc);
@@@ -342,12 -306,16 +306,16 @@@ MUTATOR_HOOKFUNCTION(ok, FilterItem
        entity item = M_ARGV(0, entity);
  
        if(item.ok_item)
-               return;
+               return false;
  
-       switch(item.items)
+       switch(item.itemdef)
        {
-               case ITEM_HealthMega.m_itemid: return !(autocvar_g_overkill_100h_anyway);
-               case ITEM_ArmorMega.m_itemid: return !(autocvar_g_overkill_100a_anyway);
+               case ITEM_HealthMega: return autocvar_g_overkill_filter_healthmega;
+               case ITEM_ArmorMedium: return autocvar_g_overkill_filter_armormedium;
+               // WARNING: next two statements look wrong because of inconsistency between cvar names and code
+               // armor cvars need renaming to be consistent with their health counterparts
+               case ITEM_ArmorLarge: return autocvar_g_overkill_filter_armorbig;
+               case ITEM_ArmorMega: return autocvar_g_overkill_filter_armorlarge;
        }
  
        return true;
@@@ -362,7 -330,7 +330,7 @@@ MUTATOR_HOOKFUNCTION(ok, SpectateCopy
        client.ok_use_ammocharge = spectatee.ok_use_ammocharge;
  }
  
- MUTATOR_HOOKFUNCTION(ok, SetStartItems)
+ MUTATOR_HOOKFUNCTION(ok, SetStartItems, CBC_ORDER_LAST)
  {
        WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
  
index 13ab781964197be8b2185023784c50fad5912b5d,a6431cf673810c1625552fc2418c644738c3e8ad..92fd5df1ac37330b1479044e7ef1cb61280d3930
  
      MSG_INFO_NOTIF(MONSTERS_DISABLED,                       1,  0, 0, "", "",           "",     _("^BGMonsters are currently disabled"), "")
  
+     MULTITEAM_INFO(NEXBALL_RETURN_HELD, 4,                  1,  0, 0, "", "",           "",     _("^BGThe ^TC^TT^BG team held the ball for too long"), "", NAME)
      MSG_INFO_NOTIF(ONSLAUGHT_CAPTURE,                       1,  2, 0, "s1 s2", "",      "",     _("^BG%s^BG captured %s^BG control point"), "")
      MULTITEAM_INFO(ONSLAUGHT_CPDESTROYED, 4,                1,  2, 0, "s1 s2", "",      "",     _("^TC^TT^BG team %s^BG control point has been destroyed by %s"), "", NAME)
      MULTITEAM_INFO(ONSLAUGHT_GENDESTROYED, 4,               1,  0, 0, "", "",           "",     _("^TC^TT^BG generator has been destroyed"), "", GENERATOR)
  
      MSG_CENTER_NOTIF(ASSAULT_ATTACKING,                 1,      0, 0, "",               CPID_ASSAULT_ROLE,      "0 0",  _("^BGYou are attacking!"), "")
      MSG_CENTER_NOTIF(ASSAULT_DEFENDING,                 1,      0, 0, "",               CPID_ASSAULT_ROLE,      "0 0",  _("^BGYou are defending!"), "")
 +    MSG_CENTER_NOTIF(ASSAULT_OBJ_DESTROYED,             1,      0, 1, "f1time",         CPID_ASSAULT_ROLE,      "0 0",  _("^BGObjective destroyed in ^F4%s^BG!"), "")
  
      MSG_CENTER_NOTIF(COUNTDOWN_BEGIN,                   1,      0, 0, "",               CPID_ROUND,             "2 0",  _("^F4Begin!"), "")
      MSG_CENTER_NOTIF(COUNTDOWN_GAMESTART,               1,      0, 1, "",               CPID_ROUND,             "1 f1", _("^F4Game starts in ^COUNT"), "")
      MSG_CENTER_NOTIF(TEAMCHANGE_SUICIDE,                1,      0, 1, "",               CPID_TEAMCHANGE,        "1 f1", _("^K1Suicide in ^COUNT"), "")
  
      MSG_CENTER_NOTIF(TIMEOUT_BEGINNING,                 1,      0, 1, "",               CPID_TIMEOUT,           "1 f1", _("^F4Timeout begins in ^COUNT"), "")
-     MSG_CENTER_NOTIF(TIMEOUT_ENDING,                    1,      0, 1, "",               CPID_TIMEOUT,           "1 f1", _("^F4Timeout ends in ^COUNT"), "")
+     MSG_CENTER_NOTIF(TIMEOUT_ENDING,                    1,      0, 1, "",               CPID_TIMEIN,            "1 f1", _("^F4Timeout ends in ^COUNT"), "")
  
      MSG_CENTER_NOTIF(JOIN_PREVENT_MINIGAME,             1,      0, 0, "",               CPID_Null,              "0 0",  _("^K1Cannot join given minigame session!"), "" )
  
diff --combined qcsrc/common/stats.qh
index 252c0fdeca645b5378a76a2e6cbce001a7e69e48,09921c6f86cbfe1cbaaceb4c83b4b0cbc5798f9e..f720d3694c149244526738e25d9781aa9420147f
@@@ -63,10 -63,9 +63,10 @@@ REGISTER_STAT(WEAPON_NEXTTHINK, float
  #ifdef SVQC
  SPECTATE_COPYFIELD(_STAT(WEAPON_NEXTTHINK))
  float W_WeaponRateFactor(entity this);
 +float gameover;
  #endif
  REGISTER_STAT(WEAPONRATEFACTOR, float, W_WeaponRateFactor(this))
 -
 +REGISTER_STAT(GAMEOVER, int, gameover)
  REGISTER_STAT(GAMESTARTTIME, float)
  REGISTER_STAT(STRENGTH_FINISHED, float)
  REGISTER_STAT(INVINCIBLE_FINISHED, float)
@@@ -264,6 -263,11 +264,11 @@@ REGISTER_STAT(CAMERA_SPECTATOR, int
  
  REGISTER_STAT(SPECTATORSPEED, float)
  
+ #ifdef SVQC
+ bool autocvar_sv_slick_applygravity;
+ #endif
+ REGISTER_STAT(SLICK_APPLYGRAVITY, bool, autocvar_sv_slick_applygravity)
  #ifdef SVQC
  #include "physics/movetypes/movetypes.qh"
  #endif
@@@ -273,6 -277,7 +278,7 @@@ REGISTER_STAT(MOVEVARS_AIRCONTROL_PENAL
  REGISTER_STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, float)
  REGISTER_STAT(MOVEVARS_AIRSTRAFEACCEL_QW, float)
  REGISTER_STAT(MOVEVARS_AIRCONTROL_POWER, float)
+ REGISTER_STAT(MOVEVARS_AIRCONTROL_BACKWARDS, bool)
  noref bool autocvar_sv_gameplayfix_nogravityonground;
  REGISTER_STAT(MOVEFLAGS, int, MOVEFLAG_VALID
                                | (autocvar_sv_gameplayfix_q2airaccelerate ? MOVEFLAG_Q2AIRACCELERATE : 0)
index 55c1bda6cc63d86153951a7c2262c399ca81d21f,bdde55b9aa94683b7ffb0901229203fb1ff59116..b5fe723c36fbb082d5a15afacdda59374fbc2c78
@@@ -177,7 -177,7 +177,7 @@@ void bot_setnameandstuff(entity this
                                        break;
                                }
                        ));
-                       RandomSelection_Add(NULL, 0, readfile, 1, prio);
+                       RandomSelection_AddString(readfile, 1, prio);
                }
                readfile = RandomSelection_chosen_string;
                fclose(file);
@@@ -631,7 -631,7 +631,7 @@@ float bot_fixcount(
  
  void bot_serverframe()
  {
 -      if (intermission_running)
 +      if (gameover)
                return;
  
        if (time < 2)
diff --combined qcsrc/server/client.qc
index ee77312d2153b6c8ea6414ac7f975ecad4841f8b,1735a78be8988464792f97b17c52af798d6678af..7b6c13e9ba56f316aceeba2b405698455de600c6
@@@ -283,8 -283,8 +283,8 @@@ void PutObserverInServer(entity this
        if (this.killcount != FRAGS_SPECTATOR)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, this.netname);
 -              if(!intermission_running)
 -              if(autocvar_g_chat_nospectators == 1 || (!(warmup_stage || gameover) && autocvar_g_chat_nospectators == 2))
 +              if(!gameover)
 +              if(autocvar_g_chat_nospectators == 1 || (!warmup_stage && autocvar_g_chat_nospectators == 2))
                        Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
  
                if(this.just_joined == false) {
@@@ -625,9 -625,11 +625,11 @@@ void PutClientInServer(entity this
                FixPlayermodel(this);
                this.drawonlytoclient = NULL;
  
+               this.viewloc = NULL;
                this.crouch = false;
-               this.view_ofs = STAT(PL_VIEW_OFS, NULL);
-               setsize(this, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL));
+               this.view_ofs = STAT(PL_VIEW_OFS, this);
+               setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
                this.spawnorigin = spot.origin;
                setorigin(this, spot.origin + '0 0 1' * (1 - this.mins.z - 24));
                // don't reset back to last position, even if new position is stuck in solid
@@@ -1208,6 -1210,9 +1210,9 @@@ void ClientConnect(entity this
        if (IS_REAL_CLIENT(this))
                sv_notice_join(this);
  
+       // update physics stats (players can spawn before physics runs)
+       Physics_UpdateStats(this, PHYS_HIGHSPEED(this));
        IL_EACH(g_initforplayer, it.init_for_player, {
                it.init_for_player(it, this);
        });
@@@ -1607,7 -1612,7 +1612,7 @@@ void SetZoomState(entity this, float z
  void GetPressedKeys(entity this)
  {
        MUTATOR_CALLHOOK(GetPressedKeys, this);
-       int keys = this.pressedkeys;
+       int keys = STAT(PRESSED_KEYS, this);
        keys = BITSET(keys, KEY_FORWARD,        this.movement.x > 0);
        keys = BITSET(keys, KEY_BACKWARD,       this.movement.x < 0);
        keys = BITSET(keys, KEY_RIGHT,          this.movement.y > 0);
        keys = BITSET(keys, KEY_CROUCH,         PHYS_INPUT_BUTTON_CROUCH(this));
        keys = BITSET(keys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(this));
        keys = BITSET(keys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(this));
-       this.pressedkeys = keys;
+       this.pressedkeys = keys; // store for other users
+       STAT(PRESSED_KEYS, this) = keys;
  }
  
  /*
@@@ -1650,7 -1657,7 +1657,7 @@@ void SpectateCopy(entity this, entity s
        this.hit_time = spectatee.hit_time;
        this.strength_finished = spectatee.strength_finished;
        this.invincible_finished = spectatee.invincible_finished;
-       this.pressedkeys = spectatee.pressedkeys;
+       STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee);
        this.weapons = spectatee.weapons;
        this.vortex_charge = spectatee.vortex_charge;
        this.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo;
        this.angles = spectatee.v_angle;
        STAT(FROZEN, this) = STAT(FROZEN, spectatee);
        this.revive_progress = spectatee.revive_progress;
+       this.viewloc = spectatee.viewloc;
        if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2)
                this.fixangle = true;
        setorigin(this, spectatee.origin);
@@@ -2301,9 -2309,8 +2309,9 @@@ void PlayerPreThink (entity this
        if (IS_PLAYER(this)) {
                CheckRules_Player(this);
  
 -              if (intermission_running) {
 -                      IntermissionThink(this);
 +              if (gameover || intermission_running) {
 +                      if(intermission_running)
 +                              IntermissionThink(this);
                        return;
                }
  
                                        {
                                                if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max))
                                                        this.deadflag = DEAD_RESPAWNING;
-                                               else if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
+                                               else if (!button_pressed || (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE)))
                                                        this.deadflag = DEAD_DEAD;
                                                break;
                                        }
  
                this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
        }
 -      else if (gameover) {
 -              if (intermission_running) IntermissionThink(this);
 +      else if (gameover || intermission_running) {
 +              if(intermission_running)
 +                      IntermissionThink(this);
                return;
        }
        else if (IS_OBSERVER(this)) {
@@@ -2598,23 -2604,13 +2606,23 @@@ void PlayerPostThink (entity this
        CheatFrame(this);
  
        //CheckPlayerJump();
 +      if (gameover)
 +      {
 +              this.solid = SOLID_NOT;
 +              this.takedamage = DAMAGE_NO;
 +              set_movetype(this, MOVETYPE_NONE);
 +      }
  
        if (IS_PLAYER(this)) {
                DrownPlayer(this);
                CheckRules_Player(this);
                UpdateChatBubble(this);
                if (this.impulse) ImpulseCommands(this);
 -              if (intermission_running) return; // intermission or finale
 +              if (gameover)
 +              {
 +                      CSQCMODEL_AUTOUPDATE(this);
 +                      return;
 +              }
                GetPressedKeys(this);
        }
  
diff --combined qcsrc/server/defs.qh
index 8b1726a0a6ee978911e2afea1ef1349e7442c4bc,9c3e7bba02148e52f34a75556c054f9affe12457..a69735a32274c4c7f951b03e69e863f94e1aa9f9
@@@ -129,6 -129,7 +129,6 @@@ const int W_TICSPERFRAME = 2
  
  void weapon_defaultspawnfunc(entity this, Weapon e);
  
 -float gameover;
  float intermission_running;
  float intermission_exittime;
  float alreadychangedlevel;
@@@ -260,7 -261,7 +260,7 @@@ bool independent_players
  
  string clientstuff;
  .float phase;
- .int pressedkeys = _STAT(PRESSED_KEYS);
+ .int pressedkeys;
  
  .string fog;
  
diff --combined qcsrc/server/g_world.qc
index f6eaace3de622e8916b47d783c26603b02938ea4,48b587e5eb2de33312210f0eb139a3587cc6bc94..67cdd248d55a12e499bde7e5dd8be084aaffe612
@@@ -320,17 -320,20 +320,20 @@@ void cvar_changes_init(
                BADCVAR("g_invasion_point_limit");
                BADCVAR("g_keyhunt_point_leadlimit");
                BADCVAR("g_nexball_goalleadlimit");
+               BADCVAR("g_new_toys_use_pickupsound");
+               BADCVAR("g_physics_predictall");
+               BADCVAR("g_piggyback");
                BADCVAR("g_tdm_point_leadlimit");
                BADCVAR("g_tdm_point_limit");
                BADCVAR("leadlimit_and_fraglimit");
                BADCVAR("leadlimit_override");
                BADCVAR("pausable");
-               BADCVAR("sv_allow_fullbright");
                BADCVAR("sv_checkforpacketsduringsleep");
                BADCVAR("sv_intermission_cdtrack");
                BADCVAR("sv_minigames");
                BADCVAR("sv_namechangetimer");
                BADCVAR("sv_precacheplayermodels");
+               BADCVAR("sv_stepheight");
                BADCVAR("sv_timeout");
                BADPREFIX("crypto_");
                BADPREFIX("gameversion_");
                BADPREFIX("net_");
                BADPREFIX("prvm_");
                BADPREFIX("skill_");
+               BADPREFIX("sv_allow_");
                BADPREFIX("sv_cullentities_");
                BADPREFIX("sv_maxidle_");
                BADPREFIX("sv_minigames_");
+               BADPREFIX("sv_radio_");
                BADPREFIX("sv_timeout_");
                BADPREFIX("sv_vote_");
                BADPREFIX("timelimit_");
                BADCVAR("g_balance_teams_scorefactor");
                BADCVAR("g_ban_sync_trusted_servers");
                BADCVAR("g_ban_sync_uri");
+               BADCVAR("g_buffs");
                BADCVAR("g_ca_teams_override");
                BADCVAR("g_ctf_ignore_frags");
                BADCVAR("g_domination_point_limit");
                BADCVAR("g_maxplayers");
                BADCVAR("g_mirrordamage");
                BADCVAR("g_nexball_goallimit");
+               BADCVAR("g_norecoil");
+               BADCVAR("g_physics_clientselect");
                BADCVAR("g_powerups");
                BADCVAR("g_spawnshieldtime");
                BADCVAR("g_start_delay");
                BADCVAR("g_grappling_hook");
                BADCVAR("g_jetpack");
  
+ #undef BADPRESUFFIX
  #undef BADPREFIX
  #undef BADCVAR
  
@@@ -908,7 -917,8 +917,8 @@@ spawnfunc(worldspawn
        if(cvar_string("g_mod_config") != cvar_defstring("g_mod_config"))
                modname = cvar_string("g_mod_config");
        // extra mutators that deserve to count as mod
-       MUTATOR_CALLHOOK(SetModname);
+       MUTATOR_CALLHOOK(SetModname, modname);
+       modname = M_ARGV(0, string);
  
        // save it for later
        modname = strzone(modname);
@@@ -1297,6 -1307,7 +1307,6 @@@ When the player presses attack or jump
  void IntermissionThink(entity this)
  {
        FixIntermissionClient(this);
 -      CSQCMODEL_AUTOUPDATE(this); // PlayerPostThink returns before calling this during intermission, so run it here
  
        float server_screenshot = (autocvar_sv_autoscreenshot && this.cvar_cl_autoscreenshot);
        float client_screenshot = (this.cvar_cl_autoscreenshot == 2);
@@@ -1484,6 -1495,9 +1494,6 @@@ void FixIntermissionClient(entity e
                e.autoscreenshot = time + 0.8;  // used for autoscreenshot
                e.health = -2342;
                // first intermission phase; voting phase has positive health (used to decide whether to send SVC_FINALE or not)
 -              e.solid = SOLID_NOT;
 -              set_movetype(e, MOVETYPE_NONE);
 -              e.takedamage = DAMAGE_NO;
                for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
                    .entity weaponentity = weaponentities[slot];
                        stuffcmd(e, "\nscr_printspeed 1000000\n");
                        RandomSelection_Init();
                        FOREACH_WORD(autocvar_sv_intermission_cdtrack, true, LAMBDA(
-                               RandomSelection_Add(NULL, 0, it, 1, 1);
+                               RandomSelection_AddString(it, 1, 1);
                        ));
                        if (RandomSelection_chosen_string != "")
                        {
@@@ -1521,7 -1535,7 +1531,7 @@@ void NextLevel(
  
        intermission_running = 1;
  
 -// enforce a wait time before allowing changelevel
 +      // enforce a wait time before allowing changelevel
        if(player_count > 0)
                intermission_exittime = time + autocvar_sv_mapchange_delay;
        else
@@@ -1828,7 -1842,7 +1838,7 @@@ void CheckRules_World(
  
        SetDefaultAlpha();
  
 -      if (gameover)   // someone else quit the game already
 +      if (intermission_running) // someone else quit the game already
        {
                if(player_count == 0) // Nobody there? Then let's go to the next map
                        MapVote_Start();