From ea04f662f6aeb325609c118f600d7f346a1bd4b3 Mon Sep 17 00:00:00 2001 From: div0 Date: Sun, 28 Feb 2010 19:43:45 +0000 Subject: [PATCH] properly transport projectiles git-svn-id: svn://svn.icculus.org/nexuiz/trunk@8704 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/Makefile | 4 +- data/qcsrc/client/csqc_builtins.qc | 2 + data/qcsrc/server/miscfunctions.qc | 15 +++- data/qcsrc/server/sv_main.qc | 2 + data/qcsrc/server/t_teleporters.qc | 2 +- data/qcsrc/warpzonelib/client.qc | 15 ++-- data/qcsrc/warpzonelib/common.qc | 26 +++++- data/qcsrc/warpzonelib/common.qh | 14 ++++ data/qcsrc/warpzonelib/server.qc | 126 ++++++++++++++++++++++------- data/qcsrc/warpzonelib/server.qh | 6 +- 10 files changed, 167 insertions(+), 45 deletions(-) diff --git a/data/Makefile b/data/Makefile index f7baac2a2..169753949 100644 --- a/data/Makefile +++ b/data/Makefile @@ -56,10 +56,10 @@ pk3here: qc clean: rm -f progs.dat menu.dat csprogs.dat -csprogs.dat: qcsrc/client/*.* qcsrc/common/*.* +csprogs.dat: qcsrc/client/*.* qcsrc/common/*.* qcsrc/warpzonelib/*.* cd qcsrc/client && $(FTEQCC) $(FTEQCCFLAGS) $(FTEQCCFLAGS_CSPROGS) -progs.dat: qcsrc/server/*.* qcsrc/common/*.* qcsrc/server/*/*.* qcsrc/server/*/*/*.* +progs.dat: qcsrc/server/*.* qcsrc/common/*.* qcsrc/server/*/*.* qcsrc/server/*/*/*.* qcsrc/warpzonelib/*.* cd qcsrc/server && $(FTEQCC) $(FTEQCCFLAGS) $(FTEQCCFLAGS_PROGS) menu.dat: qcsrc/menu/*.* qcsrc/menu/*/*.* qcsrc/common/*.* diff --git a/data/qcsrc/client/csqc_builtins.qc b/data/qcsrc/client/csqc_builtins.qc index 55dbe3f1c..d3e42cd98 100644 --- a/data/qcsrc/client/csqc_builtins.qc +++ b/data/qcsrc/client/csqc_builtins.qc @@ -306,3 +306,5 @@ float DEG2RAD = 0.01745329251994329576923690768488612713442871888541725456097191 float RAD2DEG = 57.2957795130823208767981548141051703324054724665643215491602438612; float PI = 3.1415926535897932384626433832795028841971693993751058209749445923; float log(float f) = #532; + +void(entity e, entity ignore) tracetoss = #64; diff --git a/data/qcsrc/server/miscfunctions.qc b/data/qcsrc/server/miscfunctions.qc index 51db59e6e..123d39a86 100644 --- a/data/qcsrc/server/miscfunctions.qc +++ b/data/qcsrc/server/miscfunctions.qc @@ -1996,7 +1996,20 @@ float SUB_NoImpactCheck() #define SUB_OwnerCheck() (other && (other == self.owner)) -#define PROJECTILE_TOUCH do { if(SUB_OwnerCheck()) return; if(SUB_NoImpactCheck()) { remove(self); return; } if(trace_ent && trace_ent.solid > SOLID_TRIGGER) UpdateCSQCProjectileNextFrame(self); } while(0) +float WarpZone_Projectile_Touch_ImpactFilter_Callback() +{ + if(SUB_OwnerCheck()) + return TRUE; + if(SUB_NoImpactCheck()) + { + remove(self); + return TRUE; + } + if(trace_ent && trace_ent.solid > SOLID_TRIGGER) + UpdateCSQCProjectileNextFrame(self); + return FALSE; +} +#define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return float MAX_IPBAN_URIS = 16; diff --git a/data/qcsrc/server/sv_main.qc b/data/qcsrc/server/sv_main.qc index 693bdc4e7..771312523 100644 --- a/data/qcsrc/server/sv_main.qc +++ b/data/qcsrc/server/sv_main.qc @@ -176,6 +176,8 @@ void StartFrame (void) UncustomizeEntitiesRun(); InitializeEntitiesRun(); + WarpZone_StartFrame(); + sv_gravity = cvar("sv_gravity"); sv_maxairspeed = cvar("sv_maxairspeed"); sv_maxspeed = cvar ("sv_maxspeed"); diff --git a/data/qcsrc/server/t_teleporters.qc b/data/qcsrc/server/t_teleporters.qc index e80e44e4a..83cd5a26d 100644 --- a/data/qcsrc/server/t_teleporters.qc +++ b/data/qcsrc/server/t_teleporters.qc @@ -298,7 +298,7 @@ void spawnfunc_trigger_teleport (void) } } -void WarpZone_PostTeleportPlayer(entity pl) +void WarpZone_PostTeleportPlayer_Callback(entity pl) { UpdateCSQCProjectileAfterTeleport(pl); if(pl.classname == "player") diff --git a/data/qcsrc/warpzonelib/client.qc b/data/qcsrc/warpzonelib/client.qc index 0a7f1ee6c..fb459f43d 100644 --- a/data/qcsrc/warpzonelib/client.qc +++ b/data/qcsrc/warpzonelib/client.qc @@ -29,12 +29,11 @@ void WarpZone_Read(float isnew) self.avelocity_y = ReadCoord(); self.avelocity_z = ReadCoord(); - self.avelocity = AnglesTransform_TurnDirectionFR(self.avelocity); + // common stuff + WarpZone_SetUp(self, self.enemy.oldorigin, self.enemy.avelocity, self.oldorigin, self.avelocity); - // for common code - self.warpzone_origin = self.enemy.oldorigin; - self.enemy.warpzone_origin = self.oldorigin; - self.warpzone_transform = AnglesTransform_Divide(self.avelocity, self.enemy.avelocity); + // engine currently wants this + self.avelocity = AnglesTransform_TurnDirectionFR(self.avelocity); self.flags = FL_CAMERA; self.drawmask = MASK_NORMAL; @@ -69,13 +68,11 @@ void WarpZone_FixView() e = WarpZone_Find(warpzone_fixview_origin - '1 1 1' * nearclip, warpzone_fixview_origin + '1 1 1' * nearclip); if(e) { - fixedmakevectors(e.enemy.avelocity); - pd = (warpzone_fixview_origin - e.enemy.oldorigin) * v_forward; + pd = WarpZone_PlaneDist(e, warpzone_fixview_origin); if(pd >= 0 && pd < nearclip) { warpzone_saved = 1; - warpzone_fixview_origin = warpzone_fixview_origin + v_forward * (nearclip - pd); - pd = (warpzone_fixview_origin - e.enemy.oldorigin) * v_forward; + warpzone_fixview_origin = warpzone_fixview_origin + e.warpzone_forward * (nearclip - pd); } } diff --git a/data/qcsrc/warpzonelib/common.qc b/data/qcsrc/warpzonelib/common.qc index 0efa19c44..c2ad3ccaa 100644 --- a/data/qcsrc/warpzonelib/common.qc +++ b/data/qcsrc/warpzonelib/common.qc @@ -1,5 +1,14 @@ -.vector warpzone_origin; -.vector warpzone_transform; +void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang) +{ + e.warpzone_transform = AnglesTransform_Divide(other_ang, AnglesTransform_TurnDirectionFR(my_ang)); + 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; +} + .entity enemy; vector WarpZoneLib_BoxTouchesBrush_mins; @@ -109,6 +118,9 @@ void WarpZone_TraceBox(vector org, vector mi, vector ma, vector end, float nomon // we hit a warpzone... so, let's perform the trace after the warp again org = WarpZone_TransformOrigin(trace_ent, trace_endpos); end = WarpZone_TransformOrigin(trace_ent, end); + WarpZone_trace_velocity = WarpZone_TransformVelocity(trace_ent, WarpZone_trace_velocity); + WarpZone_trace_angles = WarpZone_TransformAngles(trace_ent, WarpZone_trace_angles); + WarpZone_trace_v_angle = WarpZone_TransformVAngles(trace_ent, WarpZone_trace_v_angle); } WarpZone_MakeAllOther(); trace_startsolid = sol; @@ -191,6 +203,16 @@ void WarpZone_TrailParticles(entity own, float eff, vector org, vector end) v_up = vu; } +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.enemy.warpzone_origin + AnglesTransform_Apply(wz.warpzone_transform, v - wz.warpzone_origin); diff --git a/data/qcsrc/warpzonelib/common.qh b/data/qcsrc/warpzonelib/common.qh index 40172341f..0f46b1d4d 100644 --- a/data/qcsrc/warpzonelib/common.qh +++ b/data/qcsrc/warpzonelib/common.qh @@ -1,3 +1,12 @@ +.vector warpzone_origin; +.vector warpzone_angles; +.vector warpzone_forward; +.vector warpzone_targetorigin; +.vector warpzone_targetangles; +.vector warpzone_targetforward; +.vector warpzone_transform; +void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang); + float FL_CAMERA = 8192; float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig); @@ -7,6 +16,9 @@ void WarpZone_MakeAllSolid(); void WarpZone_MakeAllOther(); var void(void) WarpZone_trace_callback; // called after every trace +vector WarpZone_trace_angles; // total angles accumulator +vector WarpZone_trace_v_angle; // total v_angle accumulator +vector WarpZone_trace_velocity; // total velocity vector WarpZone_trace_endpos; // UNtransformed endpos vector WarpZone_tracetoss_velocity; // ending velocity of a tracetoss (post-transform) float WarpZone_tracetoss_time; // duration of toss (approximate) @@ -15,6 +27,8 @@ void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent) void WarpZone_TraceToss(entity e, entity forent); void WarpZone_TrailParticles(entity own, float eff, vector org, vector end); +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); diff --git a/data/qcsrc/warpzonelib/server.qc b/data/qcsrc/warpzonelib/server.qc index 7f8b2e0e8..cb29d6d74 100644 --- a/data/qcsrc/warpzonelib/server.qc +++ b/data/qcsrc/warpzonelib/server.qc @@ -1,4 +1,14 @@ -void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags) +.vector warpzone_oldorigin, warpzone_oldvelocity, warpzone_oldangles; +.float warpzone_teleport_time; + +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) { vector from; @@ -19,13 +29,9 @@ void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector if(player.classname == "player") player.flags &~= FL_ONGROUND; - WarpZone_PostTeleportPlayer(player); + WarpZone_PostTeleportPlayer_Callback(player); } -// the transform -.vector warpzone_angles; -.vector warpzone_forward; - float WarpZone_Teleport(entity player) { vector o0, a0, v0, o1, a1, v1; @@ -34,7 +40,7 @@ float WarpZone_Teleport(entity player) v0 = player.velocity; a0 = player.angles; - if((o0 - self.warpzone_origin) * self.warpzone_forward >= 0) // wrong side of the portal + if(WarpZone_PlaneDist(self, o0) >= 0) // wrong side of the portal return 2; // no failure, we simply don't want to teleport yet; TODO in // this situation we may want to create a temporary clone @@ -71,7 +77,7 @@ float WarpZone_Teleport(entity player) } } - if((o1 - self.enemy.warpzone_origin) * self.enemy.warpzone_forward <= 0) // wrong side of the portal post-teleport + if(WarpZone_TargetPlaneDist(self, o1) <= 0) { print("inconsistent warp zones or evil roundoff error\n"); return 0; @@ -80,7 +86,9 @@ float WarpZone_Teleport(entity player) //print(sprintf("warpzone: %f %f %f -> %f %f %f\n", o0_x, o0_y, o0_z, o1_x, o1_y, o1_z)); //o1 = trace_endpos; - TeleportPlayer(self, other, o1 - player.view_ofs, a1, v1, '0 0 0', '0 0 0', TELEPORT_FLAGS_WARPZONE); + WarpZone_TeleportPlayer(self, other, o1 - player.view_ofs, a1, v1); + WarpZone_StoreProjectileData(player); + player.warpzone_teleport_time = time; return 1; } @@ -89,6 +97,9 @@ void WarpZone_Touch (void) { entity oldself, e; + if(other.classname == "trigger_warpzone") + return; + // FIXME needs a better check to know what is safe to teleport and what not if(other.movetype == MOVETYPE_NONE) return; @@ -138,12 +149,12 @@ float WarpZone_Send(entity to, float sendflags) 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.enemy.warpzone_origin_x); - WriteCoord(MSG_ENTITY, self.enemy.warpzone_origin_y); - WriteCoord(MSG_ENTITY, self.enemy.warpzone_origin_z); - WriteCoord(MSG_ENTITY, self.enemy.warpzone_angles_x); - WriteCoord(MSG_ENTITY, self.enemy.warpzone_angles_y); - WriteCoord(MSG_ENTITY, self.enemy.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); return TRUE; } @@ -203,24 +214,81 @@ void WarpZone_InitStep_UpdateTransform() return; } - // 1. update this, and the enemy, warp zone - self.warpzone_origin = self.aiment.origin; - self.warpzone_angles = self.aiment.angles; - self.enemy.warpzone_origin = self.enemy.aiment.origin; - self.enemy.warpzone_angles = self.enemy.aiment.angles; - - // 2. combine the angle transforms - // current forward must be turned into previous backward - self.warpzone_transform = AnglesTransform_Divide(AnglesTransform_TurnDirectionFR(self.enemy.warpzone_angles), self.warpzone_angles); - - // 3. store off a saved forward vector for plane hit decisions - fixedmakevectors(self.warpzone_angles); - self.warpzone_forward = v_forward; + WarpZone_SetUp(self, self.aiment.origin, self.aiment.angles, self.enemy.aiment.origin, self.enemy.aiment.angles); // now enable touch self.touch = WarpZone_Touch; // our mins/maxs are set to the warpzone... so all we need: self.flags |= FL_CAMERA; - self.view_ofs = self.enemy.warpzone_origin; + self.view_ofs = self.warpzone_targetorigin; +} + +float WarpZone_CheckProjectileImpact() +{ + // if self hit a warpzone, abort + vector o0, v0, a0; + float mpd, pd, dpd; + entity wz; + wz = WarpZone_Find(self.origin + self.mins, self.origin + self.maxs); + if(!wz) + return FALSE; + o0 = self.origin; + v0 = self.velocity; + a0 = self.angles; + + // this approach transports the projectile at its full speed, but does + // not properly retain the projectile trail (but we can't retain it + // easily anyway without delaying the projectile by two frames, so who + // cares) + WarpZone_trace_angles = self.angles; + WarpZone_trace_velocity = self.velocity; + WarpZone_TraceBox(self.warpzone_oldorigin, self.mins, self.maxs, self.warpzone_oldorigin + self.warpzone_oldvelocity * frametime, MOVE_NORMAL, self); // this will get us through the warpzone + setorigin(self, trace_endpos); + self.angles = WarpZone_trace_angles; + self.velocity = WarpZone_trace_velocity; + + // in case we are in our warp zone post-teleport, shift the projectile forward a bit + mpd = max(vlen(self.mins), vlen(self.maxs)); + pd = WarpZone_TargetPlaneDist(wz, self.origin); + if(pd < mpd) + { + dpd = normalize(self.velocity) * self.warpzone_targetforward; + setorigin(self, self.origin + normalize(self.velocity) * ((mpd - pd) / dpd)); + if(!WarpZoneLib_MoveOutOfSolid(self)) + { + setorigin(self, o0); + self.angles = a0; + self.velocity = v0; + return FALSE; + } + } + WarpZone_StoreProjectileData(self); + self.warpzone_teleport_time = time; + + return TRUE; +} +void WarpZone_StartFrame() +{ + entity e; + for(e = world; (e = nextent(e)); ) + WarpZone_StoreProjectileData(e); +} +float WarpZone_Projectile_Touch() +{ + if(other.classname == "trigger_warpzone") + return TRUE; + if(WarpZone_Projectile_Touch_ImpactFilter_Callback()) + return TRUE; + if(WarpZone_CheckProjectileImpact()) + return TRUE; + if(self.warpzone_teleport_time == time) // already got teleported this frame? no collision then please + { + setorigin(self, self.warpzone_oldorigin); + self.velocity = self.warpzone_oldvelocity; + self.angles = self.warpzone_oldangles; + return TRUE; + } + + return FALSE; } diff --git a/data/qcsrc/warpzonelib/server.qh b/data/qcsrc/warpzonelib/server.qh index b92296bf5..b20147058 100644 --- a/data/qcsrc/warpzonelib/server.qh +++ b/data/qcsrc/warpzonelib/server.qh @@ -2,9 +2,13 @@ void WarpZone_InitStep_SpawnFunc(); void WarpZone_InitStep_FindTarget(); void WarpZone_InitStep_UpdateTransform(); +void WarpZone_StartFrame(); +float WarpZone_Projectile_Touch(); + // THESE must be defined by calling QC code: void spawnfunc_trigger_warpzone(); // must call the init steps in order, first all spawnfunc init steps, then all findtarget init steps, then all updatetransform init steps -void WarpZone_PostTeleportPlayer(entity pl); +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; -- 2.39.2