]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge commit 'origin/fruitiex/newpanelhud'
authorRudolf Polzer <divverent@alientrap.org>
Thu, 6 May 2010 18:02:12 +0000 (20:02 +0200)
committerRudolf Polzer <divverent@alientrap.org>
Thu, 6 May 2010 18:02:12 +0000 (20:02 +0200)
Conflicts:
qcsrc/client/sbar.qc

51 files changed:
config_update.cfg
defaultXonotic.cfg
effectinfo.txt
physics10.cfg
physics11.cfg
physics151.cfg
physics151b.cfg
physics16rc1.cfg
physics20.cfg
physics25.cfg
physics26.cfg
physicsCPMA.cfg
physicsHavoc.cfg
physicsLeeStricklin.cfg [new file with mode: 0644]
physicsLzd.cfg
physicsNexrun.cfg
physicsNexrun_old.cfg
physicsNoQWBunny.cfg
physicsQ.cfg
physicsQ2.cfg
physicsQ2a.cfg
physicsQ3.cfg
physicsQBF.cfg
physicsQBFplus.cfg
physicsSamual.cfg
physicsWarsow.cfg
physicsWarsowClassicBunny.cfg
physicsWarsowDev.cfg
qcsrc/client/Main.qc
qcsrc/client/View.qc
qcsrc/client/csqc_builtins.qc
qcsrc/client/hud.qc
qcsrc/client/progs.src
qcsrc/client/target_music.qc [new file with mode: 0644]
qcsrc/common/constants.qh
qcsrc/common/mapinfo.qc
qcsrc/menu/xonotic/dialog_settings_audio.c
qcsrc/server/cl_client.qc
qcsrc/server/cl_physics.qc
qcsrc/server/cl_player.qc
qcsrc/server/extensions.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_world.qc
qcsrc/server/mutators/base.qh
qcsrc/server/progs.src
qcsrc/server/scores.qc
qcsrc/server/sv_main.qc
qcsrc/server/t_items.qc
qcsrc/server/target_music.qc [new file with mode: 0644]
qcsrc/server/target_spawn.qc
qcsrc/warpzonelib/common.qc

index 0143318be3e98c8aa12e4a1f110730582142e8e6..372784dd780c5cc14b7e4affc50518ddca673458 100644 (file)
@@ -20,3 +20,6 @@ _update_configversion_$g_configversion
 _update_generic
 
 set g_configversion 2
+
+// we now use mastervolume
+volume 1
index 6348745d3a0d25fd5391a9324612c2fade7c732d..a6d5d6bd147d7c12f68a01d4e74325e9f2b430eb 100644 (file)
@@ -245,6 +245,8 @@ cl_deathfade 1 // fade screen to dark red when dead, value represents how fast t
 cl_bobcycle 0 // how long the cycle of up/down view movement takes (only works if cl_bob is not 0), default is 0.6
 cl_bob 0.01 // how much view moves up/down when moving (does not move if cl_bobcycle is 0, but still enables cl_bobmodel), default is 0.02
 cl_bobmodel 1 // whether to have gun model move around on screen when moving (only works if cl_bob is not 0), default is 1
+cl_leanmodel 1 // enables weapon leaning effect when looking around
+cl_followmodel 1 // enables weapon pushing / pulling effect when walking
 cl_rollangle 0 // amount of view tilt when strafing, default is 2.0
 v_kicktime 0 // how long damage kicks of the view last, default is 0 seconds
 gl_polyblend 0.5 // whether to use screen tints, default is 1
@@ -311,6 +313,10 @@ set g_telefrags 1
 set g_telefrags_avoid 0
 set g_teleport_maxspeed 0 "maximum speed that a player can keep when going through a teleporter (if a misc_teleporter_dest also has a cap the smallest one of these will be used), 0 = don't limit, -1 = keep no speed"
 
+set g_respawn_ghosts 1 "if 1 dead bodies become ghosts and float away when the player respawns"
+set g_respawn_ghosts_speed 5 "the speed with which respawn ghosts float and rotate"
+set g_respawn_ghosts_maxtime 6 "maximum amount of time a respawn ghost can last, minimum time is half this value. 0 disables and ghosts fade when the body would"
+
 // fragmessage: This allows extra information to be displayed with the frag centerprints. 
 set sv_fragmessage_information_ping 0 "Enable ping display information, 0 = Never display; 1 = Always display (If the player is a bot, it will say bot instead of the ping.)"
 set sv_fragmessage_information_handicap 1 "Enable handicap display information, 0 = Never display; 1 = Only when the player has handicap on; 2 = Always display (Displays Off if off)"
@@ -1884,3 +1890,12 @@ mod_q1bsp_polygoncollisions 1
 // improve some minor details
 sv_gameplayfix_gravityunaffectedbyticrate 1
 sv_gameplayfix_nogravityonground 1
+
+// autodemo deleting
+seta cl_autodemo_delete_keeprecords 0 "when 1, records with a newly made race/cts demo are kept even if cl_autodemo_delete is used to delete demos"
+
+// freeze camera
+set cl_lockview 0 "when 1, the camera does not move any more"
+
+// we now use mastervolume
+volume 1
index 2885afb563c834ae6f7a6203ca53c8783f1d93dc..7dfb6713439325289360315abe338136f2521f31 100644 (file)
@@ -4630,3 +4630,17 @@ originjitter 10 10 10
 velocitymultiplier 20
 velocityoffset 0 0 10
 airfriction 1
+
+// effect for respawn ghosts
+// used in qcsrc/server/cl_client.qc:          pointparticles(particleeffectnum("respawn_ghost"), self.origin, '0 0 0', 1)
+effect respawn_ghost
+count 75
+type static
+color 0xA0A0A0 0xFFFFFF
+size 2 2
+alpha 32 64 128
+airfriction 1
+liquidfriction 4
+originoffset 0 0 -8
+originjitter 28 28 16
+velocityjitter 0 0 256
\ No newline at end of file
index 30f22a6cbc8e4f0a0ac843064df4e36880383c45..4d9a118b34054eaefa65f3d51a55d368faa25b65 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 46d6587b9e49af9a84b690d306a5d1ae871f7207..8fba5746a6449e439c5c8cbe79c3530a64067fcd 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index e56e6f1a334a84c2e219bd82a577db4e96584d7b..59cf1de9dd3c39e3331c2388c2c3deb8c68f361b 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 528f62336bdf65b4ca90d78469cdbfc3277a1ce1..6ab373ffaedf270e66f3132b3612168998c617bd 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index bdf1525518be8ffadbefede42bb266a339bcfde6..e6926e4c8ad39c9bdd166d34814879865787a7a7 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 6aaf747cc1c05ddac18ecf178af1dba271667f5f..39d1e6af5e6ec9ea8cc0304c518a2e02eda92e24 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index b60f74b9a580c8e046da2cff350e07bb3ff72a8c..048d2bb061b5afbee95706b1800c744e6ff3a9b4 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index a31467897663c3b706e5a0ab69b99e4983bb5301..b28cb4f7a0975389ac2da2bbc23e73607c29dc3a 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 95b34c25bdeeec83e7310cd058a528cf7d21647c..4ee66f297bc16ad994597771f9bbbdc959d5142f 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 2.5
 sv_airstrafeaccelerate 70
 sv_maxairstrafespeed 30
 sv_aircontrol 150
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 78d4240430771aec3fc85b43529e2a73b702d6f7..1731b12d4b32b73c84e755283802a392ea1ec1f3 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
diff --git a/physicsLeeStricklin.cfg b/physicsLeeStricklin.cfg
new file mode 100644 (file)
index 0000000..c0a5e21
--- /dev/null
@@ -0,0 +1,30 @@
+// These have been modified from Nexuiz 2.4.2's physicsQBR.cfg file
+sv_gravity 800
+sv_gravity 802
+sv_maxspeed 417
+sv_maxairspeed 202
+sv_stopspeed 100
+sv_accelerate 5.8
+sv_airaccelerate 5.5
+sv_friction 4.1
+edgefriction 1
+sv_stepheight 34
+sv_jumpvelocity 307
+sv_wateraccelerate -1
+sv_waterfriction -1
+sv_airaccel_sideways_friction 0.207
+sv_airaccel_qw -0.93
+sv_airstopaccelerate 0
+sv_airstrafeaccelerate 0
+sv_maxairstrafespeed 0
+sv_aircontrol 0
+sv_aircontrol_power 2
+sv_warsowbunny_turnaccel 0
+sv_warsowbunny_accel 0.1593
+sv_warsowbunny_topspeed 925
+sv_warsowbunny_backtosideratio 0.8
+sv_friction_on_land 0
+sv_doublejump 0
+sv_jumpspeedcap_min ""
+sv_jumpspeedcap_max ""
+sv_jumpspeedcap_max_disable_on_ramps 0
index 0349610e30309357587fd6bd7fb498c4d5da2ee2..d408285ea730d9592c40b784e0fc82be7f9aaabf 100644 (file)
@@ -18,6 +18,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 122c89b02270f12431187b497a7f4f17c01441f0..da81a24ee2a06a3537ee736bceb8dd130a346db4 100644 (file)
@@ -21,6 +21,7 @@ sv_airstopaccelerate 2.5
 sv_airstrafeaccelerate 70
 sv_maxairstrafespeed 30
 sv_aircontrol 150
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 6142cf2fc319cfcbd2dae6b6fca480d72eeab33d..164c48d4162e95346a94328d128fa8a750d9d4e1 100644 (file)
@@ -21,6 +21,7 @@ sv_airstopaccelerate 2.5
 sv_airstrafeaccelerate 70
 sv_maxairstrafespeed 30
 sv_aircontrol 150
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 363a425558d4e48e363f41bd513b247b7d2d3fb1..88290d68c4c1feb0676d57b3544704473b9e7dc3 100644 (file)
@@ -1,22 +1,23 @@
-// Xonotic 2.0-2.4.2 physics minus QW-bunnyhopping-bug, faster onground accel, CPMA air control
+// 2.0-2.4.2 physics minus QW-bunnyhopping-bug, faster onground accel, CPMA air control
 sv_gravity 800
-sv_maxspeed 320
-sv_maxairspeed 320
+sv_maxspeed 400
+sv_maxairspeed 220
 sv_stopspeed 100
-sv_accelerate 15
-sv_airaccelerate 5.5
-sv_friction 5
+sv_accelerate 12
+sv_airaccelerate 8
+sv_friction 7
 edgefriction 1
 sv_stepheight 34
 sv_jumpvelocity 300
 sv_wateraccelerate -1
 sv_waterfriction -1
-sv_airaccel_sideways_friction -1
+sv_airaccel_sideways_friction -0.125
 sv_airaccel_qw -0.95
 sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
-sv_aircontrol 70
+sv_aircontrol 100
+sv_aircontrol_power 3
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 51cf682f360ca615174528c9f98ebbf6e132f6ed..343971ca1df1229a10f21486605c48efb9ef09ef 100644 (file)
@@ -18,6 +18,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index ecbd2a3dde74c0640af838c773b0dabb78beb157..de8ff7239c7a23e5c1b10d256a082922ddd2f2cb 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 76c0ba17d91919283ae4ac2849fae94d2a9c79cc..ff08d0784f74edc5d310fe38715e06931c3899ff 100644 (file)
@@ -18,6 +18,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 6b8d4c1f85218e5e432c3e044daf09281b4cf21e..716728e9aa64849b0176e9aeb798ef5677b1c202 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 2e2d0b5e47fd5240d9511044bb2770947b3b1814..88e7e8f40e2e2dc5f932e21c4b43e39bfdda3181 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index f64b2be4676d186176f348996f726487fcdb07cc..7c5da3f5e281fdb2158864c4c22ca697e739424e 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index ce1d1d8c1f61720d6f4824e69be0bec4569416a1..3631c8011f140dd4871badad981bfe414f65044e 100644 (file)
@@ -16,6 +16,7 @@ sv_airstopaccelerate 0
 sv_airstrafeaccelerate 0
 sv_maxairstrafespeed 0
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index eeb919bf86c42084c368b7db836f4b83c953c75e..bc53f7a6764faf514828af8766f7f4b48ffd86bf 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 2.5
 sv_airstrafeaccelerate 70
 sv_maxairstrafespeed 30
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 9 // activates warsow movement mode
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 0a66f454377864ccc8ed3b065258a5969ce35858..6c60724d2228d343f1bab5c886b2c9400296f215 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 2.5
 sv_airstrafeaccelerate 70
 sv_maxairstrafespeed 30
 sv_aircontrol 150
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 0
 sv_warsowbunny_accel 0.1593
 sv_warsowbunny_topspeed 925
index 4f7fff927cc4b0ffedc38359d0dab238f867a5e0..324676d2ee587ccb6349ece0fec6a1f2ec21a596 100644 (file)
@@ -17,6 +17,7 @@ sv_airstopaccelerate 2
 sv_airstrafeaccelerate 70
 sv_maxairstrafespeed 30
 sv_aircontrol 0
+sv_aircontrol_power 2
 sv_warsowbunny_turnaccel 6 // activates warsow movement mode
 sv_warsowbunny_accel 0.1585
 sv_warsowbunny_topspeed 900
index 662d33e0f58866922224a4fad0881d5bb9afdeac..4462074503dc3d7e3f33026f9ea61ed58e03b4f4 100644 (file)
@@ -907,6 +907,7 @@ void(float bIsNewEntity) CSQC_Ent_Update =
                case ENT_CLIENT_TUBANOTE: Ent_TubaNote(bIsNewEntity); break;
                case ENT_CLIENT_WARPZONE: WarpZone_Read(bIsNewEntity); break;
                case ENT_CLIENT_WARPZONE_CAMERA: WarpZone_Camera_Read(bIsNewEntity); break;
+               case ENT_CLIENT_TRIGGER_MUSIC: Ent_ReadTriggerMusic(); break;
                default:
                        error(strcat("unknown entity type in CSQC_Ent_Update: ", ftos(self.enttype), "\n"));
                        break;
@@ -1236,6 +1237,10 @@ float CSQC_Parse_TempEntity()
                // NOTE: Could just do return instead of break...
        switch(nTEID)
        {
+               case TE_CSQC_TARGET_MUSIC:
+                       Net_TargetMusic();
+                       bHandled = true;
+                       break;
                case TE_CSQC_PICTURE:
                        Net_MapVote_Picture();
                        bHandled = true;
index 281a50d4bf3e986dd28d7118282f4187417307ec..0184c96765e9c00cad6e5dd1acdfa4a8de5a080c 100644 (file)
@@ -343,6 +343,8 @@ string NextFrameCommand;
 void CSQC_SPIDER_HUD();
 void CSQC_RAPTOR_HUD();
 
+vector freeze_pmove_org, freeze_input_angles;
+
 void CSQC_UpdateView(float w, float h)
 {
        entity e;
@@ -366,6 +368,17 @@ void CSQC_UpdateView(float w, float h)
        pmove_org = warpzone_fixview_origin - vo;
        input_angles = warpzone_fixview_angles;
 
+       if(cvar("cl_lockview"))
+       {
+               pmove_org = warpzone_fixview_origin = freeze_pmove_org;
+               input_angles = freeze_input_angles;
+               R_SetView(VF_ORIGIN, pmove_org + vo);
+               R_SetView(VF_ANGLES, input_angles);
+               //R_SetView(VF_CL_VIEWANGLES, input_angles);
+       }
+       freeze_pmove_org = pmove_org;
+       freeze_input_angles = input_angles;
+
        // Render the Scene
        if(!intermission || !view_set)
        {
@@ -404,6 +417,7 @@ void CSQC_UpdateView(float w, float h)
        }
 #endif
 
+       TargetMusic_Advance();
        Fog_Force();
 
        drawframetime = max(0.000001, time - drawtime);
index d3e42cd986a566348f5a193fe5b62fec97ff5290..c108a4ca0ab152a2239f0551e8364ab98c343a2f 100644 (file)
@@ -308,3 +308,5 @@ float PI      = 3.14159265358979323846264338327950288419716939937510582097494459
 float log(float f) = #532;
 
 void(entity e, entity ignore) tracetoss = #64;
+
+float(entity e, float ch) getsoundtime = #533; // (DP_SND_GETSOUNDTIME)
index 4a118d4b778c659a574d4ae95fdd7a97528e5f53..feab482e6a00a7fef71f99c224e44b8df9c1b8b4 100644 (file)
@@ -2302,8 +2302,15 @@ void CSQC_race_hud(void)
                rr = RACE_RECORD;
        t = stof(db_get(ClientProgsDB, strcat(shortmapname, rr, "time")));
 
-       if(score && score < t || !t)
+       if(score && (score < t || !t)) {
                db_put(ClientProgsDB, strcat(shortmapname, rr, "time"), ftos(score));
+               if(cvar("cl_autodemo_delete_keeprecords"))
+               {
+                       f = cvar("cl_autodemo_delete");
+                       f &~= 1;
+                       cvar_set("cl_autodemo_delete", ftos(f)); // don't delete demo with new record!
+               }
+       }
 
        if(t != crecordtime_prev) {
                crecordtime_prev = t;
index 9fc7ed3e8d246c2ef4aef59d1b6fc84f23ed4af1..ade8777247faa158c74630e492534a3036eed434 100644 (file)
@@ -52,6 +52,7 @@ effects.qc
 wall.qc
 modeleffects.qc
 tuba.qc
+target_music.qc
 
 //vehicles/spiderbot.qc
 Main.qc
diff --git a/qcsrc/client/target_music.qc b/qcsrc/client/target_music.qc
new file mode 100644 (file)
index 0000000..4ef9a37
--- /dev/null
@@ -0,0 +1,185 @@
+float music_disabled;
+entity music_default;
+entity music_target;
+entity music_trigger;
+
+.float state;
+
+void TargetMusic_Advance()
+{
+       // run AFTER all the thinks!
+       entity best, e;
+       float s0;
+       best = music_default;
+       if(music_target && time < music_target.lifetime)
+               best = music_target;
+       if(music_trigger)
+               best = music_trigger;
+       for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); ) if(e.noise)
+       {
+               s0 = e.state;
+               if(getsoundtime(e, CHAN_VOICE) < 0)
+               {
+                       s0 = -1;
+               }
+               if(e == best)
+               {
+                       // increase volume
+                       if(e.fade_time > 0)
+                               e.state = bound(0, e.state + frametime / e.fade_time, 1);
+                       else
+                               e.state = 1;
+               }
+               else
+               {
+                       // decrease volume
+                       if(e.fade_rate > 0)
+                               e.state = bound(0, e.state - frametime / e.fade_rate, 1);
+                       else
+                               e.state = 0;
+               }
+               if(e.state != s0)
+               {
+                       if(s0 < 0)
+                               sound(e, CHAN_VOICE, e.noise, e.volume * e.state * cvar("bgmvolume"), ATTN_NONE); // restart
+                       else
+                               sound(e, CHAN_VOICE, "", e.volume * e.state * cvar("bgmvolume"), ATTN_NONE);
+               }
+       }
+       music_trigger = world;
+}
+
+void Net_TargetMusic()
+{
+       float vol, fai, fao, tim, id;
+       string noi, s;
+       entity e;
+
+       id = ReadShort();
+       vol = ReadByte() / 255.0;
+       fai = ReadByte() / 16.0;
+       fao = ReadByte() / 16.0;
+       tim = ReadByte();
+       noi = ReadString();
+
+       for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); )
+       {
+               if(e.count == id)
+                       break;
+       }
+       if(!e)
+       {
+               e = spawn();
+               e.enttype = ENT_CLIENT_TRIGGER_MUSIC;
+       }
+       s = e.noise;
+       if(e.noise)
+               strunzone(e.noise);
+       e.noise = strzone(noi);
+       if(e.noise != s)
+       {
+               precache_sound(e.noise);
+               sound(e, CHAN_VOICE, e.noise, 0, ATTN_NONE);
+               if(getsoundtime(e, CHAN_VOICE) < 0)
+               {
+                       print("Cannot initialize sound ", e.noise, "\n");
+                       strunzone(e.noise);
+                       e.noise = string_null;
+               }
+       }
+       e.volume = vol;
+       e.fade_time = fai;
+       e.fade_rate = fao;
+       if(vol > 0)
+       {
+               if(tim == 0)
+               {
+                       music_default = e;
+                       if(!music_disabled)
+                       {
+                               e.state = 2;
+                               localcmd("cd stop\n"); // just in case
+                               music_disabled = 1;
+                       }
+               }
+               else
+               {
+                       music_target = e;
+                       e.lifetime = time + tim;
+               }
+       }
+}
+
+void Ent_TriggerMusic_Think()
+{
+       if(WarpZoneLib_BoxTouchesBrush(view_origin, view_origin, self, world))
+       {
+               music_trigger = self;
+       }
+       self.nextthink = time;
+}
+
+void Ent_TriggerMusic_Remove()
+{
+       if(self.noise)
+               strunzone(self.noise);
+       self.noise = string_null;
+}
+
+void Ent_ReadTriggerMusic()
+{
+       float f;
+       string s;
+       f = ReadByte();
+       if(f & 4)
+       {
+               self.origin_x = ReadCoord();
+               self.origin_y = ReadCoord();
+               self.origin_z = ReadCoord();
+       }
+       if(f & 1)
+       {
+               self.modelindex = ReadShort();
+               if(self.modelindex)
+               {
+                       self.mins_x = ReadCoord();
+                       self.mins_y = ReadCoord();
+                       self.mins_z = ReadCoord();
+                       self.maxs_x = ReadCoord();
+                       self.maxs_y = ReadCoord();
+                       self.maxs_z = ReadCoord();
+               }
+               else
+               {
+                       self.mins    = '0 0 0';
+                       self.maxs_x = ReadCoord();
+                       self.maxs_y = ReadCoord();
+                       self.maxs_z = ReadCoord();
+               }
+
+               self.volume = ReadByte() / 255.0;
+               self.fade_time = ReadByte() / 16.0;
+               self.fade_rate = ReadByte() / 16.0;
+               s = self.noise;
+               if(self.noise)
+                       strunzone(self.noise);
+               self.noise = strzone(ReadString());
+               if(self.noise != s)
+               {
+                       precache_sound(self.noise);
+                       sound(self, CHAN_VOICE, self.noise, 0, ATTN_NONE);
+                       if(getsoundtime(self, CHAN_VOICE) < 0)
+                       {
+                               print("Cannot initialize sound ", self.noise, "\n");
+                               strunzone(self.noise);
+                               self.noise = string_null;
+                       }
+               }
+       }
+
+       setorigin(self, self.origin);
+       setsize(self, self.mins, self.maxs);
+       self.cnt = 1;
+       self.think = Ent_TriggerMusic_Think;
+       self.nextthink = time;
+}
index f67f4dff9b929f62ecdf08cc59e1d5f77b539e79..3351913998a828fe37fb80be7bb83a7e042f85e3 100644 (file)
@@ -56,6 +56,7 @@ const float TE_CSQC_PINGPLREPORT = 107;
 const float TE_CSQC_VOTE = 108;
 const float TE_CSQC_VOTERESET = 109;
 const float TE_CSQC_ANNOUNCE = 110;
+const float TE_CSQC_TARGET_MUSIC = 111;
 
 const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
 const float RACE_NET_CHECKPOINT_CLEAR = 1;
@@ -98,6 +99,7 @@ const float ENT_CLIENT_MODELEFFECT = 22;
 const float ENT_CLIENT_TUBANOTE = 23;
 const float ENT_CLIENT_WARPZONE = 24;
 const float ENT_CLIENT_WARPZONE_CAMERA = 25;
+const float ENT_CLIENT_TRIGGER_MUSIC = 26;
 
 const float ENT_CLIENT_TURRET = 40;
 
@@ -371,7 +373,7 @@ float       CHAN_VOICE                              = 2; // Voice/Radio
        // on world: UNUSED
        // on players: voice                             VOICE
        // on entities: ambient                          AMBIENT
-       // on csqc: UNUSED
+       // on csqc: background music                     BGM
 float  CHAN_TRIGGER                    = 3; // Triggers/Items
        // on world: UNUSED
        // on players: item pickup                       ITEMS
index 003377e8c30d0d0ab15f5c590914ee9a2ea25d0b..53a07186b6a126461fa1af1a05f2445e7ee33539 100644 (file)
@@ -324,6 +324,8 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp
                                        { }
                                else if(startsWith(v, "weapon_"))
                                        MapInfo_Map_supportedFeatures |= MAPINFO_FEATURE_WEAPONS;
+                               else if(v == "target_music" || v == "trigger_music")
+                                       _MapInfo_Map_worldspawn_music = string_null; // don't use regular BGM
                        }
                }
        }
@@ -630,7 +632,7 @@ float MapInfo_Get_ByName(string pFilename, float pAllowGenerate, float pGametype
                        else
                                fputs(fh, strcat("cdtrack ", _MapInfo_Map_worldspawn_music, "\n"));
                }
-               else
+               else if(_MapInfo_Map_worldspawn_music)
                {
                        n = tokenize_console(cvar_string("g_cdtracks_remaplist"));
                        s = strcat(" ", cvar_string("g_cdtracks_dontusebydefault"), " ");
index 1c589eccd175a59b6a87c57037c7b832f046b3c1..7c3c754d4cce746dbb49ad9acf44c44ec8814fa4 100644 (file)
@@ -23,13 +23,14 @@ void fillXonoticAudioSettingsTab(entity me)
        entity e, s, sl;
 
        me.TR(me);
-               s = makeXonoticDecibelsSlider(-20, 0, 0.5, "bgmvolume");
-               me.TD(me, 1, 1, e = makeXonoticSliderCheckBox(-1000000, 1, s, "Music:"));
+               s = makeXonoticDecibelsSlider(-20, 0, 0.5, "mastervolume");
+               me.TD(me, 1, 1, e = makeXonoticSliderCheckBox(-1000000, 1, s, "Master:"));
                me.TD(me, 1, 2, s);
        me.TR(me);
-       me.TR(me);
-               s = makeXonoticDecibelsSlider(-20, 0, 0.5, "volume");
-               me.TD(me, 1, 1, e = makeXonoticSliderCheckBox(-1000000, 1, s, "Master:"));
+               me.TDempty(me, 0.2);
+               s = makeXonoticDecibelsSlider(-20, 0, 0.5, "bgmvolume");
+               makeMulti(s, "snd_csqcchannel2volume");
+               me.TD(me, 1, 0.8, e = makeXonoticSliderCheckBox(-1000000, 1, s, "Music:"));
                me.TD(me, 1, 2, s);
        me.TR(me);
                me.TDempty(me, 0.2);
index ef83ef63543c7dc1a77c1633be408fb5ba45a0c1..8a3fe88fd54ef39d6eb4de33f658417e57f7fba7 100644 (file)
@@ -1748,10 +1748,31 @@ void UpdateTeamBubble()
        else self.colormod = '1 1 1';
 };*/
 
+.float oldcolormap;
 void respawn(void)
 {
+       if(self.modelindex != 0 && cvar("g_respawn_ghosts"))
+       {
+               self.solid = SOLID_NOT;
+               self.takedamage = DAMAGE_NO;
+               self.movetype = MOVETYPE_FLY;
+               self.velocity = '0 0 1' * cvar("g_respawn_ghosts_speed");
+               self.avelocity = randomvec() * cvar("g_respawn_ghosts_speed") * 3 - randomvec() * cvar("g_respawn_ghosts_speed") * 3;
+               self.effects |= EF_ADDITIVE;
+               self.oldcolormap = self.colormap;
+               self.colormap = 512;
+               pointparticles(particleeffectnum("respawn_ghost"), self.origin, '0 0 0', 1);
+               if(cvar("g_respawn_ghosts_maxtime"))
+                       SUB_SetFade (self, time + cvar("g_respawn_ghosts_maxtime") / 2 + random () * (cvar("g_respawn_ghosts_maxtime") - cvar("g_respawn_ghosts_maxtime") / 2), 1.5);
+       }
+
        CopyBody(1);
        self.effects |= EF_NODRAW; // prevent another CopyBody
+       if(self.oldcolormap)
+       {
+               self.colormap = self.oldcolormap;
+               self.oldcolormap = 0;
+       }
        PutClientInServer();
 }
 
index 52477cb9a8976093372af11c0119dbd37238c3f7..ff5fbaa37ee4cf436796d3bc709e8164993c5de6 100644 (file)
@@ -14,6 +14,7 @@ float sv_airstopaccelerate;
 float sv_airstrafeaccelerate;
 float sv_maxairstrafespeed;
 float sv_aircontrol;
+float sv_aircontrol_power;
 float sv_warsowbunny_airforwardaccel;
 float sv_warsowbunny_accel;
 float sv_warsowbunny_topspeed;
@@ -416,10 +417,10 @@ void CPM_PM_Aircontrol(vector wishdir, float wishspeed)
        xyspeed = vlen(self.velocity); self.velocity = normalize(self.velocity);
 
        dot = self.velocity * wishdir;
-       k *= sv_aircontrol*dot*dot*frametime;
 
        if(dot > 0) // we can't change direction while slowing down
        {
+               k *= fabs(sv_aircontrol)*pow(dot, sv_aircontrol_power)*frametime;
                self.velocity = normalize(self.velocity * xyspeed + wishdir * k);
        }
 
index 8925f171340d0de0cbab5feb0076a9b3370aaa65..47b7ac069587e036ff5e583f15b55d43309f8814 100644 (file)
@@ -412,7 +412,7 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float
        self.dmg_take = self.dmg_take + take;//max(take - 10, 0);
        self.dmg_inflictor = inflictor;
 
-       if (self.health <= -75 && self.modelindex != 0)
+       if (self.health <= -100 && self.modelindex != 0)
        {
                // don't use any animations as a gib
                self.frame = 0;
@@ -636,6 +636,7 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht
 
                frag_attacker = attacker;
                frag_inflictor = inflictor;
+               frag_target = self;
                MUTATOR_CALLHOOK(PlayerDies);
 
                if(self.flagcarried)
index e5df457c150d293f0fcb182fd46f3b76f2e29b68..ea6f0b068945772a13e3aecf340e2dc461fcd35d 100644 (file)
@@ -1306,6 +1306,17 @@ float(entity clent) clienttype = #455; // returns one of the CLIENTTYPE_* consta
 //implementation notes:
 //entity customization is done before per-client culling (visibility for instance) because the entity may be doing setorigin to display itself in different locations on different clients, may be altering its .modelindex, .effects and other fields important to culling, so customized entities increase cpu usage (non-customized entities can use all the early culling they want however, as they are not changing on a per client basis).
 
+//DP_SV_DISCARDABLEDEMO
+//idea: parasti
+//darkplaces implementation: parasti
+//field definitions:
+.float discardabledemo;
+//description:
+//when this field is set to a non-zero value on a player entity, a possibly recorded server-side demo for the player is discarded
+//Note that this extension only works if:
+//  auto demos are enabled (the cvar sv_autodemo_perclient is set)
+//  discarding demos is enabled (the cvar sv_autodemo_perclient_discardable is set)
+
 //DP_SV_DRAWONLYTOCLIENT
 //idea: LordHavoc
 //darkplaces implementation: LordHavoc
index 338204c0c3a2cf30ba72cd7fff44b64b0e9d9c2d..0c446484d2a21d753aa8a7f4a744da7cbd529620 100644 (file)
@@ -149,6 +149,7 @@ void GiveFrags (entity attacker, entity targ, float f)
        entity oldself;
        oldself = self;
        self = attacker;
+       frag_attacker = attacker;
        frag_target = targ;
        frag_score = f;
        if(MUTATOR_CALLHOOK(GiveFragsForKill))
index 228782748d2aa6fd160719863791434b2fae502e..c815b0815a8539690c0c882f2b0e9b5a7663e6f5 100644 (file)
@@ -2697,6 +2697,7 @@ float RedirectionThink()
        return TRUE;
 }
 
+void TargetMusic_RestoreGame();
 void RestoreGame()
 {
        // Loaded from a save game
@@ -2710,6 +2711,8 @@ void RestoreGame()
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1);
        WeaponStats_Init();
+
+       TargetMusic_RestoreGame();
 }
 
 void SV_Shutdown()
index 9ed316ee1574a00bdbfe517894c6c2c259e86be6..73c16a9cd01c371a05d151d24499c82bf660faa8 100644 (file)
@@ -51,10 +51,12 @@ MUTATOR_HOOKABLE(PlayerDies);
        // INPUT:
                entity frag_inflictor;
                entity frag_attacker;
+               entity frag_target; // same as self
 
 MUTATOR_HOOKABLE(GiveFragsForKill);
        // called when someone was fragged by "self", and is expected to change frag_score to adjust scoring for the kill
        // INPUT:
+               entity frag_attacker; // same as self
                entity frag_target;
        // INPUT, OUTPUT:
                float frag_score;
index b325251cfd611ffdcf70b97112a5f1ff879ccacb..d1d0d1d3af9677dc9f6470d359a82707ee8f7b9c 100644 (file)
@@ -156,6 +156,7 @@ portals.qc
 
 target_spawn.qc
 func_breakable.qc
+target_music.qc
 
 ../common/items.qc
 
index 97b78ca7978a22e058ef4598f57c9c8b7b682340..59480ab656db12c789baf9852b8a52ad5e41f4d8 100644 (file)
@@ -324,7 +324,8 @@ float PlayerScore_Add(entity player, float scorefield, float score)
        {
                if(gameover)
                        return 0;
-               error("Adding score to unknown player!");
+               backtrace("Adding score to unknown player!");
+               return 0;
        }
        if(score)
                if(scores_label[scorefield] != "")
index f9eb9d2a0a41cb6fbf36c1653df8d28f8f7c1ba8..603aad7fd0977eb30b0f84f651db59d1677a1358 100644 (file)
@@ -191,6 +191,7 @@ void StartFrame (void)
        sv_airstrafeaccelerate = cvar("sv_airstrafeaccelerate");
        sv_maxairstrafespeed = cvar("sv_maxairstrafespeed");
        sv_aircontrol = cvar("sv_aircontrol");
+       sv_aircontrol_power = cvar("sv_aircontrol_power");
        sv_warsowbunny_airforwardaccel = cvar("sv_warsowbunny_airforwardaccel");
        sv_warsowbunny_accel = cvar("sv_warsowbunny_accel");
        sv_warsowbunny_topspeed = cvar("sv_warsowbunny_topspeed");
index 9d32f3234bf7ae2f429f4c4038f84e1666cc67df..d9c3240603852704483caeea7b341d8195221120 100644 (file)
@@ -682,6 +682,9 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
 {
        startitem_failed = FALSE;
 
+       self.items = itemid;
+       self.weapons = weaponid;
+
        // is it a dropped weapon?
        if (self.classname == "droppedweapon")
        {
@@ -702,9 +705,6 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
        }
        else
        {
-               self.items = itemid;
-               self.weapons = weaponid;
-
                if(MUTATOR_CALLHOOK(FilterItem)) // error means we do not want the item
                {
                        startitem_failed = TRUE;
diff --git a/qcsrc/server/target_music.qc b/qcsrc/server/target_music.qc
new file mode 100644 (file)
index 0000000..daab646
--- /dev/null
@@ -0,0 +1,129 @@
+.float lifetime;
+// values:
+//   volume
+//   noise
+//   targetname
+//   lifetime
+//   fade_time
+//   fade_rate
+// when triggered, the music is overridden for activator until lifetime (or forever, if lifetime is 0)
+// when targetname is not set, THIS ONE is default
+void target_music_sendto(float to, float is)
+{
+       WriteByte(to, SVC_TEMPENTITY);
+       WriteByte(to, TE_CSQC_TARGET_MUSIC);
+       WriteShort(to, num_for_edict(self));
+       WriteByte(to, self.volume * 255.0 * is);
+       WriteByte(to, self.fade_time * 16.0);
+       WriteByte(to, self.fade_rate * 16.0);
+       WriteByte(to, self.lifetime);
+       WriteString(to, self.noise);
+}
+void target_music_reset()
+{
+       if(self.targetname == "")
+               target_music_sendto(MSG_ALL, 1);
+}
+void target_music_use()
+{
+       if(!activator)
+               return;
+       msg_entity = activator;
+       target_music_sendto(MSG_ONE, 1);
+}
+void spawnfunc_target_music()
+{
+       self.use = target_music_use;
+       self.reset = target_music_reset;
+       if(!self.volume)
+               self.volume = 1;
+       if(self.targetname == "")
+               target_music_sendto(MSG_INIT, 1);
+       else
+               target_music_sendto(MSG_INIT, 0);
+}
+void TargetMusic_RestoreGame()
+{
+       for(self = world; (self = find(self, classname, "target_music")); )
+       {
+               if(self.targetname == "")
+                       target_music_sendto(MSG_INIT, 1);
+               else
+                       target_music_sendto(MSG_INIT, 0);
+       }
+}
+// values:
+//   volume
+//   noise
+//   targetname
+//   fade_time
+// spawnflags:
+//   1 = START_OFF
+// when triggered, it is disabled/enabled for everyone
+float trigger_music_SendEntity(entity to, float sf)
+{
+       WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
+       sf &~= 0x80;
+       if(self.cnt)
+               sf |= 0x80;
+       WriteByte(MSG_ENTITY, sf);
+       if(sf & 4)
+       {
+               WriteCoord(MSG_ENTITY, self.origin_x);
+               WriteCoord(MSG_ENTITY, self.origin_y);
+               WriteCoord(MSG_ENTITY, self.origin_z);
+       }
+       if(sf & 1)
+       {
+               if(self.model != "null")
+               {
+                       WriteShort(MSG_ENTITY, self.modelindex);
+                       WriteCoord(MSG_ENTITY, self.mins_x);
+                       WriteCoord(MSG_ENTITY, self.mins_y);
+                       WriteCoord(MSG_ENTITY, self.mins_z);
+                       WriteCoord(MSG_ENTITY, self.maxs_x);
+                       WriteCoord(MSG_ENTITY, self.maxs_y);
+                       WriteCoord(MSG_ENTITY, self.maxs_z);
+               }
+               else
+               {
+                       WriteShort(MSG_ENTITY, 0);
+                       WriteCoord(MSG_ENTITY, self.maxs_x);
+                       WriteCoord(MSG_ENTITY, self.maxs_y);
+                       WriteCoord(MSG_ENTITY, self.maxs_z);
+               }
+               WriteByte(MSG_ENTITY, self.volume * 255.0);
+               WriteByte(MSG_ENTITY, self.fade_time * 16.0);
+               WriteByte(MSG_ENTITY, self.fade_rate * 16.0);
+               WriteString(MSG_ENTITY, self.noise);
+       }
+       return 1;
+}
+void trigger_music_reset()
+{
+       self.cnt = !(self.spawnflags & 1);
+       self.SendFlags |= 0x80;
+}
+void trigger_music_use()
+{
+       self.cnt = !self.cnt;
+       self.SendFlags |= 0x80;
+}
+void spawnfunc_trigger_music()
+{
+       if(self.model != "")
+               setmodel(self, self.model);
+       if(!self.volume)
+               self.volume = 1;
+       if(!self.modelindex)
+       {
+               setorigin(self, self.origin + self.mins);
+               setsize(self, '0 0 0', self.maxs - self.mins);
+       }
+       trigger_music_reset();
+
+       self.use = trigger_music_use;
+       self.reset = trigger_music_reset;
+
+       Net_LinkEntity(self, FALSE, 0, trigger_music_SendEntity);
+}
index 5e1c78262432f051d6572e2bdb39af804aa0c0a6..1253fe1c07abb9132279becd9becbeff6b00bbfa 100644 (file)
@@ -269,6 +269,12 @@ void target_spawn_use()
                target_spawn_useon(e);
                e.target_spawn_id = self.target_spawn_id;
        }
+       else if(self.target == "*activator")
+       {
+               // edit entity
+               if(activator)
+                       target_spawn_useon(activator);
+       }
        else
        {
                // edit entity
index 4aaef971db5b32ff4cde0a0931ba14ea54a9d4d4..3f6bb10a2ebe872b77bc88e45f44558beced4bb1 100644 (file)
@@ -150,7 +150,7 @@ void WarpZone_Trace_AddTransform(entity wz)
 
 void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb)
 {
-       float frac, sol;
+       float frac, sol, i;
        vector o0, e0;
        entity wz;
        vector vf, vr, vu;
@@ -179,8 +179,14 @@ void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end,
        WarpZone_MakeAllSolid();
        sol = -1;
        frac = 0;
+       i = 16;
        for(;;)
        {
+               if(--i < 1)
+               {
+                       dprint("Too many warpzones in sequence, aborting trace.\n");
+                       break;
+               }
                tracebox(org, mi, ma, end, nomonsters, forent);
                if(cb)
                        cb(org, trace_endpos, end);
@@ -225,7 +231,7 @@ void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
 
 void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb)
 {
-       float g, dt;
+       float g, dt, i;
        vector vf, vr, vu, v0, o0;
        entity wz;
 
@@ -254,8 +260,14 @@ void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZo
        WarpZone_MakeAllSolid();
        g = cvar("sv_gravity") * e.gravity;
        WarpZone_tracetoss_time = 0;
+       i = 16;
        for(;;)
        {
+               if(--i < 1)
+               {
+                       dprint("Too many warpzones in sequence, aborting trace.\n");
+                       break;
+               }
                tracetoss(e, forent);
                if(cb)
                        cb(e.origin, trace_endpos, trace_endpos);