lib: move csqcmodellib and warpzonelib
authorTimePath <andrew.hardaker1995@gmail.com>
Sun, 11 Oct 2015 01:08:03 +0000 (12:08 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Sun, 11 Oct 2015 01:08:03 +0000 (12:08 +1100)
103 files changed:
qcsrc/Makefile
qcsrc/client/csqcmodel_hooks.qc
qcsrc/client/hook.qc
qcsrc/client/hud.qc
qcsrc/client/laser.qc
qcsrc/client/main.qc
qcsrc/client/miscfunctions.qc
qcsrc/client/particles.qc
qcsrc/client/player_skeleton.qc
qcsrc/client/progs.inc
qcsrc/client/shownames.qc
qcsrc/client/t_items.qc
qcsrc/client/teamradar.qc
qcsrc/client/view.qc
qcsrc/client/wall.qc
qcsrc/client/weapons/projectile.qc
qcsrc/common/monsters/monster.qh
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/movetypes/movetypes.qc
qcsrc/common/nades/all.qc
qcsrc/common/triggers/func/breakable.qc
qcsrc/common/triggers/misc/laser.qc
qcsrc/common/triggers/teleporters.qc
qcsrc/common/triggers/trigger/swamp.qc
qcsrc/common/triggers/trigger/viewloc.qc
qcsrc/common/weapons/all.qc
qcsrc/csqcmodellib/cl_model.qc [deleted file]
qcsrc/csqcmodellib/cl_model.qh [deleted file]
qcsrc/csqcmodellib/cl_player.qc [deleted file]
qcsrc/csqcmodellib/cl_player.qh [deleted file]
qcsrc/csqcmodellib/common.qh [deleted file]
qcsrc/csqcmodellib/interpolate.qc [deleted file]
qcsrc/csqcmodellib/interpolate.qh [deleted file]
qcsrc/csqcmodellib/settings.qh [deleted file]
qcsrc/csqcmodellib/sv_model.qc [deleted file]
qcsrc/csqcmodellib/sv_model.qh [deleted file]
qcsrc/lib/_all.inc
qcsrc/lib/csqcmodel/cl_model.qc [new file with mode: 0644]
qcsrc/lib/csqcmodel/cl_model.qh [new file with mode: 0644]
qcsrc/lib/csqcmodel/cl_player.qc [new file with mode: 0644]
qcsrc/lib/csqcmodel/cl_player.qh [new file with mode: 0644]
qcsrc/lib/csqcmodel/common.qh [new file with mode: 0644]
qcsrc/lib/csqcmodel/interpolate.qc [new file with mode: 0644]
qcsrc/lib/csqcmodel/interpolate.qh [new file with mode: 0644]
qcsrc/lib/csqcmodel/settings.qh [new file with mode: 0644]
qcsrc/lib/csqcmodel/sv_model.qc [new file with mode: 0644]
qcsrc/lib/csqcmodel/sv_model.qh [new file with mode: 0644]
qcsrc/lib/warpzone/COPYING [new file with mode: 0644]
qcsrc/lib/warpzone/TODO [new file with mode: 0644]
qcsrc/lib/warpzone/anglestransform.qc [new file with mode: 0644]
qcsrc/lib/warpzone/anglestransform.qh [new file with mode: 0644]
qcsrc/lib/warpzone/client.qc [new file with mode: 0644]
qcsrc/lib/warpzone/client.qh [new file with mode: 0644]
qcsrc/lib/warpzone/common.qc [new file with mode: 0644]
qcsrc/lib/warpzone/common.qh [new file with mode: 0644]
qcsrc/lib/warpzone/mathlib.qc [new file with mode: 0644]
qcsrc/lib/warpzone/mathlib.qh [new file with mode: 0644]
qcsrc/lib/warpzone/server.qc [new file with mode: 0644]
qcsrc/lib/warpzone/server.qh [new file with mode: 0644]
qcsrc/lib/warpzone/util_server.qc [new file with mode: 0644]
qcsrc/lib/warpzone/util_server.qh [new file with mode: 0644]
qcsrc/server/bot/bot.qc
qcsrc/server/bot/havocbot/havocbot.qc
qcsrc/server/bot/waypoints.qc
qcsrc/server/cheats.qc
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/command/cmd.qc
qcsrc/server/command/common.qc
qcsrc/server/command/radarmap.qc
qcsrc/server/g_damage.qc
qcsrc/server/g_damage.qh
qcsrc/server/g_hook.qc
qcsrc/server/g_models.qc
qcsrc/server/g_subs.qc
qcsrc/server/item_key.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/gamemode.qh
qcsrc/server/mutators/gamemode_ctf.qc
qcsrc/server/mutators/mutator.qh
qcsrc/server/mutators/mutators_include.qc
qcsrc/server/portals.qc
qcsrc/server/progs.inc
qcsrc/server/race.qc
qcsrc/server/spawnpoints.qc
qcsrc/server/sv_main.qc
qcsrc/server/t_items.qc
qcsrc/server/weapons/tracing.qc
qcsrc/server/weapons/weaponsystem.qc
qcsrc/warpzonelib/COPYING [deleted file]
qcsrc/warpzonelib/TODO [deleted file]
qcsrc/warpzonelib/anglestransform.qc [deleted file]
qcsrc/warpzonelib/anglestransform.qh [deleted file]
qcsrc/warpzonelib/client.qc [deleted file]
qcsrc/warpzonelib/client.qh [deleted file]
qcsrc/warpzonelib/common.qc [deleted file]
qcsrc/warpzonelib/common.qh [deleted file]
qcsrc/warpzonelib/mathlib.qc [deleted file]
qcsrc/warpzonelib/mathlib.qh [deleted file]
qcsrc/warpzonelib/server.qc [deleted file]
qcsrc/warpzonelib/server.qh [deleted file]
qcsrc/warpzonelib/util_server.qc [deleted file]
qcsrc/warpzonelib/util_server.qh [deleted file]

index 51440d4..452dfc9 100644 (file)
@@ -42,17 +42,17 @@ $(QCCVERSIONFILE):
        $(RM) qccversion.*
        echo This file intentionally left blank. > $@
 
-FILES_CSPROGS = $(shell find client lib common warpzonelib csqcmodellib -type f -not -name fteqcc.log -not -name qc.asm)
+FILES_CSPROGS = $(shell find lib common client -type f)
 ../csprogs.dat: $(FILES_CSPROGS) $(QCCVERSIONFILE)
        @echo make[1]: Entering directory \`$(PWD)/client\'
        cd client && $(QCC) $(QCCFLAGS) -DCSQC
 
-FILES_PROGS = $(shell find server lib common warpzonelib csqcmodellib -type f -not -name fteqcc.log -not -name qc.asm)
+FILES_PROGS = $(shell find lib common server -type f)
 ../progs.dat: $(FILES_PROGS) $(QCCVERSIONFILE)
        @echo make[1]: Entering directory \`$(PWD)/server\'
        cd server && $(QCC) $(QCCFLAGS) -DSVQC
 
-FILES_MENU = $(shell find menu lib common warpzonelib -type f -not -name fteqcc.log -not -name qc.asm)
+FILES_MENU = $(shell find lib common menu -type f)
 ../menu.dat: $(FILES_MENU) $(QCCVERSIONFILE)
        @echo make[1]: Entering directory \`$(PWD)/menu\'
        cd menu && $(QCC) $(QCCFLAGS) -DMENUQC
index 708e305..6e7e5a8 100644 (file)
@@ -4,9 +4,9 @@
 #include "../common/animdecide.qh"
 #include "../common/movetypes/movetypes.qh"
 #include "../common/viewloc.qh"
-#include "../csqcmodellib/cl_model.qh"
-#include "../csqcmodellib/cl_player.qh"
-#include "../csqcmodellib/interpolate.qh"
+#include "../lib/csqcmodel/cl_model.qh"
+#include "../lib/csqcmodel/cl_player.qh"
+#include "../lib/csqcmodel/interpolate.qh"
 
 .float death_time;
 .int modelflags;
index 6143874..3f623b2 100644 (file)
@@ -1,7 +1,7 @@
 #include "hook.qh"
 
-#include "../csqcmodellib/interpolate.qh"
-#include "../warpzonelib/common.qh"
+#include "../lib/csqcmodel/interpolate.qh"
+#include "../lib/warpzone/common.qh"
 
 entityclass(Hook);
 class(Hook) .float HookType; // ENT_CLIENT_*
index 4e83ac3..0e52460 100644 (file)
@@ -12,7 +12,7 @@
 #include "../common/mutators/mutator/waypoints/all.qh"
 #include "../common/nades/all.qh"
 #include "../common/stats.qh"
-#include "../csqcmodellib/cl_player.qh"
+#include "../lib/csqcmodel/cl_player.qh"
 #include "../server/mutators/gamemode_ctf.qh"
 
 
index 4d52c8e..1c63a0d 100644 (file)
@@ -1,6 +1,6 @@
 #include "laser.qh"
 
-#include "../csqcmodellib/interpolate.qh"
+#include "../lib/csqcmodel/interpolate.qh"
 
 // a laser goes from origin in direction angles
 // it has color 'colormod'
index 8571d43..05704e5 100644 (file)
@@ -29,9 +29,9 @@
 #include "../common/triggers/include.qh"
 #include "../common/turrets/cl_turrets.qh"
 #include "../common/vehicles/all.qh"
-#include "../csqcmodellib/cl_model.qh"
-#include "../csqcmodellib/interpolate.qh"
-#include "../warpzonelib/client.qh"
+#include "../lib/csqcmodel/cl_model.qh"
+#include "../lib/csqcmodel/interpolate.qh"
+#include "../lib/warpzone/client.qh"
 
 // --------------------------------------------------------------------------
 // BEGIN REQUIRED CSQC FUNCTIONS
index 8a5b707..7983e74 100644 (file)
@@ -6,7 +6,7 @@
 
 #include "../common/teams.qh"
 
-#include "../csqcmodellib/cl_model.qh"
+#include "../lib/csqcmodel/cl_model.qh"
 
 
 void AuditLists()
index 75f293f..0c7f7a3 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "../common/stats.qh"
 
-#include "../warpzonelib/common.qh"
+#include "../lib/warpzone/common.qh"
 
 void Net_ReadVortexBeamParticle()
 {
index cdb1fdf..d6b2b0d 100644 (file)
@@ -1,8 +1,8 @@
 #include "player_skeleton.qh"
 
 #include "mutators/events.qh"
-#include "../csqcmodellib/cl_player.qh"
-#include "../warpzonelib/anglestransform.qh"
+#include "../lib/csqcmodel/cl_player.qh"
+#include "../lib/warpzone/anglestransform.qh"
 
 .vector v_angle;
 
index 367e5ff..04eb788 100644 (file)
 
 #include "../common/triggers/include.qc"
 
-#include "../csqcmodellib/cl_model.qc"
-#include "../csqcmodellib/cl_player.qc"
-#include "../csqcmodellib/interpolate.qc"
+#include "../lib/csqcmodel/cl_model.qc"
+#include "../lib/csqcmodel/cl_player.qc"
+#include "../lib/csqcmodel/interpolate.qc"
 
 #include "../server/mutators/mutator_multijump.qc"
 
-#include "../warpzonelib/anglestransform.qc"
-#include "../warpzonelib/client.qc"
-#include "../warpzonelib/common.qc"
-#include "../warpzonelib/util_server.qc"
+#include "../lib/warpzone/anglestransform.qc"
+#include "../lib/warpzone/client.qc"
+#include "../lib/warpzone/common.qc"
+#include "../lib/warpzone/util_server.qc"
 
 #if BUILD_MOD
 #include "../../mod/client/progs.inc"
index 994a1ae..80a15ad 100644 (file)
@@ -6,7 +6,7 @@
 #include "../common/mapinfo.qh"
 #include "../common/teams.qh"
 
-#include "../csqcmodellib/cl_model.qh"
+#include "../lib/csqcmodel/cl_model.qh"
 
 // self.isactive = player is in range and coordinates/status (health and armor) are up to date
 // self.origin = player origin TODO: should maybe move this so it's the origin of the shownames tag already in SSQC for culling?
index 9bb99f4..f4096b8 100644 (file)
@@ -2,7 +2,7 @@
 #include "../common/buffs/all.qh"
 #include "../common/movetypes/movetypes.qh"
 #include "../common/weapons/all.qh"
-#include "../csqcmodellib/cl_model.qh"
-#include "../csqcmodellib/common.qh"
+#include "../lib/csqcmodel/cl_model.qh"
+#include "../lib/csqcmodel/common.qh"
 
 #include "../server/t_items.qc"
index d429d20..c866a1b 100644 (file)
@@ -4,7 +4,7 @@
 
 #include "../common/mutators/mutator/waypoints/all.qh"
 
-#include "../csqcmodellib/interpolate.qh"
+#include "../lib/csqcmodel/interpolate.qh"
 
 vector teamradar_3dcoord_to_texcoord(vector in)
 {
index 6fcc79b..fad769d 100644 (file)
 #include "../common/minigames/cl_minigames.qh"
 #include "../common/minigames/cl_minigames_hud.qh"
 
-#include "../csqcmodellib/cl_player.qh"
+#include "../lib/csqcmodel/cl_player.qh"
 
-#include "../warpzonelib/client.qh"
-#include "../warpzonelib/common.qh"
+#include "../lib/warpzone/client.qh"
+#include "../lib/warpzone/common.qh"
 
 entity porto;
 vector polyline[16];
index b97f757..9da9bb5 100644 (file)
@@ -3,7 +3,7 @@
 #include "bgmscript.qh"
 
 
-#include "../csqcmodellib/interpolate.qh"
+#include "../lib/csqcmodel/interpolate.qh"
 
 .float alpha;
 .float scale;
index b52a3fa..807d95c 100644 (file)
@@ -9,9 +9,9 @@
 #include "../../common/nades/all.qh"
 #include "../../common/movetypes/movetypes.qh"
 
-#include "../../csqcmodellib/interpolate.qh"
+#include "../../lib/csqcmodel/interpolate.qh"
 
-#include "../../warpzonelib/anglestransform.qh"
+#include "../../lib/warpzone/anglestransform.qh"
 
 .float alpha;
 .float scale;
index 84253b1..b455926 100644 (file)
@@ -9,7 +9,7 @@
 #include "../../server/weapons/tracing.qh"
 #include "../../server/weapons/weaponsystem.qh"
 #include "../mutators/mutator/waypoints/waypointsprites.qh"
-#include "../../warpzonelib/server.qh"
+#include "../../lib/warpzone/server.qh"
 #endif
 
 // special spawn flags
index b8bff02..e42908f 100644 (file)
@@ -1,7 +1,7 @@
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
-    #include "../../warpzonelib/common.qh"
+    #include "../../lib/warpzone/common.qh"
     #include "../constants.qh"
     #include "../teams.qh"
     #include "../util.qh"
@@ -20,7 +20,7 @@
     #include "../../server/command/common.qh"
     #include "../../server/command/cmd.qh"
        #include "../triggers/triggers.qh"
-    #include "../../csqcmodellib/sv_model.qh"
+    #include "../../lib/csqcmodel/sv_model.qh"
     #include "../../server/round_handler.qh"
 #endif
 
index 0fed28f..8c96174 100644 (file)
@@ -6,7 +6,7 @@
        #include "../stats.qh"
        #include "../util.qh"
        #include "movetypes.qh"
-       #include "../../csqcmodellib/common.qh"
+       #include "../../lib/csqcmodel/common.qh"
        #include "../../server/t_items.qh"
 #elif defined(MENUQC)
 #elif defined(SVQC)
index 724837b..30ad178 100644 (file)
@@ -4,7 +4,7 @@
        #include "../buffs/all.qh"
        #include "../movetypes/movetypes.qh"
        #include "../../client/main.qh"
-       #include "../../csqcmodellib/cl_model.qh"
+       #include "../../lib/csqcmodel/cl_model.qh"
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include "../constants.qh"
index a0d266c..2effa16 100644 (file)
@@ -4,7 +4,7 @@
 #include "../../../server/g_damage.qh"
 #include "../../../server/bot/bot.qh"
 #include "../../../common/csqcmodel_settings.qh"
-#include "../../../csqcmodellib/sv_model.qh"
+#include "../../../lib/csqcmodel/sv_model.qh"
 #include "../../../server/weapons/common.qh"
 
 .entity sprite;
index cc15516..54029cd 100644 (file)
@@ -1,8 +1,8 @@
 #if defined(CSQC)
        #include "../../buffs/all.qh"
-       #include "../../../csqcmodellib/interpolate.qh"
+       #include "../../../lib/csqcmodel/interpolate.qh"
        #include "../../../client/main.qh"
-       #include "../../../csqcmodellib/cl_model.qh"
+       #include "../../../lib/csqcmodel/cl_model.qh"
 #elif defined(MENUQC)
 #elif defined(SVQC)
 #endif
index 438292a..b4b2103 100644 (file)
@@ -3,9 +3,9 @@
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
-    #include "../../warpzonelib/common.qh"
-    #include "../../warpzonelib/util_server.qh"
-    #include "../../warpzonelib/server.qh"
+    #include "../../lib/warpzone/common.qh"
+    #include "../../lib/warpzone/util_server.qh"
+    #include "../../lib/warpzone/server.qh"
     #include "../constants.qh"
        #include "../triggers/subs.qh"
     #include "../util.qh"
index 029ee96..33241aa 100644 (file)
@@ -1,7 +1,7 @@
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
-    #include "../../../warpzonelib/util_server.qh"
+    #include "../../../lib/warpzone/util_server.qh"
     #include "../../weapons/all.qh"
     #include "../../../server/defs.qh"
     #include "../../deathtypes.qh"
index 00695cf..c21fe6b 100644 (file)
@@ -1,7 +1,7 @@
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
-    #include "../../../warpzonelib/util_server.qh"
+    #include "../../../lib/warpzone/util_server.qh"
     #include "../../../server/defs.qh"
 #endif
 
index 0121433..37d49b2 100644 (file)
@@ -7,23 +7,23 @@
        #include "../../client/defs.qh"
        #include "../constants.qh"
        #include "../stats.qh"
-       #include "../../warpzonelib/anglestransform.qh"
-       #include "../../warpzonelib/common.qh"
-       #include "../../warpzonelib/client.qh"
+       #include "../../lib/warpzone/anglestransform.qh"
+       #include "../../lib/warpzone/common.qh"
+       #include "../../lib/warpzone/client.qh"
        #include "../util.qh"
        #include "../buffs/all.qh"
        #include "../../client/autocvars.qh"
        #include "../deathtypes.qh"
-       #include "../../csqcmodellib/interpolate.qh"
+       #include "../../lib/csqcmodel/interpolate.qh"
        #include "../movetypes/movetypes.qh"
        #include "../../client/main.qh"
-       #include "../../csqcmodellib/cl_model.qh"
+       #include "../../lib/csqcmodel/cl_model.qh"
 #elif defined(MENUQC)
 #elif defined(SVQC)
-    #include "../../warpzonelib/anglestransform.qh"
-    #include "../../warpzonelib/common.qh"
-    #include "../../warpzonelib/util_server.qh"
-    #include "../../warpzonelib/server.qh"
+    #include "../../lib/warpzone/anglestransform.qh"
+    #include "../../lib/warpzone/common.qh"
+    #include "../../lib/warpzone/util_server.qh"
+    #include "../../lib/warpzone/server.qh"
     #include "../constants.qh"
     #include "../stats.qh"
     #include "../teams.qh"
@@ -42,7 +42,7 @@
     #include "../../server/mutators/mutators_include.qh"
     #include "../mapinfo.qh"
     #include "../../server/command/common.qh"
-    #include "../../csqcmodellib/sv_model.qh"
+    #include "../../lib/csqcmodel/sv_model.qh"
     #include "../../server/portals.qh"
     #include "../../server/g_hook.qh"
 #endif
diff --git a/qcsrc/csqcmodellib/cl_model.qc b/qcsrc/csqcmodellib/cl_model.qc
deleted file mode 100644 (file)
index b42f5c4..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright (c) 2011 Rudolf PolzerCSQCModel_InterpolateAnimation_2To4_PreNote
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #if defined(CSQC)
-        #include "../client/defs.qh"
-        #include "../common/util.qh"
-        #include "../common/animdecide.qh"
-        #include "interpolate.qh"
-        #include "../common/csqcmodel_settings.qh"
-        #include "common.qh"
-        #include "cl_model.qh"
-        #include "cl_player.qh"
- #elif defined(MENUQC)
- #elif defined(SVQC)
- #endif
-
-float autocvar_cl_lerpanim_maxdelta_framegroups = 0.1;
-float autocvar_cl_nolerp = 0;
-
-.float csqcmodel_lerpfrac;
-.float csqcmodel_lerpfrac2;
-.float csqcmodel_lerpfractime;
-.float csqcmodel_lerpfrac2time;
-
-void CSQCModel_InterpolateAnimation_2To4_PreNote(int sf)
-{SELFPARAM();
-       if(sf & CSQCMODEL_PROPERTY_FRAME)
-       {
-               self.frame3 = self.frame;
-               self.frame3time = self.frame1time;
-       }
-       if(sf & CSQCMODEL_PROPERTY_FRAME2)
-       {
-               self.frame4 = self.frame2;
-               self.frame4time = self.frame2time;
-       }
-       if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
-       {
-               self.csqcmodel_lerpfrac2 = self.csqcmodel_lerpfrac;
-               self.csqcmodel_lerpfrac2time = self.csqcmodel_lerpfractime;
-               self.lerpfrac = self.csqcmodel_lerpfrac;
-       }
-}
-void CSQCModel_InterpolateAnimation_1To2_PreNote(int sf)
-{SELFPARAM();
-       if(sf & CSQCMODEL_PROPERTY_FRAME)
-       {
-               self.frame2 = self.frame;
-               self.frame2time = self.frame1time;
-       }
-}
-void CSQCModel_InterpolateAnimation_PreNote(int sf)
-{
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
-       CSQCModel_InterpolateAnimation_2To4_PreNote(sf);
-#else
-       CSQCModel_InterpolateAnimation_1To2_PreNote(sf);
-#endif
-}
-
-void CSQCModel_InterpolateAnimation_2To4_Note(int sf, float set_times)
-{SELFPARAM();
-       if(sf & CSQCMODEL_PROPERTY_FRAME)
-       {
-               if(set_times)
-                       self.frame1time = time;
-       }
-       if(sf & CSQCMODEL_PROPERTY_FRAME2)
-       {
-               if(set_times)
-                       self.frame2time = time;
-       }
-       if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
-       {
-               self.csqcmodel_lerpfrac = self.lerpfrac;
-               if(set_times)
-                       self.csqcmodel_lerpfractime = time;
-       }
-}
-void CSQCModel_InterpolateAnimation_1To2_Note(int sf, float set_times)
-{SELFPARAM();
-       if(sf & CSQCMODEL_PROPERTY_FRAME)
-       {
-               if(set_times)
-                       self.frame1time = time;
-       }
-}
-void CSQCModel_InterpolateAnimation_Note(int sf)
-{
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
-       CSQCModel_InterpolateAnimation_2To4_Note(sf, true);
-#else
-       CSQCModel_InterpolateAnimation_1To2_Note(sf, true);
-#endif
-}
-
-void CSQCModel_InterpolateAnimation_2To4_Do()
-{SELFPARAM();
-       if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
-       {
-               self.lerpfrac = self.csqcmodel_lerpfrac;
-               self.lerpfrac3 = 0;
-               self.lerpfrac4 = 0;
-       }
-       else
-       {
-               float l13, l24, llf;
-               float l24_13;
-
-               if(self.frame3time == 0) // if frame1/3 were not previously displayed, only frame1 can make sense
-                       l13 = 1;
-               else
-                       l13 = bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
-
-               if(self.frame4time == 0) // if frame2/4 were not previously displayed, only frame2 can make sense
-                       l24 = 1;
-               else
-                       l24 = bound(0, (time - self.frame2time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
-
-               if(self.csqcmodel_lerpfrac2time == 0) // if there is no old lerpfrac (newly displayed model), only lerpfrac makes sense
-                       llf = 1;
-               else
-                       llf = bound(0, (time - self.csqcmodel_lerpfractime) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
-
-               l24_13 = self.csqcmodel_lerpfrac * llf + self.csqcmodel_lerpfrac2 * (1 - llf);
-
-               self.lerpfrac  = l24 * l24_13;
-               self.lerpfrac4 = (1 - l24) * l24_13;
-               self.lerpfrac3 = (1 - l13) * (1 - l24_13);
-
-               if(l24_13 == 0) // if frames 2/4 are not displayed, clear their frametime
-               {
-                       self.frame2time = 0;
-                       self.frame4time = 0;
-               }
-
-               if(l24_13 == 1) // if frames 1/3 are not displayed, clear their frametime
-               {
-                       self.frame1time = 0;
-                       self.frame3time = 0;
-               }
-       }
-}
-void CSQCModel_InterpolateAnimation_1To2_Do()
-{SELFPARAM();
-       if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
-       {
-               self.lerpfrac = 0;
-       }
-       else
-       {
-               if(self.frame2time == 0) // if frame2 was not previously displayed, only frame1 can make sense
-                       self.lerpfrac = 0;
-               else
-                       self.lerpfrac = 1 - bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
-       }
-}
-void CSQCModel_InterpolateAnimation_Do()
-{
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
-       CSQCModel_InterpolateAnimation_2To4_Do();
-#else
-       CSQCModel_InterpolateAnimation_1To2_Do();
-#endif
-}
-
-void CSQCModel_Draw()
-{SELFPARAM();
-       // some nice flags for CSQCMODEL_IF and the hooks
-       bool isplayer = (self.entnum >= 1 && self.entnum <= maxclients);
-       noref bool islocalplayer = (self.entnum == player_localnum + 1);
-       noref bool isnolocalplayer = (isplayer && (self.entnum != player_localnum + 1));
-
-       // we don't do this for the local player as that one is already handled
-       // by CSQCPlayer_SetCamera()
-       if(!CSQCPlayer_IsLocalPlayer())
-               InterpolateOrigin_Do();
-
-       CSQCModel_InterpolateAnimation_Do();
-
-       { CSQCMODEL_HOOK_PREDRAW }
-
-       // inherit draw flags easily
-       entity root = self;
-       while(root.tag_entity)
-               root = root.tag_entity;
-       if(self != root)
-       {
-               self.renderflags &= ~(RF_EXTERNALMODEL | RF_VIEWMODEL);
-               self.renderflags |= (root.renderflags & (RF_EXTERNALMODEL | RF_VIEWMODEL));
-       }
-
-       // we're drawn, now teleporting is over
-       self.csqcmodel_teleported = 0;
-}
-
-void CSQCModel_Read(bool isnew)
-{SELFPARAM();
-       int sf = ReadInt24_t();
-
-       // some nice flags for CSQCMODEL_IF and the hooks
-       bool isplayer = (self.entnum >= 1 && self.entnum <= maxclients);
-       bool islocalplayer = (self.entnum == player_localnum + 1);
-       noref bool isnolocalplayer = (isplayer && (self.entnum != player_localnum + 1));
-
-       self.classname = "csqcmodel";
-       self.iflags |= IFLAG_ORIGIN; // interpolate origin too
-       self.iflags |= IFLAG_ANGLES; // interpolate angles too
-       self.iflags |= IFLAG_VELOCITY | IFLAG_AUTOVELOCITY; // let's calculate velocity automatically
-
-       { CSQCMODEL_HOOK_PREUPDATE }
-
-       CSQCPlayer_PreUpdate();
-       InterpolateOrigin_Undo();
-       CSQCModel_InterpolateAnimation_PreNote(sf);
-
-#define CSQCMODEL_IF(cond) if(cond) {
-#define CSQCMODEL_ENDIF }
-#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
-       if(sf & flag) \
-               self.f = r();
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
-       if(sf & flag) \
-               self.f = (r() + mi) / s;
-       ALLPROPERTIES
-#undef CSQCMODEL_PROPERTY_SCALED
-#undef CSQCMODEL_PROPERTY
-#undef CSQCMODEL_ENDIF
-#undef CSQCMODEL_IF
-
-       if(sf & CSQCMODEL_PROPERTY_MODELINDEX)
-       {
-               vector pmin = self.mins, pmax = self.maxs;
-               setmodelindex(self, self.modelindex); // this retrieves the .model key and sets mins/maxs/absmin/absmax
-               setsize(self, pmin, pmax);
-       }
-
-       if(sf & CSQCMODEL_PROPERTY_TELEPORTED)
-       {
-               self.iflags |= IFLAG_TELEPORTED;
-               self.csqcmodel_teleported = 1;
-       }
-
-       CSQCModel_InterpolateAnimation_Note(sf);
-       InterpolateOrigin_Note();
-       CSQCPlayer_PostUpdate();
-
-       { CSQCMODEL_HOOK_POSTUPDATE }
-
-#ifdef CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
-       InterpolateOrigin_Do();
-       CSQCModel_InterpolateAnimation_Do();
-#endif
-
-       // relink
-       setorigin(self, self.origin);
-
-       // set obvious render flags
-       if(self.entnum == player_localentnum)
-               self.renderflags |= RF_EXTERNALMODEL;
-       else
-               self.renderflags &= ~RF_EXTERNALMODEL;
-
-       // draw it
-       self.drawmask = MASK_NORMAL;
-       self.predraw = CSQCModel_Draw;
-}
-
-entity CSQCModel_server2csqc(float pl)
-{
-       return findfloat(world, entnum, pl); // FIXME optimize this using an array
-}
diff --git a/qcsrc/csqcmodellib/cl_model.qh b/qcsrc/csqcmodellib/cl_model.qh
deleted file mode 100644 (file)
index 98f1da0..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#ifndef CL_MODEL_H
-#define CL_MODEL_H
-
-#include "common.qh"
-
-void CSQCModel_Read(bool isnew);
-
-#define CSQCMODEL_IF(cond)
-#define CSQCMODEL_ENDIF
-#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
-       .t f;
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
-       ALLPROPERTIES
-#undef CSQCMODEL_PROPERTY_SCALED
-#undef CSQCMODEL_PROPERTY
-#undef CSQCMODEL_ENDIF
-#undef CSQCMODEL_IF
-
-entity CSQCModel_server2csqc(float pl);
-.float csqcmodel_teleported;
-
-// this is exported for custom frame animation code. Use with care.
-// to update frames, first call this:
-void CSQCModel_InterpolateAnimation_2To4_PreNote(int sf);
-void CSQCModel_InterpolateAnimation_1To2_PreNote(int sf);
-// then update frame, frame1time (and possibly frame2, frame2time, lerpfrac)
-// if set_times is not set, caller is responsible for frame1time, frame2time, csqcmodel_lerpfractime!
-void CSQCModel_InterpolateAnimation_2To4_Note(int sf, float set_times);
-void CSQCModel_InterpolateAnimation_1To2_Note(int sf, float set_times);
-// to retrieve animation state, call this
-void CSQCModel_InterpolateAnimation_2To4_Do();
-void CSQCModel_InterpolateAnimation_1To2_Do();
-// will overwrite lerpfrac, lerpfrac3, lerpfrac4, and possibly clear frame*time if they are undisplayed according to lerpfracs
-#endif
diff --git a/qcsrc/csqcmodellib/cl_player.qc b/qcsrc/csqcmodellib/cl_player.qc
deleted file mode 100644 (file)
index 7aedd52..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright (c) 2011 Rudolf Polzer
- * Copyright (c) 2015 Micah Talkiewicz
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#if defined(CSQC)
-       #include "../client/defs.qh"
-       #include "../common/constants.qh"
-       #include "../common/stats.qh"
-       #include "../common/util.qh"
-       #include "interpolate.qh"
-       #include "../client/main.qh"
-       #include "common.qh"
-       #include "cl_model.qh"
-       #include "cl_player.qh"
-       #include "../common/triggers/trigger/viewloc.qh"
-       #include "../common/viewloc.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-
-float autocvar_cl_movement_errorcompensation = 0;
-int autocvar_cl_movement = 1;
-
-// engine stuff
-float pmove_onground; // weird engine flag we shouldn't really use but have to for now
-
-vector csqcplayer_origin, csqcplayer_velocity;
-float csqcplayer_sequence;
-int player_pmflags;
-float csqcplayer_moveframe;
-vector csqcplayer_predictionerroro;
-vector csqcplayer_predictionerrorv;
-float csqcplayer_predictionerrortime;
-float csqcplayer_predictionerrorfactor;
-
-vector CSQCPlayer_GetPredictionErrorO()
-{
-       if(time >= csqcplayer_predictionerrortime)
-               return '0 0 0';
-       return csqcplayer_predictionerroro * (csqcplayer_predictionerrortime - time) * csqcplayer_predictionerrorfactor;
-}
-
-vector CSQCPlayer_GetPredictionErrorV()
-{
-       if(time >= csqcplayer_predictionerrortime)
-               return '0 0 0';
-       return csqcplayer_predictionerrorv * (csqcplayer_predictionerrortime - time) * csqcplayer_predictionerrorfactor;
-}
-
-void CSQCPlayer_SetPredictionError(vector o, vector v, float onground_diff)
-{
-       // error too big to compensate, we LIKELY hit a teleport or a
-       // jumppad, or it's a jump time disagreement that'll get fixed
-       // next frame
-
-       // FIXME we sometimes have disagreement in order of jump velocity. Do not act on them!
-       /*
-       // commented out as this one did not help
-       if(onground_diff)
-       {
-               printf("ONGROUND MISMATCH: %d x=%v v=%v\n", onground_diff, o, v);
-               return;
-       }
-       */
-       if(vlen(o) > 32 || vlen(v) > 192)
-       {
-               //printf("TOO BIG: x=%v v=%v\n", o, v);
-               return;
-       }
-
-       if(!autocvar_cl_movement_errorcompensation)
-       {
-               csqcplayer_predictionerrorfactor = 0;
-               return;
-       }
-
-       csqcplayer_predictionerroro = CSQCPlayer_GetPredictionErrorO() + o;
-       csqcplayer_predictionerrorv = CSQCPlayer_GetPredictionErrorV() + v;
-       csqcplayer_predictionerrorfactor = autocvar_cl_movement_errorcompensation / ticrate;
-       csqcplayer_predictionerrortime = time + 1.0 / csqcplayer_predictionerrorfactor;
-}
-
-void CSQCPlayer_Unpredict()
-{SELFPARAM();
-       if(csqcplayer_status == CSQCPLAYERSTATUS_UNPREDICTED)
-               return;
-       if(csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED)
-               error("Cannot unpredict in current status");
-       self.origin = csqcplayer_origin;
-       self.velocity = csqcplayer_velocity;
-       csqcplayer_moveframe = csqcplayer_sequence+1; //+1 because the recieved frame has the move already done (server side)
-       self.flags = player_pmflags;
-}
-
-void CSQCPlayer_SetMinsMaxs()
-{SELFPARAM();
-       if(self.flags & FL_DUCKED)
-       {
-               self.mins = PL_CROUCH_MIN;
-               self.maxs = PL_CROUCH_MAX;
-               self.view_ofs = PL_CROUCH_VIEW_OFS;
-       }
-       else
-       {
-               self.mins = PL_MIN;
-               self.maxs = PL_MAX;
-               self.view_ofs = PL_VIEW_OFS;
-       }
-}
-
-void CSQCPlayer_SavePrediction()
-{SELFPARAM();
-       player_pmflags = self.flags;
-       csqcplayer_origin = self.origin;
-       csqcplayer_velocity = self.velocity;
-       csqcplayer_sequence = servercommandframe;
-       csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
-}
-
-void CSQC_ClientMovement_PlayerMove_Frame();
-
-void PM_Movement_Move()
-{SELFPARAM();
-       runstandardplayerphysics(self);
-#ifdef CSQC
-       self.flags =
-                       ((self.pmove_flags & PMF_DUCKED) ? FL_DUCKED : 0) |
-                       (!(self.pmove_flags & PMF_JUMP_HELD) ? FL_JUMPRELEASED : 0) |
-                       ((self.pmove_flags & PMF_ONGROUND) ? FL_ONGROUND : 0);
-#endif
-}
-
-void CSQCPlayer_Physics(void)
-{
-       switch(autocvar_cl_movement)
-       {
-               case 1: CSQC_ClientMovement_PlayerMove_Frame(); break;
-               case 2: PM_Movement_Move(); break;
-       }
-}
-
-void CSQCPlayer_PredictTo(float endframe, float apply_error)
-{SELFPARAM();
-       CSQCPlayer_Unpredict();
-       if(apply_error)
-       {
-               self.origin += CSQCPlayer_GetPredictionErrorO();
-               self.velocity += CSQCPlayer_GetPredictionErrorV();
-       }
-       CSQCPlayer_SetMinsMaxs();
-
-       csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
-
-#if 0
-       // we don't need this
-       // darkplaces makes servercommandframe == 0 in these cases anyway
-       if (getstatf(STAT_HEALTH) <= 0)
-       {
-               csqcplayer_moveframe = clientcommandframe;
-               getinputstate(csqcplayer_moveframe-1);
-               LOG_INFO("the Weird code path got hit\n");
-               return;
-       }
-#endif
-
-       if(csqcplayer_moveframe >= endframe)
-       {
-               getinputstate(csqcplayer_moveframe - 1);
-       }
-       else
-       {
-               do
-               {
-                       if (!getinputstate(csqcplayer_moveframe))
-                               break;
-                       CSQCPlayer_Physics();
-                       CSQCPlayer_SetMinsMaxs();
-                       csqcplayer_moveframe++;
-               }
-               while(csqcplayer_moveframe < endframe);
-       }
-
-       //add in anything that was applied after (for low packet rate protocols)
-       input_angles = view_angles;
-}
-
-bool CSQCPlayer_IsLocalPlayer()
-{SELFPARAM();
-       return (self == csqcplayer);
-}
-
-void CSQCPlayer_SetViewLocation()
-{
-       viewloc_SetViewLocation();
-}
-
-void CSQCPlayer_SetCamera()
-{SELFPARAM();
-       vector v0;
-       v0 = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
-
-       if(csqcplayer)
-       {
-               setself(csqcplayer);
-
-               if(servercommandframe == 0 || clientcommandframe == 0)
-               {
-                       InterpolateOrigin_Do();
-                       self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
-
-                       // get crouch state from the server
-                       if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
-                               self.flags &= ~FL_DUCKED;
-                       else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
-                               self.flags |= FL_DUCKED;
-
-                       // get onground state from the server
-                       if(pmove_onground)
-                               self.flags |= FL_ONGROUND;
-                       else
-                               self.flags &= ~FL_ONGROUND;
-
-                       CSQCPlayer_SetMinsMaxs();
-
-                       // override it back just in case
-                       self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
-
-                       // set velocity
-                       self.velocity = v0;
-               }
-               else
-               {
-                       float flg = self.iflags;
-                       self.iflags &= ~(IFLAG_ORIGIN | IFLAG_ANGLES);
-                       InterpolateOrigin_Do();
-                       self.iflags = flg;
-
-                       if(csqcplayer_status == CSQCPLAYERSTATUS_FROMSERVER)
-                       {
-                               vector o, v;
-                               o = self.origin;
-                               v = v0;
-                               csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
-                               CSQCPlayer_PredictTo(servercommandframe + 1, false);
-                               CSQCPlayer_SetPredictionError(self.origin - o, self.velocity - v, pmove_onground - !!(self.flags & FL_ONGROUND));
-                               self.origin = o;
-                               self.velocity = v;
-
-                               // get crouch state from the server
-                               if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
-                                       self.flags &= ~FL_DUCKED;
-                               else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
-                                       self.flags |= FL_DUCKED;
-
-                               // get onground state from the server
-                               if(pmove_onground)
-                                       self.flags |= FL_ONGROUND;
-                               else
-                                       self.flags &= ~FL_ONGROUND;
-
-                               CSQCPlayer_SavePrediction();
-                       }
-                       CSQCPlayer_PredictTo(clientcommandframe + 1, true);
-
-#ifdef CSQCMODEL_SERVERSIDE_CROUCH
-                       // get crouch state from the server (LAG)
-                       if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
-                               self.flags &= ~FL_DUCKED;
-                       else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
-                               self.flags |= FL_DUCKED;
-#endif
-
-                       CSQCPlayer_SetMinsMaxs();
-
-                       self.angles_y = input_angles.y;
-               }
-
-               // relink
-               setorigin(self, self.origin);
-
-               setself(this);
-       }
-
-       entity view = CSQCModel_server2csqc(player_localentnum);
-
-       if(view && view != csqcplayer)
-       {
-               WITH(entity, self, view, InterpolateOrigin_Do());
-               view.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
-       }
-
-       if(view)
-       {
-               int refdefflags = 0;
-
-               if(view.csqcmodel_teleported)
-                       refdefflags |= REFDEFFLAG_TELEPORTED;
-
-               if(input_buttons & 4)
-                       refdefflags |= REFDEFFLAG_JUMPING;
-
-               // note: these two only work in WIP2, but are harmless in WIP1
-               if(getstati(STAT_HEALTH) <= 0)
-                       refdefflags |= REFDEFFLAG_DEAD;
-
-               if(intermission)
-                       refdefflags |= REFDEFFLAG_INTERMISSION;
-
-               V_CalcRefdef(view, refdefflags);
-       }
-       else
-       {
-               // FIXME by CSQC spec we have to do this:
-               // but it breaks chase cam
-               /*
-               setproperty(VF_ORIGIN, pmove_org + '0 0 1' * getstati(STAT_VIEWHEIGHT));
-               setproperty(VF_ANGLES, view_angles);
-               */
-       }
-
-       { CSQCPLAYER_HOOK_POSTCAMERASETUP }
-}
-
-void CSQCPlayer_Remove()
-{
-       csqcplayer = world;
-       cvar_settemp("cl_movement_replay", "1");
-}
-
-float CSQCPlayer_PreUpdate()
-{SELFPARAM();
-       if(self != csqcplayer)
-               return 0;
-       if(csqcplayer_status != CSQCPLAYERSTATUS_FROMSERVER)
-               CSQCPlayer_Unpredict();
-       return 1;
-}
-
-float CSQCPlayer_PostUpdate()
-{SELFPARAM();
-       if(self.entnum != player_localnum + 1)
-               return 0;
-       csqcplayer = self;
-       csqcplayer_status = CSQCPLAYERSTATUS_FROMSERVER;
-       cvar_settemp("cl_movement_replay", "0");
-       self.entremove = CSQCPlayer_Remove;
-       return 1;
-}
diff --git a/qcsrc/csqcmodellib/cl_player.qh b/qcsrc/csqcmodellib/cl_player.qh
deleted file mode 100644 (file)
index e427e6c..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#ifndef CL_PLAYER_H
-#define CL_PLAYER_H
-
-entity csqcplayer;
-float csqcplayer_status;
-const int CSQCPLAYERSTATUS_UNPREDICTED = 0;
-const int CSQCPLAYERSTATUS_FROMSERVER = 1;
-const int CSQCPLAYERSTATUS_PREDICTED = 2;
-
-// only ever READ these!
-.int pmove_flags;
-const int PMF_JUMP_HELD = 1;
-//const int PMF_DUCKED = 4;
-//const int PMF_ONGROUND = 8;
-
-const int FL_DUCKED = 524288;
-
-void CSQCPlayer_SetCamera();
-float CSQCPlayer_PreUpdate();
-float CSQCPlayer_PostUpdate();
-float CSQCPlayer_IsLocalPlayer();
-#endif
diff --git a/qcsrc/csqcmodellib/common.qh b/qcsrc/csqcmodellib/common.qh
deleted file mode 100644 (file)
index de02e7a..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#ifndef CSQCMODELLIB_COMMON_H
-#define CSQCMODELLIB_COMMON_H
-
-#include "../common/csqcmodel_settings.qh"
-
-noref string csqcmodel_license = "\
-Copyright (c) 2011 Rudolf Polzer\
-\
-Permission is hereby granted, free of charge, to any person obtaining a copy\
-of this software and associated documentation files (the \"Software\"), to\
-deal in the Software without restriction, including without limitation the\
-rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\
-sell copies of the Software, and to permit persons to whom the Software is\
-furnished to do so, subject to the following conditions:\
-\
-The above copyright notice and this permission notice shall be included in\
-all copies or substantial portions of the Software.\
-\
-THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\
-IN THE SOFTWARE.\
-";
-
-.vector glowmod;
-.vector view_ofs;
-.int frame;
-.float frame1time;
-.int frame2;
-.float frame2time;
-.float lerpfrac;
-
-const int CSQCMODEL_PROPERTY_FRAME = 8388608;
-const int CSQCMODEL_PROPERTY_TELEPORTED = 4194304; // the "teleport bit" cancelling interpolation
-const int CSQCMODEL_PROPERTY_MODELINDEX = 2097152;
-const int CSQCMODEL_PROPERTY_ORIGIN = 1048576;
-const int CSQCMODEL_PROPERTY_YAW = 524288;
-const int CSQCMODEL_PROPERTY_PITCHROLL = 262144;
-const int CSQCMODEL_PROPERTY_FRAME2 = 131072;
-const int CSQCMODEL_PROPERTY_LERPFRAC = 65536;
-const int CSQCMODEL_PROPERTY_SIZE = 32768;
-
-#define ALLPROPERTIES_COMMON \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME, int, ReadByte, WriteByte, frame) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_MODELINDEX, int, ReadShort, WriteShort, modelindex) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_x) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_y) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_z) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_x) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_y) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_z) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_x) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_y) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_z) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_x) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_YAW, float, ReadAngle, WriteAngle, angles_y) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_z) \
-       CSQCMODEL_EXTRAPROPERTIES
-
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
-.float frame3;
-.float frame3time;
-.float lerpfrac3;
-.float frame4;
-.float frame4time;
-.float lerpfrac4;
-#define ALLPROPERTIES ALLPROPERTIES_COMMON \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME2, int, ReadByte, WriteByte, frame2) \
-       CSQCMODEL_PROPERTY_SCALED(CSQCMODEL_PROPERTY_LERPFRAC, float, ReadByte, WriteByte, lerpfrac, 255, 0, 255)
-#else
-#define ALLPROPERTIES ALLPROPERTIES_COMMON
-#endif
-#endif
diff --git a/qcsrc/csqcmodellib/interpolate.qc b/qcsrc/csqcmodellib/interpolate.qc
deleted file mode 100644 (file)
index fb1094f..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#if defined(CSQC)
-       #include "../client/defs.qh"
-       #include "../warpzonelib/anglestransform.qh"
-       #include "../client/autocvars.qh"
-       #include "interpolate.qh"
-       #include "cl_model.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-
-.vector iorigin1, iorigin2;
-.vector ivelocity1, ivelocity2;
-.vector iforward1, iforward2;
-.vector iup1, iup2;
-.vector ivforward1, ivforward2;
-.vector ivup1, ivup2;
-.float itime1, itime2;
-void InterpolateOrigin_Reset()
-{SELFPARAM();
-       self.iflags &= ~IFLAG_INTERNALMASK;
-       self.itime1 = self.itime2 = 0;
-}
-void InterpolateOrigin_Note()
-{SELFPARAM();
-       float dt;
-       int f0;
-
-       dt = time - self.itime2;
-
-       f0 = self.iflags;
-       if(self.iflags & IFLAG_PREVALID)
-               self.iflags |= IFLAG_VALID;
-       else
-               self.iflags |= IFLAG_PREVALID;
-
-       if(self.iflags & IFLAG_ORIGIN)
-       {
-               self.iorigin1 = self.iorigin2;
-               self.iorigin2 = self.origin;
-       }
-
-       if(self.iflags & IFLAG_AUTOANGLES)
-               if(self.iorigin2 != self.iorigin1)
-                       self.angles = vectoangles(self.iorigin2 - self.iorigin1);
-
-       if(self.iflags & IFLAG_AUTOVELOCITY)
-               if(self.itime2 != self.itime1)
-                       self.velocity = (self.iorigin2 - self.iorigin1) * (1.0 / (self.itime2 - self.itime1));
-
-       if(self.iflags & IFLAG_ANGLES)
-       {
-               fixedmakevectors(self.angles);
-               if(f0 & IFLAG_VALID)
-               {
-                       self.iforward1 = self.iforward2;
-                       self.iup1 = self.iup2;
-               }
-               else
-               {
-                       self.iforward1 = v_forward;
-                       self.iup1 = v_up;
-               }
-               self.iforward2 = v_forward;
-               self.iup2 = v_up;
-       }
-
-       if(self.iflags & IFLAG_V_ANGLE)
-       {
-               fixedmakevectors(self.v_angle);
-               if(f0 & IFLAG_VALID)
-               {
-                       self.ivforward1 = self.ivforward2;
-                       self.ivup1 = self.ivup2;
-               }
-               else
-               {
-                       self.ivforward1 = v_forward;
-                       self.ivup1 = v_up;
-               }
-               self.ivforward2 = v_forward;
-               self.ivup2 = v_up;
-       }
-       else if(self.iflags & IFLAG_V_ANGLE_X)
-       {
-               self.ivforward1_x = self.ivforward2_x;
-               self.ivforward2_x = self.v_angle.x;
-       }
-
-       if(self.iflags & IFLAG_VELOCITY)
-       {
-               self.ivelocity1 = self.ivelocity2;
-               self.ivelocity2 = self.velocity;
-       }
-
-       if(self.iflags & IFLAG_TELEPORTED)
-       {
-               self.iflags &= ~IFLAG_TELEPORTED;
-               self.itime1 = self.itime2 = time; // don't lerp
-       }
-       else if(vlen(self.iorigin2 - self.iorigin1) > 1000)
-       {
-               self.itime1 = self.itime2 = time; // don't lerp
-       }
-       else if((self.iflags & IFLAG_VELOCITY) && (vlen(self.ivelocity2 - self.ivelocity1) > 1000))
-       {
-               self.itime1 = self.itime2 = time; // don't lerp
-       }
-       else if(dt >= 0.2)
-       {
-               self.itime1 = self.itime2 = time;
-       }
-       else
-       {
-               self.itime1 = serverprevtime;
-               self.itime2 = time;
-       }
-}
-void InterpolateOrigin_Do()
-{SELFPARAM();
-       vector forward, up;
-       if(self.itime1 && self.itime2 && self.itime1 != self.itime2)
-       {
-               float f;
-               f = bound(0, (time - self.itime1) / (self.itime2 - self.itime1), 1 + autocvar_cl_lerpexcess);
-               if(self.iflags & IFLAG_ORIGIN)
-                       setorigin(self, (1 - f) * self.iorigin1 + f * self.iorigin2);
-               if(self.iflags & IFLAG_ANGLES)
-               {
-                       forward = (1 - f) * self.iforward1 + f * self.iforward2;
-                       up = (1 - f) * self.iup1 + f * self.iup2;
-                       self.angles = fixedvectoangles2(forward, up);
-               }
-               if(self.iflags & IFLAG_V_ANGLE)
-               {
-                       forward = (1 - f) * self.ivforward1 + f * self.ivforward2;
-                       up = (1 - f) * self.ivup1 + f * self.ivup2;
-                       self.v_angle = fixedvectoangles2(forward, up);
-               }
-               else if(self.iflags & IFLAG_V_ANGLE_X)
-                       self.v_angle_x = (1 - f) * self.ivforward1_x + f * self.ivforward2_x;
-               if(self.iflags & IFLAG_VELOCITY)
-                       self.velocity = (1 - f) * self.ivelocity1 + f * self.ivelocity2;
-       }
-}
-void InterpolateOrigin_Undo()
-{SELFPARAM();
-       if(self.iflags & IFLAG_ORIGIN)
-               setorigin(self, self.iorigin2);
-       if(self.iflags & IFLAG_ANGLES)
-               self.angles = fixedvectoangles2(self.iforward2, self.iup2);
-       if(self.iflags & IFLAG_V_ANGLE)
-               self.v_angle = fixedvectoangles2(self.ivforward2, self.ivup2);
-       else if(self.iflags & IFLAG_V_ANGLE_X)
-               self.v_angle_x = self.ivforward2_x;
-       if(self.iflags & IFLAG_VELOCITY)
-               self.velocity = self.ivelocity2;
-}
-
diff --git a/qcsrc/csqcmodellib/interpolate.qh b/qcsrc/csqcmodellib/interpolate.qh
deleted file mode 100644 (file)
index 5ee5785..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#ifndef INTERPOLATE_H
-#define INTERPOLATE_H
-
-.int iflags;
-const int IFLAG_VELOCITY = 1;
-const int IFLAG_ANGLES = 2;
-const int IFLAG_AUTOANGLES = 4;
-const int IFLAG_VALID = 8;
-const int IFLAG_PREVALID = 16;
-const int IFLAG_TELEPORTED = 32;
-const int IFLAG_AUTOVELOCITY = 64;
-const int IFLAG_V_ANGLE = 128;
-const int IFLAG_V_ANGLE_X = 256;
-const int IFLAG_ORIGIN = 512;
-#define IFLAG_INTERNALMASK (IFLAG_VALID | IFLAG_PREVALID)
-
-// call this BEFORE reading an entity update
-void InterpolateOrigin_Undo();
-
-// call this AFTER receiving an entity update
-void InterpolateOrigin_Note();
-
-// call this when the entity got teleported, before InterpolateOrigin_Note
-void InterpolateOrigin_Reset();
-
-// call this BEFORE drawing
-void InterpolateOrigin_Do();
-
-// in case we interpolate that:
-.vector v_angle;
-#endif
diff --git a/qcsrc/csqcmodellib/settings.qh b/qcsrc/csqcmodellib/settings.qh
deleted file mode 100644 (file)
index b30d7e9..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef CSQCMODELLIB_SETTINGS_H
-#define CSQCMODELLIB_SETTINGS_H
-// define this if svqc code wants to use .frame2 and .lerpfrac
-//#define CSQCMODEL_HAVE_TWO_FRAMES
-
-// don't define this ever
-//#define CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
-
-// add properties you want networked to CSQC here
-#define CSQCMODEL_EXTRAPROPERTIES \
-       /* CSQCMODEL_PROPERTY(1, float, ReadShort, WriteShort, colormap) */ \
-       /* CSQCMODEL_PROPERTY(2, float, ReadInt24_t, WriteInt24_t, effects) */
-
-// add hook function calls here
-#define CSQCMODEL_HOOK_PREUPDATE
-#define CSQCMODEL_HOOK_POSTUPDATE
-#define CSQCMODEL_HOOK_PREDRAW
-#define CSQCPLAYER_HOOK_POSTCAMERASETUP
-
-// force updates of player entities that often even if unchanged
-#define CSQCPLAYER_FORCE_UPDATES 0.25
-
-// mod must define:
-//vector PL_MIN  = ...;
-//vector PL_MAX  = ...;
-//vector PL_VIEW_OFS  = ...;
-//vector PL_CROUCH_MIN  = ...;
-//vector PL_CROUCH_MAX  = ...;
-//vector PL_CROUCH_VIEW_OFS  = ...;
-#endif
diff --git a/qcsrc/csqcmodellib/sv_model.qc b/qcsrc/csqcmodellib/sv_model.qc
deleted file mode 100644 (file)
index 0fc2ad8..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-       #include "../common/constants.qh"
-       #include "../common/util.qh"
-       #include "../common/animdecide.qh"
-       #include "../server/constants.qh"
-       #include "../server/defs.qh"
-       #include "common.qh"
-       #include "sv_model.qh"
-#endif
-
-// generic CSQC model code
-
-bool CSQCModel_Send(entity to, int sf)
-{SELFPARAM();
-       // some nice flags for CSQCMODEL_IF
-       float isplayer = (IS_CLIENT(self));
-       float islocalplayer = (self == to);
-       float isnolocalplayer = (isplayer && (self != to));
-
-       unused_float = isplayer;
-       unused_float = islocalplayer;
-       unused_float = isnolocalplayer;
-
-       WriteByte(MSG_ENTITY, ENT_CLIENT_MODEL);
-       WriteInt24_t(MSG_ENTITY, sf);
-
-#define CSQCMODEL_IF(cond) if(cond) {
-#define CSQCMODEL_ENDIF }
-#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
-       if(sf & flag) \
-       { \
-               w(MSG_ENTITY, self.csqcmodel_##f); \
-       }
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
-       ALLPROPERTIES
-#undef CSQCMODEL_PROPERTY_SCALED
-#undef CSQCMODEL_PROPERTY
-#undef CSQCMODEL_ENDIF
-#undef CSQCMODEL_IF
-
-       return true;
-}
-
-#ifdef CSQCPLAYER_FORCE_UPDATES
-.float csqcmodel_nextforcedupdate;
-#endif
-void CSQCModel_CheckUpdate(entity e)
-{
-       // some nice flags for CSQCMODEL_IF
-       float isplayer = (IS_CLIENT(e));
-       float islocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
-       float isnolocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
-
-       unused_float = isplayer;
-       unused_float = islocalplayer;
-       unused_float = isnolocalplayer;
-
-#ifdef CSQCPLAYER_FORCE_UPDATES
-       if(isplayer && time > e.csqcmodel_nextforcedupdate)
-       {
-               e.SendFlags |= CSQCMODEL_PROPERTY_ORIGIN;
-               e.csqcmodel_nextforcedupdate = time + CSQCPLAYER_FORCE_UPDATES * (0.5 + random()); // ensure about 4 origin sends per sec
-       }
-#endif
-
-       if(e.effects & EF_RESTARTANIM_BIT)
-       {
-               e.SendFlags |= CSQCMODEL_PROPERTY_FRAME | CSQCMODEL_PROPERTY_FRAME2; // full anim resend please
-               e.effects &= ~EF_RESTARTANIM_BIT;
-       }
-
-       if(e.effects & EF_TELEPORT_BIT)
-       {
-               e.SendFlags |= CSQCMODEL_PROPERTY_TELEPORTED; // no interpolation please
-               e.effects &= ~EF_TELEPORT_BIT;
-       }
-
-#define CSQCMODEL_IF(cond) if(cond) {
-#define CSQCMODEL_ENDIF }
-#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
-       { \
-               t tmp = e.f; \
-               if(tmp != e.csqcmodel_##f) \
-               { \
-                       e.csqcmodel_##f = tmp; \
-                       e.SendFlags |= flag; \
-               } \
-       }
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
-       { \
-               t tmp = rint(bound(mi, s * e.f, ma) - mi); \
-               if(tmp != e.csqcmodel_##f) \
-               { \
-                       e.csqcmodel_##f = tmp; \
-                       e.SendFlags |= flag; \
-               } \
-       }
-       ALLPROPERTIES
-#undef CSQCMODEL_PROPERTY_SCALED
-#undef CSQCMODEL_PROPERTY
-#undef CSQCMODEL_ENDIF
-#undef CSQCMODEL_IF
-}
-
-void CSQCModel_LinkEntity(entity e)
-{
-       e.SendEntity = CSQCModel_Send;
-       e.SendFlags = 0xFFFFFF;
-       CSQCModel_CheckUpdate(e);
-}
-
-void CSQCModel_UnlinkEntity(entity e)
-{
-       e.SendEntity = func_null;
-}
diff --git a/qcsrc/csqcmodellib/sv_model.qh b/qcsrc/csqcmodellib/sv_model.qh
deleted file mode 100644 (file)
index 713e8c2..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #ifndef SV_MODEL_H
- #define SV_MODEL_H
-
- #include "common.qh"
-
-// generic CSQC model code
-
-void CSQCModel_CheckUpdate(entity e);
-void CSQCModel_LinkEntity(entity e);
-void CSQCModel_UnlinkEntity(entity e);
-
-#define CSQCMODEL_IF(cond)
-#define CSQCMODEL_ENDIF
-#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
-       .t f; \
-       .t csqcmodel_##f;
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
-       ALLPROPERTIES
-#undef CSQCMODEL_PROPERTY_SCALED
-#undef CSQCMODEL_PROPERTY
-#undef CSQCMODEL_ENDIF
-#undef CSQCMODEL_IF
-#endif
index 66a79c8..49b8ef7 100644 (file)
@@ -25,7 +25,7 @@
     #include "../dpdefs/keycodes.qh"
 #endif
 
-#include "../warpzonelib/mathlib.qc"
+#include "warpzone/mathlib.qc"
 
 #include "accumulate.qh"
 #include "bits.qh"
diff --git a/qcsrc/lib/csqcmodel/cl_model.qc b/qcsrc/lib/csqcmodel/cl_model.qc
new file mode 100644 (file)
index 0000000..8d3d4ab
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2011 Rudolf PolzerCSQCModel_InterpolateAnimation_2To4_PreNote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "cl_model.qh"
+
+#include "cl_player.qh"
+#include "common.qh"
+#include "interpolate.qh"
+#include "../../client/defs.qh"
+#include "../../common/animdecide.qh"
+#include "../../common/csqcmodel_settings.qh"
+#include "../../common/util.qh"
+
+float autocvar_cl_lerpanim_maxdelta_framegroups = 0.1;
+float autocvar_cl_nolerp = 0;
+
+.float csqcmodel_lerpfrac;
+.float csqcmodel_lerpfrac2;
+.float csqcmodel_lerpfractime;
+.float csqcmodel_lerpfrac2time;
+
+void CSQCModel_InterpolateAnimation_2To4_PreNote(int sf)
+{SELFPARAM();
+       if(sf & CSQCMODEL_PROPERTY_FRAME)
+       {
+               self.frame3 = self.frame;
+               self.frame3time = self.frame1time;
+       }
+       if(sf & CSQCMODEL_PROPERTY_FRAME2)
+       {
+               self.frame4 = self.frame2;
+               self.frame4time = self.frame2time;
+       }
+       if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
+       {
+               self.csqcmodel_lerpfrac2 = self.csqcmodel_lerpfrac;
+               self.csqcmodel_lerpfrac2time = self.csqcmodel_lerpfractime;
+               self.lerpfrac = self.csqcmodel_lerpfrac;
+       }
+}
+void CSQCModel_InterpolateAnimation_1To2_PreNote(int sf)
+{SELFPARAM();
+       if(sf & CSQCMODEL_PROPERTY_FRAME)
+       {
+               self.frame2 = self.frame;
+               self.frame2time = self.frame1time;
+       }
+}
+void CSQCModel_InterpolateAnimation_PreNote(int sf)
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+       CSQCModel_InterpolateAnimation_2To4_PreNote(sf);
+#else
+       CSQCModel_InterpolateAnimation_1To2_PreNote(sf);
+#endif
+}
+
+void CSQCModel_InterpolateAnimation_2To4_Note(int sf, float set_times)
+{SELFPARAM();
+       if(sf & CSQCMODEL_PROPERTY_FRAME)
+       {
+               if(set_times)
+                       self.frame1time = time;
+       }
+       if(sf & CSQCMODEL_PROPERTY_FRAME2)
+       {
+               if(set_times)
+                       self.frame2time = time;
+       }
+       if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
+       {
+               self.csqcmodel_lerpfrac = self.lerpfrac;
+               if(set_times)
+                       self.csqcmodel_lerpfractime = time;
+       }
+}
+void CSQCModel_InterpolateAnimation_1To2_Note(int sf, float set_times)
+{SELFPARAM();
+       if(sf & CSQCMODEL_PROPERTY_FRAME)
+       {
+               if(set_times)
+                       self.frame1time = time;
+       }
+}
+void CSQCModel_InterpolateAnimation_Note(int sf)
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+       CSQCModel_InterpolateAnimation_2To4_Note(sf, true);
+#else
+       CSQCModel_InterpolateAnimation_1To2_Note(sf, true);
+#endif
+}
+
+void CSQCModel_InterpolateAnimation_2To4_Do()
+{SELFPARAM();
+       if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
+       {
+               self.lerpfrac = self.csqcmodel_lerpfrac;
+               self.lerpfrac3 = 0;
+               self.lerpfrac4 = 0;
+       }
+       else
+       {
+               float l13, l24, llf;
+               float l24_13;
+
+               if(self.frame3time == 0) // if frame1/3 were not previously displayed, only frame1 can make sense
+                       l13 = 1;
+               else
+                       l13 = bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+
+               if(self.frame4time == 0) // if frame2/4 were not previously displayed, only frame2 can make sense
+                       l24 = 1;
+               else
+                       l24 = bound(0, (time - self.frame2time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+
+               if(self.csqcmodel_lerpfrac2time == 0) // if there is no old lerpfrac (newly displayed model), only lerpfrac makes sense
+                       llf = 1;
+               else
+                       llf = bound(0, (time - self.csqcmodel_lerpfractime) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+
+               l24_13 = self.csqcmodel_lerpfrac * llf + self.csqcmodel_lerpfrac2 * (1 - llf);
+
+               self.lerpfrac  = l24 * l24_13;
+               self.lerpfrac4 = (1 - l24) * l24_13;
+               self.lerpfrac3 = (1 - l13) * (1 - l24_13);
+
+               if(l24_13 == 0) // if frames 2/4 are not displayed, clear their frametime
+               {
+                       self.frame2time = 0;
+                       self.frame4time = 0;
+               }
+
+               if(l24_13 == 1) // if frames 1/3 are not displayed, clear their frametime
+               {
+                       self.frame1time = 0;
+                       self.frame3time = 0;
+               }
+       }
+}
+void CSQCModel_InterpolateAnimation_1To2_Do()
+{SELFPARAM();
+       if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
+       {
+               self.lerpfrac = 0;
+       }
+       else
+       {
+               if(self.frame2time == 0) // if frame2 was not previously displayed, only frame1 can make sense
+                       self.lerpfrac = 0;
+               else
+                       self.lerpfrac = 1 - bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+       }
+}
+void CSQCModel_InterpolateAnimation_Do()
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+       CSQCModel_InterpolateAnimation_2To4_Do();
+#else
+       CSQCModel_InterpolateAnimation_1To2_Do();
+#endif
+}
+
+void CSQCModel_Draw()
+{SELFPARAM();
+       // some nice flags for CSQCMODEL_IF and the hooks
+       bool isplayer = (self.entnum >= 1 && self.entnum <= maxclients);
+       noref bool islocalplayer = (self.entnum == player_localnum + 1);
+       noref bool isnolocalplayer = (isplayer && (self.entnum != player_localnum + 1));
+
+       // we don't do this for the local player as that one is already handled
+       // by CSQCPlayer_SetCamera()
+       if(!CSQCPlayer_IsLocalPlayer())
+               InterpolateOrigin_Do();
+
+       CSQCModel_InterpolateAnimation_Do();
+
+       { CSQCMODEL_HOOK_PREDRAW }
+
+       // inherit draw flags easily
+       entity root = self;
+       while(root.tag_entity)
+               root = root.tag_entity;
+       if(self != root)
+       {
+               self.renderflags &= ~(RF_EXTERNALMODEL | RF_VIEWMODEL);
+               self.renderflags |= (root.renderflags & (RF_EXTERNALMODEL | RF_VIEWMODEL));
+       }
+
+       // we're drawn, now teleporting is over
+       self.csqcmodel_teleported = 0;
+}
+
+void CSQCModel_Read(bool isnew)
+{SELFPARAM();
+       int sf = ReadInt24_t();
+
+       // some nice flags for CSQCMODEL_IF and the hooks
+       bool isplayer = (self.entnum >= 1 && self.entnum <= maxclients);
+       bool islocalplayer = (self.entnum == player_localnum + 1);
+       noref bool isnolocalplayer = (isplayer && (self.entnum != player_localnum + 1));
+
+       self.classname = "csqcmodel";
+       self.iflags |= IFLAG_ORIGIN; // interpolate origin too
+       self.iflags |= IFLAG_ANGLES; // interpolate angles too
+       self.iflags |= IFLAG_VELOCITY | IFLAG_AUTOVELOCITY; // let's calculate velocity automatically
+
+       { CSQCMODEL_HOOK_PREUPDATE }
+
+       CSQCPlayer_PreUpdate();
+       InterpolateOrigin_Undo();
+       CSQCModel_InterpolateAnimation_PreNote(sf);
+
+#define CSQCMODEL_IF(cond) if(cond) {
+#define CSQCMODEL_ENDIF }
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+       if(sf & flag) \
+               self.f = r();
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
+       if(sf & flag) \
+               self.f = (r() + mi) / s;
+       ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+
+       if(sf & CSQCMODEL_PROPERTY_MODELINDEX)
+       {
+               vector pmin = self.mins, pmax = self.maxs;
+               setmodelindex(self, self.modelindex); // this retrieves the .model key and sets mins/maxs/absmin/absmax
+               setsize(self, pmin, pmax);
+       }
+
+       if(sf & CSQCMODEL_PROPERTY_TELEPORTED)
+       {
+               self.iflags |= IFLAG_TELEPORTED;
+               self.csqcmodel_teleported = 1;
+       }
+
+       CSQCModel_InterpolateAnimation_Note(sf);
+       InterpolateOrigin_Note();
+       CSQCPlayer_PostUpdate();
+
+       { CSQCMODEL_HOOK_POSTUPDATE }
+
+#ifdef CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
+       InterpolateOrigin_Do();
+       CSQCModel_InterpolateAnimation_Do();
+#endif
+
+       // relink
+       setorigin(self, self.origin);
+
+       // set obvious render flags
+       if(self.entnum == player_localentnum)
+               self.renderflags |= RF_EXTERNALMODEL;
+       else
+               self.renderflags &= ~RF_EXTERNALMODEL;
+
+       // draw it
+       self.drawmask = MASK_NORMAL;
+       self.predraw = CSQCModel_Draw;
+}
+
+entity CSQCModel_server2csqc(float pl)
+{
+       return findfloat(world, entnum, pl); // FIXME optimize this using an array
+}
diff --git a/qcsrc/lib/csqcmodel/cl_model.qh b/qcsrc/lib/csqcmodel/cl_model.qh
new file mode 100644 (file)
index 0000000..55401e4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef LIB_CSQCMODEL_CL_MODEL_H
+#define LIB_CSQCMODEL_CL_MODEL_H
+
+#include "common.qh"
+
+void CSQCModel_Read(bool isnew);
+
+#define CSQCMODEL_IF(cond)
+#define CSQCMODEL_ENDIF
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+       .t f;
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+       ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+
+entity CSQCModel_server2csqc(float pl);
+.float csqcmodel_teleported;
+
+// this is exported for custom frame animation code. Use with care.
+// to update frames, first call this:
+void CSQCModel_InterpolateAnimation_2To4_PreNote(int sf);
+void CSQCModel_InterpolateAnimation_1To2_PreNote(int sf);
+// then update frame, frame1time (and possibly frame2, frame2time, lerpfrac)
+// if set_times is not set, caller is responsible for frame1time, frame2time, csqcmodel_lerpfractime!
+void CSQCModel_InterpolateAnimation_2To4_Note(int sf, float set_times);
+void CSQCModel_InterpolateAnimation_1To2_Note(int sf, float set_times);
+// to retrieve animation state, call this
+void CSQCModel_InterpolateAnimation_2To4_Do();
+void CSQCModel_InterpolateAnimation_1To2_Do();
+// will overwrite lerpfrac, lerpfrac3, lerpfrac4, and possibly clear frame*time if they are undisplayed according to lerpfracs
+#endif
diff --git a/qcsrc/lib/csqcmodel/cl_player.qc b/qcsrc/lib/csqcmodel/cl_player.qc
new file mode 100644 (file)
index 0000000..ae4e55a
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ * Copyright (c) 2015 Micah Talkiewicz
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "cl_player.qh"
+
+#include "cl_model.qh"
+#include "common.qh"
+#include "interpolate.qh"
+#include "../../client/defs.qh"
+#include "../../client/main.qh"
+#include "../../common/constants.qh"
+#include "../../common/stats.qh"
+#include "../../common/triggers/trigger/viewloc.qh"
+#include "../../common/util.qh"
+#include "../../common/viewloc.qh"
+
+float autocvar_cl_movement_errorcompensation = 0;
+int autocvar_cl_movement = 1;
+
+// engine stuff
+float pmove_onground; // weird engine flag we shouldn't really use but have to for now
+
+vector csqcplayer_origin, csqcplayer_velocity;
+float csqcplayer_sequence;
+int player_pmflags;
+float csqcplayer_moveframe;
+vector csqcplayer_predictionerroro;
+vector csqcplayer_predictionerrorv;
+float csqcplayer_predictionerrortime;
+float csqcplayer_predictionerrorfactor;
+
+vector CSQCPlayer_GetPredictionErrorO()
+{
+       if(time >= csqcplayer_predictionerrortime)
+               return '0 0 0';
+       return csqcplayer_predictionerroro * (csqcplayer_predictionerrortime - time) * csqcplayer_predictionerrorfactor;
+}
+
+vector CSQCPlayer_GetPredictionErrorV()
+{
+       if(time >= csqcplayer_predictionerrortime)
+               return '0 0 0';
+       return csqcplayer_predictionerrorv * (csqcplayer_predictionerrortime - time) * csqcplayer_predictionerrorfactor;
+}
+
+void CSQCPlayer_SetPredictionError(vector o, vector v, float onground_diff)
+{
+       // error too big to compensate, we LIKELY hit a teleport or a
+       // jumppad, or it's a jump time disagreement that'll get fixed
+       // next frame
+
+       // FIXME we sometimes have disagreement in order of jump velocity. Do not act on them!
+       /*
+       // commented out as this one did not help
+       if(onground_diff)
+       {
+               printf("ONGROUND MISMATCH: %d x=%v v=%v\n", onground_diff, o, v);
+               return;
+       }
+       */
+       if(vlen(o) > 32 || vlen(v) > 192)
+       {
+               //printf("TOO BIG: x=%v v=%v\n", o, v);
+               return;
+       }
+
+       if(!autocvar_cl_movement_errorcompensation)
+       {
+               csqcplayer_predictionerrorfactor = 0;
+               return;
+       }
+
+       csqcplayer_predictionerroro = CSQCPlayer_GetPredictionErrorO() + o;
+       csqcplayer_predictionerrorv = CSQCPlayer_GetPredictionErrorV() + v;
+       csqcplayer_predictionerrorfactor = autocvar_cl_movement_errorcompensation / ticrate;
+       csqcplayer_predictionerrortime = time + 1.0 / csqcplayer_predictionerrorfactor;
+}
+
+void CSQCPlayer_Unpredict()
+{SELFPARAM();
+       if(csqcplayer_status == CSQCPLAYERSTATUS_UNPREDICTED)
+               return;
+       if(csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED)
+               error("Cannot unpredict in current status");
+       self.origin = csqcplayer_origin;
+       self.velocity = csqcplayer_velocity;
+       csqcplayer_moveframe = csqcplayer_sequence+1; //+1 because the recieved frame has the move already done (server side)
+       self.flags = player_pmflags;
+}
+
+void CSQCPlayer_SetMinsMaxs()
+{SELFPARAM();
+       if(self.flags & FL_DUCKED)
+       {
+               self.mins = PL_CROUCH_MIN;
+               self.maxs = PL_CROUCH_MAX;
+               self.view_ofs = PL_CROUCH_VIEW_OFS;
+       }
+       else
+       {
+               self.mins = PL_MIN;
+               self.maxs = PL_MAX;
+               self.view_ofs = PL_VIEW_OFS;
+       }
+}
+
+void CSQCPlayer_SavePrediction()
+{SELFPARAM();
+       player_pmflags = self.flags;
+       csqcplayer_origin = self.origin;
+       csqcplayer_velocity = self.velocity;
+       csqcplayer_sequence = servercommandframe;
+       csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
+}
+
+void CSQC_ClientMovement_PlayerMove_Frame();
+
+void PM_Movement_Move()
+{SELFPARAM();
+       runstandardplayerphysics(self);
+#ifdef CSQC
+       self.flags =
+                       ((self.pmove_flags & PMF_DUCKED) ? FL_DUCKED : 0) |
+                       (!(self.pmove_flags & PMF_JUMP_HELD) ? FL_JUMPRELEASED : 0) |
+                       ((self.pmove_flags & PMF_ONGROUND) ? FL_ONGROUND : 0);
+#endif
+}
+
+void CSQCPlayer_Physics(void)
+{
+       switch(autocvar_cl_movement)
+       {
+               case 1: CSQC_ClientMovement_PlayerMove_Frame(); break;
+               case 2: PM_Movement_Move(); break;
+       }
+}
+
+void CSQCPlayer_PredictTo(float endframe, float apply_error)
+{SELFPARAM();
+       CSQCPlayer_Unpredict();
+       if(apply_error)
+       {
+               self.origin += CSQCPlayer_GetPredictionErrorO();
+               self.velocity += CSQCPlayer_GetPredictionErrorV();
+       }
+       CSQCPlayer_SetMinsMaxs();
+
+       csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
+
+#if 0
+       // we don't need this
+       // darkplaces makes servercommandframe == 0 in these cases anyway
+       if (getstatf(STAT_HEALTH) <= 0)
+       {
+               csqcplayer_moveframe = clientcommandframe;
+               getinputstate(csqcplayer_moveframe-1);
+               LOG_INFO("the Weird code path got hit\n");
+               return;
+       }
+#endif
+
+       if(csqcplayer_moveframe >= endframe)
+       {
+               getinputstate(csqcplayer_moveframe - 1);
+       }
+       else
+       {
+               do
+               {
+                       if (!getinputstate(csqcplayer_moveframe))
+                               break;
+                       CSQCPlayer_Physics();
+                       CSQCPlayer_SetMinsMaxs();
+                       csqcplayer_moveframe++;
+               }
+               while(csqcplayer_moveframe < endframe);
+       }
+
+       //add in anything that was applied after (for low packet rate protocols)
+       input_angles = view_angles;
+}
+
+bool CSQCPlayer_IsLocalPlayer()
+{SELFPARAM();
+       return (self == csqcplayer);
+}
+
+void CSQCPlayer_SetViewLocation()
+{
+       viewloc_SetViewLocation();
+}
+
+void CSQCPlayer_SetCamera()
+{SELFPARAM();
+       vector v0;
+       v0 = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
+
+       if(csqcplayer)
+       {
+               setself(csqcplayer);
+
+               if(servercommandframe == 0 || clientcommandframe == 0)
+               {
+                       InterpolateOrigin_Do();
+                       self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
+
+                       // get crouch state from the server
+                       if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+                               self.flags &= ~FL_DUCKED;
+                       else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+                               self.flags |= FL_DUCKED;
+
+                       // get onground state from the server
+                       if(pmove_onground)
+                               self.flags |= FL_ONGROUND;
+                       else
+                               self.flags &= ~FL_ONGROUND;
+
+                       CSQCPlayer_SetMinsMaxs();
+
+                       // override it back just in case
+                       self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
+
+                       // set velocity
+                       self.velocity = v0;
+               }
+               else
+               {
+                       float flg = self.iflags;
+                       self.iflags &= ~(IFLAG_ORIGIN | IFLAG_ANGLES);
+                       InterpolateOrigin_Do();
+                       self.iflags = flg;
+
+                       if(csqcplayer_status == CSQCPLAYERSTATUS_FROMSERVER)
+                       {
+                               vector o, v;
+                               o = self.origin;
+                               v = v0;
+                               csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
+                               CSQCPlayer_PredictTo(servercommandframe + 1, false);
+                               CSQCPlayer_SetPredictionError(self.origin - o, self.velocity - v, pmove_onground - !!(self.flags & FL_ONGROUND));
+                               self.origin = o;
+                               self.velocity = v;
+
+                               // get crouch state from the server
+                               if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+                                       self.flags &= ~FL_DUCKED;
+                               else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+                                       self.flags |= FL_DUCKED;
+
+                               // get onground state from the server
+                               if(pmove_onground)
+                                       self.flags |= FL_ONGROUND;
+                               else
+                                       self.flags &= ~FL_ONGROUND;
+
+                               CSQCPlayer_SavePrediction();
+                       }
+                       CSQCPlayer_PredictTo(clientcommandframe + 1, true);
+
+#ifdef CSQCMODEL_SERVERSIDE_CROUCH
+                       // get crouch state from the server (LAG)
+                       if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+                               self.flags &= ~FL_DUCKED;
+                       else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+                               self.flags |= FL_DUCKED;
+#endif
+
+                       CSQCPlayer_SetMinsMaxs();
+
+                       self.angles_y = input_angles.y;
+               }
+
+               // relink
+               setorigin(self, self.origin);
+
+               setself(this);
+       }
+
+       entity view = CSQCModel_server2csqc(player_localentnum);
+
+       if(view && view != csqcplayer)
+       {
+               WITH(entity, self, view, InterpolateOrigin_Do());
+               view.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
+       }
+
+       if(view)
+       {
+               int refdefflags = 0;
+
+               if(view.csqcmodel_teleported)
+                       refdefflags |= REFDEFFLAG_TELEPORTED;
+
+               if(input_buttons & 4)
+                       refdefflags |= REFDEFFLAG_JUMPING;
+
+               // note: these two only work in WIP2, but are harmless in WIP1
+               if(getstati(STAT_HEALTH) <= 0)
+                       refdefflags |= REFDEFFLAG_DEAD;
+
+               if(intermission)
+                       refdefflags |= REFDEFFLAG_INTERMISSION;
+
+               V_CalcRefdef(view, refdefflags);
+       }
+       else
+       {
+               // FIXME by CSQC spec we have to do this:
+               // but it breaks chase cam
+               /*
+               setproperty(VF_ORIGIN, pmove_org + '0 0 1' * getstati(STAT_VIEWHEIGHT));
+               setproperty(VF_ANGLES, view_angles);
+               */
+       }
+
+       { CSQCPLAYER_HOOK_POSTCAMERASETUP }
+}
+
+void CSQCPlayer_Remove()
+{
+       csqcplayer = world;
+       cvar_settemp("cl_movement_replay", "1");
+}
+
+float CSQCPlayer_PreUpdate()
+{SELFPARAM();
+       if(self != csqcplayer)
+               return 0;
+       if(csqcplayer_status != CSQCPLAYERSTATUS_FROMSERVER)
+               CSQCPlayer_Unpredict();
+       return 1;
+}
+
+float CSQCPlayer_PostUpdate()
+{SELFPARAM();
+       if(self.entnum != player_localnum + 1)
+               return 0;
+       csqcplayer = self;
+       csqcplayer_status = CSQCPLAYERSTATUS_FROMSERVER;
+       cvar_settemp("cl_movement_replay", "0");
+       self.entremove = CSQCPlayer_Remove;
+       return 1;
+}
diff --git a/qcsrc/lib/csqcmodel/cl_player.qh b/qcsrc/lib/csqcmodel/cl_player.qh
new file mode 100644 (file)
index 0000000..c9598c8
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef LIB_CSQCMODEL_CL_PLAYER_H
+#define LIB_CSQCMODEL_CL_PLAYER_H
+
+entity csqcplayer;
+float csqcplayer_status;
+const int CSQCPLAYERSTATUS_UNPREDICTED = 0;
+const int CSQCPLAYERSTATUS_FROMSERVER = 1;
+const int CSQCPLAYERSTATUS_PREDICTED = 2;
+
+// only ever READ these!
+.int pmove_flags;
+const int PMF_JUMP_HELD = 1;
+//const int PMF_DUCKED = 4;
+//const int PMF_ONGROUND = 8;
+
+const int FL_DUCKED = 524288;
+
+void CSQCPlayer_SetCamera();
+float CSQCPlayer_PreUpdate();
+float CSQCPlayer_PostUpdate();
+float CSQCPlayer_IsLocalPlayer();
+#endif
diff --git a/qcsrc/lib/csqcmodel/common.qh b/qcsrc/lib/csqcmodel/common.qh
new file mode 100644 (file)
index 0000000..884977f
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef LIB_CSQCMODEL_COMMON_H
+#define LIB_CSQCMODEL_COMMON_H
+
+#include "../../common/csqcmodel_settings.qh"
+
+noref string csqcmodel_license = "\
+Copyright (c) 2011 Rudolf Polzer\
+\
+Permission is hereby granted, free of charge, to any person obtaining a copy\
+of this software and associated documentation files (the \"Software\"), to\
+deal in the Software without restriction, including without limitation the\
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\
+sell copies of the Software, and to permit persons to whom the Software is\
+furnished to do so, subject to the following conditions:\
+\
+The above copyright notice and this permission notice shall be included in\
+all copies or substantial portions of the Software.\
+\
+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\
+IN THE SOFTWARE.\
+";
+
+.vector glowmod;
+.vector view_ofs;
+.int frame;
+.float frame1time;
+.int frame2;
+.float frame2time;
+.float lerpfrac;
+
+const int CSQCMODEL_PROPERTY_FRAME = 8388608;
+const int CSQCMODEL_PROPERTY_TELEPORTED = 4194304; // the "teleport bit" cancelling interpolation
+const int CSQCMODEL_PROPERTY_MODELINDEX = 2097152;
+const int CSQCMODEL_PROPERTY_ORIGIN = 1048576;
+const int CSQCMODEL_PROPERTY_YAW = 524288;
+const int CSQCMODEL_PROPERTY_PITCHROLL = 262144;
+const int CSQCMODEL_PROPERTY_FRAME2 = 131072;
+const int CSQCMODEL_PROPERTY_LERPFRAC = 65536;
+const int CSQCMODEL_PROPERTY_SIZE = 32768;
+
+#define ALLPROPERTIES_COMMON \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME, int, ReadByte, WriteByte, frame) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_MODELINDEX, int, ReadShort, WriteShort, modelindex) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_x) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_y) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_z) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_x) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_y) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_z) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_x) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_y) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_z) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_x) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_YAW, float, ReadAngle, WriteAngle, angles_y) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_z) \
+       CSQCMODEL_EXTRAPROPERTIES
+
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+.float frame3;
+.float frame3time;
+.float lerpfrac3;
+.float frame4;
+.float frame4time;
+.float lerpfrac4;
+#define ALLPROPERTIES ALLPROPERTIES_COMMON \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME2, int, ReadByte, WriteByte, frame2) \
+       CSQCMODEL_PROPERTY_SCALED(CSQCMODEL_PROPERTY_LERPFRAC, float, ReadByte, WriteByte, lerpfrac, 255, 0, 255)
+#else
+#define ALLPROPERTIES ALLPROPERTIES_COMMON
+#endif
+#endif
diff --git a/qcsrc/lib/csqcmodel/interpolate.qc b/qcsrc/lib/csqcmodel/interpolate.qc
new file mode 100644 (file)
index 0000000..ca846da
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "interpolate.qh"
+
+#if defined(CSQC)
+//     #include "../../client/defs.qh"
+//     #include "../warpzone/anglestransform.qh"
+//     #include "../../client/autocvars.qh"
+//     #include "cl_model.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+#endif
+
+.vector iorigin1, iorigin2;
+.vector ivelocity1, ivelocity2;
+.vector iforward1, iforward2;
+.vector iup1, iup2;
+.vector ivforward1, ivforward2;
+.vector ivup1, ivup2;
+.float itime1, itime2;
+void InterpolateOrigin_Reset()
+{SELFPARAM();
+       self.iflags &= ~IFLAG_INTERNALMASK;
+       self.itime1 = self.itime2 = 0;
+}
+void InterpolateOrigin_Note()
+{SELFPARAM();
+       float dt;
+       int f0;
+
+       dt = time - self.itime2;
+
+       f0 = self.iflags;
+       if(self.iflags & IFLAG_PREVALID)
+               self.iflags |= IFLAG_VALID;
+       else
+               self.iflags |= IFLAG_PREVALID;
+
+       if(self.iflags & IFLAG_ORIGIN)
+       {
+               self.iorigin1 = self.iorigin2;
+               self.iorigin2 = self.origin;
+       }
+
+       if(self.iflags & IFLAG_AUTOANGLES)
+               if(self.iorigin2 != self.iorigin1)
+                       self.angles = vectoangles(self.iorigin2 - self.iorigin1);
+
+       if(self.iflags & IFLAG_AUTOVELOCITY)
+               if(self.itime2 != self.itime1)
+                       self.velocity = (self.iorigin2 - self.iorigin1) * (1.0 / (self.itime2 - self.itime1));
+
+       if(self.iflags & IFLAG_ANGLES)
+       {
+               fixedmakevectors(self.angles);
+               if(f0 & IFLAG_VALID)
+               {
+                       self.iforward1 = self.iforward2;
+                       self.iup1 = self.iup2;
+               }
+               else
+               {
+                       self.iforward1 = v_forward;
+                       self.iup1 = v_up;
+               }
+               self.iforward2 = v_forward;
+               self.iup2 = v_up;
+       }
+
+       if(self.iflags & IFLAG_V_ANGLE)
+       {
+               fixedmakevectors(self.v_angle);
+               if(f0 & IFLAG_VALID)
+               {
+                       self.ivforward1 = self.ivforward2;
+                       self.ivup1 = self.ivup2;
+               }
+               else
+               {
+                       self.ivforward1 = v_forward;
+                       self.ivup1 = v_up;
+               }
+               self.ivforward2 = v_forward;
+               self.ivup2 = v_up;
+       }
+       else if(self.iflags & IFLAG_V_ANGLE_X)
+       {
+               self.ivforward1_x = self.ivforward2_x;
+               self.ivforward2_x = self.v_angle.x;
+       }
+
+       if(self.iflags & IFLAG_VELOCITY)
+       {
+               self.ivelocity1 = self.ivelocity2;
+               self.ivelocity2 = self.velocity;
+       }
+
+       if(self.iflags & IFLAG_TELEPORTED)
+       {
+               self.iflags &= ~IFLAG_TELEPORTED;
+               self.itime1 = self.itime2 = time; // don't lerp
+       }
+       else if(vlen(self.iorigin2 - self.iorigin1) > 1000)
+       {
+               self.itime1 = self.itime2 = time; // don't lerp
+       }
+       else if((self.iflags & IFLAG_VELOCITY) && (vlen(self.ivelocity2 - self.ivelocity1) > 1000))
+       {
+               self.itime1 = self.itime2 = time; // don't lerp
+       }
+       else if(dt >= 0.2)
+       {
+               self.itime1 = self.itime2 = time;
+       }
+       else
+       {
+               self.itime1 = serverprevtime;
+               self.itime2 = time;
+       }
+}
+void InterpolateOrigin_Do()
+{SELFPARAM();
+       vector forward, up;
+       if(self.itime1 && self.itime2 && self.itime1 != self.itime2)
+       {
+               float f;
+               f = bound(0, (time - self.itime1) / (self.itime2 - self.itime1), 1 + autocvar_cl_lerpexcess);
+               if(self.iflags & IFLAG_ORIGIN)
+                       setorigin(self, (1 - f) * self.iorigin1 + f * self.iorigin2);
+               if(self.iflags & IFLAG_ANGLES)
+               {
+                       forward = (1 - f) * self.iforward1 + f * self.iforward2;
+                       up = (1 - f) * self.iup1 + f * self.iup2;
+                       self.angles = fixedvectoangles2(forward, up);
+               }
+               if(self.iflags & IFLAG_V_ANGLE)
+               {
+                       forward = (1 - f) * self.ivforward1 + f * self.ivforward2;
+                       up = (1 - f) * self.ivup1 + f * self.ivup2;
+                       self.v_angle = fixedvectoangles2(forward, up);
+               }
+               else if(self.iflags & IFLAG_V_ANGLE_X)
+                       self.v_angle_x = (1 - f) * self.ivforward1_x + f * self.ivforward2_x;
+               if(self.iflags & IFLAG_VELOCITY)
+                       self.velocity = (1 - f) * self.ivelocity1 + f * self.ivelocity2;
+       }
+}
+void InterpolateOrigin_Undo()
+{SELFPARAM();
+       if(self.iflags & IFLAG_ORIGIN)
+               setorigin(self, self.iorigin2);
+       if(self.iflags & IFLAG_ANGLES)
+               self.angles = fixedvectoangles2(self.iforward2, self.iup2);
+       if(self.iflags & IFLAG_V_ANGLE)
+               self.v_angle = fixedvectoangles2(self.ivforward2, self.ivup2);
+       else if(self.iflags & IFLAG_V_ANGLE_X)
+               self.v_angle_x = self.ivforward2_x;
+       if(self.iflags & IFLAG_VELOCITY)
+               self.velocity = self.ivelocity2;
+}
+
diff --git a/qcsrc/lib/csqcmodel/interpolate.qh b/qcsrc/lib/csqcmodel/interpolate.qh
new file mode 100644 (file)
index 0000000..e07ad4a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef LIB_CSQCMODEL_INTERPOLATE_H
+#define LIB_CSQCMODEL_INTERPOLATE_H
+
+.int iflags;
+const int IFLAG_VELOCITY = 1;
+const int IFLAG_ANGLES = 2;
+const int IFLAG_AUTOANGLES = 4;
+const int IFLAG_VALID = 8;
+const int IFLAG_PREVALID = 16;
+const int IFLAG_TELEPORTED = 32;
+const int IFLAG_AUTOVELOCITY = 64;
+const int IFLAG_V_ANGLE = 128;
+const int IFLAG_V_ANGLE_X = 256;
+const int IFLAG_ORIGIN = 512;
+#define IFLAG_INTERNALMASK (IFLAG_VALID | IFLAG_PREVALID)
+
+// call this BEFORE reading an entity update
+void InterpolateOrigin_Undo();
+
+// call this AFTER receiving an entity update
+void InterpolateOrigin_Note();
+
+// call this when the entity got teleported, before InterpolateOrigin_Note
+void InterpolateOrigin_Reset();
+
+// call this BEFORE drawing
+void InterpolateOrigin_Do();
+
+// in case we interpolate that:
+.vector v_angle;
+#endif
diff --git a/qcsrc/lib/csqcmodel/settings.qh b/qcsrc/lib/csqcmodel/settings.qh
new file mode 100644 (file)
index 0000000..128da85
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef LIB_CSQCMODEL_SETTINGS_H
+#define LIB_CSQCMODEL_SETTINGS_H
+// define this if svqc code wants to use .frame2 and .lerpfrac
+//#define CSQCMODEL_HAVE_TWO_FRAMES
+
+// don't define this ever
+//#define CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
+
+// add properties you want networked to CSQC here
+#define CSQCMODEL_EXTRAPROPERTIES \
+       /* CSQCMODEL_PROPERTY(1, float, ReadShort, WriteShort, colormap) */ \
+       /* CSQCMODEL_PROPERTY(2, float, ReadInt24_t, WriteInt24_t, effects) */
+
+// add hook function calls here
+#define CSQCMODEL_HOOK_PREUPDATE
+#define CSQCMODEL_HOOK_POSTUPDATE
+#define CSQCMODEL_HOOK_PREDRAW
+#define CSQCPLAYER_HOOK_POSTCAMERASETUP
+
+// force updates of player entities that often even if unchanged
+#define CSQCPLAYER_FORCE_UPDATES 0.25
+
+// mod must define:
+//vector PL_MIN  = ...;
+//vector PL_MAX  = ...;
+//vector PL_VIEW_OFS  = ...;
+//vector PL_CROUCH_MIN  = ...;
+//vector PL_CROUCH_MAX  = ...;
+//vector PL_CROUCH_VIEW_OFS  = ...;
+#endif
diff --git a/qcsrc/lib/csqcmodel/sv_model.qc b/qcsrc/lib/csqcmodel/sv_model.qc
new file mode 100644 (file)
index 0000000..8fcdcfb
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "sv_model.qh"
+
+#include "common.qh"
+#include "../../common/animdecide.qh"
+#include "../../common/constants.qh"
+#include "../../common/util.qh"
+#include "../../server/constants.qh"
+#include "../../server/defs.qh"
+
+// generic CSQC model code
+
+bool CSQCModel_Send(entity to, int sf)
+{SELFPARAM();
+       // some nice flags for CSQCMODEL_IF
+       float isplayer = (IS_CLIENT(self));
+       float islocalplayer = (self == to);
+       float isnolocalplayer = (isplayer && (self != to));
+
+       unused_float = isplayer;
+       unused_float = islocalplayer;
+       unused_float = isnolocalplayer;
+
+       WriteByte(MSG_ENTITY, ENT_CLIENT_MODEL);
+       WriteInt24_t(MSG_ENTITY, sf);
+
+#define CSQCMODEL_IF(cond) if(cond) {
+#define CSQCMODEL_ENDIF }
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+       if(sf & flag) \
+       { \
+               w(MSG_ENTITY, self.csqcmodel_##f); \
+       }
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+       ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+
+       return true;
+}
+
+#ifdef CSQCPLAYER_FORCE_UPDATES
+.float csqcmodel_nextforcedupdate;
+#endif
+void CSQCModel_CheckUpdate(entity e)
+{
+       // some nice flags for CSQCMODEL_IF
+       float isplayer = (IS_CLIENT(e));
+       float islocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
+       float isnolocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
+
+       unused_float = isplayer;
+       unused_float = islocalplayer;
+       unused_float = isnolocalplayer;
+
+#ifdef CSQCPLAYER_FORCE_UPDATES
+       if(isplayer && time > e.csqcmodel_nextforcedupdate)
+       {
+               e.SendFlags |= CSQCMODEL_PROPERTY_ORIGIN;
+               e.csqcmodel_nextforcedupdate = time + CSQCPLAYER_FORCE_UPDATES * (0.5 + random()); // ensure about 4 origin sends per sec
+       }
+#endif
+
+       if(e.effects & EF_RESTARTANIM_BIT)
+       {
+               e.SendFlags |= CSQCMODEL_PROPERTY_FRAME | CSQCMODEL_PROPERTY_FRAME2; // full anim resend please
+               e.effects &= ~EF_RESTARTANIM_BIT;
+       }
+
+       if(e.effects & EF_TELEPORT_BIT)
+       {
+               e.SendFlags |= CSQCMODEL_PROPERTY_TELEPORTED; // no interpolation please
+               e.effects &= ~EF_TELEPORT_BIT;
+       }
+
+#define CSQCMODEL_IF(cond) if(cond) {
+#define CSQCMODEL_ENDIF }
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+       { \
+               t tmp = e.f; \
+               if(tmp != e.csqcmodel_##f) \
+               { \
+                       e.csqcmodel_##f = tmp; \
+                       e.SendFlags |= flag; \
+               } \
+       }
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
+       { \
+               t tmp = rint(bound(mi, s * e.f, ma) - mi); \
+               if(tmp != e.csqcmodel_##f) \
+               { \
+                       e.csqcmodel_##f = tmp; \
+                       e.SendFlags |= flag; \
+               } \
+       }
+       ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+}
+
+void CSQCModel_LinkEntity(entity e)
+{
+       e.SendEntity = CSQCModel_Send;
+       e.SendFlags = 0xFFFFFF;
+       CSQCModel_CheckUpdate(e);
+}
+
+void CSQCModel_UnlinkEntity(entity e)
+{
+       e.SendEntity = func_null;
+}
diff --git a/qcsrc/lib/csqcmodel/sv_model.qh b/qcsrc/lib/csqcmodel/sv_model.qh
new file mode 100644 (file)
index 0000000..3e043d3
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef LIB_CSQCMODEL_SV_MODEL_H
+#define LIB_CSQCMODEL_SV_MODEL_H
+
+#include "common.qh"
+
+// generic CSQC model code
+
+void CSQCModel_CheckUpdate(entity e);
+void CSQCModel_LinkEntity(entity e);
+void CSQCModel_UnlinkEntity(entity e);
+
+#define CSQCMODEL_IF(cond)
+#define CSQCMODEL_ENDIF
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+       .t f; \
+       .t csqcmodel_##f;
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+       ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+#endif
diff --git a/qcsrc/lib/warpzone/COPYING b/qcsrc/lib/warpzone/COPYING
new file mode 100644 (file)
index 0000000..d61ba0a
--- /dev/null
@@ -0,0 +1,369 @@
+The code in this directory is dual-licensed MIT and GPLv2 "or any later version".
+
+
+
+MIT license:
+
+Copyright (c) 2010 Rudolf Polzer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+
+GPL v2:
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/qcsrc/lib/warpzone/TODO b/qcsrc/lib/warpzone/TODO
new file mode 100644 (file)
index 0000000..927ab12
--- /dev/null
@@ -0,0 +1,24 @@
+Open issues:
+- grep for TODO and FIXME
+- when shot origin is inside warpzone, vortex shot fails (and is even drawn in totally wrong direction). WHY? Possibly v_forward got lost?
+
+Weapon support:
+
+- blaster: YES
+- shotgun: YES
+- machinegun: YES
+- mortar: YES
+- electro: YES
+- crylink: YES
+- vortex: YES
+- hagar: YES
+- devastator: YES (except for trail bug)
+- porto: YES (bwahahahaha)
+- hlac: YES
+- vaporizer: YES
+- rifle: YES
+- fireball: YES (BFG effect cannot work through warpzones by design, so it's not available through warpzones)
+- hook: YES
+
+- shockwave: NO (does not support warpzones currently)
+- tuba: NO (sound)
diff --git a/qcsrc/lib/warpzone/anglestransform.qc b/qcsrc/lib/warpzone/anglestransform.qc
new file mode 100644 (file)
index 0000000..d6423f1
--- /dev/null
@@ -0,0 +1,225 @@
+#include "anglestransform.qh"
+
+#ifdef POSITIVE_PITCH_IS_DOWN
+vector fixedvectoangles(vector a)
+{
+       vector ang;
+       ang = vectoangles(a);
+       ang.x = -ang.x;
+       return ang;
+}
+vector fixedvectoangles2(vector a, vector b)
+{
+       vector ang;
+       ang = vectoangles2(a, b);
+       ang.x = -ang.x;
+       return ang;
+}
+#else
+void fixedmakevectors(vector a)
+{
+       // a makevectors that actually inverts vectoangles
+       a.x = -a.x;
+       makevectors(a);
+}
+#endif
+
+// angles transforms
+// angles in fixedmakevectors/fixedvectoangles space
+vector AnglesTransform_Apply(vector transform, vector v)
+{
+       fixedmakevectors(transform);
+       return v_forward * v.x
+               + v_right   * (-v.y)
+               + v_up      * v.z;
+}
+
+vector AnglesTransform_Multiply(vector t1, vector t2)
+{
+       vector m_forward, m_up;
+       fixedmakevectors(t2); m_forward = v_forward; m_up = v_up;
+       m_forward = AnglesTransform_Apply(t1, m_forward); m_up = AnglesTransform_Apply(t1, m_up);
+       return fixedvectoangles2(m_forward, m_up);
+}
+
+vector AnglesTransform_Invert(vector transform)
+{
+       vector i_forward, i_up;
+       fixedmakevectors(transform);
+       // we want angles that turn v_forward into '1 0 0', v_right into '0 1 0' and v_up into '0 0 1'
+       // but these are orthogonal unit vectors!
+       // so to invert, we can simply fixedvectoangles the TRANSPOSED matrix
+       // TODO is this always -transform?
+       i_forward.x = v_forward.x;
+       i_forward.y = -v_right.x;
+       i_forward.z = v_up.x;
+       i_up.x = v_forward.z;
+       i_up.y = -v_right.z;
+       i_up.z = v_up.z;
+       return fixedvectoangles2(i_forward, i_up);
+}
+
+vector AnglesTransform_TurnDirectionFR(vector transform)
+{
+       // turn 180 degrees around v_up
+       // changes in-direction to out-direction
+       //fixedmakevectors(transform);
+       //return fixedvectoangles2(-1 * v_forward, 1 * v_up);
+       transform.x = -transform.x;
+       transform.y = 180 + transform.y;
+       transform.z = -transform.z;
+       // pitch: -s +c
+       // yaw:   -s -c
+       // roll:  -s +c
+       return transform;
+}
+
+vector AnglesTransform_TurnDirectionFU(vector transform)
+{
+       // turn 180 degrees around v_up
+       // changes in-direction to out-direction
+       //fixedmakevectors(transform);
+       //return fixedvectoangles2(-1 * v_forward, 1 * v_up);
+       transform.x = -transform.x;
+       transform.y = 180 + transform.y;
+       transform.z = 180 - transform.z;
+       return transform;
+}
+
+vector AnglesTransform_RightDivide(vector to_transform, vector from_transform)
+{
+       return AnglesTransform_Multiply(to_transform, AnglesTransform_Invert(from_transform));
+}
+
+vector AnglesTransform_LeftDivide(vector from_transform, vector to_transform)
+{
+       return AnglesTransform_Multiply(AnglesTransform_Invert(from_transform), to_transform);
+}
+
+vector AnglesTransform_Normalize(vector t, float minimize_roll)
+{
+       float need_flip;
+       // first, bring all angles in their range...
+       t.x = t.x - 360 * rint(t.x / 360);
+       t.y = t.y - 360 * rint(t.y / 360);
+       t.z = t.z - 360 * rint(t.z / 360);
+       if(minimize_roll)
+               need_flip = (t.z > 90 || t.z <= -90);
+       else
+               need_flip = (t.x > 90 || t.x < -90); // for pitch we prefer to allow exactly -90 degrees for looking straight down
+       if(need_flip)
+       {
+               if(t.x >= 0) t.x = 180 - t.x; else t.x = -180 - t.x;
+               if(t.y > 0) t.y -= 180; else t.y += 180;
+               if(t.z > 0) t.z -= 180; else t.z += 180;
+       }
+       return t;
+}
+
+vector AnglesTransform_CancelRoll(vector t)
+{
+       const float epsilon = 30;
+       float f;
+
+       // constraints:
+       // forward vector (NOT SO important)
+       // right vector, up vector: screen rotation (MORE important)
+       // choose best match among all pitch-yaw only rotations
+
+       // FIXME find a better method
+
+       f = fabs(t.x - (-90)) / epsilon;
+       if(f < 1)
+       {
+               //t_x = -90;
+               t.y += t.z;
+               t.z = 0;
+       }
+       else
+       {
+               f = fabs(t.x - 90) / epsilon;
+               if(f < 1)
+               {
+                       //t_x = 90;
+                       t.y -= t.z;
+                       t.z = 0;
+               }
+       }
+       return t;
+}
+
+#ifdef POSITIVE_PITCH_IS_DOWN
+vector AnglesTransform_ApplyToAngles(vector transform, vector v)
+{
+       v.x = -v.x;
+       v = AnglesTransform_Multiply(transform, v);
+       v.x = -v.x;
+       return v;
+}
+vector AnglesTransform_ApplyToVAngles(vector transform, vector v)
+{
+       v = AnglesTransform_Multiply(transform, v);
+       return v;
+}
+vector AnglesTransform_FromAngles(vector v)
+{
+       v.x = -v.x;
+       return v;
+}
+vector AnglesTransform_ToAngles(vector v)
+{
+       v.x = -v.x;
+       return v;
+}
+vector AnglesTransform_FromVAngles(vector v)
+{
+       return v;
+}
+vector AnglesTransform_ToVAngles(vector v)
+{
+       return v;
+}
+#else
+vector AnglesTransform_ApplyToAngles(vector transform, vector v)
+{
+       v = AnglesTransform_Multiply(transform, v);
+       return v;
+}
+vector AnglesTransform_ApplyToVAngles(vector transform, vector v)
+{
+       v.x = -v.x;
+       v = AnglesTransform_Multiply(transform, v);
+       v.x = -v.x;
+       return v;
+}
+vector AnglesTransform_FromAngles(vector v)
+{
+       return v;
+}
+vector AnglesTransform_ToAngles(vector v)
+{
+       return v;
+}
+vector AnglesTransform_FromVAngles(vector v)
+{
+       v.x = -v.x;
+       return v;
+}
+vector AnglesTransform_ToVAngles(vector v)
+{
+       v.x = -v.x;
+       return v;
+}
+#endif
+
+vector AnglesTransform_Multiply_GetPostShift(vector t0, vector st0, vector t1, vector st1)
+{
+       // we want the result of:
+       //   t0 * (t1 * p + st1) + st0
+       //   t0 * t1 * p + t0 * st1 + st0
+       return st0 + AnglesTransform_Apply(t0, st1);
+}
+vector AnglesTransform_PrePostShift_GetPostShift(vector sf, vector t, vector st)
+{
+       return st - AnglesTransform_Apply(t, sf);
+}
diff --git a/qcsrc/lib/warpzone/anglestransform.qh b/qcsrc/lib/warpzone/anglestransform.qh
new file mode 100644 (file)
index 0000000..5c356ea
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef LIB_WARPZONE_ANGLETRANSFORM_H
+#define LIB_WARPZONE_ANGLETRANSFORM_H
+
+#define POSITIVE_PITCH_IS_DOWN
+
+#ifdef POSITIVE_PITCH_IS_DOWN
+#define fixedmakevectors makevectors
+vector fixedvectoangles(vector a);
+vector fixedvectoangles2(vector a, vector b);
+#else
+void fixedmakevectors(vector a);
+#define fixedvectoangles2 vectoangles2
+#define fixedvectoangles vectoangles
+#endif
+
+vector AnglesTransform_Apply(vector transform, vector v);
+vector AnglesTransform_Multiply(vector t1, vector t2); // A B
+vector AnglesTransform_Invert(vector transform);
+vector AnglesTransform_TurnDirectionFU(vector transform);
+vector AnglesTransform_TurnDirectionFR(vector transform);
+vector AnglesTransform_RightDivide(vector to_transform, vector from_transform); // A B^-1
+vector AnglesTransform_LeftDivide(vector from_transform, vector to_transform); // A^-1 B
+
+vector AnglesTransform_Normalize(vector t, float minimize_roll); // makes sure all angles are in their range: yaw in -180..180, pitch in -90..90, roll in -180..180 (or if minimize_roll is set, pitch in -180..180, roll in -90..90)
+
+vector AnglesTransform_ApplyToAngles(vector transform, vector v);
+vector AnglesTransform_ApplyToVAngles(vector transform, vector v);
+vector AnglesTransform_FromAngles(vector v);
+vector AnglesTransform_ToAngles(vector v);
+vector AnglesTransform_FromVAngles(vector v);
+vector AnglesTransform_ToVAngles(vector v);
+
+// transformed = original * transform + postshift
+vector AnglesTransform_Multiply_GetPostShift(vector sf0, vector st0, vector t1, vector st1);
+vector AnglesTransform_PrePostShift_GetPostShift(vector sf, vector t, vector st);
+#endif
diff --git a/qcsrc/lib/warpzone/client.qc b/qcsrc/lib/warpzone/client.qc
new file mode 100644 (file)
index 0000000..aba39c2
--- /dev/null
@@ -0,0 +1,289 @@
+#include "client.qh"
+#include "common.qh"
+
+#if defined(CSQC)
+       #include "../../client/autocvars.qh"
+       #include "../csqcmodel/cl_model.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+#endif
+
+void WarpZone_Fade_PreDraw()
+{SELFPARAM();
+       vector org;
+       org = getpropertyvec(VF_ORIGIN);
+       if(!checkpvs(org, self)) // this makes sense as long as we don't support recursive warpzones
+               self.alpha = 0;
+       else if(self.warpzone_fadestart)
+               self.alpha = bound(0, (self.warpzone_fadeend - vlen(org - self.origin - 0.5 * (self.mins + self.maxs))) / (self.warpzone_fadeend - self.warpzone_fadestart), 1);
+       else
+               self.alpha = 1;
+       //printf("%v <-> %v\n", view_origin, self.origin + 0.5 * (self.mins + self.maxs));
+       if(self.alpha <= 0)
+               self.drawmask = 0;
+       else
+               self.drawmask = MASK_NORMAL;
+}
+
+void WarpZone_Read(float isnew)
+{SELFPARAM();
+       warpzone_warpzones_exist = 1;
+       if (!self.enemy)
+       {
+               self.enemy = spawn();
+               self.enemy.classname = "warpzone_from";
+       }
+       self.classname = "trigger_warpzone";
+
+       int f = ReadByte();
+       self.warpzone_isboxy = (f & 1);
+       if(f & 4)
+       {
+               self.origin_x = ReadCoord();
+               self.origin_y = ReadCoord();
+               self.origin_z = ReadCoord();
+       }
+       else
+               self.origin = '0 0 0';
+       self.modelindex = ReadShort();
+       self.mins_x = ReadCoord();
+       self.mins_y = ReadCoord();
+       self.mins_z = ReadCoord();
+       self.maxs_x = ReadCoord();
+       self.maxs_y = ReadCoord();
+       self.maxs_z = ReadCoord();
+       self.scale = ReadByte() / 16;
+       self.enemy.oldorigin_x = ReadCoord();
+       self.enemy.oldorigin_y = ReadCoord();
+       self.enemy.oldorigin_z = ReadCoord();
+       self.enemy.avelocity_x = ReadCoord();
+       self.enemy.avelocity_y = ReadCoord();
+       self.enemy.avelocity_z = ReadCoord();
+       self.oldorigin_x = ReadCoord();
+       self.oldorigin_y = ReadCoord();
+       self.oldorigin_z = ReadCoord();
+       self.avelocity_x = ReadCoord();
+       self.avelocity_y = ReadCoord();
+       self.avelocity_z = ReadCoord();
+
+       if(f & 2)
+       {
+               self.warpzone_fadestart = ReadShort();
+               self.warpzone_fadeend = max(self.warpzone_fadestart + 1, ReadShort());
+       }
+       else
+       {
+               self.warpzone_fadestart = 0;
+               self.warpzone_fadeend = 0;
+       }
+
+       // common stuff
+       WarpZone_SetUp(self, self.enemy.oldorigin, self.enemy.avelocity, self.oldorigin, self.avelocity);
+
+       // link me
+       //setmodel(self, self.model);
+       setorigin(self, self.origin);
+       setsize(self, self.mins, self.maxs);
+
+       // how to draw
+       // engine currently wants this
+       self.predraw = WarpZone_Fade_PreDraw;
+}
+
+void WarpZone_Camera_Read(float isnew)
+{SELFPARAM();
+       warpzone_cameras_exist = 1;
+       self.classname = "func_warpzone_camera";
+
+       int f = ReadByte();
+       if(f & 4)
+       {
+               self.origin_x = ReadCoord();
+               self.origin_y = ReadCoord();
+               self.origin_z = ReadCoord();
+       }
+       else
+               self.origin = '0 0 0';
+       self.modelindex = ReadShort();
+       self.mins_x = ReadCoord();
+       self.mins_y = ReadCoord();
+       self.mins_z = ReadCoord();
+       self.maxs_x = ReadCoord();
+       self.maxs_y = ReadCoord();
+       self.maxs_z = ReadCoord();
+       self.scale = ReadByte() / 16;
+       self.oldorigin_x = ReadCoord();
+       self.oldorigin_y = ReadCoord();
+       self.oldorigin_z = ReadCoord();
+       self.avelocity_x = ReadCoord();
+       self.avelocity_y = ReadCoord();
+       self.avelocity_z = ReadCoord();
+
+       if(f & 2)
+       {
+               self.warpzone_fadestart = ReadShort();
+               self.warpzone_fadeend = max(self.warpzone_fadestart + 1, ReadShort());
+       }
+       else
+       {
+               self.warpzone_fadestart = 0;
+               self.warpzone_fadeend = 0;
+       }
+
+       // common stuff
+       WarpZone_Camera_SetUp(self, self.oldorigin, self.avelocity);
+
+       // engine currently wants this
+       self.drawmask = MASK_NORMAL;
+
+       // link me
+       //setmodel(self, self.model);
+       setorigin(self, self.origin);
+       setsize(self, self.mins, self.maxs);
+
+       // how to draw
+       // engine currently wants this
+       self.predraw = WarpZone_Fade_PreDraw;
+}
+
+void CL_RotateMoves(vector ang) = #638;
+void WarpZone_Teleported_Read(float isnew)
+{SELFPARAM();
+       vector v;
+       self.classname = "warpzone_teleported";
+       v.x = ReadCoord();
+       v.y = ReadCoord();
+       v.z = ReadCoord();
+       if(!isnew)
+               return;
+       self.warpzone_transform = v;
+       setproperty(VF_CL_VIEWANGLES, WarpZone_TransformVAngles(self, getpropertyvec(VF_CL_VIEWANGLES)));
+       if(checkextension("DP_CSQC_ROTATEMOVES"))
+               CL_RotateMoves(v);
+               //CL_RotateMoves('0 90 0');
+}
+
+float warpzone_fixingview;
+float warpzone_fixingview_drawexteriormodel;
+
+void WarpZone_View_Outside()
+{
+       if(!warpzone_fixingview)
+               return;
+       warpzone_fixingview = 0;
+       cvar_set("r_drawexteriormodel", ftos(warpzone_fixingview_drawexteriormodel));
+}
+
+void WarpZone_View_Inside()
+{
+       if(autocvar_chase_active)
+       {
+               WarpZone_View_Outside();
+               return;
+       }
+       if(warpzone_fixingview)
+               return;
+       warpzone_fixingview = 1;
+       warpzone_fixingview_drawexteriormodel = cvar("r_drawexteriormodel");
+       cvar_set("r_drawexteriormodel", "0");
+}
+
+vector WarpZone_FixNearClip(vector o, vector c0, vector c1, vector c2, vector c3)
+{
+       vector mi, ma;
+       entity e;
+       float pd;
+
+       mi.x = min(o.x, c0_x, c1_x, c2_x, c3_x);
+       ma.x = max(o.x, c0_x, c1_x, c2_x, c3_x);
+       mi.y = min(o.y, c0_y, c1_y, c2_y, c3_y);
+       ma.y = max(o.y, c0_y, c1_y, c2_y, c3_y);
+       mi.z = min(o.z, c0_z, c1_z, c2_z, c3_z);
+       ma.z = max(o.z, c0_z, c1_z, c2_z, c3_z);
+
+       e = WarpZone_Find(mi, ma);
+       if(e)
+       {
+               if(WarpZone_PlaneDist(e, o) < 0)
+                       return '0 0 0';
+                       // can't really be, though, but if it is, this is not my warpzone, but a random different one in the same mins/maxs
+               pd = min(
+                               WarpZone_PlaneDist(e, c0),
+                               WarpZone_PlaneDist(e, c1),
+                               WarpZone_PlaneDist(e, c2),
+                               WarpZone_PlaneDist(e, c3)
+                       );
+               if(pd < 0)
+                       return e.warpzone_forward * -pd;
+       }
+
+       return '0 0 0';
+}
+
+void WarpZone_FixPMove()
+{
+       entity e;
+       e = WarpZone_Find(pmove_org, pmove_org);
+       if(e)
+       {
+               pmove_org = WarpZone_TransformOrigin(e, pmove_org);
+               input_angles = WarpZone_TransformVAngles(e, input_angles);
+       }
+}
+
+#ifndef KEEP_ROLL
+float autocvar_cl_rollkillspeed = 10;
+#endif
+void WarpZone_FixView()
+{
+       entity e;
+       vector org, ang, nearclip, corner0, corner1, corner2, corner3, o;
+       float f;
+
+       warpzone_save_view_origin = org = getpropertyvec(VF_ORIGIN);
+       warpzone_save_view_angles = ang = getpropertyvec(VF_ANGLES);
+
+       e = WarpZone_Find(org, org);
+       if(e)
+       {
+               org = WarpZone_TransformOrigin(e, org);
+               ang = WarpZone_TransformVAngles(e, ang);
+               WarpZone_View_Inside();
+       }
+       else
+               WarpZone_View_Outside();
+
+#ifndef KEEP_ROLL
+       float rick;
+       if(autocvar_cl_rollkillspeed)
+               f = max(0, (1 - frametime * autocvar_cl_rollkillspeed));
+       else
+               f = 0;
+
+       rick = getproperty(VF_CL_VIEWANGLES_Z);
+       rick *= f;
+       setproperty(VF_CL_VIEWANGLES_Z, rick);
+       ang.z *= f;
+#endif
+
+       setproperty(VF_ORIGIN, org);
+       setproperty(VF_ANGLES, ang);
+
+       nearclip = '0 0 1' * (cvar("r_nearclip") * 1.125);
+       corner0 = cs_unproject('0 0 0' + nearclip);
+       corner1 = cs_unproject('1 0 0' * cvar("vid_conwidth") + nearclip);
+       corner2 = cs_unproject('0 1 0' * cvar("vid_conheight") + nearclip);
+       corner3 = cs_unproject('1 0 0' * cvar("vid_conwidth") + '0 1 0' * cvar("vid_conheight") + nearclip);
+       o = WarpZone_FixNearClip(org, corner0, corner1, corner2, corner3);
+       if(o != '0 0 0')
+               setproperty(VF_ORIGIN, org + o);
+}
+
+void WarpZone_Init()
+{
+}
+
+void WarpZone_Shutdown()
+{
+       WarpZone_View_Outside();
+}
diff --git a/qcsrc/lib/warpzone/client.qh b/qcsrc/lib/warpzone/client.qh
new file mode 100644 (file)
index 0000000..016ac58
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef LIB_WARPZONE_CLIENT_H
+#define LIB_WARPZONE_CLIENT_H
+
+void WarpZone_Read(float bIsNewEntity);
+void WarpZone_Camera_Read(float bIsNewEntity);
+void WarpZone_Teleported_Read(float bIsNewEntity);
+
+void WarpZone_FixPMove();
+void WarpZone_FixView();
+
+void WarpZone_Init();
+void WarpZone_Shutdown();
+
+vector warpzone_save_view_origin;
+vector warpzone_save_view_angles;
+#endif
diff --git a/qcsrc/lib/warpzone/common.qc b/qcsrc/lib/warpzone/common.qc
new file mode 100644 (file)
index 0000000..6fe901b
--- /dev/null
@@ -0,0 +1,874 @@
+#include "common.qh"
+
+#if defined(CSQC)
+    #include "../../server/t_items.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+    #include "../../common/weapons/all.qh"
+#endif
+
+void WarpZone_Accumulator_Clear(entity acc)
+{
+       acc.warpzone_transform = '0 0 0';
+       acc.warpzone_shift = '0 0 0';
+}
+void WarpZone_Accumulator_AddTransform(entity acc, vector t, vector s)
+{
+       vector tr, st;
+       tr = AnglesTransform_Multiply(t, acc.warpzone_transform);
+       st = AnglesTransform_Multiply_GetPostShift(t, s, acc.warpzone_transform, acc.warpzone_shift);
+       acc.warpzone_transform = tr;
+       acc.warpzone_shift = st;
+}
+void WarpZone_Accumulator_Add(entity acc, entity wz)
+{
+       WarpZone_Accumulator_AddTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
+}
+void WarpZone_Accumulator_AddInverseTransform(entity acc, vector t, vector s)
+{
+       vector tt, ss;
+       tt = AnglesTransform_Invert(t);
+       ss = AnglesTransform_PrePostShift_GetPostShift(s, tt, '0 0 0');
+       WarpZone_Accumulator_AddTransform(acc, tt, ss);
+       // yes, this probably can be done simpler... but this way is "obvious" :)
+}
+void WarpZone_Accumulator_AddInverse(entity acc, entity wz)
+{
+       WarpZone_Accumulator_AddInverseTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
+}
+
+.vector(vector, vector) camera_transform;
+float autocvar_cl_warpzone_usetrace = 1;
+vector WarpZone_camera_transform(vector org, vector ang)
+{SELFPARAM();
+       vector vf, vr, vu;
+       if(self.warpzone_fadestart)
+               if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400)
+                       return org;
+                       // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
+                       // unneeded on client, on server this helps a lot
+       vf = v_forward;
+       vr = v_right;
+       vu = v_up;
+       org = WarpZone_TransformOrigin(self, org);
+       vf = WarpZone_TransformVelocity(self, vf);
+       vr = WarpZone_TransformVelocity(self, vr);
+       vu = WarpZone_TransformVelocity(self, vu);
+       if(autocvar_cl_warpzone_usetrace)
+               traceline(self.warpzone_targetorigin, org, MOVE_NOMONSTERS, world);
+       else
+               trace_endpos = self.warpzone_targetorigin;
+       v_forward = vf;
+       v_right = vr;
+       v_up = vu;
+       return org;
+}
+
+void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
+{
+       e.warpzone_transform = AnglesTransform_RightDivide(other_ang, AnglesTransform_TurnDirectionFR(my_ang));
+       e.warpzone_shift = AnglesTransform_PrePostShift_GetPostShift(my_org, e.warpzone_transform, other_org);
+       e.warpzone_origin = my_org;
+       e.warpzone_targetorigin = other_org;
+       e.warpzone_angles = my_ang;
+       e.warpzone_targetangles = other_ang;
+       fixedmakevectors(my_ang); e.warpzone_forward = v_forward;
+       fixedmakevectors(other_ang); e.warpzone_targetforward = v_forward;
+       e.camera_transform = WarpZone_camera_transform;
+}
+
+vector WarpZone_Camera_camera_transform(vector org, vector ang)
+{SELFPARAM();
+       // a fixed camera view
+       if(self.warpzone_fadestart)
+               if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400)
+                       return org;
+                       // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
+                       // unneeded on client, on server this helps a lot
+       trace_endpos = self.warpzone_origin;
+       makevectors(self.warpzone_angles);
+       return self.warpzone_origin;
+}
+
+void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang) // we assume that e.oldorigin and e.avelocity point to view origin and direction
+{
+       e.warpzone_origin = my_org;
+       e.warpzone_angles = my_ang;
+       e.camera_transform = WarpZone_Camera_camera_transform;
+}
+
+.entity enemy;
+
+vector WarpZoneLib_BoxTouchesBrush_mins;
+vector WarpZoneLib_BoxTouchesBrush_maxs;
+entity WarpZoneLib_BoxTouchesBrush_ent;
+entity WarpZoneLib_BoxTouchesBrush_ignore;
+float WarpZoneLib_BoxTouchesBrush_Recurse()
+{
+       float s;
+       entity se;
+       float f;
+
+       tracebox('0 0 0', WarpZoneLib_BoxTouchesBrush_mins, WarpZoneLib_BoxTouchesBrush_maxs, '0 0 0', MOVE_NOMONSTERS, WarpZoneLib_BoxTouchesBrush_ignore);
+#ifdef CSQC
+       if (trace_networkentity)
+       {
+               LOG_TRACE("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush\n");
+               // we cannot continue, as a player blocks us...
+               // so, abort
+               return 0;
+       }
+#endif
+       if (!trace_ent)
+               return 0;
+       if (trace_ent == WarpZoneLib_BoxTouchesBrush_ent)
+               return 1;
+
+       se = trace_ent;
+       s = se.solid;
+       se.solid = SOLID_NOT;
+       f = WarpZoneLib_BoxTouchesBrush_Recurse();
+       se.solid = s;
+
+       return f;
+}
+
+float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
+{
+    float f, s;
+
+    if(!e.modelindex || e.warpzone_isboxy)
+        return 1;
+
+    s = e.solid;
+    e.solid = SOLID_BSP;
+    WarpZoneLib_BoxTouchesBrush_mins = mi;
+    WarpZoneLib_BoxTouchesBrush_maxs = ma;
+    WarpZoneLib_BoxTouchesBrush_ent = e;
+    WarpZoneLib_BoxTouchesBrush_ignore = ig;
+    f = WarpZoneLib_BoxTouchesBrush_Recurse();
+    e.solid = s;
+
+    return f;
+}
+
+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 world;
+       for(e = world; (e = find(e, classname, "trigger_warpzone")); )
+               if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world))
+                       return e;
+       return world;
+}
+
+void WarpZone_MakeAllSolid()
+{
+       entity e;
+       if(!warpzone_warpzones_exist)
+               return;
+       for(e = world; (e = find(e, classname, "trigger_warpzone")); )
+               e.solid = SOLID_BSP;
+}
+
+void WarpZone_MakeAllOther()
+{
+       entity e;
+       if(!warpzone_warpzones_exist)
+               return;
+       for(e = world; (e = find(e, classname, "trigger_warpzone")); )
+               e.solid = SOLID_TRIGGER;
+}
+
+void WarpZone_Trace_InitTransform()
+{
+       if(!WarpZone_trace_transform)
+       {
+               WarpZone_trace_transform = spawn();
+               WarpZone_trace_transform.classname = "warpzone_trace_transform";
+       }
+       WarpZone_Accumulator_Clear(WarpZone_trace_transform);
+}
+void WarpZone_Trace_AddTransform(entity wz)
+{
+       WarpZone_Accumulator_Add(WarpZone_trace_transform, 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 nomonsters_adjusted;
+       float frac, sol, i;
+       float contentshack;
+       vector o0, e0;
+       entity wz;
+       vector vf, vr, vu;
+
+       WarpZone_trace_forent = forent;
+       WarpZone_trace_firstzone = world;
+       WarpZone_trace_lastzone = world;
+       WarpZone_Trace_InitTransform();
+       if(!warpzone_warpzones_exist)
+       {
+               if(nomonsters == MOVE_NOTHING)
+               {
+                       trace_endpos = end;
+                       trace_fraction = 1;
+                       if(cb)
+                               cb(org, trace_endpos, end);
+                       return;
+               }
+               else
+               {
+                       tracebox(org, mi, ma, end, nomonsters, WarpZone_trace_forent);
+                       if(cb)
+                               cb(org, trace_endpos, end);
+                       return;
+               }
+       }
+
+       vf = v_forward;
+       vr = v_right;
+       vu = v_up;
+       o0 = org;
+       e0 = end;
+
+       switch(nomonsters)
+       {
+               case MOVE_WORLDONLY:
+               case MOVE_NOTHING:
+                       nomonsters_adjusted = MOVE_NOMONSTERS;
+                       break;
+               default:
+                       nomonsters_adjusted = nomonsters;
+                       break;
+       }
+       if((contentshack = (WarpZone_trace_forent.dphitcontentsmask && !(WarpZone_trace_forent.dphitcontentsmask & DPCONTENTS_SOLID))))
+               BITSET_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
+
+       // if starting in warpzone, first transform
+       wz = WarpZone_Find(org + mi, org + ma);
+       if(wz)
+       {
+               WarpZone_trace_firstzone = wz;
+               WarpZone_trace_lastzone = wz;
+               if(zone && wz != zone)
+               {
+                       // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
+                       sol = 1;
+                       trace_fraction = 0;
+                       trace_endpos = org;
+                       goto fail;
+               }
+               WarpZone_Trace_AddTransform(wz);
+               org = WarpZone_TransformOrigin(wz, org);
+               end = WarpZone_TransformOrigin(wz, end);
+       }
+       WarpZone_MakeAllSolid();
+       sol = -1;
+       frac = 0;
+       i = 16;
+       for (;;)
+       {
+               if(--i < 1)
+               {
+                       LOG_TRACE("Too many warpzones in sequence, aborting trace.\n");
+                       trace_ent = world;
+                       break;
+               }
+               tracebox(org, mi, ma, end, nomonsters_adjusted, WarpZone_trace_forent);
+               if(cb)
+                       cb(org, trace_endpos, end);
+               if(sol < 0)
+                       sol = trace_startsolid;
+
+               frac = trace_fraction = frac + (1 - frac) * trace_fraction;
+               if(trace_fraction >= 1)
+                       break;
+               if(trace_ent.classname != "trigger_warpzone")
+               {
+                       if((nomonsters == MOVE_NOTHING) || ((nomonsters == MOVE_WORLDONLY) && trace_ent) || (contentshack && (trace_dphitcontents & WarpZone_trace_forent.dphitcontentsmask) == DPCONTENTS_SOLID))
+                       {
+                               // continue the trace, ignoring this hit (we only care for warpzones)
+                               org = trace_endpos + normalize(end - org);
+                               continue;
+                               // we cannot do an inverted trace here, as we do care for further warpzones inside that "solid" to be found
+                               // otherwise, players could block entrances that way
+                       }
+                       break;
+               }
+               if(trace_ent == wz)
+               {
+                       // FIXME can this check be removed? Do we really need it?
+                       LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace\n");
+                       trace_ent = world;
+                       break;
+               }
+               wz = trace_ent;
+               if(!WarpZone_trace_firstzone)
+                       WarpZone_trace_firstzone = wz;
+               WarpZone_trace_lastzone = wz;
+               if(zone && wz != zone)
+                       break;
+               WarpZone_Trace_AddTransform(wz);
+               // we hit a warpzone... so, let's perform the trace after the warp again
+               org = WarpZone_TransformOrigin(wz, trace_endpos);
+               end = WarpZone_TransformOrigin(wz, end);
+
+               // we got warped, so let's step back a bit
+               tracebox(org, mi, ma, org + normalize(org - end) * 32, nomonsters_adjusted, WarpZone_trace_forent);
+               org = trace_endpos;
+       }
+       WarpZone_MakeAllOther();
+:fail
+       if(contentshack)
+               BITCLR_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
+       trace_startsolid = sol;
+       v_forward = vf;
+       v_right = vr;
+       v_up = vu;
+}
+
+void WarpZone_TraceBox(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent)
+{
+       WarpZone_TraceBox_ThroughZone(org, mi, ma, end, nomonsters, forent, world, WarpZone_trace_callback_t_null);
+}
+
+void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
+{
+       WarpZone_TraceBox(org, '0 0 0', '0 0 0', end, nomonsters, forent);
+}
+
+void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb)
+{
+       float g, dt, i;
+       vector vf, vr, vu, v0, o0;
+       entity wz;
+
+       o0 = e.origin;
+       v0 = e.velocity;
+       g = cvar("sv_gravity") * e.gravity;
+
+       WarpZone_trace_forent = forent;
+       WarpZone_trace_firstzone = world;
+       WarpZone_trace_lastzone = world;
+       WarpZone_Trace_InitTransform();
+       WarpZone_tracetoss_time = 0;
+       if(!warpzone_warpzones_exist)
+       {
+               tracetoss(e, WarpZone_trace_forent);
+               if(cb)
+                       cb(e.origin, trace_endpos, trace_endpos);
+               dt = vlen(e.origin - o0) / vlen(e.velocity);
+               WarpZone_tracetoss_time += dt;
+               e.velocity_z -= dt * g;
+               WarpZone_tracetoss_velocity = e.velocity;
+               e.velocity = v0;
+               return;
+       }
+
+       vf = v_forward;
+       vr = v_right;
+       vu = v_up;
+
+       // if starting in warpzone, first transform
+       wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
+       if(wz)
+       {
+               WarpZone_trace_firstzone = wz;
+               WarpZone_trace_lastzone = wz;
+               if(zone && wz != zone)
+               {
+                       // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
+
+                       WarpZone_tracetoss_time = 0;
+                       trace_endpos = o0;
+                       goto fail;
+               }
+               WarpZone_Trace_AddTransform(wz);
+               setorigin(e, WarpZone_TransformOrigin(wz, e.origin));
+               e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
+       }
+       WarpZone_MakeAllSolid();
+       i = 16;
+       for (;;)
+       {
+               if(--i < 1)
+               {
+                       LOG_TRACE("Too many warpzones in sequence, aborting trace.\n");
+                       trace_ent = world;
+                       break;
+               }
+               tracetoss(e, WarpZone_trace_forent);
+               if(cb)
+                       cb(e.origin, trace_endpos, trace_endpos);
+               dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
+               WarpZone_tracetoss_time += dt;
+               e.origin = trace_endpos;
+               e.velocity_z -= dt * g;
+               if(trace_fraction >= 1)
+                       break;
+               if(trace_ent.classname != "trigger_warpzone")
+                       break;
+               if(trace_ent == wz)
+               {
+                       // FIXME can this check be removed? Do we really need it?
+                       LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace\n");
+                       trace_ent = world;
+                       break;
+               }
+               wz = trace_ent;
+               if(!WarpZone_trace_firstzone)
+                       WarpZone_trace_firstzone = wz;
+               WarpZone_trace_lastzone = wz;
+               if(zone && wz != zone)
+                       break;
+               WarpZone_Trace_AddTransform(wz);
+               // we hit a warpzone... so, let's perform the trace after the warp again
+               e.origin = WarpZone_TransformOrigin(wz, e.origin);
+               e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
+
+               // we got warped, so let's step back a bit
+               e.velocity = -e.velocity;
+               tracetoss(e, WarpZone_trace_forent);
+               dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
+               WarpZone_tracetoss_time -= dt;
+               e.origin = trace_endpos;
+               e.velocity = -e.velocity;
+       }
+       WarpZone_MakeAllOther();
+:fail
+       WarpZone_tracetoss_velocity = e.velocity;
+       v_forward = vf;
+       v_right = vr;
+       v_up = vu;
+       // restore old entity data (caller just uses trace_endpos, WarpZone_tracetoss_velocity and the transform)
+       e.velocity = v0;
+       e.origin = o0;
+}
+
+void WarpZone_TraceToss(entity e, entity forent)
+{
+       WarpZone_TraceToss_ThroughZone(e, forent, world, WarpZone_trace_callback_t_null);
+}
+
+entity WarpZone_TrailParticles_trace_callback_own;
+float WarpZone_TrailParticles_trace_callback_eff;
+void WarpZone_TrailParticles_trace_callback(vector from, vector endpos, vector to)
+{
+       trailparticles(WarpZone_TrailParticles_trace_callback_own, WarpZone_TrailParticles_trace_callback_eff, from, endpos);
+}
+
+void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
+{
+       WarpZone_TrailParticles_trace_callback_own = own;
+       WarpZone_TrailParticles_trace_callback_eff = eff;
+       WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_trace_callback);
+}
+
+#ifdef CSQC
+float WarpZone_TrailParticles_trace_callback_f;
+float WarpZone_TrailParticles_trace_callback_flags;
+void WarpZone_TrailParticles_WithMultiplier_trace_callback(vector from, vector endpos, vector to)
+{
+       boxparticles(WarpZone_TrailParticles_trace_callback_eff, WarpZone_TrailParticles_trace_callback_own, from, endpos, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_f, WarpZone_TrailParticles_trace_callback_flags);
+}
+
+void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, int boxflags)
+{
+       WarpZone_TrailParticles_trace_callback_own = own;
+       WarpZone_TrailParticles_trace_callback_eff = eff;
+       WarpZone_TrailParticles_trace_callback_f = f;
+       WarpZone_TrailParticles_trace_callback_flags = boxflags | PARTICLES_DRAWASTRAIL;
+       WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_WithMultiplier_trace_callback);
+}
+#endif
+
+float WarpZone_PlaneDist(entity wz, vector v)
+{
+       return (v - wz.warpzone_origin) * wz.warpzone_forward;
+}
+
+float WarpZone_TargetPlaneDist(entity wz, vector v)
+{
+       return (v - wz.warpzone_targetorigin) * wz.warpzone_targetforward;
+}
+
+vector WarpZone_TransformOrigin(entity wz, vector v)
+{
+       return wz.warpzone_shift + AnglesTransform_Apply(wz.warpzone_transform, v);
+}
+
+vector WarpZone_TransformVelocity(entity wz, vector v)
+{
+       return AnglesTransform_Apply(wz.warpzone_transform, v);
+}
+
+vector WarpZone_TransformAngles(entity wz, vector v)
+{
+       return AnglesTransform_ApplyToAngles(wz.warpzone_transform, v);
+}
+
+vector WarpZone_TransformVAngles(entity wz, vector ang)
+{
+#ifdef KEEP_ROLL
+       float roll;
+       roll = ang.z;
+       ang.z = 0;
+#endif
+
+       ang = AnglesTransform_ApplyToVAngles(wz.warpzone_transform, ang);
+
+#ifdef KEEP_ROLL
+       ang = AnglesTransform_Normalize(ang, true);
+       ang = AnglesTransform_CancelRoll(ang);
+       ang.z = roll;
+#else
+       ang = AnglesTransform_Normalize(ang, false);
+#endif
+
+       return ang;
+}
+
+vector WarpZone_UnTransformOrigin(entity wz, vector v)
+{
+       return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v - wz.warpzone_shift);
+}
+
+vector WarpZone_UnTransformVelocity(entity wz, vector v)
+{
+       return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v);
+}
+
+vector WarpZone_UnTransformAngles(entity wz, vector v)
+{
+       return AnglesTransform_ApplyToAngles(AnglesTransform_Invert(wz.warpzone_transform), v);
+}
+
+vector WarpZone_UnTransformVAngles(entity wz, vector ang)
+{
+       float roll;
+
+       roll = ang.z;
+       ang.z = 0;
+
+       ang = AnglesTransform_ApplyToVAngles(AnglesTransform_Invert(wz.warpzone_transform), ang);
+       ang = AnglesTransform_Normalize(ang, true);
+       ang = AnglesTransform_CancelRoll(ang);
+
+       ang.z = roll;
+       return ang;
+}
+
+vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
+{
+       vector nearest;
+       nearest.x = bound(mi.x, org.x, ma.x);
+       nearest.y = bound(mi.y, org.y, ma.y);
+       nearest.z = bound(mi.z, org.z, ma.z);
+       return nearest;
+}
+
+bool WarpZoneLib_BadEntity(entity e)
+{
+       string myclassname = e.classname;
+       if (e.instanceOfObject) return true;
+       switch(myclassname)
+       {
+               case "deathtype":
+               case "weaponentity":
+               case "exteriorweaponentity":
+               case "csqc_score_team":
+               case "pingplreport":
+               case "ent_client_scoreinfo":
+               case "saved_cvar_value":
+               case "accuracy":
+               case "entcs_sender":
+               case "entcs_receiver":
+               case "clientinit":
+               case "sprite_waypoint":
+               case "waypoint":
+               case "gibsplash":
+               //case "net_linked": // actually some real entities are linked without classname, fail
+               case "":
+                       return true;
+       }
+
+       if(startsWith(myclassname, "msg_"))
+               return true;
+
+       if(startsWith(myclassname, "target_"))
+               return true;
+
+       if(startsWith(myclassname, "info_"))
+               return true;
+
+       return false;
+}
+
+.float WarpZone_findradius_hit;
+.entity WarpZone_findradius_next;
+void WarpZone_FindRadius_Recurse(vector org, float rad,        vector org0,               vector transform, vector shift, float needlineofsight)
+//                               blast origin of current search   original blast origin   how to untransform (victim to blast system)
+{
+       vector org_new;
+       vector org0_new;
+       vector shift_new, transform_new;
+       vector p;
+       entity e, e0;
+       entity wz;
+       if(rad <= 0)
+               return;
+       e0 = findradius(org, rad);
+       wz = world;
+
+       for(e = e0; e; e = e.chain)
+       {
+               if(WarpZoneLib_BadEntity(e))
+                       continue;
+               p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
+               if(needlineofsight)
+               {
+                       traceline(org, p, MOVE_NOMONSTERS, e);
+                       if(trace_fraction < 1)
+                               continue;
+               }
+               if(!e.WarpZone_findradius_hit || vlen(e.WarpZone_findradius_dist) > vlen(org0 - p))
+               {
+                       e.WarpZone_findradius_nearest = p;
+                       e.WarpZone_findradius_dist = org0 - p;
+                       e.WarpZone_findradius_findorigin = org;
+                       e.WarpZone_findradius_findradius = rad;
+                       if(e.classname == "warpzone_refsys")
+                       {
+                               // ignore, especially: do not overwrite the refsys parameters
+                       }
+                       else if(e.classname == "trigger_warpzone")
+                       {
+                               e.WarpZone_findradius_next = wz;
+                               wz = e;
+                               e.WarpZone_findradius_hit = 1;
+                               e.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
+                               e.enemy.WarpZone_findradius_hit = 1;
+                       }
+                       else
+                       {
+                               e.warpzone_transform = transform;
+                               e.warpzone_shift = shift;
+                               e.WarpZone_findradius_hit = 1;
+                       }
+               }
+       }
+       for(e = wz; e; e = e.WarpZone_findradius_next)
+       {
+               if(WarpZoneLib_BadEntity(e))
+                       continue;
+
+               org0_new = WarpZone_TransformOrigin(e, org);
+               traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
+               org_new = trace_endpos;
+
+               transform_new = AnglesTransform_Multiply(e.warpzone_transform, transform);
+               shift_new = AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift);
+               WarpZone_FindRadius_Recurse(
+                       org_new,
+                       bound(0, rad - vlen(org_new - org0_new), rad - 8),
+                       org0_new,
+                       transform_new, shift_new,
+                       needlineofsight);
+               e.WarpZone_findradius_hit = 0;
+               e.enemy.WarpZone_findradius_hit = 0;
+       }
+}
+entity WarpZone_FindRadius(vector org, float rad, float needlineofsight)
+{
+       entity e0, e;
+       WarpZone_FindRadius_Recurse(org, rad, org, '0 0 0', '0 0 0', needlineofsight);
+       e0 = findchainfloat(WarpZone_findradius_hit, 1);
+       for(e = e0; e; e = e.chain)
+               e.WarpZone_findradius_hit = 0;
+       return e0;
+}
+
+.entity WarpZone_refsys;
+void WarpZone_RefSys_GC()
+{SELFPARAM();
+       // garbage collect unused reference systems
+       self.nextthink = time + 1;
+       if(self.owner.WarpZone_refsys != self)
+               remove(self);
+}
+void WarpZone_RefSys_CheckCreate(entity me)
+{
+       if(me.WarpZone_refsys.owner != me)
+       {
+               me.WarpZone_refsys = spawn();
+               me.WarpZone_refsys.classname = "warpzone_refsys";
+               me.WarpZone_refsys.owner = me;
+               me.WarpZone_refsys.think = WarpZone_RefSys_GC;
+               me.WarpZone_refsys.nextthink = time + 1;
+               WarpZone_Accumulator_Clear(me.WarpZone_refsys);
+       }
+}
+void WarpZone_RefSys_Clear(entity me)
+{
+       if(me.WarpZone_refsys)
+       {
+               remove(me.WarpZone_refsys);
+               me.WarpZone_refsys = world;
+       }
+}
+void WarpZone_RefSys_AddTransform(entity me, vector t, vector s)
+{
+       if(t != '0 0 0' || s != '0 0 0')
+       {
+               WarpZone_RefSys_CheckCreate(me);
+               WarpZone_Accumulator_AddTransform(me.WarpZone_refsys, t, s);
+       }
+}
+void WarpZone_RefSys_Add(entity me, entity wz)
+{
+       WarpZone_RefSys_AddTransform(me, wz.warpzone_transform, wz.warpzone_shift);
+}
+void WarpZone_RefSys_AddInverseTransform(entity me, vector t, vector s)
+{
+       if(t != '0 0 0' || s != '0 0 0')
+       {
+               WarpZone_RefSys_CheckCreate(me);
+               WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, t, s);
+       }
+}
+void WarpZone_RefSys_AddInverse(entity me, entity wz)
+{
+       WarpZone_RefSys_AddInverseTransform(me, wz.warpzone_transform, wz.warpzone_shift);
+}
+.vector WarpZone_refsys_incremental_shift;
+.vector WarpZone_refsys_incremental_transform;
+void WarpZone_RefSys_AddIncrementally(entity me, entity ref)
+{
+       //vector t, s;
+       if(me.WarpZone_refsys_incremental_transform == ref.WarpZone_refsys.warpzone_transform)
+       if(me.WarpZone_refsys_incremental_shift == ref.WarpZone_refsys.warpzone_shift)
+               return;
+       WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, me.WarpZone_refsys_incremental_transform, me.WarpZone_refsys_incremental_shift);
+       WarpZone_Accumulator_Add(me.WarpZone_refsys, ref.WarpZone_refsys);
+       me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
+       me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
+}
+void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref)
+{
+       me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
+       me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
+}
+vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
+{
+       if(from.WarpZone_refsys)
+               org = WarpZone_UnTransformOrigin(from.WarpZone_refsys, org);
+       if(to.WarpZone_refsys)
+               org = WarpZone_TransformOrigin(to.WarpZone_refsys, org);
+       return org;
+}
+vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
+{
+       if(from.WarpZone_refsys)
+               vel = WarpZone_UnTransformVelocity(from.WarpZone_refsys, vel);
+       if(to.WarpZone_refsys)
+               vel = WarpZone_TransformVelocity(to.WarpZone_refsys, vel);
+       return vel;
+}
+vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang)
+{
+       if(from.WarpZone_refsys)
+               ang = WarpZone_UnTransformAngles(from.WarpZone_refsys, ang);
+       if(to.WarpZone_refsys)
+               ang = WarpZone_TransformAngles(to.WarpZone_refsys, ang);
+       return ang;
+}
+vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang)
+{
+       if(from.WarpZone_refsys)
+               ang = WarpZone_UnTransformVAngles(from.WarpZone_refsys, ang);
+       if(to.WarpZone_refsys)
+               ang = WarpZone_TransformVAngles(to.WarpZone_refsys, ang);
+       return ang;
+}
+void WarpZone_RefSys_Copy(entity me, entity from)
+{
+       if(from.WarpZone_refsys)
+       {
+               WarpZone_RefSys_CheckCreate(me);
+               me.WarpZone_refsys.warpzone_shift = from.WarpZone_refsys.warpzone_shift;
+               me.WarpZone_refsys.warpzone_transform = from.WarpZone_refsys.warpzone_transform;
+       }
+       else
+               WarpZone_RefSys_Clear(me);
+}
+entity WarpZone_RefSys_SpawnSameRefSys(entity me)
+{
+       entity e;
+       e = spawn();
+       WarpZone_RefSys_Copy(e, me);
+       return e;
+}
+
+float WarpZoneLib_ExactTrigger_Touch()
+{SELFPARAM();
+       return !WarpZoneLib_BoxTouchesBrush(other.absmin, other.absmax, self, other);
+}
+
+
+void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by)
+{
+       float eps = 0.0625;
+       tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
+       if (trace_startsolid)
+               return;
+       if (trace_fraction < 1)
+       {
+               // hit something
+               // adjust origin in the other direction...
+               setorigin(e,e.origin - by * (1 - trace_fraction));
+       }
+}
+
+float WarpZoneLib_MoveOutOfSolid(entity e)
+{
+       vector o, m0, m1;
+
+       o = e.origin;
+       traceline(o, o, MOVE_WORLDONLY, e);
+       if (trace_startsolid)
+               return false;
+
+       tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
+       if (!trace_startsolid)
+               return true;
+
+       m0 = e.mins;
+       m1 = e.maxs;
+       e.mins = '0 0 0';
+       e.maxs = '0 0 0';
+       WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m0_x);
+       e.mins_x = m0_x;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m1_x);
+       e.maxs_x = m1_x;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m0_y);
+       e.mins_y = m0_y;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m1_y);
+       e.maxs_y = m1_y;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m0_z);
+       e.mins_z = m0_z;
+       WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m1_z);
+       e.maxs_z = m1_z;
+       setorigin(e, e.origin);
+
+       tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
+       if (trace_startsolid)
+       {
+               setorigin(e, o);
+               return false;
+       }
+
+       return true;
+}
diff --git a/qcsrc/lib/warpzone/common.qh b/qcsrc/lib/warpzone/common.qh
new file mode 100644 (file)
index 0000000..d0c1f22
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef LIB_WARPZONE_COMMON_H
+#define LIB_WARPZONE_COMMON_H
+
+// uncomment this if your mod uses the roll angle in fixangle
+// #define KEEP_ROLL
+
+float warpzone_warpzones_exist;
+float warpzone_cameras_exist;
+
+.float warpzone_isboxy;
+.vector warpzone_shift;
+.vector warpzone_origin;
+.vector warpzone_angles;
+.vector warpzone_forward;
+.vector warpzone_targetorigin;
+.vector warpzone_targetangles;
+.vector warpzone_targetforward;
+.vector warpzone_transform;
+.float warpzone_fadestart;
+.float warpzone_fadeend;
+void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang);
+void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang);
+
+float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig);
+vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org);
+
+entity WarpZone_Find(vector mi, vector ma);
+void WarpZone_MakeAllSolid();
+void WarpZone_MakeAllOther();
+
+#define MOVE_NOTHING -1
+entity WarpZone_trace_forent; // temp, callback is allowed to change it
+typedef void(vector start, vector hit, vector end) WarpZone_trace_callback_t; // called on every elementary trace
+var WarpZone_trace_callback_t WarpZone_trace_callback_t_null;
+entity WarpZone_trace_transform; // transform accumulator during a trace
+entity WarpZone_trace_firstzone; // first warpzone hit by a trace (can differ from the requested zone in case of _ThroughZone, the trace is aborted then)
+entity WarpZone_trace_lastzone; // first warpzone hit by a trace (can differ from the requested zone in case of _ThroughZone, the trace is aborted then)
+vector WarpZone_tracetoss_velocity; // ending velocity of a tracetoss (post-transform)
+float WarpZone_tracetoss_time; // duration of toss (approximate)
+void WarpZone_TraceBox(vector org, vector min, vector max, vector end, float nomonsters, entity forent);
+void WarpZone_TraceBox_ThroughZone(vector org, vector min, vector max, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb);
+void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent);
+void WarpZone_TraceToss(entity e, entity forent);
+void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb);
+void WarpZone_TrailParticles(entity own, float eff, vector org, vector end);
+#ifdef CSQC
+void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, float boxflags);
+#endif
+
+.vector WarpZone_findradius_dist;
+.vector WarpZone_findradius_nearest;
+// also set: warpzone parameters, so WarpZone_TransformOrigin can transform vectors from blast's to victim's system
+.vector WarpZone_findradius_findorigin;
+.float WarpZone_findradius_findradius;
+entity WarpZone_FindRadius(vector org, float radius, float needlineofsight);
+
+float WarpZone_PlaneDist(entity wz, vector v);
+float WarpZone_TargetPlaneDist(entity wz, vector v);
+vector WarpZone_TransformOrigin(entity wz, vector v);
+vector WarpZone_TransformVelocity(entity wz, vector v);
+vector WarpZone_TransformAngles(entity wz, vector v);
+vector WarpZone_TransformVAngles(entity wz, vector v);
+vector WarpZone_UnTransformOrigin(entity wz, vector v);
+vector WarpZone_UnTransformVelocity(entity wz, vector v);
+vector WarpZone_UnTransformAngles(entity wz, vector v);
+vector WarpZone_UnTransformVAngles(entity wz, vector v);
+
+// reference systems (chained warpzone transforms)
+void WarpZone_RefSys_Clear(entity me); // R := id
+void WarpZone_RefSys_Add(entity me, entity wz); // me.R := wz me.R
+void WarpZone_RefSys_AddInverse(entity me, entity wz); // me.R := wz^-1 me.R
+void WarpZone_RefSys_AddTransform(entity me, vector t, vector s); // me.R := [t s] me.R
+void WarpZone_RefSys_AddInverseTransform(entity me, vector t, vector s); // me.R := [t s]^-1 me.R
+
+// makes this reference system track ref's changes
+// NOTE: this is ONLY sensible if WarpZone_RefSys_Add is no longer called on "me" while doing this
+// To achieve this, make sure no touch events on warpzone are raised by this entity
+// or set a movetype that causes no warpzoning (e.g. MOVETYPE_NONE, MOVETYPE_FOLLOW)
+void WarpZone_RefSys_AddIncrementally(entity me, entity ref); // me.R := ref.R me.Rref^-1 me.R; me.Rref := ref.R
+void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref); // me.Rref := ref.R
+
+vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org); // return to.R from.R^-1 org
+vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel); // return to.R from.R^-1 vel
+vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang); // return to.R from.R^-1 ang
+vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang); // return to.R from.R^-1 ang
+void WarpZone_RefSys_Copy(entity me, entity from); // to.R := from.R
+entity WarpZone_RefSys_SpawnSameRefSys(entity me); // spawn().R = me.R
+
+#ifndef BITCLR
+# define BITCLR(a,b) ((a) - ((a) & (b)))
+#endif
+#ifndef BITSET
+# define BITSET(a,b) ((a) | (b))
+#endif
+#ifndef BITXOR
+# define BITXOR(a,b) (((a) | (b)) - ((a) & (b)))
+#endif
+#ifndef BITCLR_ASSIGN
+# define BITCLR_ASSIGN(a,b) ((a) = (a) - ((a) & (b)))
+#endif
+#ifndef BITSET_ASSIGN
+# define BITSET_ASSIGN(a,b) ((a) |= (b))
+#endif
+#ifndef BITXOR_ASSIGN
+# define BITXOR_ASSIGN(a,b) ((a) = ((a) | (b)) - ((a) & (b)))
+#endif
+float WarpZoneLib_MoveOutOfSolid(entity e);
+#define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
+
+float WarpZoneLib_ExactTrigger_Touch();
+void WarpZoneLib_ExactTrigger_Init();
+
+// WARNING: this kills the trace globals
+#define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
+#define EXACTTRIGGER_INIT  WarpZoneLib_ExactTrigger_Init()
+#endif
diff --git a/qcsrc/lib/warpzone/mathlib.qc b/qcsrc/lib/warpzone/mathlib.qc
new file mode 100644 (file)
index 0000000..92b7ee1
--- /dev/null
@@ -0,0 +1,300 @@
+#include "mathlib.qh"
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+#endif
+
+int fpclassify(float x)
+{
+       if(isnan(x))
+               return FP_NAN;
+       if(isinf(x))
+               return FP_INFINITE;
+       if(x == 0)
+               return FP_ZERO;
+       return FP_NORMAL;
+}
+bool isfinite(float x)
+{
+       return !(isnan(x) || isinf(x));
+}
+bool isinf(float x)
+{
+       return (x != 0) && (x + x == x);
+}
+bool isnan(float x)
+{
+       float y;
+       y = x;
+       return (x != y);
+}
+bool isnormal(float x)
+{
+       return isfinite(x);
+}
+bool signbit(float x)
+{
+       return (x < 0);
+}
+
+float acosh(float x)
+{
+       return log(x + sqrt(x*x - 1));
+}
+float asinh(float x)
+{
+       return log(x + sqrt(x*x + 1));
+}
+float atanh(float x)
+{
+       return 0.5 * log((1+x) / (1-x));
+}
+float cosh(float x)
+{
+       return 0.5 * (exp(x) + exp(-x));
+}
+float sinh(float x)
+{
+       return 0.5 * (exp(x) - exp(-x));
+}
+float tanh(float x)
+{
+       return sinh(x) / cosh(x);
+}
+
+float exp(float x)
+{
+       return pow(M_E, x);
+}
+float exp2(float x)
+{
+       return pow(2, x);
+}
+float expm1(float x)
+{
+       return exp(x) - 1;
+}
+
+vector frexp(float x)
+{
+       vector v;
+       v.z = 0;
+       v.y = ilogb(x) + 1;
+       v.x = x / exp2(v.y);
+       return v;
+}
+int ilogb(float x)
+{
+       return floor(log2(fabs(x)));
+}
+float ldexp(float x, int e)
+{
+       return x * pow(2, e);
+}
+float logn(float x, float base)
+{
+       return log(x) / log(base);
+}
+float log10(float x)
+{
+       return log(x) * M_LOG10E;
+}
+float log1p(float x)
+{
+       return log(x + 1);
+}
+float log2(float x)
+{
+       return log(x) * M_LOG2E;
+}
+float logb(float x)
+{
+       return floor(log2(fabs(x)));
+}
+vector modf(float f)
+{
+       return '1 0 0' * (f - trunc(f)) + '0 1 0' * trunc(f);
+}
+
+float scalbn(float x, int n)
+{
+       return x * pow(2, n);
+}
+
+float cbrt(float x)
+{
+       return copysign(pow(fabs(x), 1.0/3.0), x);
+}
+float hypot(float x, float y)
+{
+       return sqrt(x*x + y*y);
+}
+
+float erf(float x)
+{
+       // approximation taken from wikipedia
+       float y;
+       y = x*x;
+       return copysign(sqrt(1 - exp(-y * (1.273239544735163 + 0.14001228868667 * y) / (1 + 0.14001228868667 * y))), x);
+}
+float erfc(float x)
+{
+       return 1.0 - erf(x);
+}
+vector lgamma(float x)
+{
+       // TODO improve accuracy
+       if(!isfinite(x))
+               return fabs(x) * '1 0 0' + copysign(1, x) * '0 1 0';
+       if(x < 1 && x == floor(x))
+               return nan("gamma") * '1 1 1';
+       if(x < 0.1)
+       {
+               vector v;
+               v = lgamma(1.0 - x);
+               // reflection formula:
+               // gamma(1-z) * gamma(z) = pi / sin(pi*z)
+               // lgamma(1-z) + lgamma(z) = log(pi) - log(sin(pi*z))
+               // sign of gamma(1-z) = sign of gamma(z) * sign of sin(pi*z)
+               v.z = sin(M_PI * x);
+               v.x = log(M_PI) - log(fabs(v.z)) - v.x;
+               if(v.z < 0)
+                       v.y = -v.y;
+               v.z = 0;
+               return v;
+       }
+       if(x < 1.1)
+               return lgamma(x + 1) - log(x) * '1 0 0';
+       x -= 1;
+       return (0.5 * log(2 * M_PI * x) + x * (log(x) - 1)) * '1 0 0' + '0 1 0';
+}
+float tgamma(float x)
+{
+       vector v;
+       v = lgamma(x);
+       return exp(v.x) * v.y;
+}
+
+/**
+ * Pythonic mod:
+ * TODO: %% operator?
+ *
+ *  1 %  2 ==  1
+ * -1 %  2 ==  1
+ *  1 % -2 == -1
+ * -1 % -2 == -1
+ */
+float pymod(float x, float y)
+{
+       return x - y * floor(x / y);
+}
+
+float nearbyint(float x)
+{
+       return rint(x);
+}
+float trunc(float x)
+{
+       return (x>=0) ? floor(x) : ceil(x);
+}
+
+float fmod(float x, float y)
+{
+       return x - y * trunc(x / y);
+}
+float remainder(float x, float y)
+{
+       return x - y * rint(x / y);
+}
+vector remquo(float x, float y)
+{
+       vector v;
+       v.z = 0;
+       v.y = rint(x / y);
+       v.x = x - y * v.y;
+       return v;
+}
+
+float copysign(float x, float y)
+{
+       return fabs(x) * ((y>0) ? 1 : -1);
+}
+float nan(string tag)
+{
+       return sqrt(-1);
+}
+float nextafter(float x, float y)
+{
+       // TODO very crude
+       if(x == y)
+               return nan("nextafter");
+       if(x > y)
+               return -nextafter(-x, -y);
+       // now we know that x < y
+       // so we need the next number > x
+       float d, a, b;
+       d = max(fabs(x), 0.00000000000000000000001);
+       a = x + d;
+       do
+       {
+               d *= 0.5;
+               b = a;
+               a = x + d;
+       }
+       while(a != x);
+       return b;
+}
+float nexttoward(float x, float y)
+{
+       return nextafter(x, y);
+}
+
+float fdim(float x, float y)
+{
+       return max(x-y, 0);
+}
+float fmax(float x, float y)
+{
+       return max(x, y);
+}
+float fmin(float x, float y)
+{
+       return min(x, y);
+}
+float fma(float x, float y, float z)
+{
+       return x * y + z;
+}
+
+int isgreater(float x, float y)
+{
+       return x > y;
+}
+int isgreaterequal(float x, float y)
+{
+       return x >= y;
+}
+int isless(float x, float y)
+{
+       return x < y;
+}
+int islessequal(float x, float y)
+{
+       return x <= y;
+}
+int islessgreater(float x, float y)
+{
+       return x < y || x > y;
+}
+int isunordered(float x, float y)
+{
+       return !(x < y || x == y || x > y);
+}
+
+vector cross(vector a, vector b)
+{
+       return
+               '1 0 0' * (a.y * b.z - a.z * b.y)
+       +       '0 1 0' * (a.z * b.x - a.x * b.z)
+       +       '0 0 1' * (a.x * b.y - a.y * b.x);
+}
diff --git a/qcsrc/lib/warpzone/mathlib.qh b/qcsrc/lib/warpzone/mathlib.qh
new file mode 100644 (file)
index 0000000..9acece2
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef LIB_WARPZONE_MATHLIB_H
+#define LIB_WARPZONE_MATHLIB_H
+
+// <math.h>
+
+// The commented-out functions need no implementation because DarkPlaces offers
+// them as builtins. They are listed here anyway for completeness sake.
+
+const int FP_NAN = 0;
+const int FP_INFINITE = 1;
+const int FP_ZERO = 2;
+const int FP_SUBNORMAL = 3;
+const int FP_NORMAL = 4;
+int fpclassify(float x);
+bool isfinite(float x);
+bool isinf(float x);
+bool isnan(float x);
+bool isnormal(float x);
+bool signbit(float x);
+
+//float acos(float x);
+//float asin(float x);
+//float atan(float x);
+//float atan2(float y, float x);
+//float cos(float x);
+//float sin(float x);
+//float tan(float x);
+
+float acosh(float x);
+float asinh(float x);
+float atanh(float x);
+float cosh(float x);
+float sinh(float x);
+float tanh(float x);
+
+float exp(float x);
+float exp2(float x);
+float expm1(float x);
+
+vector frexp(float x); // returns mantissa as _x, exponent as _y
+int ilogb(float x);
+float ldexp(float x, int e);
+//float log(float x);
+float logn(float x, float base);
+float log10(float x);
+float log1p(float x);
+float log2(float x);
+float logb(float x);
+vector modf(float f); // fraction as _x, integer as _y
+
+float scalbn(float x, int n);
+
+float cbrt(float x);
+//float fabs(float x);
+float hypot(float x, float y);
+//float pow(float x, float y);
+//float sqrt(float x, float y);
+
+float erf(float x);
+float erfc(float x);
+vector lgamma(float x); // value in _x, sign in _y
+float tgamma(float x);
+
+/**
+ * Pythonic mod:
+ * TODO: %% operator?
+ *
+ *  1 %  2 ==  1
+ * -1 %  2 ==  1
+ *  1 % -2 == -1
+ * -1 % -2 == -1
+ */
+float pymod(float x, float y);
+
+//float ceil(float x);
+//float floor(float x);
+float nearbyint(float x);
+//float rint(float x);
+//float round(float x);
+float trunc(float x);
+
+float fmod(float x, float y);
+float remainder(float x, float y);
+vector remquo(float x, float y);
+
+float copysign(float x, float y);
+float nan(string tag);
+float nextafter(float x, float y);
+float nexttoward(float x, float y);
+
+float fdim(float x, float y);
+float fmax(float x, float y);
+float fmin(float x, float y);
+float fma(float x, float y, float z);
+
+int isgreater(float x, float y);
+int isgreaterequal(float x, float y);
+int isless(float x, float y);
+int islessequal(float x, float y);
+int islessgreater(float x, float y);
+int isunordered(float x, float y);
+
+const float M_E        = 2.7182818284590452354;   /* e */
+const float M_LOG2E    = 1.4426950408889634074;   /* log_2 e */
+const float M_LOG10E   = 0.43429448190325182765;  /* log_10 e */
+const float M_LN2      = 0.69314718055994530942;  /* log_e 2 */
+const float M_LN10     = 2.30258509299404568402;  /* log_e 10 */
+// -Wdouble-declaration
+#define M_PI             3.14159265358979323846   /* pi */
+const float M_PI_2     = 1.57079632679489661923;  /* pi/2 */
+const float M_PI_4     = 0.78539816339744830962;  /* pi/4 */
+const float M_1_PI     = 0.31830988618379067154;  /* 1/pi */
+const float M_2_PI     = 0.63661977236758134308;  /* 2/pi */
+const float M_2_SQRTPI = 1.12837916709551257390;  /* 2/sqrt(pi) */
+const float M_SQRT2    = 1.41421356237309504880;  /* sqrt(2) */
+const float M_SQRT1_2  = 0.70710678118654752440;  /* 1/sqrt(2) */
+
+// Non-<math.h> stuff follows here.
+vector cross(vector a, vector b);
+
+#endif
diff --git a/qcsrc/lib/warpzone/server.qc b/qcsrc/lib/warpzone/server.qc
new file mode 100644 (file)
index 0000000..e21e4ca
--- /dev/null
@@ -0,0 +1,899 @@
+#include "server.qh"
+
+#include "common.qh"
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+       #include "../../common/constants.qh"
+       #include "../../common/triggers/subs.qh"
+       #include "../../common/util.qh"
+       #include "../../server/command/common.qh"
+       #include "../../server/constants.qh"
+       #include "../../server/defs.qh"
+#endif
+
+#ifdef WARPZONELIB_KEEPDEBUG
+#define WARPZONELIB_REMOVEHACK
+#endif
+
+// for think function
+.vector warpzone_save_origin;
+.vector warpzone_save_angles;
+.vector warpzone_save_eorigin;
+.vector warpzone_save_eangles;
+
+// for all entities
+.vector warpzone_oldorigin, warpzone_oldvelocity, warpzone_oldangles;
+.float warpzone_teleport_time;
+.float warpzone_teleport_finishtime;
+.entity warpzone_teleport_zone;
+
+void WarpZone_StoreProjectileData(entity e)
+{
+       e.warpzone_oldorigin = e.origin;
+       e.warpzone_oldvelocity = e.velocity;
+       e.warpzone_oldangles = e.angles;
+}
+
+void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity)
+{
+       setorigin (player, to); // NOTE: this also aborts the move, when this is called by touch
+       player.oldorigin = to; // for DP's unsticking
+       player.angles = to_angles;
+       player.fixangle = true;
+       player.velocity = to_velocity;
+
+       BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
+
+       if(IS_PLAYER(player))
+               BITCLR_ASSIGN(player.flags, FL_ONGROUND);
+
+       WarpZone_PostTeleportPlayer_Callback(player);
+}
+
+bool WarpZone_Teleported_Send(entity to, int sf)
+{SELFPARAM();
+       WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
+       WriteCoord(MSG_ENTITY, self.angles.x);
+       WriteCoord(MSG_ENTITY, self.angles.y);
+       WriteCoord(MSG_ENTITY, self.angles.z);
+       return true;
+}
+
+float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
+{
+       vector o0, a0, v0, o1, a1, v1, o10;
+
+       o0 = player.origin + player.view_ofs;
+       v0 = player.velocity;
+       a0 = player.angles;
+
+       o10 = o1 = WarpZone_TransformOrigin(wz, o0);
+       v1 = WarpZone_TransformVelocity(wz, v0);
+       if (!IS_NOT_A_CLIENT(player))
+               a1 = WarpZone_TransformVAngles(wz, player.v_angle);
+       else
+               a1 = WarpZone_TransformAngles(wz, a0);
+
+       if(f0 != 0 || f1 != 0)
+       {
+               // retry last move but behind the warpzone!
+               // we must first go back as far as we can, then forward again, to not cause double touch events!
+
+               tracebox(o1 - player.view_ofs + v1 * frametime * f1, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f0, MOVE_WORLDONLY, player);
+               {
+                       entity own;
+                       own = player.owner;
+                       player.owner = world;
+                       tracebox(trace_endpos, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f1, MOVE_NORMAL, player); // this should get us through the warpzone
+                       player.owner = own;
+               }
+               o1 = trace_endpos + player.view_ofs;
+
+               float d, dv, md;
+               md = max(vlen(player.mins), vlen(player.maxs));
+               d = WarpZone_TargetPlaneDist(wz, o1);
+               dv = WarpZone_TargetPlaneDist(wz, v1);
+               if(d < 0)
+                       o1 = o1 - v1 * (d / dv);
+       }
+
+       // put him out of solid
+       tracebox(o1 - player.view_ofs, player.mins, player.maxs, o1 - player.view_ofs, MOVE_NOMONSTERS, player);
+       if(trace_startsolid)
+       {
+               setorigin(player, o1 - player.view_ofs);
+               if(WarpZoneLib_MoveOutOfSolid(player))
+               {
+                       o1 = player.origin + player.view_ofs;
+                       setorigin(player, o0 - player.view_ofs);
+               }
+               else
+               {
+                       LOG_INFO("would have to put player in solid, won't do that\n");
+                       setorigin(player, o0 - player.view_ofs);
+                       return 0;
+               }
+       }
+
+       // do the teleport
+       WarpZone_RefSys_Add(player, wz);
+       WarpZone_TeleportPlayer(wz, player, o1 - player.view_ofs, a1, v1);
+       WarpZone_StoreProjectileData(player);
+       player.warpzone_teleport_time = time;
+       player.warpzone_teleport_finishtime = time;
+       player.warpzone_teleport_zone = wz;
+
+       // prevent further teleports back
+       float dt = (o1 - o10) * v1 * (1 / (v1 * v1));
+       if(dt < sys_frametime)
+               player.warpzone_teleport_finishtime += sys_frametime - dt;
+
+#ifndef WARPZONE_USE_FIXANGLE
+       if(IS_VEHICLE(player) && player.owner)
+               player = player.owner; // hax
+       if(IS_PLAYER(player))
+       {
+               // instead of fixangle, send the transform to the client for smoother operation
+               player.fixangle = false;
+
+               entity ts = spawn();
+               setmodel(ts, MDL_Null);
+               ts.SendEntity = WarpZone_Teleported_Send;
+               ts.SendFlags = 0xFFFFFF;
+               ts.drawonlytoclient = player;
+               ts.think = SUB_Remove;
+               ts.nextthink = time + 1;
+               ts.owner = player;
+               ts.enemy = wz;
+               ts.effects = EF_NODEPTHTEST;
+               ts.classname = "warpzone_teleported";
+               ts.angles = wz.warpzone_transform;
+       }
+#endif
+
+       return 1;
+}
+
+void WarpZone_Touch (void)
+{SELFPARAM();
+       if(other.classname == "trigger_warpzone")
+               return;
+
+       if(time <= other.warpzone_teleport_finishtime) // already teleported this frame
+               return;
+
+       // FIXME needs a better check to know what is safe to teleport and what not
+       if(other.movetype == MOVETYPE_NONE || other.movetype == MOVETYPE_FOLLOW || other.tag_entity)
+               return;
+
+       if(WarpZoneLib_ExactTrigger_Touch())
+               return;
+
+       if(WarpZone_PlaneDist(self, other.origin + other.view_ofs) >= 0) // wrong side of the trigger_warpzone (don't teleport yet)
+               return;
+
+       float f;
+       // number of frames we need to go back:
+       //   dist = 16*sqrt(2) qu
+       //   dist ~ 24 qu
+       //   24 qu = v*t
+       //   24 qu = v*frametime*n
+       //       n = 24 qu/(v*frametime)
+       // for clients go only one frame though, may be too irritating otherwise
+       // but max 0.25 sec = 0.25/frametime frames
+       //       24/(0.25/frametime)
+       //       96*frametime
+       float d;
+       d = 24 + max(vlen(other.mins), vlen(other.maxs));
+       if(IS_NOT_A_CLIENT(other))
+               f = -d / bound(frametime * d * 1, frametime * vlen(other.velocity), d);
+       else
+               f = -1;
+       if(WarpZone_Teleport(self, other, f, 0))
+       {
+               string save1, save2;
+               activator = other;
+
+               save1 = self.target; self.target = string_null;
+               save2 = self.target3; self.target3 = string_null;
+               SUB_UseTargets();
+               if (!self.target) self.target = save1;
+               if (!self.target3) self.target3 = save2;
+
+               setself(self.enemy);
+               save1 = self.target; self.target = string_null;
+               save2 = self.target2; self.target2 = string_null;
+               SUB_UseTargets();
+               if (!self.target) self.target = save1;
+               if (!self.target2) self.target2 = save2;
+               setself(this);
+       }
+       else
+       {
+               LOG_TRACE("WARPZONE FAIL AHAHAHAHAH))\n");
+       }
+}
+
+bool WarpZone_Send(entity to, int sendflags)
+{SELFPARAM();
+       WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE);
+
+       // we must send this flag for clientside to match properly too
+       int f = 0;
+       if(self.warpzone_isboxy)
+               BITSET_ASSIGN(f, 1);
+       if(self.warpzone_fadestart)
+               BITSET_ASSIGN(f, 2);
+       if(self.origin != '0 0 0')
+               BITSET_ASSIGN(f, 4);
+       WriteByte(MSG_ENTITY, f);
+
+       // we need THESE to render the warpzone (and cull properly)...
+       if(f & 4)
+       {
+               WriteCoord(MSG_ENTITY, self.origin.x);
+               WriteCoord(MSG_ENTITY, self.origin.y);
+               WriteCoord(MSG_ENTITY, self.origin.z);
+       }
+
+       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);
+       WriteByte(MSG_ENTITY, bound(1, self.scale * 16, 255));
+
+       // we need THESE to calculate the proper transform
+       WriteCoord(MSG_ENTITY, self.warpzone_origin.x);
+       WriteCoord(MSG_ENTITY, self.warpzone_origin.y);
+       WriteCoord(MSG_ENTITY, self.warpzone_origin.z);
+       WriteCoord(MSG_ENTITY, self.warpzone_angles.x);
+       WriteCoord(MSG_ENTITY, self.warpzone_angles.y);
+       WriteCoord(MSG_ENTITY, self.warpzone_angles.z);
+       WriteCoord(MSG_ENTITY, self.warpzone_targetorigin.x);
+       WriteCoord(MSG_ENTITY, self.warpzone_targetorigin.y);
+       WriteCoord(MSG_ENTITY, self.warpzone_targetorigin.z);
+       WriteCoord(MSG_ENTITY, self.warpzone_targetangles.x);
+       WriteCoord(MSG_ENTITY, self.warpzone_targetangles.y);
+       WriteCoord(MSG_ENTITY, self.warpzone_targetangles.z);
+
+       if(f & 2)
+       {
+               WriteShort(MSG_ENTITY, self.warpzone_fadestart);
+               WriteShort(MSG_ENTITY, self.warpzone_fadeend);
+       }
+
+       return true;
+}
+
+bool WarpZone_Camera_Send(entity to, int sendflags)
+{SELFPARAM();
+       int f = 0;
+       WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA);
+
+       if(self.warpzone_fadestart)
+               BITSET_ASSIGN(f, 2);
+       if(self.origin != '0 0 0')
+               BITSET_ASSIGN(f, 4);
+       WriteByte(MSG_ENTITY, f);
+
+       // we need THESE to render the warpzone (and cull properly)...
+       if(f & 4)
+       {
+               WriteCoord(MSG_ENTITY, self.origin.x);
+               WriteCoord(MSG_ENTITY, self.origin.y);
+               WriteCoord(MSG_ENTITY, self.origin.z);
+       }
+
+       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);
+       WriteByte(MSG_ENTITY, bound(1, self.scale * 16, 255));
+
+       // we need THESE to calculate the proper transform
+       WriteCoord(MSG_ENTITY, self.enemy.origin.x);
+       WriteCoord(MSG_ENTITY, self.enemy.origin.y);
+       WriteCoord(MSG_ENTITY, self.enemy.origin.z);
+       WriteCoord(MSG_ENTITY, self.enemy.angles.x);
+       WriteCoord(MSG_ENTITY, self.enemy.angles.y);
+       WriteCoord(MSG_ENTITY, self.enemy.angles.z);
+
+       if(f & 2)
+       {
+               WriteShort(MSG_ENTITY, self.warpzone_fadestart);
+               WriteShort(MSG_ENTITY, self.warpzone_fadeend);
+       }
+
+       return true;
+}
+
+#ifdef WARPZONELIB_KEEPDEBUG
+float WarpZone_CheckProjectileImpact(entity player)
+{SELFPARAM();
+       vector o0, v0;
+
+       o0 = player.origin + player.view_ofs;
+       v0 = player.velocity;
+
+       // if we teleported shortly before, abort
+       if(time <= player.warpzone_teleport_finishtime + 0.1)
+               return 0;
+
+       // if player hit a warpzone, abort
+       entity wz;
+       wz = WarpZone_Find(o0 + player.mins, o0 + player.maxs);
+       if(!wz)
+               return 0;
+
+#ifdef WARPZONELIB_REMOVEHACK
+       LOG_INFO("impactfilter found something - and it no longer gets handled correctly - please tell divVerent whether anything behaves broken now\n");
+#else
+       LOG_INFO("impactfilter found something - and it even gets handled correctly - please tell divVerent that this code apparently gets triggered again\n");
+#endif
+       LOG_INFO("Entity type: ", player.classname, "\n");
+       LOG_INFO("Origin: ", vtos(player.origin), "\n");
+       LOG_INFO("Velocity: ", vtos(player.velocity), "\n");
+
+#ifdef WARPZONELIB_REMOVEHACK
+       return 0;
+#else
+       // retry previous move
+       setorigin(player, player.warpzone_oldorigin);
+       player.velocity = player.warpzone_oldvelocity;
+       if(WarpZone_Teleport(wz, player, 0, 1))
+       {
+               entity oldself;
+               string save1, save2;
+
+               oldself = self;
+               self = wz;
+               other = player;
+               activator = player;
+
+               save1 = self.target; self.target = string_null;
+               save2 = self.target3; self.target3 = string_null;
+               SUB_UseTargets();
+               if (!self.target) self.target = save1;
+               if (!self.target3) self.target3 = save2;
+
+               self = self.enemy;
+               save1 = self.target; self.target = string_null;
+               save2 = self.target2; self.target2 = string_null;
+               SUB_UseTargets();
+               if (!self.target) self.target = save1;
+               if (!self.target2) self.target2 = save2;
+               self = oldself;
+       }
+       else
+       {
+               setorigin(player, o0 - player.view_ofs);
+               player.velocity = v0;
+       }
+
+       return +1;
+#endif
+}
+#endif
+
+float WarpZone_Projectile_Touch()
+{SELFPARAM();
+       if(other.classname == "trigger_warpzone")
+               return true;
+
+       // no further impacts if we teleported this frame!
+       // this is because even if we did teleport, the engine still may raise
+       // touch events for the previous location
+       // engine now aborts moves on teleport, so this SHOULD not happen any more
+       // but if this is called from TouchAreaGrid of the projectile moving,
+       // then this won't do
+       if(time == self.warpzone_teleport_time)
+               return true;
+
+#ifdef WARPZONELIB_KEEPDEBUG
+       // this SEEMS to not happen at the moment, but if it did, it would be more reliable
+       {
+               float save_dpstartcontents;
+               float save_dphitcontents;
+               float save_dphitq3surfaceflags;
+               string save_dphittexturename;
+               float save_allsolid;
+               float save_startsolid;
+               float save_fraction;
+               vector save_endpos;
+               vector save_plane_normal;
+               float save_plane_dist;
+               entity save_ent;
+               float save_inopen;
+               float save_inwater;
+               save_dpstartcontents = trace_dpstartcontents;
+               save_dphitcontents = trace_dphitcontents;
+               save_dphitq3surfaceflags = trace_dphitq3surfaceflags;
+               save_dphittexturename = trace_dphittexturename;
+               save_allsolid = trace_allsolid;
+               save_startsolid = trace_startsolid;
+               save_fraction = trace_fraction;
+               save_endpos = trace_endpos;
+               save_plane_normal = trace_plane_normal;
+               save_plane_dist = trace_plane_dist;
+               save_ent = trace_ent;
+               save_inopen = trace_inopen;
+               save_inwater = trace_inwater;
+               float f;
+               if((f = WarpZone_CheckProjectileImpact(self)) != 0)
+                       return (f > 0);
+               trace_dpstartcontents = save_dpstartcontents;
+               trace_dphitcontents = save_dphitcontents;
+               trace_dphitq3surfaceflags = save_dphitq3surfaceflags;
+               trace_dphittexturename = save_dphittexturename;
+               trace_allsolid = save_allsolid;
+               trace_startsolid = save_startsolid;
+               trace_fraction = save_fraction;
+               trace_endpos = save_endpos;
+               trace_plane_normal = save_plane_normal;
+               trace_plane_dist = save_plane_dist;
+               trace_ent = save_ent;
+               trace_inopen = save_inopen;
+               trace_inwater = save_inwater;
+       }
+#endif
+
+       if(WarpZone_Projectile_Touch_ImpactFilter_Callback())
+               return true;
+
+       return false;
+}
+
+void WarpZone_InitStep_FindOriginTarget()
+{SELFPARAM();
+       if(self.killtarget != "")
+       {
+               self.aiment = find(world, targetname, self.killtarget);
+               if(self.aiment == world)
+               {
+                       error("Warp zone with nonexisting killtarget");
+                       return;
+               }
+               self.killtarget = string_null;
+       }
+}
+
+void WarpZonePosition_InitStep_FindTarget()
+{SELFPARAM();
+       if(self.target == "")
+       {
+               error("Warp zone position with no target");
+               return;
+       }
+       self.enemy = find(world, targetname, self.target);
+       if(self.enemy == world)
+       {
+               error("Warp zone position with nonexisting target");
+               return;
+       }
+       if(self.enemy.aiment)
+       {
+               // already is positioned
+               error("Warp zone position targeting already oriented warpzone");
+               return;
+       }
+       self.enemy.aiment = self;
+}
+
+void WarpZoneCamera_Think(void)
+{SELFPARAM();
+       if(self.warpzone_save_origin != self.origin
+       || self.warpzone_save_angles != self.angles
+       || self.warpzone_save_eorigin != self.enemy.origin
+       || self.warpzone_save_eangles != self.enemy.angles)
+       {
+               WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles);
+               self.warpzone_save_origin = self.origin;
+               self.warpzone_save_angles = self.angles;
+               self.warpzone_save_eorigin = self.enemy.origin;
+               self.warpzone_save_eangles = self.enemy.angles;
+       }
+       self.nextthink = time;
+}
+
+void WarpZoneCamera_InitStep_FindTarget()
+{SELFPARAM();
+       entity e;
+       float i;
+       if(self.target == "")
+       {
+               error("Camera with no target");
+               return;
+       }
+       self.enemy = world;
+       for(e = world, i = 0; (e = find(e, targetname, self.target)); )
+               if(random() * ++i < 1)
+                       self.enemy = e;
+       if(self.enemy == world)
+       {
+               error("Camera with nonexisting target");
+               return;
+       }
+       warpzone_cameras_exist = 1;
+       WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles);
+       self.SendFlags = 0xFFFFFF;
+       if(self.spawnflags & 1)
+       {
+               self.think = WarpZoneCamera_Think;
+               self.nextthink = time;
+       }
+       else
+               self.nextthink = 0;
+}
+
+void WarpZone_InitStep_UpdateTransform()
+{SELFPARAM();
+       vector org, ang, norm, point;
+       float area;
+       vector tri, a, b, c, n;
+       float i_s, i_t, n_t;
+       string tex;
+
+       org = self.origin;
+       if(org == '0 0 0')
+               org = 0.5 * (self.mins + self.maxs);
+
+       norm = point = '0 0 0';
+       area = 0;
+       for(i_s = 0; ; ++i_s)
+       {
+               tex = getsurfacetexture(self, i_s);
+               if (!tex)
+                       break; // this is beyond the last one
+               if(tex == "textures/common/trigger" || tex == "trigger")
+                       continue;
+               n_t = getsurfacenumtriangles(self, i_s);
+               for(i_t = 0; i_t < n_t; ++i_t)
+               {
+                       tri = getsurfacetriangle(self, i_s, i_t);
+                       a = getsurfacepoint(self, i_s, tri.x);
+                       b = getsurfacepoint(self, i_s, tri.y);
+                       c = getsurfacepoint(self, i_s, tri.z);
+                       n = cross(c - a, b - a);
+                       area = area + vlen(n);
+                       norm = norm + n;
+                       point = point + vlen(n) * (a + b + c);
+               }
+       }
+       if(area > 0)
+       {
+               norm = norm * (1 / area);
+               point = point * (1 / (3 * area));
+               if(vlen(norm) < 0.99)
+               {
+                       LOG_INFO("trigger_warpzone near ", vtos(self.aiment.origin), " is nonplanar. BEWARE.\n");
+                       area = 0; // no autofixing in this case
+               }
+               norm = normalize(norm);
+       }
+
+       ang = '0 0 0';
+       if(self.aiment)
+       {
+               org = self.aiment.origin;
+               ang = self.aiment.angles;
+               if(area > 0)
+               {
+                       org = org - ((org - point) * norm) * norm; // project to plane
+                       makevectors(ang);
+                       if(norm * v_forward < 0)
+                       {
+                               LOG_INFO("Position target of trigger_warpzone near ", vtos(self.aiment.origin), " points into trigger_warpzone. BEWARE.\n");
+                               norm = -1 * norm;
+                       }
+                       ang = vectoangles2(norm, v_up); // keep rotation, but turn exactly against plane
+                       ang.x = -ang.x;
+                       if(norm * v_forward < 0.99)
+                               LOG_INFO("trigger_warpzone near ", vtos(self.aiment.origin), " has been turned to match plane orientation (", vtos(self.aiment.angles), " -> ", vtos(ang), "\n");
+                       if(vlen(org - self.aiment.origin) > 0.5)
+                               LOG_INFO("trigger_warpzone near ", vtos(self.aiment.origin), " has been moved to match the plane (", vtos(self.aiment.origin), " -> ", vtos(org), ").\n");
+               }
+       }
+       else if(area > 0)
+       {
+               org = point;
+               ang = vectoangles(norm);
+               ang.x = -ang.x;
+       }
+       else
+               error("cannot infer origin/angles for this warpzone, please use a killtarget or a trigger_warpzone_position");
+
+       self.warpzone_origin = org;
+       self.warpzone_angles = ang;
+}
+
+void WarpZone_InitStep_ClearTarget()
+{SELFPARAM();
+       if(self.enemy)
+               self.enemy.enemy = world;
+       self.enemy = world;
+}
+
+entity warpzone_first; .entity warpzone_next;
+void WarpZone_InitStep_FindTarget()
+{SELFPARAM();
+       float i;
+       entity e, e2;
+
+       if(self.enemy)
+               return;
+
+       // this way only one of the two ents needs to target
+       if(self.target != "")
+       {
+               self.enemy = self; // so the if(!e.enemy) check also skips self, saves one IF
+
+               e2 = world;
+               for(e = world, i = 0; (e = find(e, targetname, self.target)); )
+                       if(!e.enemy)
+                               if(e.classname == self.classname) // possibly non-warpzones may use the same targetname!
+                                       if(random() * ++i < 1)
+                                               e2 = e;
+               if(!e2)
+               {
+                       self.enemy = world;
+                       error("Warpzone with non-existing target");
+                       return;
+               }
+               self.enemy = e2;
+               e2.enemy = self;
+       }
+}
+
+void WarpZone_Think();
+void WarpZone_InitStep_FinalizeTransform()
+{SELFPARAM();
+       if(!self.enemy || self.enemy.enemy != self)
+       {
+               error("Invalid warp zone detected. Killed.");
+               return;
+       }
+
+       warpzone_warpzones_exist = 1;
+       WarpZone_SetUp(self, self.warpzone_origin, self.warpzone_angles, self.enemy.warpzone_origin, self.enemy.warpzone_angles);
+       self.touch = WarpZone_Touch;
+       self.SendFlags = 0xFFFFFF;
+       if(self.spawnflags & 1)
+       {
+               self.think = WarpZone_Think;
+               self.nextthink = time;
+       }
+       else
+               self.nextthink = 0;
+}
+
+float warpzone_initialized;
+//entity warpzone_first;
+entity warpzone_position_first;
+entity warpzone_camera_first;
+.entity warpzone_next;
+spawnfunc(misc_warpzone_position)
+{
+       // "target", "angles", "origin"
+       self.warpzone_next = warpzone_position_first;
+       warpzone_position_first = self;
+}
+spawnfunc(trigger_warpzone_position)
+{
+       spawnfunc_misc_warpzone_position(this);
+}
+spawnfunc(trigger_warpzone)
+{
+       // warp zone entities must have:
+       // "killtarget" pointing to a target_position with a direction arrow
+       //              that points AWAY from the warp zone, and that is inside
+       //              the warp zone trigger
+       // "target"     pointing to an identical warp zone at another place in
+       //              the map, with another killtarget to designate its
+       //              orientation
+
+       if(!self.scale)
+               self.scale = self.modelscale;
+       if(!self.scale)
+               self.scale = 1;
+       string m;
+       m = self.model;
+       WarpZoneLib_ExactTrigger_Init();
+       if(m != "")
+       {
+               precache_model(m);
+               _setmodel(self, m); // no precision needed
+       }
+       setorigin(self, self.origin);
+       if(self.scale)
+               setsize(self, self.mins * self.scale, self.maxs * self.scale);
+       else
+               setsize(self, self.mins, self.maxs);
+       self.SendEntity = WarpZone_Send;
+       self.SendFlags = 0xFFFFFF;
+       BITSET_ASSIGN(self.effects, EF_NODEPTHTEST);
+       self.warpzone_next = warpzone_first;
+       warpzone_first = self;
+}
+spawnfunc(func_camera)
+{
+       if(!self.scale)
+               self.scale = self.modelscale;
+       if(!self.scale)
+               self.scale = 1;
+       if(self.model != "")
+       {
+               precache_model(self.model);
+               _setmodel(self, self.model); // no precision needed
+       }
+       setorigin(self, self.origin);
+       if(self.scale)
+               setsize(self, self.mins * self.scale, self.maxs * self.scale);
+       else
+               setsize(self, self.mins, self.maxs);
+       if(!self.solid)
+               self.solid = SOLID_BSP;
+       else if(self.solid < 0)
+               self.solid = SOLID_NOT;
+       self.SendEntity = WarpZone_Camera_Send;
+       self.SendFlags = 0xFFFFFF;
+       self.warpzone_next = warpzone_camera_first;
+       warpzone_camera_first = self;
+}
+void WarpZones_Reconnect()
+{SELFPARAM();
+       for(setself(warpzone_first); self; setself(self.warpzone_next))
+               WarpZone_InitStep_ClearTarget();
+       for(setself(warpzone_first); self; setself(self.warpzone_next))
+               WarpZone_InitStep_FindTarget();
+       for(setself(warpzone_camera_first); self; setself(self.warpzone_next))
+               WarpZoneCamera_InitStep_FindTarget();
+       for(setself(warpzone_first); self; setself(self.warpzone_next))
+               WarpZone_InitStep_FinalizeTransform();
+       setself(this);
+}
+
+void WarpZone_Think()
+{SELFPARAM();
+       if(self.warpzone_save_origin != self.origin
+       || self.warpzone_save_angles != self.angles
+       || self.warpzone_save_eorigin != self.enemy.origin
+       || self.warpzone_save_eangles != self.enemy.angles)
+       {
+               WarpZone_InitStep_UpdateTransform();
+               setself(self.enemy);
+               WarpZone_InitStep_UpdateTransform();
+               setself(this);
+               WarpZone_InitStep_FinalizeTransform();
+               setself(self.enemy);
+               WarpZone_InitStep_FinalizeTransform();
+               setself(this);
+               self.warpzone_save_origin = self.origin;
+               self.warpzone_save_angles = self.angles;
+               self.warpzone_save_eorigin = self.enemy.origin;
+               self.warpzone_save_eangles = self.enemy.angles;
+       }
+       self.nextthink = time;
+}
+
+void WarpZone_StartFrame()
+{SELFPARAM();
+       entity e;
+       if(warpzone_initialized == 0)
+       {
+               warpzone_initialized = 1;
+               for(setself(warpzone_first); self; setself(self.warpzone_next))
+                       WarpZone_InitStep_FindOriginTarget();
+               for(setself(warpzone_position_first); self; setself(self.warpzone_next))
+                       WarpZonePosition_InitStep_FindTarget();
+               for(setself(warpzone_first); self; setself(self.warpzone_next))
+                       WarpZone_InitStep_UpdateTransform();
+               setself(this);
+               WarpZones_Reconnect();
+               WarpZone_PostInitialize_Callback();
+       }
+
+       entity oldother;
+       oldother = other;
+       for(e = world; (e = nextent(e)); )
+       {
+               if(warpzone_warpzones_exist) { WarpZone_StoreProjectileData(e); }
+
+               if(IS_REAL_CLIENT(e))
+               {
+                       if(e.solid == SOLID_NOT) // not spectating?
+                       if(e.movetype == MOVETYPE_NOCLIP || e.movetype == MOVETYPE_FLY || e.movetype == MOVETYPE_FLY_WORLDONLY) // not spectating? (this is to catch observers)
+                       {
+                               other = e; // player
+
+                               // warpzones
+                               if(warpzone_warpzones_exist) {
+                               setself(WarpZone_Find(e.origin + e.mins, e.origin + e.maxs));
+                               if(self)
+                               if(!WarpZoneLib_ExactTrigger_Touch())
+                                       if(WarpZone_PlaneDist(self, e.origin + e.view_ofs) <= 0)
+                                               WarpZone_Teleport(self, e, -1, 0); } // NOT triggering targets by this!
+
+                               // teleporters
+                               setself(Teleport_Find(e.origin + e.mins, e.origin + e.maxs));
+                               if(self)
+                               if(!WarpZoneLib_ExactTrigger_Touch())
+                                       Simple_TeleportPlayer(self, other); // NOT triggering targets by this!
+                       }
+               }
+
+               if(IS_NOT_A_CLIENT(e))
+               {
+                       if(warpzone_warpzones_exist)
+                               for (; (e = nextent(e)); )
+                                       WarpZone_StoreProjectileData(e);
+                       break;
+               }
+       }
+       setself(this);
+       other = oldother;
+}
+
+.float warpzone_reconnecting;
+float visible_to_some_client(entity ent)
+{
+       entity e;
+       for(e = nextent(world); !IS_NOT_A_CLIENT(e); e = nextent(e))
+               if(IS_PLAYER(e) && IS_REAL_CLIENT(e))
+                       if(checkpvs(e.origin + e.view_ofs, ent))
+                               return 1;
+       return 0;
+}
+void trigger_warpzone_reconnect_use()
+{SELFPARAM();
+       entity e;
+       e = self;
+       // NOTE: this matches for target, not targetname, but of course
+       // targetname must be set too on the other entities
+       for(setself(warpzone_first); self; setself(self.warpzone_next))
+               self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && (visible_to_some_client(self) || visible_to_some_client(self.enemy))));
+       for(setself(warpzone_camera_first); self; setself(self.warpzone_next))
+               self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && visible_to_some_client(self)));
+       for(setself(warpzone_first); self; setself(self.warpzone_next))
+               if(self.warpzone_reconnecting)
+                       WarpZone_InitStep_ClearTarget();
+       for(setself(warpzone_first); self; setself(self.warpzone_next))
+               if(self.warpzone_reconnecting)
+                       WarpZone_InitStep_FindTarget();
+       for(setself(warpzone_camera_first); self; setself(self.warpzone_next))
+               if(self.warpzone_reconnecting)
+                       WarpZoneCamera_InitStep_FindTarget();
+       for(setself(warpzone_first); self; setself(self.warpzone_next))
+               if(self.warpzone_reconnecting || self.enemy.warpzone_reconnecting)
+                       WarpZone_InitStep_FinalizeTransform();
+       setself(e);
+}
+
+spawnfunc(trigger_warpzone_reconnect)
+{
+       self.use = trigger_warpzone_reconnect_use;
+}
+
+spawnfunc(target_warpzone_reconnect)
+{
+       spawnfunc_trigger_warpzone_reconnect(this); // both names make sense here :(
+}
+
+void WarpZone_PlayerPhysics_FixVAngle(void)
+{SELFPARAM();
+#ifndef WARPZONE_DONT_FIX_VANGLE
+       if(IS_REAL_CLIENT(self))
+       if(self.v_angle.z <= 360) // if not already adjusted
+       if(time - self.ping * 0.001 < self.warpzone_teleport_time)
+       {
+               self.v_angle = WarpZone_TransformVAngles(self.warpzone_teleport_zone, self.v_angle);
+               self.v_angle_z += 720; // mark as adjusted
+       }
+#endif
+}
diff --git a/qcsrc/lib/warpzone/server.qh b/qcsrc/lib/warpzone/server.qh
new file mode 100644 (file)
index 0000000..943f032
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef LIB_WARPZONE_SERVER_H
+#define LIB_WARPZONE_SERVER_H
+
+void WarpZone_StartFrame();
+float WarpZone_Projectile_Touch();
+
+// THESE must be defined by calling QC code:
+void WarpZone_PostTeleportPlayer_Callback(entity pl);
+float WarpZone_Projectile_Touch_ImpactFilter_Callback();
+
+// server must also define a float called ENT_CLIENT_WARPZONE for the initial byte of WarpZone entities
+//const float ENT_CLIENT_WARPZONE;
+//const float ENT_CLIENT_WARPZONE_CAMERA;
+
+void WarpZone_PlayerPhysics_FixVAngle(void);
+
+void WarpZone_PostInitialize_Callback(void);
+#endif
diff --git a/qcsrc/lib/warpzone/util_server.qc b/qcsrc/lib/warpzone/util_server.qc
new file mode 100644 (file)
index 0000000..742ec3e
--- /dev/null
@@ -0,0 +1,49 @@
+#include "util_server.qh"
+
+#include "common.qh"
+
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+    #include "../csqcmodel/sv_model.qh"
+#endif
+#include "common.qh"
+
+void WarpZoneLib_ExactTrigger_Init()
+{SELFPARAM();
+       vector mi, ma;
+       if (self.movedir == '0 0 0')
+       if (self.angles != '0 0 0')
+       {
+               makevectors (self.angles);
+               self.movedir = v_forward;
+       }
+       if(self.model == "")
+       {
+               // It's a box! No need to match with exacttriggers.
+               self.warpzone_isboxy = 1;
+       }
+       else
+       {
+               mi = self.mins;
+               ma = self.maxs;
+               precache_model(self.model);
+               _setmodel(self, self.model);
+               // let mapper-set mins/maxs override the model's bounds if set
+               if(mi != '0 0 0' || ma != '0 0 0')
+               {
+                       // It's a box! No need to match with exacttriggers.
+                       self.mins = mi;
+                       self.maxs = ma;
+                       self.warpzone_isboxy = 1;
+               }
+       }
+       setorigin(self, self.origin);
+       if(self.scale)
+               setsize(self, self.mins * self.scale, self.maxs * self.scale);
+       else
+               setsize(self, self.mins, self.maxs);
+       self.movetype = MOVETYPE_NONE;
+       self.solid = SOLID_TRIGGER;
+       self.model = "";
+}
diff --git a/qcsrc/lib/warpzone/util_server.qh b/qcsrc/lib/warpzone/util_server.qh
new file mode 100644 (file)
index 0000000..75df5d8
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef LIB_WARPZONE_UTIL_SERVER_H
+#define LIB_WARPZONE_UTIL_SERVER_H
+
+float WarpZoneLib_MoveOutOfSolid(entity e);
+float WarpZoneLib_ExactTrigger_Touch();
+#ifdef SVQC
+void WarpZoneLib_ExactTrigger_Init();
+#endif
+#endif
index dbcd900..3b2af5d 100644 (file)
 
 #include "../../common/weapons/all.qh"
 
-#include "../../csqcmodellib/sv_model.qh"
+#include "../../lib/csqcmodel/sv_model.qh"
 
-#include "../../warpzonelib/common.qh"
-#include "../../warpzonelib/util_server.qh"
+#include "../../lib/warpzone/common.qh"
+#include "../../lib/warpzone/util_server.qh"
 
 entity bot_spawn()
 {SELFPARAM();
index ec27e3e..ced6463 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "../../../common/triggers/trigger/jumppads.qh"
 
-#include "../../../warpzonelib/common.qh"
+#include "../../../lib/warpzone/common.qh"
 
 .float speed;
 
index ffd78e9..156ad79 100644 (file)
@@ -7,8 +7,8 @@
 
 #include "../../common/constants.qh"
 
-#include "../../warpzonelib/common.qh"
-#include "../../warpzonelib/util_server.qh"
+#include "../../lib/warpzone/common.qh"
+#include "../../lib/warpzone/util_server.qh"
 
 // create a new spawnfunc_waypoint and automatically link it to other waypoints, and link
 // them back to it as well
index c17a1d0..0f43d92 100644 (file)
 
 #include "../common/triggers/func/breakable.qh"
 
-#include "../csqcmodellib/sv_model.qh"
+#include "../lib/csqcmodel/sv_model.qh"
 
-#include "../warpzonelib/anglestransform.qh"
-#include "../warpzonelib/util_server.qh"
+#include "../lib/warpzone/anglestransform.qh"
+#include "../lib/warpzone/util_server.qh"
 
 void CopyBody(float keepvelocity);
 
index ad0d71d..ddbc18d 100644 (file)
@@ -46,7 +46,7 @@
 
 #include "../common/monsters/sv_monsters.qh"
 
-#include "../warpzonelib/server.qh"
+#include "../lib/warpzone/server.qh"
 
 
 void send_CSQC_teamnagger() {
index 13d7b62..dafd7d2 100644 (file)
@@ -15,7 +15,7 @@
 #include "../common/deathtypes.qh"
 #include "../common/triggers/subs.qh"
 #include "../common/playerstats.qh"
-#include "../csqcmodellib/sv_model.qh"
+#include "../lib/csqcmodel/sv_model.qh"
 
 #include "../common/minigames/sv_minigames.qh"
 
index 9cf020d..3cd7f23 100644 (file)
@@ -33,7 +33,7 @@
 #include "../../common/monsters/spawn.qh"
 #include "../../common/monsters/sv_monsters.qh"
 
-#include "../../warpzonelib/common.qh"
+#include "../../lib/warpzone/common.qh"
 
 void ClientKill_TeamChange (float targetteam); // 0 = don't change, -1 = auto, -2 = spec
 
index 7dea85e..4d390e7 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "../../common/monsters/all.qh"
 #include "../../common/notifications.qh"
-#include "../../warpzonelib/common.qh"
+#include "../../lib/warpzone/common.qh"
 
 
 // ====================================================
index 50b09f7..60e6bde 100644 (file)
@@ -6,7 +6,7 @@
 
 #include "../../common/util.qh"
 
-#include "../../csqcmodellib/sv_model.qh"
+#include "../../lib/csqcmodel/sv_model.qh"
 
 // ===============================================
 //     Generates radar map images for use in the HUD
index 8f9b305..845fd56 100644 (file)
@@ -21,8 +21,8 @@
 #include "../common/teams.qh"
 #include "../common/util.qh"
 #include "../common/weapons/all.qh"
-#include "../csqcmodellib/sv_model.qh"
-#include "../warpzonelib/common.qh"
+#include "../lib/csqcmodel/sv_model.qh"
+#include "../lib/warpzone/common.qh"
 
 bool Damage_DamageInfo_SendEntity(entity this, entity to, int sf)
 {
index 6e0f5b5..064d31f 100644 (file)
@@ -4,7 +4,7 @@
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
-    #include "../warpzonelib/common.qh"
+    #include "../lib/warpzone/common.qh"
     #include "../common/constants.qh"
     #include "../common/teams.qh"
     #include "../common/util.qh"
@@ -21,7 +21,7 @@
     #include "mutators/mutators_include.qh"
     #include "../common/turrets/sv_turrets.qh"
     #include "../common/vehicles/all.qh"
-    #include "../csqcmodellib/sv_model.qh"
+    #include "../lib/csqcmodel/sv_model.qh"
     #include "../common/playerstats.qh"
     #include "g_hook.qh"
     #include "scores.qh"
index d372d35..7a77d4a 100644 (file)
@@ -12,8 +12,8 @@
 #include "../common/constants.qh"
 #include "../common/util.qh"
 #include "../common/weapons/all.qh"
-#include "../warpzonelib/common.qh"
-#include "../warpzonelib/server.qh"
+#include "../lib/warpzone/common.qh"
+#include "../lib/warpzone/server.qh"
 
 .int state;
 
index a9353cf..8bc5387 100644 (file)
@@ -11,7 +11,7 @@ class(BGMScript) .float bgmscriptsustain;
 class(BGMScript) .float bgmscriptrelease;
 
 #include "../common/constants.qh"
-#include "../csqcmodellib/sv_model.qh"
+#include "../lib/csqcmodel/sv_model.qh"
 
 .float modelscale;
 
index 8544cd9..af1cf7c 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "antilag.qh"
 #include "command/common.qh"
-#include "../warpzonelib/common.qh"
+#include "../lib/warpzone/common.qh"
 #include "../common/triggers/subs.qh"
 
 spawnfunc(info_null)
index fc0dbd4..8df6e3b 100644 (file)
@@ -4,7 +4,7 @@
 #include "../common/monsters/all.qh"
 #include "../common/notifications.qh"
 #include "../common/util.qh"
-#include "../warpzonelib/util_server.qh"
+#include "../lib/warpzone/util_server.qh"
 
 /*
 TODO:
index ccefc4c..4c8fdea 100644 (file)
@@ -23,9 +23,9 @@
 #include "../common/vehicles/sv_vehicles.qh"
 #include "../common/vehicles/vehicle.qh"
 #include "../common/items/all.qc"
-#include "../csqcmodellib/sv_model.qh"
-#include "../warpzonelib/anglestransform.qh"
-#include "../warpzonelib/server.qh"
+#include "../lib/csqcmodel/sv_model.qh"
+#include "../lib/warpzone/anglestransform.qh"
+#include "../lib/warpzone/server.qh"
 
 void crosshair_trace(entity pl)
 {
index 2ee316d..9de38ea 100644 (file)
@@ -37,8 +37,8 @@
 #include "../../common/stats.qh"
 #include "../../common/teams.qh"
 
-#include "../../warpzonelib/server.qh"
-#include "../../warpzonelib/util_server.qh"
+#include "../../lib/warpzone/server.qh"
+#include "../../lib/warpzone/util_server.qh"
 
 .float lastground;
 float total_players;
index 78c1924..eff5811 100644 (file)
@@ -7,7 +7,7 @@
 #include "../teamplay.qh"
 #endif
 
-#include "../../warpzonelib/common.qh"
+#include "../../lib/warpzone/common.qh"
 
 void ctf_FakeTimeLimit(entity e, float t)
 {
index 39adb17..ac60070 100644 (file)
@@ -38,8 +38,8 @@
 
 #include "../../common/monsters/all.qh"
 
-#include "../../warpzonelib/anglestransform.qh"
-#include "../../warpzonelib/server.qh"
-#include "../../warpzonelib/util_server.qh"
+#include "../../lib/warpzone/anglestransform.qh"
+#include "../../lib/warpzone/server.qh"
+#include "../../lib/warpzone/util_server.qh"
 
 #endif
index e948ab6..fe8fe0f 100644 (file)
@@ -1,10 +1,10 @@
 #if defined(CSQC)
 #elif defined(MENUQC)
 #elif defined(SVQC)
-    #include "../../warpzonelib/anglestransform.qh"
-    #include "../../warpzonelib/common.qh"
-    #include "../../warpzonelib/util_server.qh"
-    #include "../../warpzonelib/server.qh"
+    #include "../../lib/warpzone/anglestransform.qh"
+    #include "../../lib/warpzone/common.qh"
+    #include "../../lib/warpzone/util_server.qh"
+    #include "../../lib/warpzone/server.qh"
     #include "../../common/constants.qh"
     #include "../../common/stats.qh"
     #include "../../common/teams.qh"
@@ -52,8 +52,8 @@
     #include "../command/cmd.qh"
     #include "../command/sv_cmd.qh"
     #include "../../common/csqcmodel_settings.qh"
-    #include "../../csqcmodellib/common.qh"
-    #include "../../csqcmodellib/sv_model.qh"
+    #include "../../lib/csqcmodel/common.qh"
+    #include "../../lib/csqcmodel/sv_model.qh"
     #include "../anticheat.qh"
     #include "../cheats.qh"
     #include "../../common/playerstats.qh"
index 09776c4..ec5d688 100644 (file)
@@ -9,10 +9,10 @@
 #include "../common/triggers/subs.qh"
 #include "../common/util.qh"
 #include "../common/weapons/all.qh"
-#include "../csqcmodellib/sv_model.qh"
-#include "../warpzonelib/anglestransform.qh"
-#include "../warpzonelib/util_server.qh"
-#include "../warpzonelib/common.qh"
+#include "../lib/csqcmodel/sv_model.qh"
+#include "../lib/warpzone/anglestransform.qh"
+#include "../lib/warpzone/util_server.qh"
+#include "../lib/warpzone/common.qh"
 #include "../common/vehicles/vehicle.qh"
 #include "../common/vehicles/sv_vehicles.qh"
 
index ee891aa..2adaf83 100644 (file)
 #include "../common/turrets/targettrigger.qc"
 #include "../common/weapons/config.qc"
 
-#include "../csqcmodellib/sv_model.qc"
+#include "../lib/csqcmodel/sv_model.qc"
 
-#include "../warpzonelib/anglestransform.qc"
-#include "../warpzonelib/common.qc"
-#include "../warpzonelib/server.qc"
-#include "../warpzonelib/util_server.qc"
+#include "../lib/warpzone/anglestransform.qc"
+#include "../lib/warpzone/common.qc"
+#include "../lib/warpzone/server.qc"
+#include "../lib/warpzone/util_server.qc"
 
 #if BUILD_MOD
 #include "../../mod/server/progs.inc"
index 3ac5582..d9d8d55 100644 (file)
@@ -11,8 +11,8 @@
 #include "../common/notifications.qh"
 #include "../common/mapinfo.qh"
 #include "../common/triggers/subs.qh"
-#include "../warpzonelib/util_server.qh"
-#include "../warpzonelib/common.qh"
+#include "../lib/warpzone/util_server.qh"
+#include "../lib/warpzone/common.qh"
 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
 
 void W_Porto_Fail(float failhard);
index ead90d3..6980a9e 100644 (file)
@@ -7,8 +7,8 @@
 #include "../common/teams.qh"
 #include "../common/triggers/subs.qh"
 #include "../common/util.qh"
-#include "../warpzonelib/common.qh"
-#include "../warpzonelib/util_server.qh"
+#include "../lib/warpzone/common.qh"
+#include "../lib/warpzone/util_server.qh"
 
 bool SpawnPoint_Send(entity this, entity to, int sf)
 {
index 05fee86..8b9e1c8 100644 (file)
 #include "../common/vehicles/all.qh"
 #include "../common/weapons/all.qh"
 
-#include "../csqcmodellib/sv_model.qh"
+#include "../lib/csqcmodel/sv_model.qh"
 
-#include "../warpzonelib/common.qh"
-#include "../warpzonelib/server.qh"
+#include "../lib/warpzone/common.qh"
+#include "../lib/warpzone/server.qh"
 
 .float lastground;
 .int state;
index eee53e6..89d6b06 100644 (file)
@@ -23,7 +23,7 @@
 
     #include "../common/weapons/all.qh"
 
-    #include "../warpzonelib/util_server.qh"
+    #include "../lib/warpzone/util_server.qh"
 #endif
 
 #ifdef CSQC
index b88acaa..4c9e0e3 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "../../common/weapons/all.qh"
 
-#include "../../warpzonelib/common.qh"
+#include "../../lib/warpzone/common.qh"
 
 // this function calculates w_shotorg and w_shotdir based on the weapon model
 // offset, trueaim and antilag, and won't put w_shotorg inside a wall.
index 3f74034..dd7e2b5 100644 (file)
@@ -12,7 +12,7 @@
 #include "../../common/notifications.qh"
 #include "../../common/util.qh"
 #include "../../common/weapons/all.qh"
-#include "../../csqcmodellib/sv_model.qh"
+#include "../../lib/csqcmodel/sv_model.qh"
 
 /*
 ===========================================================================
diff --git a/qcsrc/warpzonelib/COPYING b/qcsrc/warpzonelib/COPYING
deleted file mode 100644 (file)
index d61ba0a..0000000
+++ /dev/null
@@ -1,369 +0,0 @@
-The code in this directory is dual-licensed MIT and GPLv2 "or any later version".
-
-
-
-MIT license:
-
-Copyright (c) 2010 Rudolf Polzer
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-
-
-GPL v2:
-
-                   GNU GENERAL PUBLIC LICENSE
-                      Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                           Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                   GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-                           NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-                    END OF TERMS AND CONDITIONS
-
-           How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License along
-    with this program; if not, write to the Free Software Foundation, Inc.,
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/qcsrc/warpzonelib/TODO b/qcsrc/warpzonelib/TODO
deleted file mode 100644 (file)
index 927ab12..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Open issues:
-- grep for TODO and FIXME
-- when shot origin is inside warpzone, vortex shot fails (and is even drawn in totally wrong direction). WHY? Possibly v_forward got lost?
-
-Weapon support:
-
-- blaster: YES
-- shotgun: YES
-- machinegun: YES
-- mortar: YES
-- electro: YES
-- crylink: YES
-- vortex: YES
-- hagar: YES
-- devastator: YES (except for trail bug)
-- porto: YES (bwahahahaha)
-- hlac: YES
-- vaporizer: YES
-- rifle: YES
-- fireball: YES (BFG effect cannot work through warpzones by design, so it's not available through warpzones)
-- hook: YES
-
-- shockwave: NO (does not support warpzones currently)
-- tuba: NO (sound)
diff --git a/qcsrc/warpzonelib/anglestransform.qc b/qcsrc/warpzonelib/anglestransform.qc
deleted file mode 100644 (file)
index f92947f..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-#include "anglestransform.qh"
-
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-
-#ifdef POSITIVE_PITCH_IS_DOWN
-vector fixedvectoangles(vector a)
-{
-       vector ang;
-       ang = vectoangles(a);
-       ang.x = -ang.x;
-       return ang;
-}
-vector fixedvectoangles2(vector a, vector b)
-{
-       vector ang;
-       ang = vectoangles2(a, b);
-       ang.x = -ang.x;
-       return ang;
-}
-#else
-void fixedmakevectors(vector a)
-{
-       // a makevectors that actually inverts vectoangles
-       a.x = -a.x;
-       makevectors(a);
-}
-#endif
-
-// angles transforms
-// angles in fixedmakevectors/fixedvectoangles space
-vector AnglesTransform_Apply(vector transform, vector v)
-{
-       fixedmakevectors(transform);
-       return v_forward * v.x
-               + v_right   * (-v.y)
-               + v_up      * v.z;
-}
-
-vector AnglesTransform_Multiply(vector t1, vector t2)
-{
-       vector m_forward, m_up;
-       fixedmakevectors(t2); m_forward = v_forward; m_up = v_up;
-       m_forward = AnglesTransform_Apply(t1, m_forward); m_up = AnglesTransform_Apply(t1, m_up);
-       return fixedvectoangles2(m_forward, m_up);
-}
-
-vector AnglesTransform_Invert(vector transform)
-{
-       vector i_forward, i_up;
-       fixedmakevectors(transform);
-       // we want angles that turn v_forward into '1 0 0', v_right into '0 1 0' and v_up into '0 0 1'
-       // but these are orthogonal unit vectors!
-       // so to invert, we can simply fixedvectoangles the TRANSPOSED matrix
-       // TODO is this always -transform?
-       i_forward.x = v_forward.x;
-       i_forward.y = -v_right.x;
-       i_forward.z = v_up.x;
-       i_up.x = v_forward.z;
-       i_up.y = -v_right.z;
-       i_up.z = v_up.z;
-       return fixedvectoangles2(i_forward, i_up);
-}
-
-vector AnglesTransform_TurnDirectionFR(vector transform)
-{
-       // turn 180 degrees around v_up
-       // changes in-direction to out-direction
-       //fixedmakevectors(transform);
-       //return fixedvectoangles2(-1 * v_forward, 1 * v_up);
-       transform.x = -transform.x;
-       transform.y = 180 + transform.y;
-       transform.z = -transform.z;
-       // pitch: -s +c
-       // yaw:   -s -c
-       // roll:  -s +c
-       return transform;
-}
-
-vector AnglesTransform_TurnDirectionFU(vector transform)
-{
-       // turn 180 degrees around v_up
-       // changes in-direction to out-direction
-       //fixedmakevectors(transform);
-       //return fixedvectoangles2(-1 * v_forward, 1 * v_up);
-       transform.x = -transform.x;
-       transform.y = 180 + transform.y;
-       transform.z = 180 - transform.z;
-       return transform;
-}
-
-vector AnglesTransform_RightDivide(vector to_transform, vector from_transform)
-{
-       return AnglesTransform_Multiply(to_transform, AnglesTransform_Invert(from_transform));
-}
-
-vector AnglesTransform_LeftDivide(vector from_transform, vector to_transform)
-{
-       return AnglesTransform_Multiply(AnglesTransform_Invert(from_transform), to_transform);
-}
-
-vector AnglesTransform_Normalize(vector t, float minimize_roll)
-{
-       float need_flip;
-       // first, bring all angles in their range...
-       t.x = t.x - 360 * rint(t.x / 360);
-       t.y = t.y - 360 * rint(t.y / 360);
-       t.z = t.z - 360 * rint(t.z / 360);
-       if(minimize_roll)
-               need_flip = (t.z > 90 || t.z <= -90);
-       else
-               need_flip = (t.x > 90 || t.x < -90); // for pitch we prefer to allow exactly -90 degrees for looking straight down
-       if(need_flip)
-       {
-               if(t.x >= 0) t.x = 180 - t.x; else t.x = -180 - t.x;
-               if(t.y > 0) t.y -= 180; else t.y += 180;
-               if(t.z > 0) t.z -= 180; else t.z += 180;
-       }
-       return t;
-}
-
-vector AnglesTransform_CancelRoll(vector t)
-{
-       const float epsilon = 30;
-       float f;
-
-       // constraints:
-       // forward vector (NOT SO important)
-       // right vector, up vector: screen rotation (MORE important)
-       // choose best match among all pitch-yaw only rotations
-
-       // FIXME find a better method
-
-       f = fabs(t.x - (-90)) / epsilon;
-       if(f < 1)
-       {
-               //t_x = -90;
-               t.y += t.z;
-               t.z = 0;
-       }
-       else
-       {
-               f = fabs(t.x - 90) / epsilon;
-               if(f < 1)
-               {
-                       //t_x = 90;
-                       t.y -= t.z;
-                       t.z = 0;
-               }
-       }
-       return t;
-}
-
-#ifdef POSITIVE_PITCH_IS_DOWN
-vector AnglesTransform_ApplyToAngles(vector transform, vector v)
-{
-       v.x = -v.x;
-       v = AnglesTransform_Multiply(transform, v);
-       v.x = -v.x;
-       return v;
-}
-vector AnglesTransform_ApplyToVAngles(vector transform, vector v)
-{
-       v = AnglesTransform_Multiply(transform, v);
-       return v;
-}
-vector AnglesTransform_FromAngles(vector v)
-{
-       v.x = -v.x;
-       return v;
-}
-vector AnglesTransform_ToAngles(vector v)
-{
-       v.x = -v.x;
-       return v;
-}
-vector AnglesTransform_FromVAngles(vector v)
-{
-       return v;
-}
-vector AnglesTransform_ToVAngles(vector v)
-{
-       return v;
-}
-#else
-vector AnglesTransform_ApplyToAngles(vector transform, vector v)
-{
-       v = AnglesTransform_Multiply(transform, v);
-       return v;
-}
-vector AnglesTransform_ApplyToVAngles(vector transform, vector v)
-{
-       v.x = -v.x;
-       v = AnglesTransform_Multiply(transform, v);
-       v.x = -v.x;
-       return v;
-}
-vector AnglesTransform_FromAngles(vector v)
-{
-       return v;
-}
-vector AnglesTransform_ToAngles(vector v)
-{
-       return v;
-}
-vector AnglesTransform_FromVAngles(vector v)
-{
-       v.x = -v.x;
-       return v;
-}
-vector AnglesTransform_ToVAngles(vector v)
-{
-       v.x = -v.x;
-       return v;
-}
-#endif
-
-vector AnglesTransform_Multiply_GetPostShift(vector t0, vector st0, vector t1, vector st1)
-{
-       // we want the result of:
-       //   t0 * (t1 * p + st1) + st0
-       //   t0 * t1 * p + t0 * st1 + st0
-       return st0 + AnglesTransform_Apply(t0, st1);
-}
-vector AnglesTransform_PrePostShift_GetPostShift(vector sf, vector t, vector st)
-{
-       return st - AnglesTransform_Apply(t, sf);
-}
diff --git a/qcsrc/warpzonelib/anglestransform.qh b/qcsrc/warpzonelib/anglestransform.qh
deleted file mode 100644 (file)
index 0538471..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef ANGLETRANSFORM_H
-#define ANGLETRANSFORM_H
-
-#define POSITIVE_PITCH_IS_DOWN
-
-#ifdef POSITIVE_PITCH_IS_DOWN
-#define fixedmakevectors makevectors
-vector fixedvectoangles(vector a);
-vector fixedvectoangles2(vector a, vector b);
-#else
-void fixedmakevectors(vector a);
-#define fixedvectoangles2 vectoangles2
-#define fixedvectoangles vectoangles
-#endif
-
-vector AnglesTransform_Apply(vector transform, vector v);
-vector AnglesTransform_Multiply(vector t1, vector t2); // A B
-vector AnglesTransform_Invert(vector transform);
-vector AnglesTransform_TurnDirectionFU(vector transform);
-vector AnglesTransform_TurnDirectionFR(vector transform);
-vector AnglesTransform_RightDivide(vector to_transform, vector from_transform); // A B^-1
-vector AnglesTransform_LeftDivide(vector from_transform, vector to_transform); // A^-1 B
-
-vector AnglesTransform_Normalize(vector t, float minimize_roll); // makes sure all angles are in their range: yaw in -180..180, pitch in -90..90, roll in -180..180 (or if minimize_roll is set, pitch in -180..180, roll in -90..90)
-
-vector AnglesTransform_ApplyToAngles(vector transform, vector v);
-vector AnglesTransform_ApplyToVAngles(vector transform, vector v);
-vector AnglesTransform_FromAngles(vector v);
-vector AnglesTransform_ToAngles(vector v);
-vector AnglesTransform_FromVAngles(vector v);
-vector AnglesTransform_ToVAngles(vector v);
-
-// transformed = original * transform + postshift
-vector AnglesTransform_Multiply_GetPostShift(vector sf0, vector st0, vector t1, vector st1);
-vector AnglesTransform_PrePostShift_GetPostShift(vector sf, vector t, vector st);
-#endif
diff --git a/qcsrc/warpzonelib/client.qc b/qcsrc/warpzonelib/client.qc
deleted file mode 100644 (file)
index 68c2984..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-#include "client.qh"
-#include "common.qh"
-
-#if defined(CSQC)
-       #include "../client/autocvars.qh"
-       #include "../csqcmodellib/cl_model.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-
-void WarpZone_Fade_PreDraw()
-{SELFPARAM();
-       vector org;
-       org = getpropertyvec(VF_ORIGIN);
-       if(!checkpvs(org, self)) // this makes sense as long as we don't support recursive warpzones
-               self.alpha = 0;
-       else if(self.warpzone_fadestart)
-               self.alpha = bound(0, (self.warpzone_fadeend - vlen(org - self.origin - 0.5 * (self.mins + self.maxs))) / (self.warpzone_fadeend - self.warpzone_fadestart), 1);
-       else
-               self.alpha = 1;
-       //printf("%v <-> %v\n", view_origin, self.origin + 0.5 * (self.mins + self.maxs));
-       if(self.alpha <= 0)
-               self.drawmask = 0;
-       else
-               self.drawmask = MASK_NORMAL;
-}
-
-void WarpZone_Read(float isnew)
-{SELFPARAM();
-       warpzone_warpzones_exist = 1;
-       if (!self.enemy)
-       {
-               self.enemy = spawn();
-               self.enemy.classname = "warpzone_from";
-       }
-       self.classname = "trigger_warpzone";
-
-       int f = ReadByte();
-       self.warpzone_isboxy = (f & 1);
-       if(f & 4)
-       {
-               self.origin_x = ReadCoord();
-               self.origin_y = ReadCoord();
-               self.origin_z = ReadCoord();
-       }
-       else
-               self.origin = '0 0 0';
-       self.modelindex = ReadShort();
-       self.mins_x = ReadCoord();
-       self.mins_y = ReadCoord();
-       self.mins_z = ReadCoord();
-       self.maxs_x = ReadCoord();
-       self.maxs_y = ReadCoord();
-       self.maxs_z = ReadCoord();
-       self.scale = ReadByte() / 16;
-       self.enemy.oldorigin_x = ReadCoord();
-       self.enemy.oldorigin_y = ReadCoord();
-       self.enemy.oldorigin_z = ReadCoord();
-       self.enemy.avelocity_x = ReadCoord();
-       self.enemy.avelocity_y = ReadCoord();
-       self.enemy.avelocity_z = ReadCoord();
-       self.oldorigin_x = ReadCoord();
-       self.oldorigin_y = ReadCoord();
-       self.oldorigin_z = ReadCoord();
-       self.avelocity_x = ReadCoord();
-       self.avelocity_y = ReadCoord();
-       self.avelocity_z = ReadCoord();
-
-       if(f & 2)
-       {
-               self.warpzone_fadestart = ReadShort();
-               self.warpzone_fadeend = max(self.warpzone_fadestart + 1, ReadShort());
-       }
-       else
-       {
-               self.warpzone_fadestart = 0;
-               self.warpzone_fadeend = 0;
-       }
-
-       // common stuff
-       WarpZone_SetUp(self, self.enemy.oldorigin, self.enemy.avelocity, self.oldorigin, self.avelocity);
-
-       // link me
-       //setmodel(self, self.model);
-       setorigin(self, self.origin);
-       setsize(self, self.mins, self.maxs);
-
-       // how to draw
-       // engine currently wants this
-       self.predraw = WarpZone_Fade_PreDraw;
-}
-
-void WarpZone_Camera_Read(float isnew)
-{SELFPARAM();
-       warpzone_cameras_exist = 1;
-       self.classname = "func_warpzone_camera";
-
-       int f = ReadByte();
-       if(f & 4)
-       {
-               self.origin_x = ReadCoord();
-               self.origin_y = ReadCoord();
-               self.origin_z = ReadCoord();
-       }
-       else
-               self.origin = '0 0 0';
-       self.modelindex = ReadShort();
-       self.mins_x = ReadCoord();
-       self.mins_y = ReadCoord();
-       self.mins_z = ReadCoord();
-       self.maxs_x = ReadCoord();
-       self.maxs_y = ReadCoord();
-       self.maxs_z = ReadCoord();
-       self.scale = ReadByte() / 16;
-       self.oldorigin_x = ReadCoord();
-       self.oldorigin_y = ReadCoord();
-       self.oldorigin_z = ReadCoord();
-       self.avelocity_x = ReadCoord();
-       self.avelocity_y = ReadCoord();
-       self.avelocity_z = ReadCoord();
-
-       if(f & 2)
-       {
-               self.warpzone_fadestart = ReadShort();
-               self.warpzone_fadeend = max(self.warpzone_fadestart + 1, ReadShort());
-       }
-       else
-       {
-               self.warpzone_fadestart = 0;
-               self.warpzone_fadeend = 0;
-       }
-
-       // common stuff
-       WarpZone_Camera_SetUp(self, self.oldorigin, self.avelocity);
-
-       // engine currently wants this
-       self.drawmask = MASK_NORMAL;
-
-       // link me
-       //setmodel(self, self.model);
-       setorigin(self, self.origin);
-       setsize(self, self.mins, self.maxs);
-
-       // how to draw
-       // engine currently wants this
-       self.predraw = WarpZone_Fade_PreDraw;
-}
-
-void CL_RotateMoves(vector ang) = #638;
-void WarpZone_Teleported_Read(float isnew)
-{SELFPARAM();
-       vector v;
-       self.classname = "warpzone_teleported";
-       v.x = ReadCoord();
-       v.y = ReadCoord();
-       v.z = ReadCoord();
-       if(!isnew)
-               return;
-       self.warpzone_transform = v;
-       setproperty(VF_CL_VIEWANGLES, WarpZone_TransformVAngles(self, getpropertyvec(VF_CL_VIEWANGLES)));
-       if(checkextension("DP_CSQC_ROTATEMOVES"))
-               CL_RotateMoves(v);
-               //CL_RotateMoves('0 90 0');
-}
-
-float warpzone_fixingview;
-float warpzone_fixingview_drawexteriormodel;
-
-void WarpZone_View_Outside()
-{
-       if(!warpzone_fixingview)
-               return;
-       warpzone_fixingview = 0;
-       cvar_set("r_drawexteriormodel", ftos(warpzone_fixingview_drawexteriormodel));
-}
-
-void WarpZone_View_Inside()
-{
-       if(autocvar_chase_active)
-       {
-               WarpZone_View_Outside();
-               return;
-       }
-       if(warpzone_fixingview)
-               return;
-       warpzone_fixingview = 1;
-       warpzone_fixingview_drawexteriormodel = cvar("r_drawexteriormodel");
-       cvar_set("r_drawexteriormodel", "0");
-}
-
-vector WarpZone_FixNearClip(vector o, vector c0, vector c1, vector c2, vector c3)
-{
-       vector mi, ma;
-       entity e;
-       float pd;
-
-       mi.x = min(o.x, c0_x, c1_x, c2_x, c3_x);
-       ma.x = max(o.x, c0_x, c1_x, c2_x, c3_x);
-       mi.y = min(o.y, c0_y, c1_y, c2_y, c3_y);
-       ma.y = max(o.y, c0_y, c1_y, c2_y, c3_y);
-       mi.z = min(o.z, c0_z, c1_z, c2_z, c3_z);
-       ma.z = max(o.z, c0_z, c1_z, c2_z, c3_z);
-
-       e = WarpZone_Find(mi, ma);
-       if(e)
-       {
-               if(WarpZone_PlaneDist(e, o) < 0)
-                       return '0 0 0';
-                       // can't really be, though, but if it is, this is not my warpzone, but a random different one in the same mins/maxs
-               pd = min(
-                               WarpZone_PlaneDist(e, c0),
-                               WarpZone_PlaneDist(e, c1),
-                               WarpZone_PlaneDist(e, c2),
-                               WarpZone_PlaneDist(e, c3)
-                       );
-               if(pd < 0)
-                       return e.warpzone_forward * -pd;
-       }
-
-       return '0 0 0';
-}
-
-void WarpZone_FixPMove()
-{
-       entity e;
-       e = WarpZone_Find(pmove_org, pmove_org);
-       if(e)
-       {
-               pmove_org = WarpZone_TransformOrigin(e, pmove_org);
-               input_angles = WarpZone_TransformVAngles(e, input_angles);
-       }
-}
-
-#ifndef KEEP_ROLL
-float autocvar_cl_rollkillspeed = 10;
-#endif
-void WarpZone_FixView()
-{
-       entity e;
-       vector org, ang, nearclip, corner0, corner1, corner2, corner3, o;
-       float f;
-
-       warpzone_save_view_origin = org = getpropertyvec(VF_ORIGIN);
-       warpzone_save_view_angles = ang = getpropertyvec(VF_ANGLES);
-
-       e = WarpZone_Find(org, org);
-       if(e)
-       {
-               org = WarpZone_TransformOrigin(e, org);
-               ang = WarpZone_TransformVAngles(e, ang);
-               WarpZone_View_Inside();
-       }
-       else
-               WarpZone_View_Outside();
-
-#ifndef KEEP_ROLL
-       float rick;
-       if(autocvar_cl_rollkillspeed)
-               f = max(0, (1 - frametime * autocvar_cl_rollkillspeed));
-       else
-               f = 0;
-
-       rick = getproperty(VF_CL_VIEWANGLES_Z);
-       rick *= f;
-       setproperty(VF_CL_VIEWANGLES_Z, rick);
-       ang.z *= f;
-#endif
-
-       setproperty(VF_ORIGIN, org);
-       setproperty(VF_ANGLES, ang);
-
-       nearclip = '0 0 1' * (cvar("r_nearclip") * 1.125);
-       corner0 = cs_unproject('0 0 0' + nearclip);
-       corner1 = cs_unproject('1 0 0' * cvar("vid_conwidth") + nearclip);
-       corner2 = cs_unproject('0 1 0' * cvar("vid_conheight") + nearclip);
-       corner3 = cs_unproject('1 0 0' * cvar("vid_conwidth") + '0 1 0' * cvar("vid_conheight") + nearclip);
-       o = WarpZone_FixNearClip(org, corner0, corner1, corner2, corner3);
-       if(o != '0 0 0')
-               setproperty(VF_ORIGIN, org + o);
-}
-
-void WarpZone_Init()
-{
-}
-
-void WarpZone_Shutdown()
-{
-       WarpZone_View_Outside();
-}
diff --git a/qcsrc/warpzonelib/client.qh b/qcsrc/warpzonelib/client.qh
deleted file mode 100644 (file)
index a9f0fe1..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef CLIENT_H
-#define CLIENT_H
-
-void WarpZone_Read(float bIsNewEntity);
-void WarpZone_Camera_Read(float bIsNewEntity);
-void WarpZone_Teleported_Read(float bIsNewEntity);
-
-void WarpZone_FixPMove();
-void WarpZone_FixView();
-
-void WarpZone_Init();
-void WarpZone_Shutdown();
-
-vector warpzone_save_view_origin;
-vector warpzone_save_view_angles;
-#endif
diff --git a/qcsrc/warpzonelib/common.qc b/qcsrc/warpzonelib/common.qc
deleted file mode 100644 (file)
index 044b4d8..0000000
+++ /dev/null
@@ -1,874 +0,0 @@
-#include "common.qh"
-
-#if defined(CSQC)
-    #include "../server/t_items.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include "../common/weapons/all.qh"
-#endif
-
-void WarpZone_Accumulator_Clear(entity acc)
-{
-       acc.warpzone_transform = '0 0 0';
-       acc.warpzone_shift = '0 0 0';
-}
-void WarpZone_Accumulator_AddTransform(entity acc, vector t, vector s)
-{
-       vector tr, st;
-       tr = AnglesTransform_Multiply(t, acc.warpzone_transform);
-       st = AnglesTransform_Multiply_GetPostShift(t, s, acc.warpzone_transform, acc.warpzone_shift);
-       acc.warpzone_transform = tr;
-       acc.warpzone_shift = st;
-}
-void WarpZone_Accumulator_Add(entity acc, entity wz)
-{
-       WarpZone_Accumulator_AddTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
-}
-void WarpZone_Accumulator_AddInverseTransform(entity acc, vector t, vector s)
-{
-       vector tt, ss;
-       tt = AnglesTransform_Invert(t);
-       ss = AnglesTransform_PrePostShift_GetPostShift(s, tt, '0 0 0');
-       WarpZone_Accumulator_AddTransform(acc, tt, ss);
-       // yes, this probably can be done simpler... but this way is "obvious" :)
-}
-void WarpZone_Accumulator_AddInverse(entity acc, entity wz)
-{
-       WarpZone_Accumulator_AddInverseTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
-}
-
-.vector(vector, vector) camera_transform;
-float autocvar_cl_warpzone_usetrace = 1;
-vector WarpZone_camera_transform(vector org, vector ang)
-{SELFPARAM();
-       vector vf, vr, vu;
-       if(self.warpzone_fadestart)
-               if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400)
-                       return org;
-                       // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
-                       // unneeded on client, on server this helps a lot
-       vf = v_forward;
-       vr = v_right;
-       vu = v_up;
-       org = WarpZone_TransformOrigin(self, org);
-       vf = WarpZone_TransformVelocity(self, vf);
-       vr = WarpZone_TransformVelocity(self, vr);
-       vu = WarpZone_TransformVelocity(self, vu);
-       if(autocvar_cl_warpzone_usetrace)
-               traceline(self.warpzone_targetorigin, org, MOVE_NOMONSTERS, world);
-       else
-               trace_endpos = self.warpzone_targetorigin;
-       v_forward = vf;
-       v_right = vr;
-       v_up = vu;
-       return org;
-}
-
-void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
-{
-       e.warpzone_transform = AnglesTransform_RightDivide(other_ang, AnglesTransform_TurnDirectionFR(my_ang));
-       e.warpzone_shift = AnglesTransform_PrePostShift_GetPostShift(my_org, e.warpzone_transform, other_org);
-       e.warpzone_origin = my_org;
-       e.warpzone_targetorigin = other_org;
-       e.warpzone_angles = my_ang;
-       e.warpzone_targetangles = other_ang;
-       fixedmakevectors(my_ang); e.warpzone_forward = v_forward;
-       fixedmakevectors(other_ang); e.warpzone_targetforward = v_forward;
-       e.camera_transform = WarpZone_camera_transform;
-}
-
-vector WarpZone_Camera_camera_transform(vector org, vector ang)
-{SELFPARAM();
-       // a fixed camera view
-       if(self.warpzone_fadestart)
-               if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400)
-                       return org;
-                       // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
-                       // unneeded on client, on server this helps a lot
-       trace_endpos = self.warpzone_origin;
-       makevectors(self.warpzone_angles);
-       return self.warpzone_origin;
-}
-
-void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang) // we assume that e.oldorigin and e.avelocity point to view origin and direction
-{
-       e.warpzone_origin = my_org;
-       e.warpzone_angles = my_ang;
-       e.camera_transform = WarpZone_Camera_camera_transform;
-}
-
-.entity enemy;
-<