From: TimePath Date: Sun, 11 Oct 2015 01:08:03 +0000 (+1100) Subject: lib: move csqcmodellib and warpzonelib X-Git-Tag: xonotic-v0.8.2~1839^2~1 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=289dc834837712c152d42d7755992e8e5ed09deb;p=xonotic%2Fxonotic-data.pk3dir.git lib: move csqcmodellib and warpzonelib --- diff --git a/qcsrc/Makefile b/qcsrc/Makefile index 51440d4a3..452dfc9a6 100644 --- a/qcsrc/Makefile +++ b/qcsrc/Makefile @@ -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 diff --git a/qcsrc/client/csqcmodel_hooks.qc b/qcsrc/client/csqcmodel_hooks.qc index 708e305fa..6e7e5a8de 100644 --- a/qcsrc/client/csqcmodel_hooks.qc +++ b/qcsrc/client/csqcmodel_hooks.qc @@ -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; diff --git a/qcsrc/client/hook.qc b/qcsrc/client/hook.qc index 6143874e6..3f623b276 100644 --- a/qcsrc/client/hook.qc +++ b/qcsrc/client/hook.qc @@ -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_* diff --git a/qcsrc/client/hud.qc b/qcsrc/client/hud.qc index 4e83ac31e..0e5246043 100644 --- a/qcsrc/client/hud.qc +++ b/qcsrc/client/hud.qc @@ -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" diff --git a/qcsrc/client/laser.qc b/qcsrc/client/laser.qc index 4d52c8eee..1c63a0dc2 100644 --- a/qcsrc/client/laser.qc +++ b/qcsrc/client/laser.qc @@ -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' diff --git a/qcsrc/client/main.qc b/qcsrc/client/main.qc index 8571d43a3..05704e5cb 100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@ -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 diff --git a/qcsrc/client/miscfunctions.qc b/qcsrc/client/miscfunctions.qc index 8a5b70704..7983e740f 100644 --- a/qcsrc/client/miscfunctions.qc +++ b/qcsrc/client/miscfunctions.qc @@ -6,7 +6,7 @@ #include "../common/teams.qh" -#include "../csqcmodellib/cl_model.qh" +#include "../lib/csqcmodel/cl_model.qh" void AuditLists() diff --git a/qcsrc/client/particles.qc b/qcsrc/client/particles.qc index 75f293feb..0c7f7a39f 100644 --- a/qcsrc/client/particles.qc +++ b/qcsrc/client/particles.qc @@ -2,7 +2,7 @@ #include "../common/stats.qh" -#include "../warpzonelib/common.qh" +#include "../lib/warpzone/common.qh" void Net_ReadVortexBeamParticle() { diff --git a/qcsrc/client/player_skeleton.qc b/qcsrc/client/player_skeleton.qc index cdb1fdf74..d6b2b0d44 100644 --- a/qcsrc/client/player_skeleton.qc +++ b/qcsrc/client/player_skeleton.qc @@ -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; diff --git a/qcsrc/client/progs.inc b/qcsrc/client/progs.inc index 367e5ffd5..04eb78822 100644 --- a/qcsrc/client/progs.inc +++ b/qcsrc/client/progs.inc @@ -61,16 +61,16 @@ #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" diff --git a/qcsrc/client/shownames.qc b/qcsrc/client/shownames.qc index 994a1ae30..80a15ad38 100644 --- a/qcsrc/client/shownames.qc +++ b/qcsrc/client/shownames.qc @@ -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? diff --git a/qcsrc/client/t_items.qc b/qcsrc/client/t_items.qc index 9bb99f41d..f4096b87a 100644 --- a/qcsrc/client/t_items.qc +++ b/qcsrc/client/t_items.qc @@ -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" diff --git a/qcsrc/client/teamradar.qc b/qcsrc/client/teamradar.qc index d429d2005..c866a1b73 100644 --- a/qcsrc/client/teamradar.qc +++ b/qcsrc/client/teamradar.qc @@ -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) { diff --git a/qcsrc/client/view.qc b/qcsrc/client/view.qc index 6fcc79b24..fad769d01 100644 --- a/qcsrc/client/view.qc +++ b/qcsrc/client/view.qc @@ -23,10 +23,10 @@ #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]; diff --git a/qcsrc/client/wall.qc b/qcsrc/client/wall.qc index b97f757a7..9da9bb5b6 100644 --- a/qcsrc/client/wall.qc +++ b/qcsrc/client/wall.qc @@ -3,7 +3,7 @@ #include "bgmscript.qh" -#include "../csqcmodellib/interpolate.qh" +#include "../lib/csqcmodel/interpolate.qh" .float alpha; .float scale; diff --git a/qcsrc/client/weapons/projectile.qc b/qcsrc/client/weapons/projectile.qc index b52a3fac1..807d95cb4 100644 --- a/qcsrc/client/weapons/projectile.qc +++ b/qcsrc/client/weapons/projectile.qc @@ -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; diff --git a/qcsrc/common/monsters/monster.qh b/qcsrc/common/monsters/monster.qh index 84253b1e9..b4559269d 100644 --- a/qcsrc/common/monsters/monster.qh +++ b/qcsrc/common/monsters/monster.qh @@ -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 diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index b8bff0201..e42908fbd 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -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 diff --git a/qcsrc/common/movetypes/movetypes.qc b/qcsrc/common/movetypes/movetypes.qc index 0fed28f15..8c96174f2 100644 --- a/qcsrc/common/movetypes/movetypes.qc +++ b/qcsrc/common/movetypes/movetypes.qc @@ -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) diff --git a/qcsrc/common/nades/all.qc b/qcsrc/common/nades/all.qc index 724837b25..30ad1782f 100644 --- a/qcsrc/common/nades/all.qc +++ b/qcsrc/common/nades/all.qc @@ -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" diff --git a/qcsrc/common/triggers/func/breakable.qc b/qcsrc/common/triggers/func/breakable.qc index a0d266ce5..2effa1676 100644 --- a/qcsrc/common/triggers/func/breakable.qc +++ b/qcsrc/common/triggers/func/breakable.qc @@ -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; diff --git a/qcsrc/common/triggers/misc/laser.qc b/qcsrc/common/triggers/misc/laser.qc index cc15516d1..54029cd6c 100644 --- a/qcsrc/common/triggers/misc/laser.qc +++ b/qcsrc/common/triggers/misc/laser.qc @@ -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 diff --git a/qcsrc/common/triggers/teleporters.qc b/qcsrc/common/triggers/teleporters.qc index 438292a43..b4b210384 100644 --- a/qcsrc/common/triggers/teleporters.qc +++ b/qcsrc/common/triggers/teleporters.qc @@ -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" diff --git a/qcsrc/common/triggers/trigger/swamp.qc b/qcsrc/common/triggers/trigger/swamp.qc index 029ee9630..33241aafd 100644 --- a/qcsrc/common/triggers/trigger/swamp.qc +++ b/qcsrc/common/triggers/trigger/swamp.qc @@ -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" diff --git a/qcsrc/common/triggers/trigger/viewloc.qc b/qcsrc/common/triggers/trigger/viewloc.qc index 00695cfa3..c21fe6b54 100644 --- a/qcsrc/common/triggers/trigger/viewloc.qc +++ b/qcsrc/common/triggers/trigger/viewloc.qc @@ -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 diff --git a/qcsrc/common/weapons/all.qc b/qcsrc/common/weapons/all.qc index 01214331c..37d49b2e2 100644 --- a/qcsrc/common/weapons/all.qc +++ b/qcsrc/common/weapons/all.qc @@ -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 index b42f5c4c5..000000000 --- a/qcsrc/csqcmodellib/cl_model.qc +++ /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 index 98f1da03b..000000000 --- a/qcsrc/csqcmodellib/cl_model.qh +++ /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 index 7aedd52e6..000000000 --- a/qcsrc/csqcmodellib/cl_player.qc +++ /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 index e427e6cf3..000000000 --- a/qcsrc/csqcmodellib/cl_player.qh +++ /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 index de02e7a6d..000000000 --- a/qcsrc/csqcmodellib/common.qh +++ /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 index fb1094f72..000000000 --- a/qcsrc/csqcmodellib/interpolate.qc +++ /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 index 5ee57850c..000000000 --- a/qcsrc/csqcmodellib/interpolate.qh +++ /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 index b30d7e94b..000000000 --- a/qcsrc/csqcmodellib/settings.qh +++ /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 index 0fc2ad8b6..000000000 --- a/qcsrc/csqcmodellib/sv_model.qc +++ /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 index 713e8c224..000000000 --- a/qcsrc/csqcmodellib/sv_model.qh +++ /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 diff --git a/qcsrc/lib/_all.inc b/qcsrc/lib/_all.inc index 66a79c83c..49b8ef779 100644 --- a/qcsrc/lib/_all.inc +++ b/qcsrc/lib/_all.inc @@ -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 index 000000000..8d3d4ab93 --- /dev/null +++ b/qcsrc/lib/csqcmodel/cl_model.qc @@ -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 index 000000000..55401e4b4 --- /dev/null +++ b/qcsrc/lib/csqcmodel/cl_model.qh @@ -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 index 000000000..ae4e55ac1 --- /dev/null +++ b/qcsrc/lib/csqcmodel/cl_player.qc @@ -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 index 000000000..c9598c880 --- /dev/null +++ b/qcsrc/lib/csqcmodel/cl_player.qh @@ -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 index 000000000..884977f90 --- /dev/null +++ b/qcsrc/lib/csqcmodel/common.qh @@ -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 index 000000000..ca846da0f --- /dev/null +++ b/qcsrc/lib/csqcmodel/interpolate.qc @@ -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 index 000000000..e07ad4ade --- /dev/null +++ b/qcsrc/lib/csqcmodel/interpolate.qh @@ -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 index 000000000..128da850f --- /dev/null +++ b/qcsrc/lib/csqcmodel/settings.qh @@ -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 index 000000000..8fcdcfbee --- /dev/null +++ b/qcsrc/lib/csqcmodel/sv_model.qc @@ -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 index 000000000..3e043d353 --- /dev/null +++ b/qcsrc/lib/csqcmodel/sv_model.qh @@ -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 index 000000000..d61ba0a78 --- /dev/null +++ b/qcsrc/lib/warpzone/COPYING @@ -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. + + + Copyright (C) + + 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. + + , 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 index 000000000..927ab1298 --- /dev/null +++ b/qcsrc/lib/warpzone/TODO @@ -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 index 000000000..d6423f177 --- /dev/null +++ b/qcsrc/lib/warpzone/anglestransform.qc @@ -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 index 000000000..5c356ea7f --- /dev/null +++ b/qcsrc/lib/warpzone/anglestransform.qh @@ -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 index 000000000..aba39c2cb --- /dev/null +++ b/qcsrc/lib/warpzone/client.qc @@ -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 index 000000000..016ac5882 --- /dev/null +++ b/qcsrc/lib/warpzone/client.qh @@ -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 index 000000000..6fe901bd8 --- /dev/null +++ b/qcsrc/lib/warpzone/common.qc @@ -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 index 000000000..d0c1f22ea --- /dev/null +++ b/qcsrc/lib/warpzone/common.qh @@ -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 index 000000000..92b7ee14d --- /dev/null +++ b/qcsrc/lib/warpzone/mathlib.qc @@ -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 index 000000000..9acece2ab --- /dev/null +++ b/qcsrc/lib/warpzone/mathlib.qh @@ -0,0 +1,121 @@ +#ifndef LIB_WARPZONE_MATHLIB_H +#define LIB_WARPZONE_MATHLIB_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- 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 index 000000000..e21e4cab4 --- /dev/null +++ b/qcsrc/lib/warpzone/server.qc @@ -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 index 000000000..943f0322a --- /dev/null +++ b/qcsrc/lib/warpzone/server.qh @@ -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 index 000000000..742ec3e20 --- /dev/null +++ b/qcsrc/lib/warpzone/util_server.qc @@ -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 index 000000000..75df5d862 --- /dev/null +++ b/qcsrc/lib/warpzone/util_server.qh @@ -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 diff --git a/qcsrc/server/bot/bot.qc b/qcsrc/server/bot/bot.qc index dbcd90052..3b2af5d92 100644 --- a/qcsrc/server/bot/bot.qc +++ b/qcsrc/server/bot/bot.qc @@ -30,10 +30,10 @@ #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(); diff --git a/qcsrc/server/bot/havocbot/havocbot.qc b/qcsrc/server/bot/havocbot/havocbot.qc index ec27e3e94..ced6463c2 100644 --- a/qcsrc/server/bot/havocbot/havocbot.qc +++ b/qcsrc/server/bot/havocbot/havocbot.qc @@ -11,7 +11,7 @@ #include "../../../common/triggers/trigger/jumppads.qh" -#include "../../../warpzonelib/common.qh" +#include "../../../lib/warpzone/common.qh" .float speed; diff --git a/qcsrc/server/bot/waypoints.qc b/qcsrc/server/bot/waypoints.qc index ffd78e931..156ad79fc 100644 --- a/qcsrc/server/bot/waypoints.qc +++ b/qcsrc/server/bot/waypoints.qc @@ -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 diff --git a/qcsrc/server/cheats.qc b/qcsrc/server/cheats.qc index c17a1d0c8..0f43d92c0 100644 --- a/qcsrc/server/cheats.qc +++ b/qcsrc/server/cheats.qc @@ -20,10 +20,10 @@ #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); diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index ad0d71db3..ddbc18da6 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -46,7 +46,7 @@ #include "../common/monsters/sv_monsters.qh" -#include "../warpzonelib/server.qh" +#include "../lib/warpzone/server.qh" void send_CSQC_teamnagger() { diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 13d7b6227..dafd7d2a6 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -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" diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc index 9cf020d33..3cd7f23cf 100644 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@ -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 diff --git a/qcsrc/server/command/common.qc b/qcsrc/server/command/common.qc index 7dea85ee6..4d390e7d9 100644 --- a/qcsrc/server/command/common.qc +++ b/qcsrc/server/command/common.qc @@ -5,7 +5,7 @@ #include "../../common/monsters/all.qh" #include "../../common/notifications.qh" -#include "../../warpzonelib/common.qh" +#include "../../lib/warpzone/common.qh" // ==================================================== diff --git a/qcsrc/server/command/radarmap.qc b/qcsrc/server/command/radarmap.qc index 50b09f799..60e6bde62 100644 --- a/qcsrc/server/command/radarmap.qc +++ b/qcsrc/server/command/radarmap.qc @@ -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 diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index 8f9b30504..845fd56f6 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -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) { diff --git a/qcsrc/server/g_damage.qh b/qcsrc/server/g_damage.qh index 6e0f5b579..064d31ff9 100644 --- a/qcsrc/server/g_damage.qh +++ b/qcsrc/server/g_damage.qh @@ -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" diff --git a/qcsrc/server/g_hook.qc b/qcsrc/server/g_hook.qc index d372d3516..7a77d4aff 100644 --- a/qcsrc/server/g_hook.qc +++ b/qcsrc/server/g_hook.qc @@ -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; diff --git a/qcsrc/server/g_models.qc b/qcsrc/server/g_models.qc index a9353cfe1..8bc538736 100644 --- a/qcsrc/server/g_models.qc +++ b/qcsrc/server/g_models.qc @@ -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; diff --git a/qcsrc/server/g_subs.qc b/qcsrc/server/g_subs.qc index 8544cd926..af1cf7cc2 100644 --- a/qcsrc/server/g_subs.qc +++ b/qcsrc/server/g_subs.qc @@ -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) diff --git a/qcsrc/server/item_key.qc b/qcsrc/server/item_key.qc index fc0dbd422..8df6e3b46 100644 --- a/qcsrc/server/item_key.qc +++ b/qcsrc/server/item_key.qc @@ -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: diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index ccefc4c1e..4c8fdeaaf 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -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) { diff --git a/qcsrc/server/mutators/gamemode.qh b/qcsrc/server/mutators/gamemode.qh index 2ee316d8c..9de38eae7 100644 --- a/qcsrc/server/mutators/gamemode.qh +++ b/qcsrc/server/mutators/gamemode.qh @@ -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; diff --git a/qcsrc/server/mutators/gamemode_ctf.qc b/qcsrc/server/mutators/gamemode_ctf.qc index 78c192433..eff581154 100644 --- a/qcsrc/server/mutators/gamemode_ctf.qc +++ b/qcsrc/server/mutators/gamemode_ctf.qc @@ -7,7 +7,7 @@ #include "../teamplay.qh" #endif -#include "../../warpzonelib/common.qh" +#include "../../lib/warpzone/common.qh" void ctf_FakeTimeLimit(entity e, float t) { diff --git a/qcsrc/server/mutators/mutator.qh b/qcsrc/server/mutators/mutator.qh index 39adb175c..ac60070e5 100644 --- a/qcsrc/server/mutators/mutator.qh +++ b/qcsrc/server/mutators/mutator.qh @@ -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 diff --git a/qcsrc/server/mutators/mutators_include.qc b/qcsrc/server/mutators/mutators_include.qc index e948ab688..fe8fe0fa5 100644 --- a/qcsrc/server/mutators/mutators_include.qc +++ b/qcsrc/server/mutators/mutators_include.qc @@ -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" diff --git a/qcsrc/server/portals.qc b/qcsrc/server/portals.qc index 09776c4d6..ec5d688f6 100644 --- a/qcsrc/server/portals.qc +++ b/qcsrc/server/portals.qc @@ -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" diff --git a/qcsrc/server/progs.inc b/qcsrc/server/progs.inc index ee891aa4d..2adaf838f 100644 --- a/qcsrc/server/progs.inc +++ b/qcsrc/server/progs.inc @@ -94,12 +94,12 @@ #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" diff --git a/qcsrc/server/race.qc b/qcsrc/server/race.qc index 3ac5582d6..d9d8d55c5 100644 --- a/qcsrc/server/race.qc +++ b/qcsrc/server/race.qc @@ -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); diff --git a/qcsrc/server/spawnpoints.qc b/qcsrc/server/spawnpoints.qc index ead90d30b..6980a9e94 100644 --- a/qcsrc/server/spawnpoints.qc +++ b/qcsrc/server/spawnpoints.qc @@ -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) { diff --git a/qcsrc/server/sv_main.qc b/qcsrc/server/sv_main.qc index 05fee86da..8b9e1c8b0 100644 --- a/qcsrc/server/sv_main.qc +++ b/qcsrc/server/sv_main.qc @@ -19,10 +19,10 @@ #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; diff --git a/qcsrc/server/t_items.qc b/qcsrc/server/t_items.qc index eee53e616..89d6b06ca 100644 --- a/qcsrc/server/t_items.qc +++ b/qcsrc/server/t_items.qc @@ -23,7 +23,7 @@ #include "../common/weapons/all.qh" - #include "../warpzonelib/util_server.qh" + #include "../lib/warpzone/util_server.qh" #endif #ifdef CSQC diff --git a/qcsrc/server/weapons/tracing.qc b/qcsrc/server/weapons/tracing.qc index b88acaa51..4c9e0e34c 100644 --- a/qcsrc/server/weapons/tracing.qc +++ b/qcsrc/server/weapons/tracing.qc @@ -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. diff --git a/qcsrc/server/weapons/weaponsystem.qc b/qcsrc/server/weapons/weaponsystem.qc index 3f74034f1..dd7e2b599 100644 --- a/qcsrc/server/weapons/weaponsystem.qc +++ b/qcsrc/server/weapons/weaponsystem.qc @@ -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 index d61ba0a78..000000000 --- a/qcsrc/warpzonelib/COPYING +++ /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. - - - Copyright (C) - - 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. - - , 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 index 927ab1298..000000000 --- a/qcsrc/warpzonelib/TODO +++ /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 index f92947f5b..000000000 --- a/qcsrc/warpzonelib/anglestransform.qc +++ /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 index 053847101..000000000 --- a/qcsrc/warpzonelib/anglestransform.qh +++ /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 index 68c2984db..000000000 --- a/qcsrc/warpzonelib/client.qc +++ /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 index a9f0fe1c2..000000000 --- a/qcsrc/warpzonelib/client.qh +++ /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 index 044b4d864..000000000 --- a/qcsrc/warpzonelib/common.qc +++ /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; - -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/warpzonelib/common.qh b/qcsrc/warpzonelib/common.qh deleted file mode 100644 index 3e2b7c7c6..000000000 --- a/qcsrc/warpzonelib/common.qh +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef WARPZONELIB_COMMON_H -#define WARPZONELIB_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/warpzonelib/mathlib.qc b/qcsrc/warpzonelib/mathlib.qc deleted file mode 100644 index 92b7ee14d..000000000 --- a/qcsrc/warpzonelib/mathlib.qc +++ /dev/null @@ -1,300 +0,0 @@ -#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/warpzonelib/mathlib.qh b/qcsrc/warpzonelib/mathlib.qh deleted file mode 100644 index 6f7adf44f..000000000 --- a/qcsrc/warpzonelib/mathlib.qh +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef MATHLIB_H -#define MATHLIB_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- stuff follows here. -vector cross(vector a, vector b); - -#endif diff --git a/qcsrc/warpzonelib/server.qc b/qcsrc/warpzonelib/server.qc deleted file mode 100644 index 033594d2e..000000000 --- a/qcsrc/warpzonelib/server.qc +++ /dev/null @@ -1,899 +0,0 @@ -#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/warpzonelib/server.qh b/qcsrc/warpzonelib/server.qh deleted file mode 100644 index 88ad6f508..000000000 --- a/qcsrc/warpzonelib/server.qh +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SERVER_H -#define 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/warpzonelib/util_server.qc b/qcsrc/warpzonelib/util_server.qc deleted file mode 100644 index 61c063667..000000000 --- a/qcsrc/warpzonelib/util_server.qc +++ /dev/null @@ -1,49 +0,0 @@ -#include "util_server.qh" - -#include "common.qh" - -#if defined(CSQC) -#elif defined(MENUQC) -#elif defined(SVQC) - #include "../csqcmodellib/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/warpzonelib/util_server.qh b/qcsrc/warpzonelib/util_server.qh deleted file mode 100644 index 0a42d7d12..000000000 --- a/qcsrc/warpzonelib/util_server.qh +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef UTIL_SERVER_H -#define UTIL_SERVER_H - -float WarpZoneLib_MoveOutOfSolid(entity e); -float WarpZoneLib_ExactTrigger_Touch(); -#ifdef SVQC -void WarpZoneLib_ExactTrigger_Init(); -#endif -#endif