]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into bones_was_here/q3compat
authorbones_was_here <bones_was_here@yahoo.com.au>
Sun, 2 Aug 2020 06:02:52 +0000 (16:02 +1000)
committerbones_was_here <bones_was_here@yahoo.com.au>
Sun, 2 Aug 2020 06:02:52 +0000 (16:02 +1000)
1  2 
qcsrc/common/mapobjects/trigger/jumppads.qc
qcsrc/common/mapobjects/trigger/multi.qc
qcsrc/common/physics/player.qc
qcsrc/common/stats.qh
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/server/client.qc
qcsrc/server/compat/quake3.qc
qcsrc/server/g_world.qc
qcsrc/server/items/spawning.qc
xonotic-server.cfg

index 261446de2b8777201d50eac354650f6c9e4f1489,b016dde9a19287d7e8c9e77ede292ee22c69c6cb..25be467807fa2404f55fc088cce2a484323e9531
@@@ -135,9 -135,9 +135,9 @@@ bool jumppad_push(entity this, entity t
  
        vector org = targ.origin;
  #ifdef SVQC
 -      if(autocvar_sv_q3defragcompat)
 +      if(q3compat)
  #elif defined(CSQC)
 -      if(STAT(Q3DEFRAGCOMPAT))
 +      if(STAT(Q3COMPAT))
  #endif
        {
                org.z += targ.mins_z;
@@@ -634,9 -634,7 +634,7 @@@ bool target_push_send(entity this, enti
        WriteString(MSG_ENTITY, this.targetname);
        WriteVector(MSG_ENTITY, this.origin);
  
-       WriteAngle(MSG_ENTITY, this.angles_x);
-       WriteAngle(MSG_ENTITY, this.angles_y);
-       WriteAngle(MSG_ENTITY, this.angles_z);
+       WriteAngleVector(MSG_ENTITY, this.angles);
  
        return true;
  }
@@@ -726,9 -724,7 +724,7 @@@ NET_HANDLE(ENT_CLIENT_TARGET_PUSH, boo
        this.targetname = strzone(ReadString());
        this.origin = ReadVector();
  
-       this.angles_x = ReadAngle();
-       this.angles_y = ReadAngle();
-       this.angles_z = ReadAngle();
+       this.angles = ReadAngleVector();
  
        return = true;
  
index 7a8c0be84c31961d0719efbf8850391b4cad50e6,9ce5f52cea877d9a1f556c9fa1ee88b06027fe08..407a75371c54cd90529d33a4741a43b4eae6fe3e
@@@ -29,16 -29,7 +29,7 @@@ void multi_trigger(entity this
                return; // only players
        }
  
-       // TODO: restructure this so that trigger_secret is more independent
-       if (this.classname == "trigger_secret")
-       {
-               if (!IS_PLAYER(this.enemy))
-                       return;
-               found_secrets = found_secrets + 1;
-               WriteByte (MSG_ALL, SVC_FOUNDSECRET);
-       }
-       if (this.noise)
+       if (this.noise && this.noise != "")
        {
                _sound (this.enemy, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
        }
@@@ -167,7 -158,7 +158,7 @@@ spawnfunc(trigger_multiple
        else if (this.sounds == 3)
                this.noise = "misc/trigger1.wav";
  
-       if(this.noise)
+       if(this.noise && this.noise != "")
                precache_sound(this.noise);
  
        if (!this.wait)
                this.wait = 0;
        this.use = multi_use;
  
 -      if(this.wait == -1 && autocvar_sv_q3defragcompat)
 +      if(this.wait == -1 && (q3compat & BIT(1)))
                this.wait = 0.1; // compatibility for q3df: "instant" return
  
        EXACTTRIGGER_INIT;
index 1cb43299fd6e3d45fedbe3cce05070562c8990d8,76bfb0334a9df8fe25f79cc7971fe78101cb8fae..1d89f687f70926f14e192004050e968846f638cc
@@@ -5,6 -5,7 +5,7 @@@
  #ifdef SVQC
  
  #include <server/miscfunctions.qh>
+ #include <common/mapobjects/defs.qh>
  #include "../mapobjects/trigger/viewloc.qh"
  
  // client side physics
@@@ -40,7 -41,7 +41,7 @@@ void Physics_UpdateStats(entity this
        STAT(MOVEVARS_HIGHSPEED, this) = autocvar_g_movement_highspeed;
  
        MUTATOR_CALLHOOK(PlayerPhysics_UpdateStats, this);
-       float maxspd_mod = PHYS_HIGHSPEED(this) * ((this.swampslug.active) ? this.swampslug.swamp_slowdown : 1);
+       float maxspd_mod = PHYS_HIGHSPEED(this) * ((this.swampslug.active == ACTIVE_ACTIVE) ? this.swampslug.swamp_slowdown : 1);
          STAT(MOVEVARS_MAXSPEED, this) = Physics_ClientOption(this, "maxspeed", autocvar_sv_maxspeed) * maxspd_mod; // also slow walking
          if (autocvar_g_movement_highspeed_q3_compat) {
            STAT(MOVEVARS_AIRACCEL_QW, this) = Physics_ClientOption(this, "airaccel_qw", autocvar_sv_airaccel_qw);
              : 0;
            STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, this) = Physics_ClientOption(this, "airspeedlimit_nonqw", autocvar_sv_airspeedlimit_nonqw) * maxspd_mod;
          }
 -      bool q3dfcompat = autocvar_sv_q3defragcompat && autocvar_sv_q3defragcompat_changehitbox; // NOTE: these hitboxes are off by 1 due to engine differences
 -      STAT(PL_MIN, this) = (q3dfcompat) ? '-15 -15 -20' : autocvar_sv_player_mins;
 -      STAT(PL_MAX, this) = (q3dfcompat) ? '15 15 36' : autocvar_sv_player_maxs;
 -      STAT(PL_VIEW_OFS, this) = (q3dfcompat) ? '0 0 30' : autocvar_sv_player_viewoffset;
 -      STAT(PL_CROUCH_MIN, this) = (q3dfcompat) ? '-15 -15 -20' : autocvar_sv_player_crouch_mins;
 -      STAT(PL_CROUCH_MAX, this) = (q3dfcompat) ? '15 15 20' : autocvar_sv_player_crouch_maxs;
 -      STAT(PL_CROUCH_VIEW_OFS, this) = (q3dfcompat) ? '0 0 16' : autocvar_sv_player_crouch_viewoffset;
 +      bool q3hb = q3compat && autocvar_sv_q3compat_changehitbox; // NOTE: these hitboxes are off by 1 due to engine differences
 +      STAT(PL_MIN, this) = (q3hb) ? '-15 -15 -20' : autocvar_sv_player_mins;
 +      STAT(PL_MAX, this) = (q3hb) ? '15 15 36' : autocvar_sv_player_maxs;
 +      STAT(PL_VIEW_OFS, this) = (q3hb) ? '0 0 30' : autocvar_sv_player_viewoffset;
 +      STAT(PL_CROUCH_MIN, this) = (q3hb) ? '-15 -15 -20' : autocvar_sv_player_crouch_mins;
 +      STAT(PL_CROUCH_MAX, this) = (q3hb) ? '15 15 20' : autocvar_sv_player_crouch_maxs;
 +      STAT(PL_CROUCH_VIEW_OFS, this) = (q3hb) ? '0 0 16' : autocvar_sv_player_crouch_viewoffset;
  
        // old stats
        // fix some new settings
diff --combined qcsrc/common/stats.qh
index a0bde6b925ef51333e85a9ac51d816c07aeaf31f,5bbc4dd26317ff9a663fee894fbeef2e5398dd67..e1aba4caa4f0620b2c0385e5f6f2172ec612d787
@@@ -3,7 -3,7 +3,8 @@@
  #ifdef SVQC
  #include <server/autocvars.qh>
  #include <server/client.qh>
 +#include <server/compat/quake3.qh>
+ #include <common/mapobjects/trigger/secret.qh>
  #endif
  
  // Full list of all stat constants, included in a single location for easy reference
@@@ -101,8 -101,8 +102,8 @@@ REGISTER_STAT(VEHICLESTAT_AMMO2, int
  REGISTER_STAT(VEHICLESTAT_RELOAD2, int)
  REGISTER_STAT(VEHICLESTAT_W2MODE, int)
  REGISTER_STAT(NADE_TIMER, float)
- REGISTER_STAT(SECRETS_TOTAL, float)
- REGISTER_STAT(SECRETS_FOUND, float)
+ REGISTER_STAT(SECRETS_TOTAL, int, secrets_total)
+ REGISTER_STAT(SECRETS_FOUND, int, secrets_found)
  REGISTER_STAT(RESPAWN_TIME, float)
  REGISTER_STAT(ROUNDSTARTTIME, float, round_starttime)
  REGISTER_STAT(MONSTERS_TOTAL, int)
@@@ -324,7 -324,10 +325,7 @@@ bool autocvar_sv_slick_applygravity
  #endif
  REGISTER_STAT(SLICK_APPLYGRAVITY, bool, autocvar_sv_slick_applygravity)
  
 -#ifdef SVQC
 -bool autocvar_sv_q3defragcompat;
 -#endif
 -REGISTER_STAT(Q3DEFRAGCOMPAT, bool, autocvar_sv_q3defragcompat)
 +REGISTER_STAT(Q3COMPAT, int, q3compat)
  
  #ifdef SVQC
  #include "physics/movetypes/movetypes.qh"
index f7c29a26e4e8cdd0b188c199d1ef80e771acd44c,3e25800cce5a69119e3073358f1822ac87d4c04c..1f3fcc32f297f7032f1583884711e28eb0683804
@@@ -5,6 -5,15 +5,6 @@@
  // enable to debug melee range
  //#define SHOTGUN_MELEEDEBUG
  
 -METHOD(Shotgun, m_spawnfunc_hookreplace, Weapon(Shotgun this, entity e))
 -{
 -      if (autocvar_sv_q3acompat_machineshotgunswap && !Item_IsLoot(e))
 -      {
 -              return WEP_MACHINEGUN;
 -      }
 -      return this;
 -}
 -
  void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float isprimary, float ammocount, float damage, float bullets, float spread, float solidpenetration, float force, entity bullet_trail_effect)
  {
        W_DecreaseAmmo(thiswep, actor, ammocount, weaponentity);
@@@ -17,7 -26,7 +17,7 @@@
                antilag_takeback_all(actor, lag);
  
        for(int sc = 0;sc < bullets;sc = sc + 1)
-               fireBullet_antilag(actor, weaponentity, w_shotorg, w_shotdir, spread, solidpenetration, damage, force, thiswep.m_id, bullet_trail_effect, false);
+               fireBullet_antilag(actor, weaponentity, w_shotorg, w_shotdir, spread, solidpenetration, damage, 0, force, thiswep.m_id, bullet_trail_effect, false);
        
        if(lag && bullets > 0)
                antilag_restore_all(actor);
diff --combined qcsrc/server/client.qc
index f54c728644cf52f877a2409009e8fa0a250539b0,0458b07af332d3b9f6b6d2d2c0ffdd3b4741ca7a..d3cc3d3fed2f5928276d272167d5e68c3b03682d
@@@ -349,7 -349,7 +349,7 @@@ void PutObserverInServer(entity this
        setthink(this, func_null);
        this.nextthink = 0;
        this.deadflag = DEAD_NO;
-       this.crouch = false;
+       UNSET_DUCKED(this);
        STAT(REVIVE_PROGRESS, this) = 0;
        this.revival_time = 0;
        this.draggable = drag_undraggable;
@@@ -614,7 -614,8 +614,7 @@@ void PutPlayerInServer(entity this
        this.respawn_flags = 0;
        this.respawn_time = 0;
        STAT(RESPAWN_TIME, this) = 0;
 -      bool q3dfcompat = autocvar_sv_q3defragcompat && autocvar_sv_q3defragcompat_changehitbox;
 -      this.scale = ((q3dfcompat) ? 0.9 : autocvar_sv_player_scale);
 +      this.scale = ((q3compat && autocvar_sv_q3compat_changehitbox) ? 0.9 : autocvar_sv_player_scale);
        this.fade_time = 0;
        this.pain_frame = 0;
        this.pain_finished = 0;
  
        this.spawnpoint_targ = NULL;
  
-       this.crouch = false;
+       UNSET_DUCKED(this);
        this.view_ofs = STAT(PL_VIEW_OFS, this);
        setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
        this.spawnorigin = spot.origin;
@@@ -1308,6 -1309,91 +1308,91 @@@ void UpdateChatBubble(entity this
        }
  }
  
+ void calculate_player_respawn_time(entity this)
+ {
+       if(MUTATOR_CALLHOOK(CalculateRespawnTime, this))
+               return;
+       float gametype_setting_tmp;
+       float sdelay_max = GAMETYPE_DEFAULTED_SETTING(respawn_delay_max);
+       float sdelay_small = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small);
+       float sdelay_large = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large);
+       float sdelay_small_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small_count);
+       float sdelay_large_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large_count);
+       float waves = GAMETYPE_DEFAULTED_SETTING(respawn_waves);
+       float pcount = 1;  // Include myself whether or not team is already set right and I'm a "player".
+       if (teamplay)
+       {
+               FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
+                       if(it.team == this.team)
+                               ++pcount;
+               });
+               if (sdelay_small_count == 0)
+                       sdelay_small_count = 1;
+               if (sdelay_large_count == 0)
+                       sdelay_large_count = 1;
+       }
+       else
+       {
+               FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
+                       ++pcount;
+               });
+               if (sdelay_small_count == 0)
+               {
+                       if (IS_INDEPENDENT_PLAYER(this))
+                       {
+                               // Players play independently. No point in requiring enemies.
+                               sdelay_small_count = 1;
+                       }
+                       else
+                       {
+                               // Players play AGAINST each other. Enemies required.
+                               sdelay_small_count = 2;
+                       }
+               }
+               if (sdelay_large_count == 0)
+               {
+                       if (IS_INDEPENDENT_PLAYER(this))
+                       {
+                               // Players play independently. No point in requiring enemies.
+                               sdelay_large_count = 1;
+                       }
+                       else
+                       {
+                               // Players play AGAINST each other. Enemies required.
+                               sdelay_large_count = 2;
+                       }
+               }
+       }
+       float sdelay;
+       if (pcount <= sdelay_small_count)
+               sdelay = sdelay_small;
+       else if (pcount >= sdelay_large_count)
+               sdelay = sdelay_large;
+       else  // NOTE: this case implies sdelay_large_count > sdelay_small_count.
+               sdelay = sdelay_small + (sdelay_large - sdelay_small) * (pcount - sdelay_small_count) / (sdelay_large_count - sdelay_small_count);
+       if(waves)
+               this.respawn_time = ceil((time + sdelay) / waves) * waves;
+       else
+               this.respawn_time = time + sdelay;
+       if(sdelay < sdelay_max)
+               this.respawn_time_max = time + sdelay_max;
+       else
+               this.respawn_time_max = this.respawn_time;
+       if((sdelay + waves >= 5.0) && (this.respawn_time - time > 1.75))
+               this.respawn_countdown = 10; // first number to count down from is 10
+       else
+               this.respawn_countdown = -1; // do not count down
+       if(autocvar_g_forced_respawn)
+               this.respawn_flags = this.respawn_flags | RESPAWN_FORCE;
+ }
  
  // LordHavoc: this hack will be removed when proper _pants/_shirt layers are
  // added to the model skins
@@@ -2266,7 -2352,6 +2351,6 @@@ bool PlayerThink(entity this
                this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
        }
  
-       secrets_setstatus(this);
        monsters_setstatus(this);
  
        return true;
index 184f84554de68d3073f61d3081a582aeb18788f3,4c8073b1ad35cfbef5d393d9ebdaf9d6532ef338..11b9f7188c8164661655a79b4e658295fe9bd621
@@@ -2,10 -2,10 +2,10 @@@
  
  #include <server/defs.qh>
  #include <server/miscfunctions.qh>
- #include <server/items.qh>
+ #include <server/items/items.qh>
+ #include <server/items/spawning.qh>
  #include <server/resources.qh>
  #include <common/gamemodes/_mod.qh>
- #include <common/t_items.qh>
  #include <common/gamemodes/gamemode/ctf/sv_ctf.qh>
  #include <common/mapobjects/triggers.qh>
  #include <common/mapobjects/trigger/counter.qh>
  #include <common/notifications/all.qh>
  #include <common/weapons/_all.qh>
  
 -//***********************
 -//QUAKE 3 ENTITIES - So people can play quake3 maps with the xonotic weapons
 -//***********************
 -
 -// NOTE: for best experience, you need to swap MGs with SGs in the map or it won't have a MG
 -
 -// SG -> SG
 -SPAWNFUNC_ITEM(ammo_shells, ITEM_Shells)
 -
 -// MG -> MG
 -SPAWNFUNC_ITEM(ammo_bullets, ITEM_Bullets)
 +/***********************
 + * QUAKE 3 ENTITIES - So people can play quake3 maps with the xonotic weapons
 + ***********************
 +
 + * Map entities NOT handled in this file:
 + holdable_invulnerability     Q3TA    currently unsupported
 + holdable_kamikaze            Q3TA    currently unsupported
 + item_ammoregen                       Q3TA    handled by buffs mutator
 + item_doubler                 Q3TA    handled by buffs mutator
 + item_guard                   Q3TA    handled by buffs mutator
 + item_scout                   Q3TA    handled by buffs mutator
 + item_armor_jacket            CPMA    handled in quake2.qc
 + item_flight                  Q3A     handled by buffs mutator
 + item_haste                   Q3A     handled by buffs mutator
 + item_health                  Q3A     handled in quake.qc
 + item_health_large            Q3A     handled in items.qc
 + item_health_small            Q3A     handled in health.qh
 + item_health_mega             Q3A     handled in health.qh
 + item_invis                   Q3A     handled by buffs mutator
 + item_quad                    Q3A     handled in items.qc
 + item_regen                   Q3A     handled by buffs mutator
 + CTF spawnfuncs handled in sv_ctf.qc
 +
 + NOTE: for best experience, you need to swap MGs with SGs in the map or it won't have a MG
 +*/
 +
 +// SG -> MG || SG
 +SPAWNFUNC_ITEM_COND(ammo_shells, (q3compat & BIT(0)), ITEM_Bullets, ITEM_Shells)
 +SPAWNFUNC_WEAPON_COND(weapon_shotgun, (q3compat & BIT(0)), WEP_MACHINEGUN, WEP_SHOTGUN)
 +
 +// MG -> SG || MG
 +SPAWNFUNC_ITEM_COND(ammo_bullets, (q3compat & BIT(0)), ITEM_Shells, ITEM_Bullets)
  
  // GL -> Mortar
  SPAWNFUNC_ITEM(ammo_grenades, ITEM_Rockets)
  
 -// Mines -> Rockets
 +// Team Arena Proximity Launcher -> Mine Layer
  SPAWNFUNC_WEAPON(weapon_prox_launcher, WEP_MINE_LAYER)
  SPAWNFUNC_ITEM(ammo_mines, ITEM_Rockets)
  
 -// LG -> Lightning
 +// Team Arena Chaingun -> HLAC
 +SPAWNFUNC_WEAPON(weapon_chaingun, WEP_HLAC)
 +SPAWNFUNC_ITEM(ammo_belt, ITEM_Cells)
 +
 +// Team Arena Nailgun -> Crylink || Quake Nailgun -> Electro
 +SPAWNFUNC_WEAPON_COND(weapon_nailgun, cvar("sv_mapformat_is_quake3"), WEP_CRYLINK, WEP_ELECTRO)
 +SPAWNFUNC_ITEM(ammo_nails, ITEM_Cells)
 +
 +// LG -> Electro
  SPAWNFUNC_WEAPON(weapon_lightning, WEP_ELECTRO)
  SPAWNFUNC_ITEM(ammo_lightning, ITEM_Cells)
  
@@@ -73,9 -44,9 +73,9 @@@ SPAWNFUNC_ITEM(ammo_cells, ITEM_Rockets
  SPAWNFUNC_WEAPON(weapon_railgun, WEP_VORTEX)
  SPAWNFUNC_ITEM(ammo_slugs, ITEM_Cells)
  
 -// BFG -> Crylink
 -SPAWNFUNC_WEAPON(weapon_bfg, WEP_CRYLINK)
 -SPAWNFUNC_ITEM(ammo_bfg, ITEM_Cells)
 +// BFG -> Crylink || Fireball
 +SPAWNFUNC_WEAPON_COND(weapon_bfg, cvar_string("g_mod_balance") == "XDF", WEP_CRYLINK, WEP_FIREBALL)
 +SPAWNFUNC_ITEM_COND(ammo_bfg, cvar_string("g_mod_balance") == "XDF", ITEM_Cells, ITEM_Rockets)
  
  // grappling hook -> hook
  SPAWNFUNC_WEAPON(weapon_grapplinghook, WEP_HOOK)
@@@ -87,9 -58,6 +87,9 @@@ SPAWNFUNC_ITEM(ammo_rockets, ITEM_Rocke
  SPAWNFUNC_ITEM(item_armor_body, ITEM_ArmorMega)
  SPAWNFUNC_ITEM(item_armor_combat, ITEM_ArmorBig)
  SPAWNFUNC_ITEM(item_armor_shard, ITEM_ArmorSmall)
 +SPAWNFUNC_ITEM(item_armor_green, ITEM_ArmorMedium) // CCTF
 +
 +// Battle Suit
  SPAWNFUNC_ITEM(item_enviro, ITEM_Shield)
  
  // medkit -> armor (we have no holdables)
@@@ -277,31 -245,35 +277,31 @@@ spawnfunc(target_fragsFilter
        this.use = fragsfilter_use;
  }
  
 -//spawnfunc(item_flight)       /* handled by buffs mutator */
 -//spawnfunc(item_doubler)        /* handled by buffs mutator */
 -//spawnfunc(item_haste)        /* handled by buffs mutator */
 -//spawnfunc(item_health)       /* handled in t_quake.qc */
 -//spawnfunc(item_health_large) /* handled in items.qc */
 -//spawnfunc(item_health_small) /* handled in items.qc */
 -//spawnfunc(item_health_mega)  /* handled in items.qc */
 -//spawnfunc(item_invis)        /* handled by buffs mutator */
 -//spawnfunc(item_regen)        /* handled by buffs mutator */
 -
 -// CTF spawnfuncs handled in mutators/gamemode_ctf.qc now
 -
 -.float notteam;
 -.float notsingle;
 -.float notfree;
 -.float notq3a;
 -.float notta;
 +.bool notteam;
 +.bool notsingle;
 +.bool notfree;
 +.bool notta;
 +.bool notvq3;
 +.bool notcpm;
  .string gametype;
  bool DoesQ3ARemoveThisEntity(entity this)
  {
        // Q3 style filters (DO NOT USE, THIS IS COMPAT ONLY)
  
 -      if(this.notq3a)
 -              if(!teamplay || g_tdm || g_ctf)
 +      // DeFRaG mappers use "notcpm" or "notvq3" to disable an entity in CPM or VQ3 physics
 +      // Xonotic is usually played with a CPM-based physics so we default to CPM mode
 +      if(cvar_string("g_mod_physics") == "Q3")
 +      {
 +              if(this.notvq3)
                        return true;
 +      }
 +      else if(this.notcpm)
 +              return true;
  
 +      // Q3 mappers use "notq3a" or "notta" to disable an entity in Q3A or Q3TA
 +      // Xonotic has ~equivalent features to Team Arena
        if(this.notta)
 -              if (!(!teamplay || g_tdm || g_ctf))
 -                      return true;
 +              return true;
  
        if(this.notsingle)
                if(maxclients == 1)
        if(this.gametype)
        {
                string gametypename;
 -              // static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester", "teamtournament"}
 +              // From ioq3 g_spawn.c: static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester"};
                gametypename = "ffa";
                if(teamplay)
                        gametypename = "team";
                        gametypename = "tournament";
                if(maxclients == 1)
                        gametypename = "single";
 -              // we do not have the other types (obelisk, harvester, teamtournament)
 +              // we do not have the other types (obelisk, harvester)
                if(strstrofs(this.gametype, gametypename, 0) < 0)
                        return true;
        }
diff --combined qcsrc/server/g_world.qc
index d5b7f069f5c5929746a0901f4d5b982fad2e6ee7,5dddc2fb3d00924ec3e257d83717c672ace9c1e4..3ade3ce84b7d4495907bb086c900b496bc2868ee
@@@ -883,8 -883,11 +883,8 @@@ spawnfunc(worldspawn
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1);
  
 -      if(fexists(strcat("scripts/", mapname, ".arena")))
 -              cvar_settemp("sv_q3acompat_machineshotgunswap", "1");
 -
 -      if(fexists(strcat("scripts/", mapname, ".defi")))
 -              cvar_settemp("sv_q3defragcompat", "1");
 +      q3compat = BITSET(q3compat, BIT(0), fexists(strcat("scripts/", mapname, ".arena")));
 +      q3compat = BITSET(q3compat, BIT(1), fexists(strcat("scripts/", mapname, ".defi")));
  
        if(whichpack(strcat("maps/", mapname, ".cfg")) != "")
        {
  
        Nagger_Init();
  
-       next_pingtime = time + 5;
        // set up information replies for clients and server to use
        maplist_reply = strzone(getmaplist());
        lsmaps_reply = strzone(getlsmaps());
index 0000000000000000000000000000000000000000,f1c8796c7211ece944ef334be60266c8a661e7b4..829e6914116ca4cd6aaa6f856ddb7b5529d42f9e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,149 +1,148 @@@
 -// FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
 -SPAWNFUNC_ITEM(item_armor1, ITEM_ArmorSmall)
+ #include "spawning.qh"
+ /// \file
+ /// \brief Source file that contains implementation of the functions related to
+ /// creation of game items.
+ /// \copyright GNU GPLv2 or any later version.
+ #include <server/mutators/_mod.qh>
+ #include <server/weapons/spawning.qh>
+ #include <common/weapons/all.qh>
+ #include <common/mapobjects/subs.qh>
+ .bool m_isloot; ///< Holds whether item is loot.
+ /// \brief Holds whether strength, shield or superweapon timers expire while
+ /// this item is on the ground.
+ .bool m_isexpiring;
+ entity Item_FindDefinition(string class_name)
+ {
+       FOREACH(Items, it.m_canonical_spawnfunc == class_name,
+       {
+               return it;
+       });
+       FOREACH(Weapons, it.m_canonical_spawnfunc == class_name,
+       {
+               return it.m_pickup;
+       });
+       return NULL;
+ }
+ bool Item_IsAllowed(string class_name)
+ {
+       entity definition = Item_FindDefinition(class_name);
+       if (definition == NULL)
+       {
+               return false;
+       }
+       return Item_IsDefinitionAllowed(definition);
+ }
+ bool Item_IsDefinitionAllowed(entity definition)
+ {
+       return !MUTATOR_CALLHOOK(FilterItemDefinition, definition);
+ }
+ entity Item_Create(string class_name, vector position, bool no_align)
+ {
+       entity item = spawn();
+       item.classname = class_name;
+       item.spawnfunc_checked = true;
+       setorigin(item, position);
+       item.noalign = no_align;
+       Item_Initialize(item, class_name);
+       if (wasfreed(item))
+       {
+               return NULL;
+       }
+       return item;
+ }
+ void Item_Initialize(entity item, string class_name)
+ {
+       FOREACH(Weapons, it.m_canonical_spawnfunc == class_name,
+       {
+               weapon_defaultspawnfunc(item, it);
+               return;
+       });
+       FOREACH(Items, it.m_canonical_spawnfunc == class_name,
+       {
+               StartItem(item, it);
+               return;
+       });
+       LOG_FATALF("Item_Initialize: Invalid classname: %s", class_name);
+ }
+ entity Item_CreateLoot(string class_name, vector position, vector vel,
+       float time_to_live)
+ {
+       entity item = spawn();
+       if (!Item_InitializeLoot(item, class_name, position, vel, time_to_live))
+       {
+               return NULL;
+       }
+       return item;
+ }
+ bool Item_InitializeLoot(entity item, string class_name, vector position,
+       vector vel, float time_to_live)
+ {
+       item.classname = class_name;
+       Item_SetLoot(item, true);
+       item.noalign = true;
+       setorigin(item, position);
+       item.pickup_anyway = true;
+       item.spawnfunc_checked = true;
+       Item_Initialize(item, class_name);
+       if (wasfreed(item))
+       {
+               return false;
+       }
+       item.gravity = 1;
+       item.velocity = vel;
+       SUB_SetFade(item, time + time_to_live, 1);
+       return true;
+ }
+ bool Item_IsLoot(entity item)
+ {
+       return item.m_isloot || item.classname == "droppedweapon";
+ }
+ void Item_SetLoot(entity item, bool loot)
+ {
+       item.m_isloot = loot;
+ }
+ bool Item_ShouldKeepPosition(entity item)
+ {
+       return item.noalign || (item.spawnflags & 1);
+ }
+ bool Item_IsExpiring(entity item)
+ {
+       return item.m_isexpiring;
+ }
+ void Item_SetExpiring(entity item, bool expiring)
+ {
+       item.m_isexpiring = expiring;
+ }
+ // Compatibility spawn functions
++SPAWNFUNC_ITEM_COND(item_armor1, cvar("sv_mapformat_is_quake3"), ITEM_ArmorSmall, ITEM_ArmorMedium)
+ SPAWNFUNC_ITEM(item_armor25, ITEM_ArmorMega)
+ SPAWNFUNC_ITEM(item_armor_large, ITEM_ArmorMega)
+ SPAWNFUNC_ITEM(item_health1, ITEM_HealthSmall)
+ SPAWNFUNC_ITEM(item_health25, ITEM_HealthMedium)
+ SPAWNFUNC_ITEM(item_health_large, ITEM_HealthBig)
+ SPAWNFUNC_ITEM(item_health100, ITEM_HealthMega)
+ SPAWNFUNC_ITEM(item_quad, ITEM_Strength)
diff --combined xonotic-server.cfg
index 69db7322d16904cd61cfae3640d09fdf67a643f0,85923c8ea5817c5eb3c8ac7ea088add4452c8e56..6e34c767438f200dbf69edac158fada9f448edba
@@@ -65,6 -65,7 +65,7 @@@ set g_respawn_ghosts_alpha 1 "respawn g
  set sv_gibhealth 100 "Minus health a dead body must have in order to get gibbed"
  
  // use default physics
+ sv_playerphysicsqc 1
  set sv_friction_on_land 0 "movement friction applied for half a second upon landing on the ground"
  set sv_friction_slick 0.5 "movement friction while on slick surfaces"
  
@@@ -495,7 -496,8 +496,7 @@@ sv_gameplayfix_consistentplayerprethin
  sv_gameplayfix_gravityunaffectedbyticrate 1
  sv_gameplayfix_nogravityonground 1
  
 -set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping machinegun and shotgun (for Q3A map compatibility in mapinfo files)"
 -set sv_q3defragcompat 0 "toggle for some compatibility hacks (for Q3DF map compatibility)"
 +set sv_q3compat_changehitbox 0 "use Q3 player hitbox dimensions and camera height on Q3 maps (maps with an entry in a .arena or .defi file)
  
  set g_movement_highspeed 1 "multiplier scale for movement speed (applies to sv_maxspeed and sv_maxairspeed, also applies to air acceleration when g_movement_highspeed_q3_compat is set to 0)"
  set g_movement_highspeed_q3_compat 0 "apply speed modifiers to air movement in a more Q3-compatible way (only apply speed buffs and g_movement_highspeed to max air speed, not to acceleration)"