#include "ammo.qh"
-#ifdef SVQC
-
-METHOD(Shells, m_spawnfunc_hookreplace, GameItem(Shells this, entity e))
-{
- if (autocvar_sv_q3acompat_machineshotgunswap && !Item_IsLoot(e))
- {
- return ITEM_Bullets;
- }
- return this;
-}
-
-#endif
if (!this.lip)
this.lip = 4;
- if(this.wait == -1 && autocvar_sv_q3defragcompat)
- this.wait = 0.1; // compatibility for q3df: "instant" return
+ if(this.wait < 0 && q3compat)
+ this.wait = 0.1; // compatibility for q3: -1 = return immediately
if(this.noise != "")
precache_sound(this.noise);
}
else if (!this.speed)
{
- if (autocvar_sv_q3defragcompat)
+ if (q3compat)
this.speed = 400;
else
this.speed = 100;
if (toucher.triggerhurttime < time)
{
EXACTTRIGGER_TOUCH(this, toucher);
- toucher.triggerhurttime = time + ((autocvar_sv_q3defragcompat && !(this.spawnflags & HURT_SLOW)) ? 0.1 : 1);
+ toucher.triggerhurttime = time + ((q3compat && !(this.spawnflags & HURT_SLOW)) ? 0.1 : 1);
entity own;
own = this.enemy;
this.use = trigger_hurt_use;
this.enemy = world; // I hate you all
if (!this.dmg)
- this.dmg = ((autocvar_sv_q3defragcompat) ? 5 : 10000);
+ this.dmg = ((q3compat) ? 5 : 10000);
if (this.message == "")
this.message = "was in the wrong place";
if (this.message2 == "")
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;
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;
{
switch(buffname)
{
- case "ammoregen": return "ammo";
- case "haste": case "scout": return "speed";
- case "guard": return "resistance";
- case "revival": case "regen": return "medic";
- case "invis": return "invisible";
- case "jumper": return "jump";
+ case "ammoregen": return "ammo"; // Q3TA ammoregen
+ case "haste": return "speed"; // Q3A haste
+ case "doubler": return "inferno"; // Q3TA doubler
+ case "scout": return "bash"; // Q3TA scout
+ case "guard": return "resistance"; // Q3TA guard
+ case "revival": case "regen": return "medic"; // WOP revival, Q3A regen
+ case "invis": return "invisible"; // Q3A invis
+ case "jumper": return "jump"; // WOP jumper
default: return buffname;
}
}
}
BUFF_SPAWNFUNCS(speed, BUFF_SPEED)
BUFF_SPAWNFUNC_Q3TA_COMPAT(haste, BUFF_SPEED)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(scout, BUFF_SPEED)
REGISTER_BUFF(MEDIC) {
this.m_name = _("Medic");
this.m_color = '1 0.39 0';
}
BUFF_SPAWNFUNCS(bash, BUFF_BASH)
-BUFF_SPAWNFUNC_Q3TA_COMPAT(doubler, BUFF_BASH)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(scout, BUFF_BASH)
REGISTER_BUFF(VAMPIRE) {
this.m_name = _("Vampire");
this.m_color = '1 0.62 0';
}
BUFF_SPAWNFUNCS(inferno, BUFF_INFERNO)
+BUFF_SPAWNFUNC_Q3TA_COMPAT(doubler, BUFF_INFERNO)
REGISTER_BUFF(SWAPPER) {
this.m_name = _("Swapper");
: 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
#ifdef SVQC
#include <server/autocvars.qh>
#include <server/client.qh>
+#include <server/compat/quake3.qh>
#include <common/mapobjects/trigger/secret.qh>
#endif
#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"
REGISTER_NET_TEMP(TE_CSQC_SHOCKWAVEPARTICLE)
#ifdef SVQC
-// enable when shockwave replaces shotgun
-#if 0
-METHOD(Shockwave, m_spawnfunc_hookreplace, Weapon(Shockwave this, entity e))
-{
- //if(autocvar_sv_q3acompat_machineshockwaveswap) // WEAPONTODO
- if (autocvar_sv_q3acompat_machineshotgunswap && !Item_IsLoot(e))
- {
- return WEP_MACHINEGUN;
- }
- return this;
-}
-#endif
const float MAX_SHOCKWAVE_HITS = 10;
//#define DEBUG_SHOCKWAVE
// 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);
ENDCLASS(Shotgun)
REGISTER_WEAPON(SHOTGUN, shotgun, NEW(Shotgun));
-SPAWNFUNC_WEAPON(weapon_shotgun, WEP_SHOTGUN)
string autocvar_sv_motd;
int autocvar_sv_name_maxlength = 64;
bool autocvar_sv_precacheplayermodels;
-bool autocvar_sv_q3acompat_machineshotgunswap;
bool autocvar_sv_servermodelsonly;
int autocvar_sv_spectate;
float autocvar_sv_spectator_speed_multiplier;
bool autocvar_g_weaponswitch_debug;
bool autocvar_g_weaponswitch_debug_alternate;
bool autocvar_g_allow_checkpoints;
-bool autocvar_sv_q3defragcompat_changehitbox = false;
+bool autocvar_sv_q3compat_changehitbox;
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;
#include <server/miscfunctions.qh>
#include <common/weapons/_all.qh>
-//***********************
-//QUAKE 1 ENTITIES - So people can play quake1 maps with the xonotic weapons
-//***********************
-SPAWNFUNC_WEAPON(weapon_nailgun, WEP_ELECTRO)
+/***********************
+ * QUAKE 1 ENTITIES - So people can play quake1 maps with the xonotic weapons
+ ***********************
+ weapon_nailgun handled in quake3.qc
+ item_armor1 handled in items.qc
+*/
+
SPAWNFUNC_WEAPON(weapon_supernailgun, WEP_HAGAR)
SPAWNFUNC_WEAPON(weapon_supershotgun, WEP_MACHINEGUN)
SPAWNFUNC_ITEM(item_spikes, ITEM_Bullets)
-//spawnfunc(item_armor1) {spawnfunc_item_armor_medium(this);} // FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
SPAWNFUNC_ITEM(item_armor2, ITEM_ArmorMega)
SPAWNFUNC_ITEM(item_armorInv, ITEM_ArmorMega) // TODO: make sure we actually want this
SPAWNFUNC_ITEM_COND(item_health, (this.spawnflags & 2), ITEM_HealthMega, ITEM_HealthMedium)
#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)
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)
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)
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;
}
#pragma once
+int q3compat = 0;
bool DoesQ3ARemoveThisEntity(entity this);
.int fragsfilter_cnt;
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")) != "")
{
// Compatibility spawn functions
-// FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
-SPAWNFUNC_ITEM(item_armor1, ITEM_ArmorSmall)
+SPAWNFUNC_ITEM_COND(item_armor1, cvar("sv_mapformat_is_quake3"), ITEM_ArmorSmall, ITEM_ArmorMedium)
SPAWNFUNC_ITEM(item_armor25, ITEM_ArmorMega)
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)"