]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Lyberta/RandomStartWeapons
authorLyberta <lyberta@lyberta.net>
Sat, 2 Sep 2017 06:33:18 +0000 (09:33 +0300)
committerLyberta <lyberta@lyberta.net>
Sat, 2 Sep 2017 06:33:18 +0000 (09:33 +0300)
44 files changed:
.gitlab-ci.yml
defaultOverkill.cfg
mutators.cfg
qcsrc/common/mutators/mutator/bloodloss/sv_bloodloss.qc
qcsrc/common/mutators/mutator/campcheck/sv_campcheck.qc
qcsrc/common/mutators/mutator/cloaked/sv_cloaked.qc
qcsrc/common/mutators/mutator/hook/sv_hook.qc
qcsrc/common/mutators/mutator/instagib/sv_instagib.qc
qcsrc/common/mutators/mutator/invincibleproj/sv_invincibleproj.qc
qcsrc/common/mutators/mutator/melee_only/sv_melee_only.qc
qcsrc/common/mutators/mutator/midair/sv_midair.qc
qcsrc/common/mutators/mutator/multijump/multijump.qc
qcsrc/common/mutators/mutator/nades/nades.qc
qcsrc/common/mutators/mutator/new_toys/sv_new_toys.qc
qcsrc/common/mutators/mutator/nix/sv_nix.qc
qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
qcsrc/common/mutators/mutator/physical_items/sv_physical_items.qc
qcsrc/common/mutators/mutator/pinata/sv_pinata.qc
qcsrc/common/mutators/mutator/rocketflying/sv_rocketflying.qc
qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc
qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc
qcsrc/common/mutators/mutator/superspec/sv_superspec.qc
qcsrc/common/mutators/mutator/touchexplode/sv_touchexplode.qc
qcsrc/common/mutators/mutator/vampire/sv_vampire.qc
qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qc
qcsrc/common/mutators/mutator/walljump/walljump.qc
qcsrc/common/physics/movetypes/movetypes.qh
qcsrc/common/physics/player.qh
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/projectiles.qh
qcsrc/dpdefs/post.qh
qcsrc/lib/_all.inc
qcsrc/lib/macro.qh
qcsrc/lib/misc.qh
qcsrc/lib/self.qh
qcsrc/lib/spawnfunc.qh
qcsrc/lib/stats.qh
qcsrc/server/autocvars.qh
qcsrc/server/g_world.qc
qcsrc/server/resources.qc
qcsrc/server/resources.qh
qcsrc/server/sv_main.qc
qcsrc/server/sv_main.qh
qcsrc/server/teamplay.qc

index 9305f527cd3abc9640d17bff880e021b854d7b17..596f61ad1dff4f98684a79992af9718aa69d7ebd 100644 (file)
@@ -29,7 +29,7 @@ test_sv_game:
     - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
     - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
     - make
-    - EXPECT=ed9be8d1b1a544f89bcdd7d36876fede
+    - EXPECT=0a08daa9132d147f533776deda07643e
     - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
       | tee /dev/stderr
       | grep '^:'
index 2444301b9e7b34c75b8bacf3ebdd367615ec4939..f63f689f34bda0b1cd03bcb62a1f944cbac88a92 100644 (file)
@@ -28,7 +28,7 @@ set g_nades_nade_newton_style 2
 set g_dodging 1
 set sv_dodging_wall_dodging 1
 
-set g_spawn_near_teammate 1
+set g_spawn_near_teammate "!g_assault !g_freezetag"
 set g_spawn_near_teammate_ignore_spawnpoint 1
 set g_spawnshieldtime 0.5
 set g_respawn_delay_forced 2
index 23c72435c1e399233872a18114c265debb945150..5eb8d1b9d6dae7d806a64bc55c8771535fd42efa 100644 (file)
@@ -108,7 +108,7 @@ set g_rocket_flying 0 "set to 1 to enable rocket flying in all balance configs"
 //  spawn near teammate
 // =====================
 seta cl_spawn_near_teammate 1 "toggle for spawning near teammates (only effective if g_spawn_near_teammate_ignore_spawnpoint is 2)"
-set g_spawn_near_teammate 0 "if set, players prefer spawns near a team mate"
+set g_spawn_near_teammate 0 "players prefer spawns near a team mate"
 set g_spawn_near_teammate_distance 640 "max distance to consider a spawn to be near a team mate"
 set g_spawn_near_teammate_ignore_spawnpoint 0 "ignore spawnpoints and spawn right at team mates, if 2, clients can ignore this option"
 set g_spawn_near_teammate_ignore_spawnpoint_max 10 "if set, test at most this many of the available teammates"
index d1b2658161ccc9c0741ba26ba5a4c01bd18e33ff..1164e0ade66efd9dcf05c924fa76ff109dcd0e65 100644 (file)
@@ -1,6 +1,7 @@
 #include "sv_bloodloss.qh"
 
-REGISTER_MUTATOR(bloodloss, cvar("g_bloodloss"));
+float autocvar_g_bloodloss;
+REGISTER_MUTATOR(bloodloss, autocvar_g_bloodloss);
 
 .float bloodloss_timer;
 
index a64f9d0805166d2e80b1516d3b1e863db1919f14..987645aaa0c719a5546ceeb03d47ee9b2901c804 100644 (file)
@@ -1,10 +1,11 @@
 #include "sv_campcheck.qh"
 
+string autocvar_g_campcheck;
 float autocvar_g_campcheck_damage;
 float autocvar_g_campcheck_distance;
 float autocvar_g_campcheck_interval;
 
-REGISTER_MUTATOR(campcheck, cvar("g_campcheck"));
+REGISTER_MUTATOR(campcheck, expr_evaluate(autocvar_g_campcheck));
 
 .float campcheck_nextcheck;
 .float campcheck_traveled_distance;
index eb45d4baf40a5950f81bdb466c0305cf616da70e..a1fe27a877c3e46e5e4dfe59a15239c583930f0a 100644 (file)
@@ -1,6 +1,7 @@
 #include "sv_cloaked.qh"
 
-REGISTER_MUTATOR(cloaked, cvar("g_cloaked"));
+string autocvar_g_cloaked;
+REGISTER_MUTATOR(cloaked, expr_evaluate(autocvar_g_cloaked));
 
 float autocvar_g_balance_cloaked_alpha;
 
index 5dfdf4386642933e5d98404e5be6914d785c2f0c..c3967811973a9ec009bbe17d120a0be38f86387d 100644 (file)
@@ -5,7 +5,7 @@
 #ifdef SVQC
 AUTOCVAR(g_grappling_hook_useammo, bool, false, "Use ammunition with the off-hand grappling hook");
 
-REGISTER_MUTATOR(hook, cvar("g_grappling_hook")) {
+REGISTER_MUTATOR(hook, expr_evaluate(cvar_string("g_grappling_hook"))) {
     MUTATOR_ONADD {
         g_grappling_hook = true;
         if(!autocvar_g_grappling_hook_useammo)
index 3de831198d7f4e5ff48056ff55ed2d1545d9778d..1561dc10db9a326acf932de70df86365e179bd4f 100644 (file)
@@ -1,5 +1,10 @@
 #include "sv_instagib.qh"
 
+bool autocvar_g_instagib_damagedbycontents = true;
+bool autocvar_g_instagib_blaster_keepdamage = false;
+bool autocvar_g_instagib_blaster_keepforce = false;
+bool autocvar_g_instagib_mirrordamage;
+bool autocvar_g_instagib_friendlypush = true;
 //int autocvar_g_instagib_ammo_drop;
 bool autocvar_g_instagib_ammo_convert_cells;
 bool autocvar_g_instagib_ammo_convert_rockets;
@@ -12,7 +17,7 @@ float autocvar_g_instagib_speed_highspeed;
 
 #include <common/items/_mod.qh>
 
-REGISTER_MUTATOR(mutator_instagib, cvar("g_instagib") && !g_nexball);
+REGISTER_MUTATOR(mutator_instagib, autocvar_g_instagib && !g_nexball);
 
 spawnfunc(item_minst_cells)
 {
index 23e0d0d85033ac05004679c72606a9f005eb9f8c..e68c687bdeb65058bac0c887c5f8aab8967bd560 100644 (file)
@@ -1,6 +1,7 @@
 #include "sv_invincibleproj.qh"
 
-REGISTER_MUTATOR(invincibleprojectiles, cvar("g_invincible_projectiles"));
+string autocvar_g_invincible_projectiles;
+REGISTER_MUTATOR(invincibleprojectiles, expr_evaluate(autocvar_g_invincible_projectiles));
 
 MUTATOR_HOOKFUNCTION(invincibleprojectiles, EditProjectile)
 {
index a542921221a6a37bc7bddf4bb485f26fdcbd8d08..ac06a8f7747160259588667e74a20ba33878da9e 100644 (file)
@@ -1,6 +1,7 @@
 #include "sv_melee_only.qh"
 
-REGISTER_MUTATOR(melee_only, cvar("g_melee_only") && !cvar("g_instagib") && !cvar("g_overkill") && !g_nexball);
+string autocvar_g_melee_only;
+REGISTER_MUTATOR(melee_only, expr_evaluate(autocvar_g_melee_only) && !cvar("g_instagib") && !cvar("g_overkill") && !g_nexball);
 
 MUTATOR_HOOKFUNCTION(melee_only, SetStartItems, CBC_ORDER_LAST)
 {
index 92bbacc00663c2eb70d50dda92b913874eb2493d..54b3673c6e245331c69b72dc69a0bffaa3f5ad13 100644 (file)
@@ -1,8 +1,9 @@
 #include "sv_midair.qh"
 
+string autocvar_g_midair;
 float autocvar_g_midair_shieldtime;
 
-REGISTER_MUTATOR(midair, cvar("g_midair"));
+REGISTER_MUTATOR(midair, expr_evaluate(autocvar_g_midair));
 
 .float midair_shieldtime;
 
index 47dcfd4afd550230ab85fbff4872d03cdc6e13bd..081a1fdb6fd69d7767de22b0ebecd8c8445e93b4 100644 (file)
@@ -9,7 +9,7 @@
 
 
 #if defined(SVQC)
-REGISTER_MUTATOR(multijump, cvar("g_multijump"));
+REGISTER_MUTATOR(multijump, autocvar_g_multijump);
 #elif defined(CSQC)
 REGISTER_MUTATOR(multijump, true);
 #endif
index 0c446952d033a60d14a52f83c4c2784cb1eaaf00..92e16b48d22e04bc65a49f33b12dbdacbf17eee3 100644 (file)
@@ -81,7 +81,7 @@ MUTATOR_HOOKFUNCTION(cl_nades, EditProjectile)
 
        entity nade_type = Nade_FromProjectile(proj.cnt);
        if (nade_type == NADE_TYPE_Null) return;
-       if(STAT(NADES_SMALL, NULL))
+       if(STAT(NADES_SMALL))
        {
                proj.mins = '-8 -8 -8';
                proj.maxs = '8 8 8';
@@ -150,7 +150,7 @@ void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expan
 #include <common/monsters/sv_monsters.qh>
 #include <server/g_subs.qh>
 
-REGISTER_MUTATOR(nades, cvar("g_nades"));
+REGISTER_MUTATOR(nades, autocvar_g_nades);
 
 .float nade_time_primed;
 .float nade_lifetime;
@@ -872,7 +872,7 @@ void nade_damage(entity this, entity inflictor, entity attacker, float damage, i
 
        hp -= damage;
        SetResourceAmount(this, RESOURCE_HEALTH, hp);
-       
+
 
        if ( this.nade_type != NADE_TYPE_HEAL.m_id || IS_PLAYER(attacker) )
                this.realowner = attacker;
index 288c2d5c8363ea473d824edf867275700221b677..af364995a1e92bc13c42b287babb5e3471938441 100644 (file)
@@ -68,9 +68,11 @@ roflsound "New toys, new toys!" sound.
 
 */
 
+string autocvar_g_new_toys;
+
 bool nt_IsNewToy(int w);
 
-REGISTER_MUTATOR(nt, cvar("g_new_toys") && !cvar("g_instagib") && !cvar("g_overkill"))
+REGISTER_MUTATOR(nt, expr_evaluate(autocvar_g_new_toys) && !cvar("g_instagib") && !cvar("g_overkill"))
 {
        MUTATOR_ONADD
        {
index 33536fb0a15d88ca00720ac7387b72cdcb93e26b..4de24a5898c8b214afb2351ec70b786ee9848434 100644 (file)
@@ -1,5 +1,6 @@
 #include "sv_nix.qh"
 
+string autocvar_g_nix;
 int autocvar_g_balance_nix_ammo_cells;
 int autocvar_g_balance_nix_ammo_plasma;
 int autocvar_g_balance_nix_ammo_fuel;
@@ -35,7 +36,7 @@ float nix_nextweapon;
 
 bool NIX_CanChooseWeapon(int wpn);
 
-REGISTER_MUTATOR(nix, cvar("g_nix") && !cvar("g_instagib") && !cvar("g_overkill"))
+REGISTER_MUTATOR(nix, expr_evaluate(autocvar_g_nix) && !cvar("g_instagib") && !cvar("g_overkill"))
 {
        MUTATOR_ONADD
        {
index d2a7308dedf04267af31ea7b599a4abd447ca08f..b47e587511643e3076e172835052c16787d3079d 100644 (file)
@@ -3,6 +3,8 @@
 #include "hmg.qh"
 #include "rpc.qh"
 
+string autocvar_g_overkill;
+
 bool autocvar_g_overkill_powerups_replace;
 
 bool autocvar_g_overkill_itemwaypoints = true;
@@ -18,7 +20,7 @@ bool autocvar_g_overkill_filter_armormega;
 
 void ok_Initialize();
 
-REGISTER_MUTATOR(ok, cvar("g_overkill") && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
+REGISTER_MUTATOR(ok, expr_evaluate(autocvar_g_overkill) && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
 {
        MUTATOR_ONADD
        {
index 62781c92073cfbd11278ea0313364bdac5bc0d8e..38cd7474b786c34343e4acf30009421d3fb8ec05 100644 (file)
@@ -4,7 +4,7 @@ int autocvar_g_physical_items;
 float autocvar_g_physical_items_damageforcescale;
 float autocvar_g_physical_items_reset;
 
-REGISTER_MUTATOR(physical_items, cvar("g_physical_items"))
+REGISTER_MUTATOR(physical_items, autocvar_g_physical_items)
 {
        // check if we have a physics engine
        MUTATOR_ONADD
index 53e4f49e60aadf08b13f9eb0880d3fe18711acd1..1084ff77895aa079e2dd9104ffe1159551f54db2 100644 (file)
@@ -1,6 +1,7 @@
 #include "sv_pinata.qh"
 
-REGISTER_MUTATOR(pinata, cvar("g_pinata") && !cvar("g_instagib") && !cvar("g_overkill"));
+string autocvar_g_pinata;
+REGISTER_MUTATOR(pinata, expr_evaluate(autocvar_g_pinata) && !cvar("g_instagib") && !cvar("g_overkill"));
 
 MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
 {
index 9f0d8fbf0d5ec4907204169f4a7e53d17e338dbb..d3c1922b997c9437ab82ba9f9c27603d1ed14e1f 100644 (file)
@@ -1,6 +1,7 @@
 #include "sv_rocketflying.qh"
 
-REGISTER_MUTATOR(rocketflying, cvar("g_rocket_flying"));
+string autocvar_g_rocket_flying;
+REGISTER_MUTATOR(rocketflying, expr_evaluate(autocvar_g_rocket_flying));
 
 MUTATOR_HOOKFUNCTION(rocketflying, EditProjectile)
 {
index 93dc602f0299df56c21597ea6cf966e951d2db78..d121cf1094685ac9263f55143b59da831cf37610 100644 (file)
@@ -1,5 +1,6 @@
 #include "sv_sandbox.qh"
 
+string autocvar_g_sandbox;
 int autocvar_g_sandbox_info;
 bool autocvar_g_sandbox_readonly;
 string autocvar_g_sandbox_storage_name;
@@ -18,7 +19,7 @@ float autocvar_g_sandbox_object_material_velocity_factor;
 float autosave_time;
 void sandbox_Database_Load();
 
-REGISTER_MUTATOR(sandbox, cvar("g_sandbox"))
+REGISTER_MUTATOR(sandbox, expr_evaluate(autocvar_g_sandbox))
 {
        MUTATOR_ONADD
        {
index 9ff3644748112eaad8c6dc1894487b52afe4dd21..61c302c3e7e0fa74bdd67d0a81a67ea00012efe1 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <lib/float.qh>
 
+string autocvar_g_spawn_near_teammate;
 float autocvar_g_spawn_near_teammate_distance;
 int autocvar_g_spawn_near_teammate_ignore_spawnpoint;
 int autocvar_g_spawn_near_teammate_ignore_spawnpoint_max;
@@ -10,7 +11,7 @@ float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
 bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
 bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
 
-REGISTER_MUTATOR(spawn_near_teammate, cvar("g_spawn_near_teammate"));
+REGISTER_MUTATOR(spawn_near_teammate, expr_evaluate(autocvar_g_spawn_near_teammate));
 
 .entity msnt_lookat;
 
@@ -20,6 +21,8 @@ REGISTER_MUTATOR(spawn_near_teammate, cvar("g_spawn_near_teammate"));
 
 MUTATOR_HOOKFUNCTION(spawn_near_teammate, Spawn_Score)
 {
+       if (!teamplay) return;
+
        entity player = M_ARGV(0, entity);
        entity spawn_spot = M_ARGV(1, entity);
        vector spawn_score = M_ARGV(2, vector);
@@ -29,9 +32,6 @@ MUTATOR_HOOKFUNCTION(spawn_near_teammate, Spawn_Score)
 
        spawn_spot.msnt_lookat = NULL;
 
-       if(!teamplay)
-               return;
-
        RandomSelection_Init();
        FOREACH_CLIENT(IS_PLAYER(it) && it != player && SAME_TEAM(it, player) && !IS_DEAD(it), {
                if(vdist(spawn_spot.origin - it.origin, >, autocvar_g_spawn_near_teammate_distance))
@@ -56,7 +56,8 @@ MUTATOR_HOOKFUNCTION(spawn_near_teammate, Spawn_Score)
 
 MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
 {
-       if(!teamplay) { return; }
+       if (!teamplay) return;
+
        entity player = M_ARGV(0, entity);
        entity spawn_spot = M_ARGV(1, entity);
 
index 4c99095b79df43f68e4daa402d97599cda72ebae..eb20082359ec1f25f92643bdd3f6a2b4624ebe17 100644 (file)
@@ -1,6 +1,7 @@
 #include "sv_superspec.qh"
 
-REGISTER_MUTATOR(superspec, cvar("g_superspectate"));
+string autocvar_g_superspectate;
+REGISTER_MUTATOR(superspec, expr_evaluate(autocvar_g_superspectate));
 
 #define _SSMAGIX "SUPERSPEC_OPTIONSFILE_V1"
 #define _ISLOCAL(ent) ((edict_num(1) == (ent)) ? true : false)
index 3e6edb04b356cf4b722504cbe2d5b04af8f494c8..a1b38fb6e750a2a44b6638189b6d18f3d89a3f0d 100644 (file)
@@ -1,11 +1,12 @@
 #include "sv_touchexplode.qh"
 
+string autocvar_g_touchexplode;
 float autocvar_g_touchexplode_radius;
 float autocvar_g_touchexplode_damage;
 float autocvar_g_touchexplode_edgedamage;
 float autocvar_g_touchexplode_force;
 
-REGISTER_MUTATOR(touchexplode, cvar("g_touchexplode"));
+REGISTER_MUTATOR(touchexplode, expr_evaluate(autocvar_g_touchexplode));
 
 .float touchexplode_time;
 
index 1b07ecd669b5467d9307fc66b239086cf2602931..199b4e202a7351a9b2d25bfb4364ec02119a259d 100644 (file)
@@ -1,6 +1,7 @@
 #include "sv_vampire.qh"
 
-REGISTER_MUTATOR(vampire, cvar("g_vampire") && !cvar("g_instagib"));
+string autocvar_g_vampire;
+REGISTER_MUTATOR(vampire, expr_evaluate(autocvar_g_vampire) && !cvar("g_instagib"));
 
 MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
 {
index e2b0f57d760e8cd13ba17925c0211809f31f8d3b..ce9e270654cb498281e01db990aa652e0ae8f8c1 100644 (file)
@@ -1,6 +1,7 @@
 #include "sv_vampirehook.qh"
 
-REGISTER_MUTATOR(vh, cvar("g_vampirehook"));
+string autocvar_g_vampirehook;
+REGISTER_MUTATOR(vh, expr_evaluate(autocvar_g_vampirehook));
 
 bool autocvar_g_vampirehook_teamheal;
 float autocvar_g_vampirehook_damage;
index b0d95ea29eb784570f48fb4621724dd930e0e292..c462a7e2b7c869398e733019a107f69049d16472 100644 (file)
@@ -4,7 +4,7 @@
 #ifdef CSQC
 REGISTER_MUTATOR(walljump, true);
 #elif defined(SVQC)
-REGISTER_MUTATOR(walljump, cvar("g_walljump"));
+REGISTER_MUTATOR(walljump, autocvar_g_walljump);
 #endif
 
 #define PHYS_WALLJUMP(s)                                               STAT(WALLJUMP, s)
index dbd765d983df928a9e6b262121cd9526b4813286..85912ee1c33f915ebdf59f907c616ef2f571c4f3 100644 (file)
@@ -13,18 +13,18 @@ const int WATERLEVEL_SUBMERGED = 3;
 #define SET_ONSLICK(s)                                         ((s).flags |= FL_ONSLICK)
 #define UNSET_ONSLICK(s)                                       ((s).flags &= ~FL_ONSLICK)
 
-#define GAMEPLAYFIX_DOWNTRACEONGROUND(s)    STAT(GAMEPLAYFIX_DOWNTRACEONGROUND, NULL)
-#define GAMEPLAYFIX_EASIERWATERJUMP(s)      STAT(GAMEPLAYFIX_EASIERWATERJUMP, NULL)
-#define GAMEPLAYFIX_STEPDOWN(s)             STAT(GAMEPLAYFIX_STEPDOWN, NULL)
-#define GAMEPLAYFIX_STEPMULTIPLETIMES(s)    STAT(GAMEPLAYFIX_STEPMULTIPLETIMES, NULL)
-#define GAMEPLAYFIX_UNSTICKPLAYERS(s)       STAT(GAMEPLAYFIX_UNSTICKPLAYERS, NULL)
-#define GAMEPLAYFIX_WATERTRANSITION(s)                 STAT(GAMEPLAYFIX_WATERTRANSITION, NULL)
-#define UPWARD_VELOCITY_CLEARS_ONGROUND(s)  STAT(GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND, NULL)
-
-#define PHYS_STEPHEIGHT(s)                  STAT(MOVEVARS_STEPHEIGHT, NULL)
-#define PHYS_NOSTEP(s)                      STAT(NOSTEP, NULL)
-#define PHYS_JUMPSTEP(s)                    STAT(MOVEVARS_JUMPSTEP, NULL)
-#define PHYS_WALLFRICTION(s)                STAT(MOVEVARS_WALLFRICTION, NULL)
+#define GAMEPLAYFIX_DOWNTRACEONGROUND(s)    STAT(GAMEPLAYFIX_DOWNTRACEONGROUND)
+#define GAMEPLAYFIX_EASIERWATERJUMP(s)      STAT(GAMEPLAYFIX_EASIERWATERJUMP)
+#define GAMEPLAYFIX_STEPDOWN(s)             STAT(GAMEPLAYFIX_STEPDOWN)
+#define GAMEPLAYFIX_STEPMULTIPLETIMES(s)    STAT(GAMEPLAYFIX_STEPMULTIPLETIMES)
+#define GAMEPLAYFIX_UNSTICKPLAYERS(s)       STAT(GAMEPLAYFIX_UNSTICKPLAYERS)
+#define GAMEPLAYFIX_WATERTRANSITION(s)                 STAT(GAMEPLAYFIX_WATERTRANSITION)
+#define UPWARD_VELOCITY_CLEARS_ONGROUND(s)  STAT(GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND)
+
+#define PHYS_STEPHEIGHT(s)                  STAT(MOVEVARS_STEPHEIGHT)
+#define PHYS_NOSTEP(s)                      STAT(NOSTEP)
+#define PHYS_JUMPSTEP(s)                    STAT(MOVEVARS_JUMPSTEP)
+#define PHYS_WALLFRICTION(s)                STAT(MOVEVARS_WALLFRICTION)
 
 #ifdef CSQC
 .float bouncestop;
index d5a8e605af8a5b1721fa4d478b35d7de88727cc7..ae59381e5c11394ce93abcf441cd5c453be4d8a6 100644 (file)
@@ -80,7 +80,7 @@ bool IsFlying(entity a);
 #define PHYS_JETPACK_MAXSPEED_UP(s)         STAT(JETPACK_MAXSPEED_UP, s)
 #define PHYS_JETPACK_REVERSE_THRUST(s)         STAT(JETPACK_REVERSE_THRUST, s)
 
-#define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS(s) STAT(MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS, NULL)
+#define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS(s) STAT(MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS)
 #define PHYS_JUMPVELOCITY(s)                STAT(MOVEVARS_JUMPVELOCITY, s)
 
 #define PHYS_MAXAIRSPEED(s)                 STAT(MOVEVARS_MAXAIRSPEED, s)
@@ -97,7 +97,7 @@ bool IsFlying(entity a);
 #define PHYS_WARSOWBUNNY_TOPSPEED(s)        STAT(MOVEVARS_WARSOWBUNNY_TOPSPEED, s)
 #define PHYS_WARSOWBUNNY_TURNACCEL(s)       STAT(MOVEVARS_WARSOWBUNNY_TURNACCEL, s)
 
-#define PHYS_SLICK_APPLYGRAVITY(s)             STAT(SLICK_APPLYGRAVITY, NULL)
+#define PHYS_SLICK_APPLYGRAVITY(s)             STAT(SLICK_APPLYGRAVITY)
 
 #define PHYS_INPUT_BUTTON_ATCK(s)           PHYS_INPUT_BUTTON_BUTTON1(s)
 #define PHYS_INPUT_BUTTON_JUMP(s)           PHYS_INPUT_BUTTON_BUTTON2(s)
index afbf79eb54777d0e2852366e9d44956ff69c3966..6605f00c26d2a2e48378f519f9a9fc86c314a7cb 100644 (file)
@@ -530,7 +530,9 @@ void CL_WeaponEntity_SetModel(entity this, string name, bool _anim)
        int compressed_shotorg = compressShotOrigin(this.movedir);
        // make them match perfectly
 #ifdef SVQC
-       this.movedir = decompressShotOrigin(this.owner.stat_shotorg = compressed_shotorg);
+    // null during init
+    if (this.owner) this.owner.stat_shotorg = compressed_shotorg;
+       this.movedir = decompressShotOrigin(compressed_shotorg);
 #else
        this.movedir = decompressShotOrigin(compressed_shotorg);
 #endif
index 73cd00d6c1c3e9eea514afa31e9c00afea76609a..5a782b98f9e462210ae5de73ec15102b340507b5 100644 (file)
@@ -41,3 +41,5 @@ const int PROJECTILE_ARC_BOLT = 35;
 // projectile IDs 40-50 reserved
 
 const int PROJECTILE_RPC = 60;
+
+// projectile IDs 70-100 reserved
index 16fd93450332e44fa0952d7003f6c50fb1fc6b03..70e5f378422af7850a91ec65cf8857d6c61ae0d8 100644 (file)
@@ -11,8 +11,8 @@
 #undef setcolor
 
 #ifdef MENUQC
-       #define NULL (0, null_entity)
+       #define NULL (RVALUE, null_entity)
        #define world NULL
 #else
-       #define NULL (0, world)
+       #define NULL (RVALUE, world)
 #endif
index 4da78f1444eb27b397d926442c7a153012adf01e..9d582091039faa12ac2028efeb9022357be3a631 100644 (file)
@@ -182,7 +182,17 @@ void make_safe_for_remove(entity this);
        #define SV_Shutdown _SV_Shutdown
 
        void _StartFrame();
-       void StartFrame() { if (_StartFrame) _StartFrame(); }
+       bool _StartFrame_init;
+       void spawnfunc_worldspawn(entity);
+       void StartFrame() {
+               if (!_StartFrame_init) {
+                       _StartFrame_init = true;
+                       float oldtime = time; time = 1;
+                       __spawnfunc_expecting = 2; NULL.__spawnfunc_constructor(NULL);
+                       time = oldtime;
+        }
+        if (_StartFrame) _StartFrame();
+       }
        #define StartFrame _StartFrame
 
        void _SetNewParms();
index 1541b9997cff5efb80c96fa1a3844c00b6dcc1ba..f2ec6df4a4206e8797f08ecb529fa0faa6adbcb3 100644 (file)
@@ -9,6 +9,9 @@
     #define MACRO_END } while (0)
 #endif
 
+/** Marker for use in (RVALUE, (expr)) */
+#define RVALUE 0
+
 #define _CAT(a, b) a ## b
 #define CAT(a, b) _CAT(a, b)
 
index 21e0c5239f59aa7399533f5c35aca8c0e0c2487b..6c29a4b88dd100f74ded51a0fe91ad82179c7d25 100644 (file)
@@ -10,6 +10,7 @@
 
        #include "p99.qh"
        #define OVERLOAD(F, ...) P99_IF_EMPTY(__VA_ARGS__)(P99_PASTE2(F, _00)())(P99_PASTE3(F, _, P00_NARG(__VA_ARGS__))(__VA_ARGS__))
+       /** for use within a macro */
        #define OVERLOAD_(F, ...) P99_IF_EMPTY(__VA_ARGS__)(P99_PASTE2(F, _00)())(P99_PASTE3(F, _, P00_NARG(__VA_ARGS__))(__VA_ARGS__))
 #else
        #define EVAL(...) __VA_ARGS__
index f4c246f33058997803e1291f243286cfce99362d..0a61cc003dfdc9046acf24dc7b33b057115732e8 100644 (file)
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "macro.qh"
+
 // Transition from global 'self' to local 'this'
 
 // Step 1: auto oldself
 
 // Step 2: const self
 #if 1
-    #define self (0, self)
+    #define self (RVALUE, self)
     [[alias("self")]] entity __self;
     #define setself(s) (__self = s)
-    #define WITHSELF(value, block) WITH(entity, __self, value, (0, block))
+    #define WITHSELF(value, block) WITH(entity, __self, value, (RVALUE, block))
 #endif
 
 // Step 3: propagate SELFPARAM()
@@ -32,7 +34,7 @@
 // Step 5: this should work
 #if 1
     #undef self
-    #define self (0, this)
+    #define self (RVALUE, this)
 #endif
 
 // Step 6: remove SELFPARAM, add parameters
@@ -56,11 +58,11 @@ noref entity _selftemp;
 #define SELFWRAP_SET(T, e, f) \
     (_selftemp = (e), _selftemp.__##T = ((f) ? T##_self : func_null), _selftemp.self##T = (f))
 #define SELFWRAP_GET(T, e) \
-    (0, (e).self##T)
+    (RVALUE, (e).self##T)
 #define _SELFWRAP_SET(T, e, f) \
     ((e).__##T = (f))
 #define _SELFWRAP_GET(T, e) \
-    (0, (e).__##T)
+    (RVALUE, (e).__##T)
 
 SELFWRAP(think, void, (), (entity this), (this))
 #define setthink(e, f) SELFWRAP_SET(think, e, f)
index e0605c93840599e8f928f359ce1f6b02cccd7016..e30e565fd3259a6916d36d5c230d7165bae4dd1c 100644 (file)
@@ -27,34 +27,71 @@ noref bool require_spawnfunc_prefix;
        #define _spawnfunc_check(fld) \
                if (fieldname == #fld) continue;
 
-       noref bool __spawnfunc_expecting;
+       noref int __spawnfunc_expecting;
        noref entity __spawnfunc_expect;
        noref bool __spawnfunc_unreachable_workaround = true;
 
+    .void(entity) __spawnfunc_constructor;
+    noref IntrusiveList g_spawn_queue;
+
+    #define SPAWNFUNC_INTERNAL_FIELDS(X) \
+        X(string, classname, "spawnfunc") \
+        X(string, targetname, string_null) \
+        /**/
+
+    #define X(T, fld, def) .T fld, __spawnfunc_##fld;
+    SPAWNFUNC_INTERNAL_FIELDS(X)
+    #undef X
+
+    void __spawnfunc_defer(entity prototype, void(entity) constructor)
+    {
+        IL_PUSH(g_spawn_queue, prototype);
+        #define X(T, fld, def) { prototype.__spawnfunc_##fld = prototype.fld; prototype.fld = def; }
+        SPAWNFUNC_INTERNAL_FIELDS(X);
+        #undef X
+        prototype.__spawnfunc_constructor = constructor;
+    }
+
+    noref IntrusiveList g_map_entities;
+    #define __spawnfunc_spawn_all() MACRO_BEGIN \
+        g_map_entities = IL_NEW(); \
+        IL_EACH(g_spawn_queue, true, __spawnfunc_spawn(it)); \
+    MACRO_END
+
+    void __spawnfunc_spawn(entity prototype)
+    {
+        entity e = new(clone);
+        copyentity(prototype, e);
+        IL_PUSH(g_map_entities, e);
+        #define X(T, fld, def) { e.fld = e.__spawnfunc_##fld; e.__spawnfunc_##fld = def; }
+        SPAWNFUNC_INTERNAL_FIELDS(X);
+        #undef X
+        e.__spawnfunc_constructor(e);
+    }
+
        #define spawnfunc_1(id) spawnfunc_2(id, FIELDS_UNION)
        #define spawnfunc_2(id, whitelist) \
                void __spawnfunc_##id(entity this); \
                [[accumulate]] void spawnfunc_##id(entity this) \
                { \
-                       if (__spawnfunc_expecting) \
-                       { \
+                   bool dospawn = true; \
+                   if (__spawnfunc_expecting > 1) { __spawnfunc_expecting = false; } \
+                       else if (__spawnfunc_expecting) { \
                                /* engine call */ \
+                if (!g_spawn_queue) { g_spawn_queue = IL_NEW(); } \
                                __spawnfunc_expecting = false; \
                                this = __spawnfunc_expect; \
                                __spawnfunc_expect = NULL; \
-                       } \
-                       else \
-                       { \
+                dospawn = false; \
+                       } else { \
+                           /* userland call */ \
                                assert(this); \
                        } \
-                       if (!this.sourceLoc) \
-                       { \
+                       if (!this.sourceLoc) { \
                                this.sourceLoc = __FILE__ ":" STR(__LINE__); \
                        } \
-                       if (!this.spawnfunc_checked) \
-                       { \
-                               for (int i = 0, n = numentityfields(); i < n; ++i) \
-                               { \
+                       if (!this.spawnfunc_checked) { \
+                               for (int i = 0, n = numentityfields(); i < n; ++i) { \
                                        string value = getentityfieldstring(i, this); \
                                        string fieldname = entityfieldname(i); \
                                        whitelist(_spawnfunc_checktypes) \
@@ -65,8 +102,15 @@ noref bool require_spawnfunc_prefix;
                                        LOG_WARNF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue."), #id, fieldname, value); \
                                } \
                                this.spawnfunc_checked = true; \
+                               if (this) { \
+                    /* not worldspawn, delay spawn */ \
+                    __spawnfunc_defer(this, __spawnfunc_##id); \
+                } else { \
+                    /* world might not be "worldspawn" */ \
+                    this.__spawnfunc_constructor = __spawnfunc_##id; \
+                } \
                        } \
-                       __spawnfunc_##id(this); \
+                       if (dospawn) { __spawnfunc_##id(this); } \
                        if (__spawnfunc_unreachable_workaround) return; \
                } \
                void __spawnfunc_##id(entity this)
index 4642f76403c3124b6cdc30fb9b3f923263394548..1100c474cb9eb49074cd85d08431fd0f0ba61012 100644 (file)
@@ -33,8 +33,8 @@ int g_magic_stats_hole = 0;
        void stats_get() {}
        #define STAT(...) EVAL_STAT(OVERLOAD(STAT, __VA_ARGS__))
        #define EVAL_STAT(...) __VA_ARGS__
-    #define STAT_1(id) STAT_2(id, NULL)
-       #define STAT_2(id, cl) (0, _STAT(id))
+    #define STAT_1(id) (RVALUE, _STAT(id))
+       #define STAT_2(id, cl) STAT_1(id)
 
        #define getstat_int(id) getstati(id, 0, 24)
        #define getstat_bool(id) boolean(getstati(id))
@@ -61,9 +61,14 @@ int g_magic_stats_hole = 0;
                }
        #define REGISTER_STAT_3(x, T, expr) REGISTER_STAT_2(x, T)
 #elif defined(SVQC)
+    /** Internal use only */
+    entity STATS;
        /** Add all registered stats, access with `STAT(ID, player)` or `.type stat = _STAT(ID); player.stat` */
        void stats_add() {}
-       #define STAT(id, cl) (cl)._STAT(id)
+       #define STAT(...) EVAL_STAT(OVERLOAD_(STAT, __VA_ARGS__))
+    #define EVAL_STAT(...) __VA_ARGS__
+    #define STAT_1(id) (RVALUE, STAT_2(id, STATS))
+       #define STAT_2(id, cl) (cl)._STAT(id)
 
        #define addstat_int(id, fld) addstat(id, AS_INT, fld)
        #define addstat_bool(id, fld) addstat(id, AS_INT, fld)
@@ -83,9 +88,10 @@ int g_magic_stats_hole = 0;
        const int AS_FLOAT = 8;
 
        .int __stat_null;
-       /** Prevent engine stats being sent */
-       STATIC_INIT(stats_clear)
+       STATIC_INIT(stats)
        {
+           STATS = new(stats);
+           // Prevent engine stats being sent
                int r = STATS_ENGINE_RESERVE;
                for (int i = 0, n = 256 - r; i < n; ++i) {
                        #define X(_, name, id) if (i == id) continue;
@@ -111,10 +117,11 @@ int g_magic_stats_hole = 0;
                        addstat_##T(STAT_##id.m_id, fld); \
                }
        void GlobalStats_update(entity this) {}
+    /** TODO: do we want the global copy to update? */
     #define REGISTER_STAT_3(id, T, expr) \
        REGISTER_STAT_2(id, T); \
        [[accumulate]] void GlobalStats_update(entity this) { STAT(id, this) = (expr); } \
-       STATIC_INIT(worldstat_##id) { entity this = NULL; STAT(id, this) = (expr); }
+       STATIC_INIT(worldstat_##id) { entity this = STATS; STAT(id, this) = (expr); }
 #else
        #define REGISTER_STAT_2(id, type)
     #define REGISTER_STAT_3(id, T, expr)
index f585a9a2c33db3eafb7b72168b2b3d8a50de8afd..fa8cee7172c6d96b73e630b417079f4d9f55211d 100644 (file)
@@ -165,12 +165,7 @@ int autocvar_g_maxplayers;
 float autocvar_g_maxplayers_spectator_blocktime;
 float autocvar_g_maxpushtime;
 float autocvar_g_maxspeed;
-#define autocvar_g_instagib cvar("g_instagib")
-bool autocvar_g_instagib_damagedbycontents = true;
-bool autocvar_g_instagib_blaster_keepdamage = false;
-bool autocvar_g_instagib_blaster_keepforce = false;
-bool autocvar_g_instagib_mirrordamage;
-bool autocvar_g_instagib_friendlypush = true;
+bool autocvar_g_instagib;
 #define autocvar_g_mirrordamage cvar("g_mirrordamage")
 #define autocvar_g_mirrordamage_virtual cvar("g_mirrordamage_virtual")
 bool autocvar_g_mirrordamage_onlyweapons;
@@ -416,7 +411,6 @@ float autocvar_g_monsters_armor_blockpercent;
 float autocvar_g_monsters_healthbars;
 bool autocvar_g_monsters_lineofsight = true;
 //bool autocvar_g_monsters_ignoretraces = true;
-#define autocvar_g_bloodloss cvar("g_bloodloss")
 bool autocvar_g_nades;
 bool autocvar_g_nades_override_dropweapon = true;
 vector autocvar_g_nades_throw_offset;
index 64aa03b5026d5b62f0e24df6fc731389a8b637e9..c47952c5d99f0c83231c5916c6f47e0fcfb13183 100644 (file)
@@ -521,7 +521,7 @@ void detect_maptype()
                o.y += random() * (world.maxs.y - world.mins.y);
                o.z += random() * (world.maxs.z - world.mins.z);
 
-               tracebox(o, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), o - '0 0 32768', MOVE_WORLDONLY, NULL);
+               tracebox(o, STAT(PL_MIN), STAT(PL_MAX), o - '0 0 32768', MOVE_WORLDONLY, NULL);
                if(trace_fraction == 1)
                        continue;
 
@@ -936,6 +936,7 @@ spawnfunc(worldspawn)
        WinningConditionHelper(this); // set worldstatus
 
        world_initialized = 1;
+       __spawnfunc_spawn_all();
 }
 
 spawnfunc(light)
index c5bbe75e1e4382d259da687c53946b2e445eb530..edf4ff16238ee591537546037eba9eff8fe14750 100644 (file)
@@ -1,9 +1,8 @@
+#include "resources.qh"
 /// \file
 /// \brief Source file that contains implementation of the resource system.
 /// \author Lyberta
-/// \copyright GNU GPLv3 or any later version.
-
-#include "resources.qh"
+/// \copyright GNU GPLv2 or any later version.
 
 #include "autocvars.qh"
 #include "miscfunctions.qh"
index 522ff5b68d5ad4dd7ed52825689f328c9825da72..ce8e1e8e5daaa3f023cfe169f814a5aa5c8ba89c 100644 (file)
@@ -1,9 +1,8 @@
+#pragma once
 /// \file
 /// \brief Header file that describes the resource system.
 /// \author Lyberta
-/// \copyright GNU GPLv3 or any later version.
-
-#pragma once
+/// \copyright GNU GPLv2 or any later version.
 
 /// \brief Unconditional maximum amount of resources the entity can have.
 const int RESOURCE_AMOUNT_HARD_LIMIT = 999;
index 1a5c8e5511420bbd00c066e37f9a641660f4ad69..68e7b375b507a09051f3607114f60d14cd9da0f2 100644 (file)
@@ -247,6 +247,77 @@ void StartFrame()
 .string gametypefilter;
 .string cvarfilter;
 bool DoesQ3ARemoveThisEntity(entity this);
+
+/**
+ * Evaluate an expression of the form: [+ | -]? [var[op]val | [op]var | val | var] ...
+ * +: all must match. this is the default
+ * -: one must NOT match
+ *
+ * var>x
+ * var<x
+ * var>=x
+ * var<=x
+ * var==x
+ * var!=x
+ * var===x
+ * var!==x
+ */
+bool expr_evaluate(string s)
+{
+    bool ret = false;
+    if (str2chr(s, 0) == '+') {
+        s = substring(s, 1, -1);
+    } else if (str2chr(s, 0) == '-') {
+        ret = true;
+        s = substring(s, 1, -1);
+    }
+    bool expr_fail = false;
+    for (int i = 0, n = tokenize_console(s); i < n; ++i) {
+        int o;
+        string k, v;
+        s = argv(i);
+        #define X(expr) \
+            if (expr) { \
+                continue; \
+            } else { \
+                expr_fail = true; \
+                break; \
+            }
+        #define BINOP(op, len, expr) \
+            if ((o = strstrofs(s, op, 0)) >= 0) { \
+                k = substring(s, 0, o); \
+                v = substring(s, o + len, -1); \
+                X(expr); \
+            }
+        BINOP(">=", 2, cvar(k) >= stof(v));
+        BINOP("<=", 2, cvar(k) <= stof(v));
+        BINOP(">",  1, cvar(k) >  stof(v));
+        BINOP("<",  1, cvar(k) <  stof(v));
+        BINOP("==", 2, cvar(k) == stof(v));
+        BINOP("!=", 2, cvar(k) != stof(v));
+        BINOP("===", 3, cvar_string(k) == v);
+        BINOP("!==", 3, cvar_string(k) != v);
+        {
+            k = s;
+            bool b = true;
+            if (str2chr(k, 0) == '!') {
+                k = substring(s, 1, -1);
+                b = false;
+            }
+            float f = stof(k);
+            bool isnum = ftos(f) == k;
+            X(boolean(isnum ? f : cvar(k)) == b);
+        }
+        #undef BINOP
+        #undef X
+    }
+    if (!expr_fail) {
+        ret = !ret;
+    }
+    // now ret is true if we want to keep the item, and false if we want to get rid of it
+    return ret;
+}
+
 void SV_OnEntityPreSpawnFunction(entity this)
 {
        __spawnfunc_expecting = true;
@@ -255,160 +326,44 @@ void SV_OnEntityPreSpawnFunction(entity this)
        if (this.gametypefilter != "")
        if (!isGametypeInFilter(MapInfo_LoadedGametype, teamplay, have_team_spawns, this.gametypefilter))
        {
-               delete(this);
-               __spawnfunc_expecting = false;
-               return;
+               goto cleanup;
        }
-       if(this.cvarfilter != "")
-       {
-               float n, i, o, inv;
-               string s, k, v;
-               inv = 0;
-
-               s = this.cvarfilter;
-               if(substring(s, 0, 1) == "+")
-               {
-                       s = substring(s, 1, -1);
-               }
-               else if(substring(s, 0, 1) == "-")
-               {
-                       inv = 1;
-                       s = substring(s, 1, -1);
-               }
-
-               n = tokenize_console(s);
-               for(i = 0; i < n; ++i)
-               {
-                       s = argv(i);
-                       // syntax:
-                       // var>x
-                       // var<x
-                       // var>=x
-                       // var<=x
-                       // var==x
-                       // var!=x
-                       // var===x
-                       // var!==x
-                       if((o = strstrofs(s, ">=", 0)) >= 0)
-                       {
-                               k = substring(s, 0, o);
-                               v = substring(s, o+2, -1);
-                               if(cvar(k) < stof(v))
-                                       goto cvar_fail;
-                       }
-                       else if((o = strstrofs(s, "<=", 0)) >= 0)
-                       {
-                               k = substring(s, 0, o);
-                               v = substring(s, o+2, -1);
-                               if(cvar(k) > stof(v))
-                                       goto cvar_fail;
-                       }
-                       else if((o = strstrofs(s, ">", 0)) >= 0)
-                       {
-                               k = substring(s, 0, o);
-                               v = substring(s, o+1, -1);
-                               if(cvar(k) <= stof(v))
-                                       goto cvar_fail;
-                       }
-                       else if((o = strstrofs(s, "<", 0)) >= 0)
-                       {
-                               k = substring(s, 0, o);
-                               v = substring(s, o+1, -1);
-                               if(cvar(k) >= stof(v))
-                                       goto cvar_fail;
-                       }
-                       else if((o = strstrofs(s, "==", 0)) >= 0)
-                       {
-                               k = substring(s, 0, o);
-                               v = substring(s, o+2, -1);
-                               if(cvar(k) != stof(v))
-                                       goto cvar_fail;
-                       }
-                       else if((o = strstrofs(s, "!=", 0)) >= 0)
-                       {
-                               k = substring(s, 0, o);
-                               v = substring(s, o+2, -1);
-                               if(cvar(k) == stof(v))
-                                       goto cvar_fail;
-                       }
-                       else if((o = strstrofs(s, "===", 0)) >= 0)
-                       {
-                               k = substring(s, 0, o);
-                               v = substring(s, o+2, -1);
-                               if(cvar_string(k) != v)
-                                       goto cvar_fail;
-                       }
-                       else if((o = strstrofs(s, "!==", 0)) >= 0)
-                       {
-                               k = substring(s, 0, o);
-                               v = substring(s, o+2, -1);
-                               if(cvar_string(k) == v)
-                                       goto cvar_fail;
-                       }
-                       else if(substring(s, 0, 1) == "!")
-                       {
-                               k = substring(s, 1, -1);
-                               if(cvar(k))
-                                       goto cvar_fail;
-                       }
-                       else
-                       {
-                               k = s;
-                               if (!cvar(k))
-                                       goto cvar_fail;
-                       }
-               }
-               inv = !inv;
-LABEL(cvar_fail)
-               // now inv is 1 if we want to keep the item, and 0 if we want to get rid of it
-               if (!inv)
-               {
-                       //print("cvarfilter fail\n");
-                       delete(this);
-                       __spawnfunc_expecting = false;
-                       return;
-               }
+       if (this.cvarfilter != "" && !expr_evaluate(this.cvarfilter)) {
+        goto cleanup;
        }
 
-       if(DoesQ3ARemoveThisEntity(this))
-       {
-               delete(this);
-               __spawnfunc_expecting = false;
-               return;
+       if (DoesQ3ARemoveThisEntity(this)) {
+               goto cleanup;
        }
 
        set_movetype(this, this.movetype);
 
-       if(this.monster_attack)
+       if (this.monster_attack) {
                IL_PUSH(g_monster_targets, this);
+    }
 
        // support special -1 and -2 angle from radiant
-       if (this.angles == '0 -1 0')
+       if (this.angles == '0 -1 0') {
                this.angles = '-90 0 0';
-       else if (this.angles == '0 -2 0')
+       } else if (this.angles == '0 -2 0') {
                this.angles = '+90 0 0';
-
-       if(this.originjitter.x != 0)
-               this.origin_x = this.origin.x + (random() * 2 - 1) * this.originjitter.x;
-       if(this.originjitter.y != 0)
-               this.origin_y = this.origin.y + (random() * 2 - 1) * this.originjitter.y;
-       if(this.originjitter.z != 0)
-               this.origin_z = this.origin.z + (random() * 2 - 1) * this.originjitter.z;
-       if(this.anglesjitter.x != 0)
-               this.angles_x = this.angles.x + (random() * 2 - 1) * this.anglesjitter.x;
-       if(this.anglesjitter.y != 0)
-               this.angles_y = this.angles.y + (random() * 2 - 1) * this.anglesjitter.y;
-       if(this.anglesjitter.z != 0)
-               this.angles_z = this.angles.z + (random() * 2 - 1) * this.anglesjitter.z;
-       if(this.anglejitter != 0)
-               this.angles_y = this.angles.y + (random() * 2 - 1) * this.anglejitter;
-
-       if(MUTATOR_CALLHOOK(OnEntityPreSpawn, this))
-       {
-               delete(this);
-               __spawnfunc_expecting = false;
-               return;
+    }
+
+    #define X(out, in) MACRO_BEGIN \
+        if (in != 0) { out = out + (random() * 2 - 1) * in; } \
+    MACRO_END
+    X(this.origin.x, this.originjitter.x); X(this.origin.y, this.originjitter.y); X(this.origin.z, this.originjitter.z);
+    X(this.angles.x, this.anglesjitter.x); X(this.angles.y, this.anglesjitter.y); X(this.angles.z, this.anglesjitter.z);
+    X(this.angles.y, this.anglejitter);
+    #undef X
+
+       if (MUTATOR_CALLHOOK(OnEntityPreSpawn, this)) {
+               goto cleanup;
        }
+       return;
+LABEL(cleanup)
+    builtin_remove(this);
+    __spawnfunc_expecting = false;
 }
 
 void WarpZone_PostInitialize_Callback()
index 6f70f09beec2219624baeca92e2cd7deaa104fb4..7f86d19c01a47bc83cfd2870c0f0c170a0e93b99 100644 (file)
@@ -1 +1,3 @@
 #pragma once
+
+bool expr_evaluate(string s);
index e93a03201a9ddf4233b229126b69d15bca035de6..4a9145f150262b57c343bab137a7ae5127b31e36 100644 (file)
@@ -43,8 +43,14 @@ void InitGameplayMode()
 
        // find out good world mins/maxs bounds, either the static bounds found by looking for solid, or the mapinfo specified bounds
        get_mi_min_max(1);
-       world.mins = mi_min;
-       world.maxs = mi_max;
+       // assign reflectively to avoid "assignment to world" warning
+       int done = 0; for (int i = 0, n = numentityfields(); i < n; ++i) {
+           string k = entityfieldname(i); vector v = (k == "mins") ? mi_min : (k == "maxs") ? mi_max : '0 0 0';
+           if (v) {
+            putentityfieldstring(i, world, sprintf("%d %d %d", v));
+            if (++done == 2) break;
+        }
+       }
        // currently, NetRadiant's limit is 131072 qu for each side
        // distance from one corner of a 131072qu cube to the opposite corner is approx. 227023 qu
        // set the distance according to map size but don't go over the limit to avoid issues with float precision