]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Mario/wepent_experimental
authorMario <mario@smbclan.net>
Mon, 24 Oct 2016 17:47:15 +0000 (03:47 +1000)
committerMario <mario@smbclan.net>
Mon, 24 Oct 2016 17:47:15 +0000 (03:47 +1000)
47 files changed:
.gitlab-ci.yml
mutators.cfg
physicsX.cfg
qcsrc/common/monsters/monster/shambler.qc
qcsrc/common/monsters/monster/spider.qc
qcsrc/common/monsters/spawner.qc
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/monsters/sv_spawn.qc
qcsrc/common/monsters/sv_spawn.qh
qcsrc/common/mutators/mutator/_mod.inc
qcsrc/common/mutators/mutator/_mod.qh
qcsrc/common/mutators/mutator/damagetext/damagetext.qc
qcsrc/common/mutators/mutator/nades/nades.qc
qcsrc/common/mutators/mutator/overkill/rpc.qc
qcsrc/common/mutators/mutator/walljump/_mod.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/walljump/_mod.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/walljump/walljump.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/walljump/walljump.qh [new file with mode: 0644]
qcsrc/common/stats.qh
qcsrc/common/triggers/func/breakable.qc
qcsrc/common/turrets/turret/ewheel.qc
qcsrc/common/turrets/turret/walker.qc
qcsrc/common/vehicles/sv_vehicles.qc
qcsrc/common/weapons/weapon/arc.qc
qcsrc/common/weapons/weapon/devastator.qc
qcsrc/common/weapons/weapon/electro.qc
qcsrc/common/weapons/weapon/hagar.qc
qcsrc/common/weapons/weapon/hook.qc
qcsrc/common/weapons/weapon/minelayer.qc
qcsrc/common/weapons/weapon/mortar.qc
qcsrc/common/weapons/weapon/seeker.qc
qcsrc/lib/warpzone/client.qc
qcsrc/lib/warpzone/common.qc
qcsrc/lib/warpzone/common.qh
qcsrc/lib/warpzone/server.qc
qcsrc/lib/warpzone/server.qh
qcsrc/menu/xonotic/dialog_settings_game_model.qc
qcsrc/server/client.qc
qcsrc/server/command/common.qc
qcsrc/server/defs.qh
qcsrc/server/g_hook.qc
qcsrc/server/mutators/events.qh
qcsrc/server/mutators/mutator/gamemode_assault.qc
qcsrc/server/mutators/mutator/gamemode_ctf.qc
qcsrc/server/mutators/mutator/gamemode_invasion.qc
qcsrc/server/player.qc
qcsrc/server/sv_main.qc

index ca68171be7bd7725de37c58f8c34bdb120894ef6..3c251dccc6bab8b822b9bf94bd5fb2e2c1d54d9e 100644 (file)
@@ -30,7 +30,7 @@ test_sv_game:
     - wget -O data/maps/g-23.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.cache
     - wget -O data/maps/g-23.waypoints.hardwired https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/g-23.waypoints.hardwired
     - make
-    - EXPECT=f17c2b4e7a8619ff77983de267669802
+    - EXPECT=0a9ea83e32e148da989cbbadc7421ea0
     - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
       | tee /dev/stderr
       | grep '^:'
index 4b8f1a2376ce25874e880eebba7340762a64f93c..abb74df30eebd389fe39cf431ad2a1d144380a26 100644 (file)
@@ -411,3 +411,13 @@ seta cl_multijump 1 "allow multijump mutator"
 set g_multijump 0      "Number of multiple jumps to allow (jumping again in the air), -1 allows for infinite jumps"
 set g_multijump_add 0  "0 = make the current z velocity equal to jumpvelocity, 1 = add jumpvelocity to the current z velocity"
 set g_multijump_speed -999999  "Minimum vertical speed a player must have in order to jump again"
+
+
+// ===========
+//  wall jump
+// ===========
+set g_walljump 0 "Enable wall jumping mutator"
+set g_walljump_delay 1 "Minimum delay between wall jumps"
+set g_walljump_force 300 "How far to bounce/jump off the wall"
+set g_walljump_velocity_xy_factor 1.15 "How much to slow down along horizontal axis, higher value = higher deceleration, if factor is < 1, you accelerate by wall jumping"
+set g_walljump_velocity_z_factor 0.5 "Upwards velocity factor, multiplied by normal jump velocity"
\ No newline at end of file
index 1fe218f06adf5d9837cf570c79720d8bf3b16859..2ef0689755b7814c6913b67a73a623fb000cf42b 100644 (file)
@@ -17,7 +17,7 @@ sv_stepheight 31
 // Samual: 31 (just below 32, keeping things smooth without allowing 32qu steps)
 
 // jump duration == 2*sv_jumpvelocity / sv_gravity
-// in this case: 0.6888888888 (thus either 20 or 21 frames)
+// in this case: 0.65 (thus either 19 or 20 frames)
 // jump height == sv_jumpvelocity^2 / (2*sv_gravity)
 // in this case: 42.25
 // player: 24+45 qu
index 8b5c268ffd860940073a5c7042832d84d4adc830..6baa4534754e499164665095255cc8a580256104 100644 (file)
@@ -142,6 +142,7 @@ void M_Shambler_Attack_Lightning(entity this)
        gren.damageforcescale = 0;
        gren.event_damage = M_Shambler_Attack_Lightning_Damage;
        gren.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, gren);
        gren.missile_flags = MIF_SPLASH | MIF_ARC;
        W_SetupProjVelocity_Explicit(gren, v_forward, v_up, (autocvar_g_monster_shambler_attack_lightning_speed), (autocvar_g_monster_shambler_attack_lightning_speed_up), 0, 0, false);
 
index 897664af51eb8e1c08039d403a3ff0f92489acee..8c90ade8a4c0f3c41bd1fd46edebce68667c0285 100644 (file)
@@ -161,6 +161,7 @@ void M_Spider_Attack_Web(entity this)
        IL_PUSH(g_projectiles, proj);
        IL_PUSH(g_bot_dodge, proj);
        proj.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, proj);
 
        proj.bouncefactor = 0.3;
        proj.bouncestop = 0.05;
index 235a24b43aad2d999444ee6be1395a3b55165026..0b34d13e659633a1892e10db93771a761ad4b629 100644 (file)
@@ -15,7 +15,7 @@ void spawner_use(entity this, entity actor, entity trigger)
        e.noalign = this.noalign;
        e.angles = this.angles;
        e.monster_skill = this.monster_skill;
-       e = spawnmonster(e, this.spawnmob, 0, this, this, this.origin, false, false, this.monster_moveflags);
+       e = spawnmonster(e, this.spawnmob, 0, this, this, this.origin, false, true, this.monster_moveflags);
 }
 
 spawnfunc(monster_spawner)
index 80fe726e348be6ac71af298e8e773eee34302524..a89e55b1ce0b6644ddde27b59bacb7b30dbefa03 100644 (file)
@@ -1328,6 +1328,8 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id)
        this.bot_attack                 = true;
        this.iscreature                 = true;
        this.teleportable               = true;
+       if(!this.damagedbycontents)
+               IL_PUSH(g_damagedbycontents, this);
        this.damagedbycontents  = true;
        this.monsterid                  = mon_id;
        this.event_damage               = Monster_Damage;
index 056379dbc41f0a88c9e9f7f03026f694bd511778..6d9daa2964cbb4c6c5c1d4c25561e22fcf2c2731 100644 (file)
@@ -8,12 +8,12 @@
     #include <server/autocvars.qh>
     #include <server/defs.qh>
 #endif
-entity spawnmonster (entity e, string monster, int monster_id, entity spawnedby, entity own, vector orig, bool respwn, bool invincible, int moveflag)
+entity spawnmonster (entity e, string monster, int monster_id, entity spawnedby, entity own, vector orig, bool respwn, bool removeifinvalid, int moveflag)
 {
        e.spawnflags = MONSTERFLAG_SPAWNED;
 
        if(!respwn) { e.spawnflags |= MONSTERFLAG_NORESPAWN; }
-       if(invincible) { e.spawnflags |= MONSTERFLAG_INVINCIBLE; }
+       //if(invincible) { e.spawnflags |= MONSTERFLAG_INVINCIBLE; }
 
        setorigin(e, orig);
 
@@ -39,8 +39,17 @@ entity spawnmonster (entity e, string monster, int monster_id, entity spawnedby,
                                break;
                        }
                });
-               if(!found)
-                       monster_id = ((monster_id > 0) ? monster_id : MON_FIRST);
+
+               if(!found && !monster_id)
+               {
+                       if(removeifinvalid)
+                       {
+                               delete(e);
+                               return NULL; // no good
+                       }
+                       else
+                               monster_id = MON_FIRST;
+               }
        }
 
        e.realowner = spawnedby;
index 8e4d480cd690ddfbab268494ee512090a74a2881..983676db87d3c4a225dd141db6017ebe173624d4 100644 (file)
@@ -1,3 +1,3 @@
 #pragma once
 
-entity spawnmonster (entity e, string monster, int monster_id, entity spawnedby, entity own, vector orig, bool respwn, bool invincible, int moveflag);
+entity spawnmonster (entity e, string monster, int monster_id, entity spawnedby, entity own, vector orig, bool respwn, bool removeifinvalid, int moveflag);
index 294047d500527146349f13811e9c6368e297d53d..0d6326fef0712b405f0ad88a856c27a61ef646ab 100644 (file)
@@ -33,5 +33,6 @@
 #include <common/mutators/mutator/touchexplode/_mod.inc>
 #include <common/mutators/mutator/vampire/_mod.inc>
 #include <common/mutators/mutator/vampirehook/_mod.inc>
+#include <common/mutators/mutator/walljump/_mod.inc>
 #include <common/mutators/mutator/waypoints/_mod.inc>
 #include <common/mutators/mutator/weaponarena_random/_mod.inc>
index de43630bedbdd822f9afe88cdad9ebcbf64489e3..917dc6557ceb02b2415649bc6d9546e6a400c9c6 100644 (file)
@@ -33,5 +33,6 @@
 #include <common/mutators/mutator/touchexplode/_mod.qh>
 #include <common/mutators/mutator/vampire/_mod.qh>
 #include <common/mutators/mutator/vampirehook/_mod.qh>
+#include <common/mutators/mutator/walljump/_mod.qh>
 #include <common/mutators/mutator/waypoints/_mod.qh>
 #include <common/mutators/mutator/weaponarena_random/_mod.qh>
index 7beb19ffd74f7e03e22fab547a148978b83c3a1c..e55b9fcd91527f8b4b82d5a831303c27cf3a6e77 100644 (file)
@@ -1,24 +1,28 @@
 #include "damagetext.qh"
 
+#define DAMAGETEXT_PRECISION_MULTIPLIER 128
+#define DAMAGETEXT_SHORT_LIMIT 256 // the smallest value that we can't send as short - 2^15 (signed short) / DAMAGETEXT_PRECISION_MULTIPLIER
+
 REGISTER_MUTATOR(damagetext, true);
 
 #if defined(CSQC) || defined(MENUQC)
 // no translatable cvar description please
-AUTOCVAR_SAVE(cl_damagetext,                    bool,   true,      "Draw damage dealt where you hit the enemy");
-AUTOCVAR_SAVE(cl_damagetext_format,             string, "-{total}", "How to format the damage text. {health}, {armor}, {total}");
+AUTOCVAR_SAVE(cl_damagetext,                        bool,   true,       "Draw damage dealt where you hit the enemy");
+AUTOCVAR_SAVE(cl_damagetext_format,                 string, "-{total}", "How to format the damage text. {health}, {armor}, {total}");
 STATIC_INIT(DamageText_LegacyFormat) {
     if (strstrofs(autocvar_cl_damagetext_format, "{", 0) < 0) autocvar_cl_damagetext_format = "-{total}";
 }
-AUTOCVAR_SAVE(cl_damagetext_color,              vector, '1 1 0',    "Damage text color");
-AUTOCVAR_SAVE(cl_damagetext_color_per_weapon,   bool,   false,      "Damage text uses weapon color");
-AUTOCVAR_SAVE(cl_damagetext_size,               float,  8,          "Damage text font size");
-AUTOCVAR_SAVE(cl_damagetext_alpha_start,        float,  1,          "Damage text initial alpha");
-AUTOCVAR_SAVE(cl_damagetext_alpha_lifetime,     float,  3,          "Damage text lifetime in seconds");
-AUTOCVAR_SAVE(cl_damagetext_velocity,           vector, '0 0 20',   "Damage text move direction");
-AUTOCVAR_SAVE(cl_damagetext_offset,             vector, '0 -40 0',  "Damage text offset");
-AUTOCVAR_SAVE(cl_damagetext_accumulate_range,   float,  30,         "Damage text spawned within this range is accumulated");
-AUTOCVAR_SAVE(cl_damagetext_friendlyfire,       bool,   true,       "Show damage text for friendlyfire too");
-AUTOCVAR_SAVE(cl_damagetext_friendlyfire_color, vector, '1 0 0',    "Damage text color for friendlyfire");
+AUTOCVAR_SAVE(cl_damagetext_color,                  vector, '1 1 0',    "Damage text color");
+AUTOCVAR_SAVE(cl_damagetext_color_per_weapon,       bool,   false,      "Damage text uses weapon color");
+AUTOCVAR_SAVE(cl_damagetext_size,                   float,  8,          "Damage text font size");
+AUTOCVAR_SAVE(cl_damagetext_alpha_start,            float,  1,          "Damage text initial alpha");
+AUTOCVAR_SAVE(cl_damagetext_alpha_lifetime,         float,  3,          "Damage text lifetime in seconds");
+AUTOCVAR_SAVE(cl_damagetext_velocity,               vector, '0 0 20',   "Damage text move direction");
+AUTOCVAR_SAVE(cl_damagetext_offset,                 vector, '0 -40 0',  "Damage text offset");
+AUTOCVAR_SAVE(cl_damagetext_accumulate_range,       float,  30,         "Damage text spawned within this range is accumulated");
+AUTOCVAR_SAVE(cl_damagetext_accumulate_alpha_rel,   float,  0.65,       "Only update existing damage text when it's above this much percentage (0 to 1) of the starting alpha");
+AUTOCVAR_SAVE(cl_damagetext_friendlyfire,           bool,   true,       "Show damage text for friendlyfire too");
+AUTOCVAR_SAVE(cl_damagetext_friendlyfire_color,     vector, '1 0 0',    "Damage text color for friendlyfire");
 #endif
 
 #ifdef CSQC
@@ -57,9 +61,9 @@ CLASS(DamageText, Object)
                 if (w != WEP_Null) rgb = w.wpcolor;
             }
             string s = autocvar_cl_damagetext_format;
-            s = strreplace("{health}", sprintf("%d", this.m_damage), s);
-            s = strreplace("{armor}",  sprintf("%d", this.m_armordamage), s);
-            s = strreplace("{total}",  sprintf("%d", this.m_damage + this.m_armordamage), s);
+            s = strreplace("{health}", sprintf("%d", rint(this.m_damage / DAMAGETEXT_PRECISION_MULTIPLIER)), s);
+            s = strreplace("{armor}",  sprintf("%d", rint(this.m_armordamage / DAMAGETEXT_PRECISION_MULTIPLIER)), s);
+            s = strreplace("{total}",  sprintf("%d", rint((this.m_damage + this.m_armordamage) / DAMAGETEXT_PRECISION_MULTIPLIER)), s);
             drawcolorcodedstring2_builtin(pos, s, this.m_size * '1 1 0', rgb, this.alpha, DRAWFLAG_NORMAL);
         }
     }
@@ -70,7 +74,7 @@ CLASS(DamageText, Object)
         this.m_armordamage = _armor;
         this.m_deathtype = _deathtype;
         setorigin(this, _origin);
-        this.alpha = 1;
+        this.alpha = autocvar_cl_damagetext_alpha_start;
     }
 
     CONSTRUCTOR(DamageText, int _group, vector _origin, int _health, int _armor, int _deathtype, bool _friendlyfire) {
@@ -95,8 +99,8 @@ MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
     if (SV_DAMAGETEXT_DISABLED()) return;
     const entity attacker = M_ARGV(0, entity);
     const entity hit = M_ARGV(1, entity); if (hit == attacker) return;
-    const int health = M_ARGV(2, int);
-    const int armor = M_ARGV(3, int);
+    const float health = M_ARGV(2, float);
+    const float armor = M_ARGV(3, float);
     const int deathtype = M_ARGV(5, int);
     const vector location = hit.origin;
     FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA(
@@ -106,16 +110,26 @@ MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
             (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_SPEC(it) && it.enemy == attacker) ||
             (SV_DAMAGETEXT_SPECTATORS_ONLY() && IS_OBSERVER(it))
         ) {
+            int flags = SAME_TEAM(hit, attacker); // BIT(0)
+            if (health >= DAMAGETEXT_SHORT_LIMIT) flags |= BIT(1);
+            if (armor >= DAMAGETEXT_SHORT_LIMIT) flags |= BIT(2);
+
             msg_entity = it;
             WriteHeader(MSG_ONE, damagetext);
-            WriteShort(MSG_ONE, rint(health));
-            WriteShort(MSG_ONE, rint(armor));
             WriteEntity(MSG_ONE, hit);
             WriteCoord(MSG_ONE, location.x);
             WriteCoord(MSG_ONE, location.y);
             WriteCoord(MSG_ONE, location.z);
             WriteInt24_t(MSG_ONE, deathtype);
-            WriteByte(MSG_ONE, SAME_TEAM(hit, attacker));
+            WriteByte(MSG_ONE, flags);
+
+            // we need to send a few decimal places to minimize errors when accumulating damage
+            // sending them multiplied saves bandwidth compared to using WriteCoord,
+            // however if the multiplied damage would be too much for (signed) short, we send an int24
+            if (health >= DAMAGETEXT_SHORT_LIMIT) WriteInt24_t(MSG_ONE, health * DAMAGETEXT_PRECISION_MULTIPLIER);
+            else WriteShort(MSG_ONE, health * DAMAGETEXT_PRECISION_MULTIPLIER);
+            if (armor >= DAMAGETEXT_SHORT_LIMIT) WriteInt24_t(MSG_ONE, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
+            else WriteShort(MSG_ONE, armor * DAMAGETEXT_PRECISION_MULTIPLIER);
         }
     ));
 }
@@ -124,12 +138,18 @@ MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
 #ifdef CSQC
 NET_HANDLE(damagetext, bool isNew)
 {
-    int health = ReadShort();
-    int armor = ReadShort();
     int group = ReadShort();
     vector location = vec3(ReadCoord(), ReadCoord(), ReadCoord());
     int deathtype = ReadInt24_t();
-    bool friendlyfire = ReadByte();
+    int flags = ReadByte();
+    bool friendlyfire = flags & 1;
+
+    int health, armor;
+    if (flags & BIT(1)) health = ReadInt24_t();
+    else health = ReadShort();
+    if (flags & BIT(2)) armor = ReadInt24_t();
+    else armor = ReadShort();
+
     return = true;
     if (autocvar_cl_damagetext) {
         if (friendlyfire && !autocvar_cl_damagetext_friendlyfire) {
@@ -137,7 +157,7 @@ NET_HANDLE(damagetext, bool isNew)
         }
         if (autocvar_cl_damagetext_accumulate_range) {
             for (entity e = findradius(location, autocvar_cl_damagetext_accumulate_range); e; e = e.chain) {
-                if (e.instanceOfDamageText && e.m_group == group) {
+                if (e.instanceOfDamageText && e.m_group == group && e.alpha > autocvar_cl_damagetext_accumulate_alpha_rel * autocvar_cl_damagetext_alpha_start) {
                     DamageText_update(e, location, e.m_damage + health, e.m_armordamage + armor, deathtype);
                     return;
                 }
index f81b58c243494d18df148a347fb8096087eacdfa..71fb67af894d91c4f8c04aa83816ab357536b5e5 100644 (file)
@@ -941,6 +941,7 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time)
        _nade.gravity = 1;
        _nade.missile_flags = MIF_SPLASH | MIF_ARC;
        _nade.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, _nade);
        _nade.angles = vectoangles(_nade.velocity);
        _nade.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, _nade);
index 62f517da642433892657b69e26b49f103d7df5a1..745b87f85349714f4ffe81241ebcbb50a9d920e4 100644 (file)
@@ -82,6 +82,7 @@ void W_RocketPropelledChainsaw_Attack (Weapon thiswep, entity actor, .entity wea
        missile.health = WEP_CVAR(rpc, health);
        missile.event_damage = W_RocketPropelledChainsaw_Damage;
        missile.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, missile);
        set_movetype(missile, MOVETYPE_FLY);
 
        missile.projectiledeathtype = WEP_RPC.m_id;
diff --git a/qcsrc/common/mutators/mutator/walljump/_mod.inc b/qcsrc/common/mutators/mutator/walljump/_mod.inc
new file mode 100644 (file)
index 0000000..4f879c8
--- /dev/null
@@ -0,0 +1,4 @@
+// generated file; do not modify
+#ifdef GAMEQC
+    #include <common/mutators/mutator/walljump/walljump.qc>
+#endif
diff --git a/qcsrc/common/mutators/mutator/walljump/_mod.qh b/qcsrc/common/mutators/mutator/walljump/_mod.qh
new file mode 100644 (file)
index 0000000..59ab515
--- /dev/null
@@ -0,0 +1,4 @@
+// generated file; do not modify
+#ifdef GAMEQC
+       #include <common/mutators/mutator/walljump/walljump.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/walljump/walljump.qc b/qcsrc/common/mutators/mutator/walljump/walljump.qc
new file mode 100644 (file)
index 0000000..96b81a5
--- /dev/null
@@ -0,0 +1,70 @@
+#include "walljump.qh"
+
+#ifdef CSQC
+REGISTER_MUTATOR(walljump, true);
+#elif defined(SVQC)
+REGISTER_MUTATOR(walljump, cvar("g_walljump"));
+#endif
+
+#define PHYS_WALLJUMP(s)                                               STAT(WALLJUMP, s)
+#define PHYS_WALLJUMP_VELOCITY_Z_FACTOR(s)             STAT(WALLJUMP_VELOCITY_Z_FACTOR, s)
+#define PHYS_WALLJUMP_VELOCITY_XY_FACTOR(s)    STAT(WALLJUMP_VELOCITY_XY_FACTOR, s)
+#define PHYS_WALLJUMP_DELAY(s)                                         STAT(WALLJUMP_DELAY, s)
+#define PHYS_WALLJUMP_FORCE(s)                                         STAT(WALLJUMP_FORCE, s)
+
+vector PlayerTouchWall(entity this)
+{
+#define TRACE(newvec) \
+       tracebox (start, this.mins, this.maxs, (newvec), true, this); \
+       if (trace_fraction < 1 && vdist(this.origin - trace_endpos, <, dist) && trace_plane_normal_z < max_normal) \
+       if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)) \
+               return trace_plane_normal;
+
+       float dist = 10, max_normal = 0.2, scaler = 100;
+       vector start = this.origin;
+       TRACE(start + v_forward * scaler)
+       TRACE(start - v_forward * scaler)
+       TRACE(start + v_right * scaler)
+       TRACE(start - v_right * scaler)
+#undef TRACE
+       return '0 0 0';
+}
+
+MUTATOR_HOOKFUNCTION(walljump, PlayerJump)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(PHYS_WALLJUMP(player))
+       if(time - STAT(LASTWJ, player) > PHYS_WALLJUMP_DELAY(player)) // can't do this on client, as it's too stupid to obey counters
+       if(!IS_ONGROUND(player))
+       if(player.move_movetype != MOVETYPE_NONE && player.move_movetype != MOVETYPE_FOLLOW && player.move_movetype != MOVETYPE_FLY && player.move_movetype != MOVETYPE_NOCLIP)
+       if(!IS_JUMP_HELD(player))
+       if(!STAT(FROZEN, player))
+       if(!IS_DEAD(player))
+       {
+               vector plane_normal = PlayerTouchWall(player);
+               
+               if(plane_normal != '0 0 0')
+               {
+                       float wj_force = PHYS_WALLJUMP_FORCE(player);
+                       float wj_xy_factor = PHYS_WALLJUMP_VELOCITY_XY_FACTOR(player);
+                       float wj_z_factor = PHYS_WALLJUMP_VELOCITY_Z_FACTOR(player);
+                       player.velocity_x += plane_normal_x * wj_force;
+                       player.velocity_x /= wj_xy_factor;
+                       player.velocity_y += plane_normal_y * wj_force;
+                       player.velocity_y /= wj_xy_factor;
+                       player.velocity_z = PHYS_JUMPVELOCITY(player) * wj_z_factor;
+                       if(PHYS_INPUT_BUTTON_CROUCH(player)) player.velocity_z *= -1;
+
+#ifdef SVQC
+                       STAT(LASTWJ, player) = time;
+                       player.oldvelocity = player.velocity;
+                       Send_Effect(EFFECT_SMOKE_RING, trace_endpos, plane_normal, 5);
+                       PlayerSound(player, playersound_jump, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
+                       animdecide_setaction(player, ANIMACTION_JUMP, true);
+#endif
+
+                       M_ARGV(2, bool) = true; // multijump
+               }
+       }
+}
diff --git a/qcsrc/common/mutators/mutator/walljump/walljump.qh b/qcsrc/common/mutators/mutator/walljump/walljump.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index f9565db48bf0f54c4e57f893812b09a332c3dbcc..c4c5172aafb8d7f8bd141a7b1a764997bb717914 100644 (file)
@@ -235,6 +235,20 @@ REGISTER_STAT(JETPACK_REVERSE_THRUST, float, autocvar_g_jetpack_reverse_thrust)
 
 REGISTER_STAT(MOVEVARS_HIGHSPEED, float, autocvar_g_movement_highspeed)
 
+#ifdef SVQC
+AUTOCVAR(g_walljump, bool, false, "Enable wall jumping mutator");
+AUTOCVAR(g_walljump_delay, float, 1, "Minimum delay between wall jumps");
+AUTOCVAR(g_walljump_force, float, 300, "How far to bounce/jump off the wall");
+AUTOCVAR(g_walljump_velocity_xy_factor, float, 1.15, "How much to slow down along horizontal axis, higher value = higher deceleration, if factor is < 1, you accelerate by wall jumping");
+AUTOCVAR(g_walljump_velocity_z_factor, float, 0.5, "Upwards velocity factor, multiplied by normal jump velocity");
+#endif
+REGISTER_STAT(WALLJUMP, int, autocvar_g_walljump)
+REGISTER_STAT(WALLJUMP_VELOCITY_Z_FACTOR, float, autocvar_g_walljump_velocity_z_factor)
+REGISTER_STAT(WALLJUMP_VELOCITY_XY_FACTOR, float, autocvar_g_walljump_velocity_xy_factor)
+REGISTER_STAT(WALLJUMP_DELAY, float, autocvar_g_walljump_delay)
+REGISTER_STAT(WALLJUMP_FORCE, float, autocvar_g_walljump_force)
+REGISTER_STAT(LASTWJ, float)
+
 // freeze tag, clan arena
 REGISTER_STAT(REDALIVE, int)
 REGISTER_STAT(BLUEALIVE, int)
index d2c8ee06770202e2c23dc25b3fe3223caae385a9..b6dcd01f8843cc5f9310db9b93d213c4848e80ed 100644 (file)
@@ -109,6 +109,7 @@ void func_breakable_look_destroyed(entity this)
                        this.origin_z = floorZ;
                }
                _setmodel(this, this.mdl_dead);
+               ApplyMinMaxScaleAngles(this);
                this.effects &= ~EF_NODRAW;
        }
 
@@ -120,6 +121,7 @@ void func_breakable_look_destroyed(entity this)
 void func_breakable_look_restore(entity this)
 {
        _setmodel(this, this.mdl);
+       ApplyMinMaxScaleAngles(this);
        this.effects &= ~EF_NODRAW;
 
        if(this.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
index b5716f7a9867195973b98d95ffa254d883da85a6..0a633c78446431fdb0f0c841d67c5d70e49da369 100644 (file)
@@ -198,6 +198,7 @@ METHOD(EWheel, tr_setup, void(EWheel this, entity it))
     it.iscreature                              = true;
     it.teleportable                    = TELEPORT_NORMAL;
     it.damagedbycontents               = true;
+    IL_PUSH(g_damagedbycontents, it);
     set_movetype(it, MOVETYPE_WALK);
     it.solid                                   = SOLID_SLIDEBOX;
     it.takedamage                              = DAMAGE_AIM;
index ffba71439ab995198c760c69843a7bfbe1b3e3d7..de744a65d7a6c6109aa43736beb3df1c82d9eff3 100644 (file)
@@ -570,6 +570,7 @@ METHOD(WalkerTurret, tr_setup, void(WalkerTurret this, entity it))
     it.iscreature = true;
     it.teleportable = TELEPORT_NORMAL;
     it.damagedbycontents = true;
+    IL_PUSH(g_damagedbycontents, it);
     it.solid = SOLID_SLIDEBOX;
     it.takedamage = DAMAGE_AIM;
     if(it.move_movetype != MOVETYPE_WALK)
index 75d2f4635889e0d78b04229fff77ad0a5794ccf3..491962b67a5f74d14f193375de0cc4c49c7022e9 100644 (file)
@@ -905,7 +905,7 @@ bool vehicle_impulse(entity this, int imp)
 
 void vehicles_enter(entity pl, entity veh)
 {
-       // Remove this when bots know how to use vehicles
+   // Remove this when bots know how to use vehicles
        if((IS_BOT_CLIENT(pl) && !autocvar_g_vehicles_allow_bots))
                return;
 
@@ -1185,6 +1185,7 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
        this.iscreature                         = true;
        this.teleportable                       = false; // no teleporting for vehicles, too buggy
        this.damagedbycontents          = true;
+       IL_PUSH(g_damagedbycontents, this);
        this.vehicleid                          = info.vehicleid;
        this.PlayerPhysplug                     = info.PlayerPhysplug;
        this.event_damage                       = func_null;
@@ -1242,7 +1243,7 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
        else
                this.nextthink = time + game_starttime;
 
-       if(!MUTATOR_CALLHOOK(VehicleInit, this))
+       if(MUTATOR_CALLHOOK(VehicleInit, this))
                return false;
 
        return true;
index 89a87433bd2bdf0bb8cce7a35150fa491ab4ec89..88ba1c768c63cacf23e4ac0524f8dbb181ea13e6 100644 (file)
@@ -291,6 +291,7 @@ void W_Arc_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
        missile.damageforcescale = WEP_CVAR(arc, bolt_damageforcescale);
        missile.event_damage = W_Arc_Bolt_Damage;
        missile.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, missile);
 
        settouch(missile, W_Arc_Bolt_Touch);
        missile.use = W_Arc_Bolt_Explode_use;
index 7bae89368b3ec992524b61c2aa78f01eaeec6d70..a6473b39274c552dc2520dc218b08cfb42fcbc91 100644 (file)
@@ -390,6 +390,7 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        missile.health = WEP_CVAR(devastator, health);
        missile.event_damage = W_Devastator_Damage;
        missile.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, missile);
 
        set_movetype(missile, MOVETYPE_FLY);
        PROJECTILE_MAKETRIGGER(missile);
index 86f327e1c2689551c5cdc02f1f554821244580d4..46e46c24059660e8fd3b30b7ffe37da13d704d9d 100644 (file)
@@ -332,6 +332,7 @@ void W_Electro_Orb_Stick(entity this, entity to)
        newproj.event_damage = this.event_damage;
        newproj.spawnshieldtime = this.spawnshieldtime;
        newproj.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, newproj);
 
        set_movetype(newproj, MOVETYPE_NONE); // lock the orb in place
        newproj.projectiledeathtype = this.projectiledeathtype;
@@ -453,6 +454,8 @@ void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity)
        IL_PUSH(g_projectiles, proj);
        IL_PUSH(g_bot_dodge, proj);
        proj.damagedbycontents = (WEP_CVAR_SEC(electro, damagedbycontents));
+       if(proj.damagedbycontents)
+               IL_PUSH(g_damagedbycontents, proj);
 
        proj.bouncefactor = WEP_CVAR_SEC(electro, bouncefactor);
        proj.bouncestop = WEP_CVAR_SEC(electro, bouncestop);
index 96479d1abed52fc59fa1a9d2f94f8d9c7dbfd2ed..aa564565bb2c7cf591bdb298a2bdbeab66ad23a9 100644 (file)
@@ -155,6 +155,7 @@ void W_Hagar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        missile.damageforcescale = WEP_CVAR_PRI(hagar, damageforcescale);
        missile.event_damage = W_Hagar_Damage;
        missile.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, missile);
 
        settouch(missile, W_Hagar_Touch);
        missile.use = W_Hagar_Explode_use;
@@ -199,6 +200,7 @@ void W_Hagar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        missile.damageforcescale = WEP_CVAR_SEC(hagar, damageforcescale);
        missile.event_damage = W_Hagar_Damage;
        missile.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, missile);
 
        settouch(missile, W_Hagar_Touch2);
        missile.cnt = 0;
@@ -260,6 +262,7 @@ void W_Hagar_Attack2_Load_Release(entity actor, .entity weaponentity)
                missile.damageforcescale = WEP_CVAR_SEC(hagar, damageforcescale);
                missile.event_damage = W_Hagar_Damage;
                missile.damagedbycontents = true;
+               IL_PUSH(g_damagedbycontents, missile);
 
                settouch(missile, W_Hagar_Touch); // not bouncy
                missile.use = W_Hagar_Explode2_use;
index 091e2f516dcb9b5e809bba8f535f05e10836acab..ff815d4619115869dff624b175e2f066a2c6b2fe 100644 (file)
@@ -169,6 +169,7 @@ void W_Hook_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        gren.damageforcescale = WEP_CVAR_SEC(hook, damageforcescale);
        gren.event_damage = W_Hook_Damage;
        gren.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, gren);
        gren.missile_flags = MIF_SPLASH | MIF_ARC;
 
        gren.velocity = '0 0 1' * WEP_CVAR_SEC(hook, speed);
index 0e1db0f1b3862833240c34c0011e7429a057f81c..00f729b113e14f7bf87dc02eb1e006c1dc7a2f65 100644 (file)
@@ -93,6 +93,7 @@ void W_MineLayer_Stick(entity this, entity to)
        newmine.event_damage = this.event_damage;
        newmine.spawnshieldtime = this.spawnshieldtime;
        newmine.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, newmine);
 
        set_movetype(newmine, MOVETYPE_NONE); // lock the mine in place
        newmine.projectiledeathtype = this.projectiledeathtype;
@@ -363,6 +364,7 @@ void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        mine.health = WEP_CVAR(minelayer, health);
        mine.event_damage = W_MineLayer_Damage;
        mine.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, mine);
 
        set_movetype(mine, MOVETYPE_TOSS);
        PROJECTILE_MAKETRIGGER(mine);
index d8cb2d0699c3a27c90205a681b7d38ba62226580..56338da17182d72edbc50b1887e3fbb968786e8b 100644 (file)
@@ -242,6 +242,7 @@ void W_Mortar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        gren.damageforcescale = WEP_CVAR_PRI(mortar, damageforcescale);
        gren.event_damage = W_Mortar_Grenade_Damage;
        gren.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, gren);
        gren.missile_flags = MIF_SPLASH | MIF_ARC;
        W_SetupProjVelocity_UP_PRI(gren, mortar);
 
@@ -291,6 +292,7 @@ void W_Mortar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        gren.damageforcescale = WEP_CVAR_SEC(mortar, damageforcescale);
        gren.event_damage = W_Mortar_Grenade_Damage;
        gren.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, gren);
        gren.missile_flags = MIF_SPLASH | MIF_ARC;
        W_SetupProjVelocity_UP_SEC(gren, mortar);
 
index 7c02491f24c3002f86c5ab8974c9049c93a1bb76..20f5995e547c06c66a407f8267b03b149cfe17cd 100644 (file)
@@ -282,6 +282,7 @@ void W_Seeker_Fire_Missile(Weapon thiswep, entity actor, .entity weaponentity, v
        missile.health          = WEP_CVAR(seeker, missile_health);
        missile.damageforcescale = WEP_CVAR(seeker, missile_damageforcescale);
        missile.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, missile);
        //missile.think           = W_Seeker_Missile_Animate; // csqc projectiles.
 
        if(missile.enemy != NULL)
index bd0397f897330d876cdede80e284e1a2062ed0cf..15a3ca4c3ccc6e90870c72ab7bc74251777dd397 100644 (file)
@@ -35,6 +35,9 @@ NET_HANDLE(ENT_CLIENT_WARPZONE, bool isnew)
        }
        this.classname = "trigger_warpzone";
 
+       if(isnew)
+               IL_PUSH(g_warpzones, this);
+
        int f = ReadByte();
        this.warpzone_isboxy = (f & 1);
        if(f & 4)
index 90e3cd76c983a803a552b32ed7af220aaccb6b6e..5a3929e1e92d58ecd6520f0bbb05d68499e61f73 100644 (file)
@@ -154,31 +154,33 @@ float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
 entity WarpZone_Find(vector mi, vector ma)
 {
        // if we are near any warpzone planes - MOVE AWAY (work around nearclip)
-       entity e;
        if(!warpzone_warpzones_exist)
                return NULL;
-       for(e = NULL; (e = find(e, classname, "trigger_warpzone")); )
-               if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, NULL))
-                       return e;
+       IL_EACH(g_warpzones, WarpZoneLib_BoxTouchesBrush(mi, ma, it, NULL),
+       {
+               return it;
+       });
        return NULL;
 }
 
 void WarpZone_MakeAllSolid()
 {
-       entity e;
        if(!warpzone_warpzones_exist)
                return;
-       for(e = NULL; (e = find(e, classname, "trigger_warpzone")); )
-               e.solid = SOLID_BSP;
+       IL_EACH(g_warpzones, true,
+       {
+               it.solid = SOLID_BSP;
+       });
 }
 
 void WarpZone_MakeAllOther()
 {
-       entity e;
        if(!warpzone_warpzones_exist)
                return;
-       for(e = NULL; (e = find(e, classname, "trigger_warpzone")); )
-               e.solid = SOLID_TRIGGER;
+       IL_EACH(g_warpzones, true,
+       {
+               it.solid = SOLID_TRIGGER;
+       });
 }
 
 void WarpZone_Trace_InitTransform()
index 4bbbb853b00bad0266f2482cd5ef7efcccd738d3..26c0e80fe4623526ee12cecc05842fb92c4f5dd0 100644 (file)
@@ -3,6 +3,9 @@
 // uncomment this if your mod uses the roll angle in fixangle
 // #define KEEP_ROLL
 
+IntrusiveList g_warpzones;
+STATIC_INIT(g_warpzones) { g_warpzones = IL_NEW(); }
+
 float warpzone_warpzones_exist;
 float warpzone_cameras_exist;
 
index 34ea2610dedd7afa60e30ce6bab89f7df643940a..51d0e15ee53a4e80a786c0f5375a13e159b59e7c 100644 (file)
@@ -631,7 +631,6 @@ void WarpZone_InitStep_ClearTarget(entity this)
        this.enemy = NULL;
 }
 
-entity warpzone_first; .entity warpzone_next;
 void WarpZone_InitStep_FindTarget(entity this)
 {
        float i;
@@ -731,6 +730,8 @@ spawnfunc(trigger_warpzone)
        BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
        this.warpzone_next = warpzone_first;
        warpzone_first = this;
+
+       IL_PUSH(g_warpzones, this);
 }
 spawnfunc(func_camera)
 {
@@ -803,10 +804,19 @@ void WarpZone_StartFrame()
                WarpZone_PostInitialize_Callback();
        }
 
-       FOREACH_ENTITY_FLOAT(pure_data, false,
+       if(warpzone_warpzones_exist)
        {
-               if(warpzone_warpzones_exist)
+               IL_EACH(g_projectiles, true,
+               {
                        WarpZone_StoreProjectileData(it);
+               });
+       }
+               
+
+       FOREACH_CLIENT(true,
+       {
+               if(warpzone_warpzones_exist)
+                       WarpZone_StoreProjectileData(it); // TODO: not actually needed
 
                if(IS_OBSERVER(it) || it.solid == SOLID_NOT)
                if(IS_CLIENT(it)) // we don't care about it being a bot
index b0c583d2dc7bf31728f28e0d53de23219f689c22..4287ef60de798195e0e963d93736a7348a88d175 100644 (file)
@@ -1,6 +1,8 @@
 #pragma once
 
 #ifdef SVQC
+entity warpzone_first; .entity warpzone_next;
+
 void WarpZone_StartFrame();
 float WarpZone_Projectile_Touch(entity this, entity toucher);
 
index f0f95d74b95963fb540c5e330a538dc891f58199..b57d7cae8a8f536a643b67d25c1c7275a61801b6 100644 (file)
@@ -50,7 +50,12 @@ void XonoticGameModelSettingsTab_fill(entity me)
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_forceplayermodels", _("Force player models to mine")));
        me.TR(me);
-               me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_forceplayercolors", _("Force player colors to mine")));
+               me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Force player colors to mine")));
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_forceplayercolors"));
+                       e.addValue(e, _("Never"), "0");
+                       e.addValue(e, _("In non teamplay modes only"), "1");
+                       e.addValue(e, _("Always"), "2");
+                       e.configureXonoticTextSliderValues(e);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Body fading:")));
                me.TD(me, 1, 2, e = makeXonoticSlider(0, 2, 0.2, "cl_deathglow"));
index d592aea08c423c82a1c226f4174f2c4dc6fa603c..2a1340408652430f9d734179b03cc6bfde26a734 100644 (file)
@@ -298,6 +298,8 @@ void PutObserverInServer(entity this)
        TRANSMUTE(Observer, this);
        this.iscreature = false;
        this.teleportable = TELEPORT_SIMPLE;
+       if(this.damagedbycontents)
+               IL_REMOVE(g_damagedbycontents, this);
        this.damagedbycontents = false;
        this.health = FRAGS_SPECTATOR;
        SetSpectatee_status(this, etof(this));
@@ -517,6 +519,8 @@ void PutClientInServer(entity this)
                this.wasplayer = true;
                this.iscreature = true;
                this.teleportable = TELEPORT_NORMAL;
+               if(!this.damagedbycontents)
+                       IL_PUSH(g_damagedbycontents, this);
                this.damagedbycontents = true;
                set_movetype(this, MOVETYPE_WALK);
                this.solid = SOLID_SLIDEBOX;
index 01997d903a5f2e371c9bc2c3e2c77eadd3ed4043..5b01f134942729fe68f746328195d4c8d70665ae 100644 (file)
@@ -381,11 +381,11 @@ void CommonCommand_editmob(int request, entity caller, int argc)
                                        if (tmp_moncount >= autocvar_g_monsters_max_perplayer) { print_to(caller, "You can't spawn any more monsters"); return; }
 
                                        bool found = false;
-                                       for (int i = MON_FIRST; i <= MON_LAST; ++i)
+                                       FOREACH(Monsters, it != MON_Null && it.netname == arg_lower,
                                        {
-                                               mon = get_monsterinfo(i);
-                                               if (mon.netname == arg_lower) { found = true; break; }
-                                       }
+                                               found = true;
+                                               break;
+                                       });
 
                                        if (!found && arg_lower != "random") { print_to(caller, "Invalid monster"); return; }
 
index 1a2ef8d8ece9b59d4a0c18ef7d1ceb7877b76518..a149906288582fee6cbdee6ae8effca53405bac9 100644 (file)
@@ -465,3 +465,6 @@ STATIC_INIT(g_bot_targets) { g_bot_targets = IL_NEW(); }
 
 IntrusiveList g_bot_dodge;
 STATIC_INIT(g_bot_dodge) { g_bot_dodge = IL_NEW(); }
+
+IntrusiveList g_damagedbycontents;
+STATIC_INIT(g_damagedbycontents) { g_damagedbycontents = IL_NEW(); }
index 32cce331a50776da625ffa35df7544f86afbcc5f..e50a066618f91784c0e74aa0fb0acc0649382e7c 100644 (file)
@@ -414,6 +414,8 @@ void FireGrapplingHook(entity actor, .entity weaponentity)
        missile.takedamage = DAMAGE_AIM;
        missile.damageforcescale = 0;
        missile.damagedbycontents = (autocvar_g_balance_grapplehook_damagedbycontents);
+       if(missile.damagedbycontents)
+               IL_PUSH(g_damagedbycontents, missile);
 
        missile.hook_start = missile.hook_end = missile.origin;
 
index 2d19df72bfc5aa92011786a0177be6f4bff52678..3135d4e3d3d629a43b1d3f4c8ca68167bccf1d83 100644 (file)
@@ -357,8 +357,8 @@ MUTATOR_HOOKABLE(PlayerDamage_Calculate, EV_PlayerDamage_Calculate);
 #define EV_PlayerDamaged(i, o) \
     /** attacker  */ i(entity, MUTATOR_ARGV_0_entity) \
     /** target    */ i(entity, MUTATOR_ARGV_1_entity) \
-    /** health    */ i(int,    MUTATOR_ARGV_2_int) \
-    /** armor     */ i(int,    MUTATOR_ARGV_3_int) \
+    /** health    */ i(float,    MUTATOR_ARGV_2_float) \
+    /** armor     */ i(float,    MUTATOR_ARGV_3_float) \
     /** location  */ i(vector, MUTATOR_ARGV_4_vector) \
     /** deathtype */ i(int,    MUTATOR_ARGV_5_int) \
     /**/
@@ -543,7 +543,7 @@ MUTATOR_HOOKABLE(HelpMePing, EV_HelpMePing);
 
 /**
  * called when a vehicle initializes
- * return false to remove the vehicle
+ * return true to remove the vehicle
  */
 #define EV_VehicleInit(i, o) \
     /** vehicle */ i(entity, MUTATOR_ARGV_0_entity) \
index b032ab01949db9c6453da64da4d96058e9a926ce..1a1d7959fd2799b4e3908d3e13736b314106aced 100644 (file)
@@ -179,8 +179,6 @@ void assault_wall_think(entity this)
 
 // trigger new round
 // reset objectives, toggle spawnpoints, reset triggers, ...
-void vehicles_clearreturn(entity veh);
-void vehicles_spawn(entity this);
 void assault_new_round(entity this)
 {
        //bprint("ASSAULT: new round\n");
@@ -535,9 +533,7 @@ MUTATOR_HOOKFUNCTION(as, VehicleInit)
 {
        entity veh = M_ARGV(0, entity);
 
-       if(veh.active != ACTIVE_NOT)
-               veh.nextthink = time + 0.5;
-       return true;
+       veh.nextthink = time + 0.5;
 }
 
 MUTATOR_HOOKFUNCTION(as, HavocBot_ChooseRole)
index 0a3c622a9b0a3575f2d73c570e2866505362ec60..8120e1cb348a77e35e545eaa2c78733f41a2ea02 100644 (file)
@@ -1257,6 +1257,8 @@ void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag e
        flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP;
        flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable;
        flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable;
+       if(flag.damagedbycontents)
+               IL_PUSH(g_damagedbycontents, flag);
        flag.velocity = '0 0 0';
        flag.mangle = flag.angles;
        flag.reset = ctf_Reset;
index 4c0976fe82a2ae58f87ee29ee324434019533cff..efed23a5df41f48dd0897ffb72c8434412f1cb47 100644 (file)
@@ -77,11 +77,8 @@ void invasion_SpawnChosenMonster(Monster mon)
                setsize(e, mon.mins, mon.maxs);
 
                if(MoveToRandomMapLocation(e, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
-                       monster = spawnmonster(spawn(), "", mon.m_id, NULL, NULL, e.origin, false, false, 2);
+                       monster = spawnmonster(e, "", mon.m_id, NULL, NULL, e.origin, false, false, 2);
                else return;
-
-               setthink(e, SUB_Remove);
-               e.nextthink = time + 0.1;
        }
        else // if spawnmob field falls through (unset), fallback to mon (relying on spawnmonster for that behaviour)
                monster = spawnmonster(spawn(), spawn_point.spawnmob, mon.m_id, spawn_point, spawn_point, spawn_point.origin, false, false, 2);
index 1656ff003b873e10d681b9baaf6370dec8aefbee..f466c4dde1cd996030227084cb06b78df89bab7c 100644 (file)
@@ -63,6 +63,8 @@ void CopyBody(entity this, float keepvelocity)
        clone.iscreature = this.iscreature;
        clone.teleportable = this.teleportable;
        clone.damagedbycontents = this.damagedbycontents;
+       if(clone.damagedbycontents)
+               IL_PUSH(g_damagedbycontents, clone);
        clone.angles = this.angles;
        clone.v_angle = this.v_angle;
        clone.avelocity = this.avelocity;
@@ -213,6 +215,8 @@ void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float da
                this.alpha = -1;
                this.solid = SOLID_NOT; // restore later
                this.takedamage = DAMAGE_NO; // restore later
+               if(this.damagedbycontents)
+                       IL_REMOVE(g_damagedbycontents, this);
                this.damagedbycontents = false;
        }
 }
index ccc309be64703b6e32047297ec678a480edbdf68..b510b43c8076b0b81c606e44ca3e6f00b076eb95 100644 (file)
@@ -127,7 +127,8 @@ void CreatureFrame_FallDamage(entity this)
 
 void CreatureFrame_All()
 {
-       FOREACH_ENTITY_FLOAT(damagedbycontents, true, {
+       IL_EACH(g_damagedbycontents, it.damagedbycontents,
+       {
                if (it.move_movetype == MOVETYPE_NOCLIP) continue;
                CreatureFrame_Liquids(it);
                CreatureFrame_FallDamage(it);
@@ -412,8 +413,8 @@ LABEL(cvar_fail)
 void WarpZone_PostInitialize_Callback()
 {
        // create waypoint links for warpzones
-       entity e;
-       for(e = NULL; (e = find(e, classname, "trigger_warpzone")); )
+       //for(entity e = warpzone_first; e; e = e.warpzone_next)
+       for(entity e = NULL; (e = find(e, classname, "trigger_warpzone")); )
        {
                vector src, dst;
                src = (e.absmin + e.absmax) * 0.5;