From 7a95ee285fd745c9063a10adae25a3fe4b68db19 Mon Sep 17 00:00:00 2001 From: div0 Date: Sun, 28 Feb 2010 19:42:26 +0000 Subject: [PATCH] warpzonelib - the beginning NOTE: this patch breaks something on CLIENT side. git-svn-id: svn://svn.icculus.org/nexuiz/trunk@8687 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/qcsrc/client/Main.qc | 47 +---- data/qcsrc/client/View.qc | 21 +-- data/qcsrc/client/progs.src | 9 + data/qcsrc/common/util.qc | 54 ------ data/qcsrc/common/util.qh | 12 -- data/qcsrc/server/miscfunctions.qc | 54 +----- data/qcsrc/server/portals.qc | 2 +- data/qcsrc/server/progs.src | 11 ++ data/qcsrc/server/t_teleporters.qc | 196 +------------------- data/qcsrc/server/w_campingrifle.qc | 81 ++++++++ data/qcsrc/warpzonelib/COPYING | 21 +++ data/qcsrc/warpzonelib/anglestransform.qc | 99 ++++++++++ data/qcsrc/warpzonelib/anglestransform.qh | 15 ++ data/qcsrc/warpzonelib/client.qc | 84 +++++++++ data/qcsrc/warpzonelib/client.qh | 6 + data/qcsrc/warpzonelib/common.qc | 1 + data/qcsrc/warpzonelib/common.qh | 1 + data/qcsrc/warpzonelib/server.qc | 214 ++++++++++++++++++++++ data/qcsrc/warpzonelib/server.qh | 10 + data/qcsrc/warpzonelib/util_server.qc | 55 ++++++ data/qcsrc/warpzonelib/util_server.qh | 1 + 21 files changed, 624 insertions(+), 370 deletions(-) create mode 100644 data/qcsrc/warpzonelib/COPYING create mode 100644 data/qcsrc/warpzonelib/anglestransform.qc create mode 100644 data/qcsrc/warpzonelib/anglestransform.qh create mode 100644 data/qcsrc/warpzonelib/client.qc create mode 100644 data/qcsrc/warpzonelib/client.qh create mode 100644 data/qcsrc/warpzonelib/common.qc create mode 100644 data/qcsrc/warpzonelib/common.qh create mode 100644 data/qcsrc/warpzonelib/server.qc create mode 100644 data/qcsrc/warpzonelib/server.qh create mode 100644 data/qcsrc/warpzonelib/util_server.qc create mode 100644 data/qcsrc/warpzonelib/util_server.qh diff --git a/data/qcsrc/client/Main.qc b/data/qcsrc/client/Main.qc index 3fcce3014..44d37ec82 100644 --- a/data/qcsrc/client/Main.qc +++ b/data/qcsrc/client/Main.qc @@ -839,51 +839,6 @@ void Ent_RandomSeed() psrandom(s); } -float FL_CAMERA = 8192; -.vector warpzone_transform; -void Ent_WarpZone(float isnew) -{ - if not(self.enemy) - { - self.enemy = spawn(); - self.enemy.classname = "warpzone_from"; - } - self.classname = "warpzone_to"; - self.origin_x = ReadCoord(); - self.origin_y = ReadCoord(); - self.origin_z = ReadCoord(); - 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.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(); - - self.avelocity = AnglesTransform_TurnDirection(self.avelocity); - self.warpzone_transform = AnglesTransform_Divide(self.avelocity, self.enemy.avelocity); - - self.flags = FL_CAMERA; - self.drawmask = MASK_NORMAL; - - // link me - //setmodel(self, self.model); - setorigin(self, self.origin); - setsize(self, self.mins, self.maxs); -} - // CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured. // The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS. void Ent_RadarLink(); @@ -941,7 +896,7 @@ void(float bIsNewEntity) CSQC_Ent_Update = case ENT_CLIENT_WALL: Ent_Wall(); break; case ENT_CLIENT_MODELEFFECT: Ent_ModelEffect(bIsNewEntity); break; case ENT_CLIENT_TUBANOTE: Ent_TubaNote(bIsNewEntity); break; - case ENT_CLIENT_WARPZONE: Ent_WarpZone(bIsNewEntity); break; + case ENT_CLIENT_WARPZONE: WarpZone_Read(bIsNewEntity); break; default: error(strcat("unknown entity type in CSQC_Ent_Update: ", ftos(self.enttype), "\n")); break; diff --git a/data/qcsrc/client/View.qc b/data/qcsrc/client/View.qc index 70105a708..c42512a1c 100644 --- a/data/qcsrc/client/View.qc +++ b/data/qcsrc/client/View.qc @@ -358,22 +358,11 @@ void CSQC_UpdateView(float w, float h) ticrate = getstatf(STAT_MOVEVARS_TICRATE) * getstatf(STAT_MOVEVARS_TIMESCALE); vo = '0 0 1' * getstati(STAT_VIEWHEIGHT); - // if view origin is INSIDE a warpzone, we are screwed and must - // temporarily move the origin to the other side of the warp - pmove_org = pmove_org + vo; - for(e = world; (e = find(e, classname, "warpzone_to")); ) - { - //print(sprintf("does %s (%s to %s) touch %s?\n", e.model, vtos(e.absmin), vtos(e.absmax), vtos(pmove_org))); - if(BoxTouchesBrush(pmove_org, pmove_org, e, world)) - { - pmove_org = AnglesTransform_Apply(e.warpzone_transform, pmove_org - e.enemy.oldorigin) + e.oldorigin; - input_angles = AnglesTransform_Multiply(e.warpzone_transform, input_angles); - R_SetView(VF_ORIGIN, pmove_org); - R_SetView(VF_ANGLES, input_angles); - break; - } - } - pmove_org = pmove_org - vo; + warpzone_fixview_origin = pmove_org + vo; + warpzone_fixview_angles = input_angles; + WarpZone_FixView(); + pmove_org = warpzone_fixview_origin - vo; + input_angles = warpzone_fixview_angles; // Render the Scene if(!intermission || !view_set) diff --git a/data/qcsrc/client/progs.src b/data/qcsrc/client/progs.src index 61c0d99d7..989fc31b2 100644 --- a/data/qcsrc/client/progs.src +++ b/data/qcsrc/client/progs.src @@ -6,6 +6,11 @@ Defs.qc csqc_constants.qc ../common/constants.qh csqc_builtins.qc + +../warpzonelib/anglestransform.qh +../warpzonelib/common.qh +../warpzonelib/client.qh + ../common/mathlib.qh ../common/util.qh ../common/items.qh @@ -61,3 +66,7 @@ bgmscript.qc ../common/items.qc ../common/mathlib.qc + +../warpzonelib/anglestransform.qc +../warpzonelib/common.qc +../warpzonelib/client.qc diff --git a/data/qcsrc/common/util.qc b/data/qcsrc/common/util.qc index 8d2b111f5..afbc36871 100644 --- a/data/qcsrc/common/util.qc +++ b/data/qcsrc/common/util.qc @@ -686,13 +686,6 @@ float CheckWireframeBox(entity forent, vector v0, vector dvx, vector dvy, vector traceline(v0 + dvy + dvz, v0 + dvx + dvy + dvz, TRUE, forent); if(trace_fraction < 1) return 0; return 1; } - -void fixedmakevectors(vector a) -{ - // a makevectors that actually inverts vectoangles - a_x = -a_x; - makevectors(a); -} #endif string fixPriorityList(string order, float from, float to, float subtract, float complete) @@ -1211,53 +1204,6 @@ float boxesoverlap(vector m1, vector m2, vector m3, vector m4) {return m2_x >= m float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) {return smins_x >= bmins_x && smaxs_x <= bmaxs_x && smins_y >= bmins_y && smaxs_y <= bmaxs_y && smins_z >= bmins_z && smaxs_z <= bmaxs_z;}; #ifndef MENUQC -// 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_TurnDirection(vector transform) -{ - // turn 180 degrees around v_up - // changes in-direction to out-direction - fixedmakevectors(transform); - return fixedvectoangles2(-1 * v_forward, 1 * v_up); -} - -vector AnglesTransform_Divide(vector to_transform, vector from_transform) -{ - return AnglesTransform_Multiply(to_transform, AnglesTransform_Invert(from_transform)); -} #endif float textLengthUpToWidth(string theText, float maxWidth, vector theSize, textLengthUpToWidth_widthFunction_t w) diff --git a/data/qcsrc/common/util.qh b/data/qcsrc/common/util.qh index 3608443df..9b863fe7b 100644 --- a/data/qcsrc/common/util.qh +++ b/data/qcsrc/common/util.qh @@ -77,10 +77,6 @@ float compressShortVector(vector vec); #ifndef MENUQC float CheckWireframeBox(entity forent, vector v0, vector dvx, vector dvy, vector dvz); - -void fixedmakevectors(vector a); -#define fixedvectoangles2 vectoangles2 -#define fixedvectoangles vectoangles #endif string fixPriorityList(string pl, float from, float to, float subtract, float complete); @@ -132,14 +128,6 @@ string rgb_to_hexcolor(vector rgb); float boxesoverlap(vector m1, vector m2, vector m3, vector m4); float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs); -#ifndef MENUQC -vector AnglesTransform_Apply(vector transform, vector v); -vector AnglesTransform_Multiply(vector t1, vector t2); -vector AnglesTransform_Invert(vector transform); -vector AnglesTransform_TurnDirection(vector transform); -vector AnglesTransform_Divide(vector to_transform, vector from_transform); -#endif - typedef float(string s, vector size) textLengthUpToWidth_widthFunction_t; typedef float(string s) textLengthUpToLength_lenFunction_t; float textLengthUpToWidth(string theText, float maxWidth, vector size, textLengthUpToWidth_widthFunction_t tw); diff --git a/data/qcsrc/server/miscfunctions.qc b/data/qcsrc/server/miscfunctions.qc index 74436841a..14813ee9b 100644 --- a/data/qcsrc/server/miscfunctions.qc +++ b/data/qcsrc/server/miscfunctions.qc @@ -51,60 +51,8 @@ float DistributeEvenly_Get(float weight) return f; } -void move_out_of_solid_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 move_out_of_solid(entity e) -{ - vector o, m0, m1; - - o = e.origin; - traceline(o, o, MOVE_WORLDONLY, e); - if (trace_startsolid) - return 0; +#define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e) - tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e); - if (!trace_startsolid) - return 1; - - m0 = e.mins; - m1 = e.maxs; - e.mins = '0 0 0'; - e.maxs = '0 0 0'; - move_out_of_solid_expand(e, '1 0 0' * m0_x); - e.mins_x = m0_x; - move_out_of_solid_expand(e, '1 0 0' * m1_x); - e.maxs_x = m1_x; - move_out_of_solid_expand(e, '0 1 0' * m0_y); - e.mins_y = m0_y; - move_out_of_solid_expand(e, '0 1 0' * m1_y); - e.maxs_y = m1_y; - move_out_of_solid_expand(e, '0 0 1' * m0_z); - e.mins_z = m0_z; - move_out_of_solid_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 0; - } - - return 1; -} string STR_PLAYER = "player"; string STR_SPECTATOR = "spectator"; diff --git a/data/qcsrc/server/portals.qc b/data/qcsrc/server/portals.qc index cedf344e0..4fd11aeb0 100644 --- a/data/qcsrc/server/portals.qc +++ b/data/qcsrc/server/portals.qc @@ -351,7 +351,7 @@ void Portal_Disconnect(entity teleporter, entity destination) void Portal_Connect(entity teleporter, entity destination) { - teleporter.portal_transform = AnglesTransform_Divide(AnglesTransform_TurnDirection(destination.angles), teleporter.angles); + teleporter.portal_transform = AnglesTransform_Divide(AnglesTransform_TurnDirectionFR(destination.angles), teleporter.angles); teleporter.enemy = destination; destination.enemy = teleporter; diff --git a/data/qcsrc/server/progs.src b/data/qcsrc/server/progs.src index 741c39b81..37b09205a 100644 --- a/data/qcsrc/server/progs.src +++ b/data/qcsrc/server/progs.src @@ -6,6 +6,12 @@ pre-builtins.qh builtins.qh extensions.qh post-builtins.qh + +../warpzonelib/anglestransform.qh +../warpzonelib/common.qh +../warpzonelib/util_server.qh +../warpzonelib/server.qh + ../common/mathlib.qh constants.qh ../common/constants.qh @@ -165,3 +171,8 @@ playerdemo.qc anticheat.qc cheats.qc + +../warpzonelib/anglestransform.qc +../warpzonelib/common.qc +../warpzonelib/util_server.qc +../warpzonelib/server.qc diff --git a/data/qcsrc/server/t_teleporters.qc b/data/qcsrc/server/t_teleporters.qc index 1a5240b5e..e80e44e4a 100644 --- a/data/qcsrc/server/t_teleporters.qc +++ b/data/qcsrc/server/t_teleporters.qc @@ -298,199 +298,19 @@ void spawnfunc_trigger_teleport (void) } } - -// the transform -.vector warpzone_origin, warpzone_angles; -.vector warpzone_forward; -.vector warpzone_transform; - -void warpzone_updatetransform() +void WarpZone_PostTeleportPlayer(entity pl) { - if(!self.enemy || self.enemy.enemy != self) - { - objerror("Invalid warp zone detected. Killed."); - 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_TurnDirection(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; -} - -float warpzone_teleport(entity player) -{ - vector o0, a0, v0, o1, a1, v1; - - o0 = player.origin + player.view_ofs; - v0 = player.velocity; - a0 = player.angles; - - if((o0 - self.warpzone_origin) * self.warpzone_forward >= 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 - // entity of the player to fix graphics glitch - - o1 = AnglesTransform_Apply(self.warpzone_transform, o0 - self.warpzone_origin) + self.enemy.warpzone_origin; - v1 = AnglesTransform_Apply(self.warpzone_transform, v0); - if(player.classname == "player") - a1 = Portal_ApplyTransformToPlayerAngle(self.warpzone_transform, player.v_angle); - else - a1 = AnglesTransform_Multiply(self.warpzone_transform, a0); - - // put him inside 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(move_out_of_solid(player)) - { - setorigin(player, o0); - o1 = player.origin + player.view_ofs; - } - else - { - setorigin(player, o0 - player.view_ofs); - return 0; // cannot fix - } - } - - if((o1 - self.enemy.warpzone_origin) * self.enemy.warpzone_forward <= 0) // wrong side of the portal post-teleport + UpdateCSQCProjectileAfterTeleport(pl); + if(pl.classname == "player") { - print("inconsistent warp zones or evil roundoff error\n"); - return 0; - } - - //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); - - return 1; -} - -void warpzone_touch (void) -{ - entity oldself, e; - - if (other.health < 1) - return; - - if(self.team) - if((self.spawnflags & 4 == 0) == (self.team != other.team)) - return; - - EXACTTRIGGER_TOUCH; - - e = self.enemy; - if(warpzone_teleport(other)) - { - if(self.aiment.target) - { - oldself = self; - activator = other; - self = self.aiment; - SUB_UseTargets(); - self = oldself; - } - } - else - { - dprint("WARPZONE FAIL AHAHAHAHAH))\n"); - } -} -void warpzone_findtarget (void) -{ - entity e; - - if(self.killtarget == "") - { - objerror("Warp zone with no killtarget"); - return; - } - self.aiment = find(world, targetname, self.killtarget); - if(self.aiment == world) - { - objerror("Warp zone with nonexisting killtarget"); - return; - } - - // this way only one of the two ents needs to target - if(self.target != "") - { - e = find(world, targetname, self.target); - if(e) - { - self.enemy = e; - self.enemy.enemy = self; - } + // reset tracking of oldvelocity for impact damage (sudden velocity changes) + pl.oldvelocity = pl.velocity; } - - // now enable touch - self.touch = warpzone_touch; -} - -float warpzone_send(entity to, float sendflags) -{ - WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE); - - // we need THESE to render the warpzone (and cull properly)... - 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); - - // 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.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); - - return TRUE; } void spawnfunc_trigger_warpzone(void) { - // 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 - - string m; - m = self.model; - EXACTTRIGGER_INIT; - setmodel(self, m); - - self.use = trigger_teleport_use; // set team - InitializeEntity(self, warpzone_findtarget, INITPRIO_FINDTARGET); - InitializeEntity(self, warpzone_updatetransform, INITPRIO_LAST); - Net_LinkEntity(self, FALSE, 0, warpzone_send); + WarpZone_InitStep_SpawnFunc(); + InitializeEntity(self, WarpZone_InitStep_FindTarget, INITPRIO_FINDTARGET); + InitializeEntity(self, WarpZone_InitStep_UpdateTransform, INITPRIO_LAST); } diff --git a/data/qcsrc/server/w_campingrifle.qc b/data/qcsrc/server/w_campingrifle.qc index e83137696..39e271886 100644 --- a/data/qcsrc/server/w_campingrifle.qc +++ b/data/qcsrc/server/w_campingrifle.qc @@ -239,3 +239,84 @@ float w_campingrifle(float req) return TRUE; }; #endif +Ç[Kg|º^fÆ,9Þ@ª w_deathtypestring = "sniped themself somehow"; + } + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + { + if(w_deathtype & HITTYPE_BOUNCE) + w_deathtypestring = "failed to hide from #'s bullet hail"; + else + w_deathtypestring = "died in #'s bullet hail"; + } + else + { + if(w_deathtype & HITTYPE_BOUNCE) + { + // TODO special headshot message here too? + w_deathtypestring = "failed to hide from #'s rifle"; + } + else + { + if(w_deathtype & HITTYPE_HEADSHOT) + w_deathtypestring = "got hit in the head by #"; + else + w_deathtypestring = "was sniped by #"; + } + } + } + else if (req == WR_RELOAD) + { + W_CampingRifle_Reload(); + } + else if (req == WR_RESETPLAYER) + { + self.campingrifle_accumulator = time - cvar("g_balance_campingrifle_bursttime"); + self.campingrifle_bulletcounter = cvar("g_balance_campingrifle_magazinecapacity"); + W_CampingRifle_CheckMaxBullets(FALSE); + } + return TRUE; +}; +#endif +tì‡{³ ío¸?~á…Ñ w_deathtypestring = "sniped themself somehow"; + } + else if (req == WR_KILLMESSAGE) + { + if(w_deathtype & HITTYPE_SECONDARY) + { + if(w_deathtype & HITTYPE_BOUNCE) + w_deathtypestring = "failed to hide from #'s bullet hail"; + else + w_deathtypestring = "died in #'s bullet hail"; + } + else + { + if(w_deathtype & HITTYPE_BOUNCE) + { + // TODO special headshot message here too? + w_deathtypestring = "failed to hide from #'s rifle"; + } + else + { + if(w_deathtype & HITTYPE_HEADSHOT) + w_deathtypestring = "got hit in the head by #"; + else + w_deathtypestring = "was sniped by #"; + } + } + } + else if (req == WR_RELOAD) + { + W_CampingRifle_Reload(); + } + else if (req == WR_RESETPLAYER) + { + self.campingrifle_accumulator = time - cvar("g_balance_campingrifle_bursttime"); + self.campingrifle_bulletcounter = cvar("g_balance_campingrifle_magazinecapacity"); + W_CampingRifle_CheckMaxBullets(FALSE); + } + return TRUE; +}; +#endif + \ No newline at end of file diff --git a/data/qcsrc/warpzonelib/COPYING b/data/qcsrc/warpzonelib/COPYING new file mode 100644 index 000000000..0e432c9fa --- /dev/null +++ b/data/qcsrc/warpzonelib/COPYING @@ -0,0 +1,21 @@ +/* +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. +*/ diff --git a/data/qcsrc/warpzonelib/anglestransform.qc b/data/qcsrc/warpzonelib/anglestransform.qc new file mode 100644 index 000000000..97510675c --- /dev/null +++ b/data/qcsrc/warpzonelib/anglestransform.qc @@ -0,0 +1,99 @@ +// helper function +void fixedmakevectors(vector a) +{ + // a makevectors that actually inverts vectoangles + a_x = -a_x; + makevectors(a); +} + +// 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 = 180 - transform_x; + transform_y = 180 + transform_y; + transform_z = -transform_z; + 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 = 180 - transform_x; + transform_y = 180 + transform_y; + transform_z = 180 - transform_z; + return transform; +} + +vector AnglesTransform_Divide(vector to_transform, vector from_transform) +{ + return AnglesTransform_Multiply(to_transform, AnglesTransform_Invert(from_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_ApplyToVAngles(vector transform, vector v) +{ + v_x = -v_x; + v = AnglesTransform_ApplyToAngles(transform, v); + v_x = -v_x; + return v; +} diff --git a/data/qcsrc/warpzonelib/anglestransform.qh b/data/qcsrc/warpzonelib/anglestransform.qh new file mode 100644 index 000000000..fb2b99d0e --- /dev/null +++ b/data/qcsrc/warpzonelib/anglestransform.qh @@ -0,0 +1,15 @@ +void fixedmakevectors(vector a); +#define fixedvectoangles2 vectoangles2 +#define fixedvectoangles vectoangles + +vector AnglesTransform_Apply(vector transform, vector v); +vector AnglesTransform_Multiply(vector t1, vector t2); +vector AnglesTransform_Invert(vector transform); +vector AnglesTransform_TurnDirectionFU(vector transform); +vector AnglesTransform_TurnDirectionFR(vector transform); +vector AnglesTransform_Divide(vector to_transform, vector from_transform); + +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) + +#define AnglesTransform_ApplyToAngles(t,v) AnglesTransform_Multiply(t, v) +vector AnglesTransform_ApplyToVAngles(vector transform, vector v); diff --git a/data/qcsrc/warpzonelib/client.qc b/data/qcsrc/warpzonelib/client.qc new file mode 100644 index 000000000..677cb783e --- /dev/null +++ b/data/qcsrc/warpzonelib/client.qc @@ -0,0 +1,84 @@ +float FL_CAMERA = 8192; +.vector warpzone_transform; +void WarpZone_Read(float isnew) +{ + if not(self.enemy) + { + self.enemy = spawn(); + self.enemy.classname = "warpzone_from"; + } + self.classname = "warpzone_to"; + self.origin_x = ReadCoord(); + self.origin_y = ReadCoord(); + self.origin_z = ReadCoord(); + 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.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(); + + self.avelocity = AnglesTransform_TurnDirectionFR(self.avelocity); + self.warpzone_transform = AnglesTransform_Divide(self.avelocity, self.enemy.avelocity); + + print(vtos(AnglesTransform_Apply(self.warpzone_transform, '0 0 1')), "\n"); + + self.flags = FL_CAMERA; + self.drawmask = MASK_NORMAL; + + // link me + //setmodel(self, self.model); + setorigin(self, self.origin); + setsize(self, self.mins, self.maxs); +} + +float warpzone_saved; +vector warpzone_saved_origin; +vector warpzone_saved_angles; +void WarpZone_FixView() +{ + entity e; + float roll; + warpzone_saved = 0; + for(e = world; (e = find(e, classname, "warpzone_to")); ) + { + //print(sprintf("does %s (%s to %s) touch %s?\n", e.model, vtos(e.absmin), vtos(e.absmax), vtos(pmove_org))); + if(BoxTouchesBrush(pmove_org, pmove_org, e, world)) + { + warpzone_saved_origin = warpzone_fixview_origin; + warpzone_saved_angles = warpzone_fixview_angles; + warpzone_saved = 1; + roll = warpzone_fixview_angles_z; + warpzone_fixview_angles_z = 0; + warpzone_fixview_origin = AnglesTransform_Apply(e.warpzone_transform, warpzone_fixview_origin - e.enemy.oldorigin) + e.oldorigin; + warpzone_fixview_angles = AnglesTransform_Normalize(AnglesTransform_ApplyToVAngles(e.warpzone_transform, warpzone_fixview_angles), TRUE); + warpzone_fixview_angles_z = roll; + R_SetView(VF_ORIGIN, warpzone_fixview_origin); + R_SetView(VF_ANGLES, warpzone_fixview_angles); + break; + } + } +} +void WarpZone_UnFixView() +{ + if(warpzone_saved) + { + warpzone_fixview_origin = warpzone_saved_origin; + warpzone_fixview_angles = warpzone_saved_angles; + R_SetView(VF_ORIGIN, warpzone_fixview_origin); + R_SetView(VF_ANGLES, warpzone_fixview_angles); + } +} diff --git a/data/qcsrc/warpzonelib/client.qh b/data/qcsrc/warpzonelib/client.qh new file mode 100644 index 000000000..9c0f8fe08 --- /dev/null +++ b/data/qcsrc/warpzonelib/client.qh @@ -0,0 +1,6 @@ +void WarpZone_Read(float bIsNewEntity); + +vector warpzone_fixview_origin; +vector warpzone_fixview_angles; +void WarpZone_FixView(); // this saves the previous values +void WarpZone_UnFixView(); // and restores them diff --git a/data/qcsrc/warpzonelib/common.qc b/data/qcsrc/warpzonelib/common.qc new file mode 100644 index 000000000..772765a0a --- /dev/null +++ b/data/qcsrc/warpzonelib/common.qc @@ -0,0 +1 @@ +// empty yet diff --git a/data/qcsrc/warpzonelib/common.qh b/data/qcsrc/warpzonelib/common.qh new file mode 100644 index 000000000..8b1a39374 --- /dev/null +++ b/data/qcsrc/warpzonelib/common.qh @@ -0,0 +1 @@ +// empty diff --git a/data/qcsrc/warpzonelib/server.qc b/data/qcsrc/warpzonelib/server.qc new file mode 100644 index 000000000..19709f8b3 --- /dev/null +++ b/data/qcsrc/warpzonelib/server.qc @@ -0,0 +1,214 @@ +void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags) +{ + vector from; + + makevectors (to_angles); + + from = player.origin; + setorigin (player, to); + player.oldorigin = to; // for DP's unsticking + player.angles = to_angles; + player.fixangle = TRUE; + player.velocity = to_velocity; + + if(player.effects & EF_TELEPORT_BIT) + player.effects &~= EF_TELEPORT_BIT; + else + player.effects |= EF_TELEPORT_BIT; + + if(player.classname == "player") + player.flags &~= FL_ONGROUND; + + WarpZone_PostTeleportPlayer(player); +} + +// the transform +.vector warpzone_origin, warpzone_angles; +.vector warpzone_forward; +.vector warpzone_transform; + +float WarpZone_Teleport(entity player) +{ + vector o0, a0, v0, o1, a1, v1; + + o0 = player.origin + player.view_ofs; + v0 = player.velocity; + a0 = player.angles; + + if((o0 - self.warpzone_origin) * self.warpzone_forward >= 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 + // entity of the player to fix graphics glitch + + o1 = AnglesTransform_Apply(self.warpzone_transform, o0 - self.warpzone_origin) + self.enemy.warpzone_origin; + v1 = AnglesTransform_Apply(self.warpzone_transform, v0); + if(player.classname == "player") + a1 = AnglesTransform_Normalize(AnglesTransform_ApplyToVAngles(self.warpzone_transform, player.v_angle), TRUE); + else + a1 = AnglesTransform_ApplyToAngles(self.warpzone_transform, a0); + + // put him inside 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)) + { + setorigin(player, o0); + o1 = player.origin + player.view_ofs; + } + else + { + setorigin(player, o0 - player.view_ofs); + return 0; // cannot fix + } + } + + if((o1 - self.enemy.warpzone_origin) * self.enemy.warpzone_forward <= 0) // wrong side of the portal post-teleport + { + print("inconsistent warp zones or evil roundoff error\n"); + return 0; + } + + //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); + + return 1; +} + +void WarpZone_Touch (void) +{ + entity oldself, e; + + // FIXME needs a better check to know what is safe to teleport and what not + if(other.movetype == MOVETYPE_NONE) + return; + + EXACTTRIGGER_TOUCH; + + e = self.enemy; + if(WarpZone_Teleport(other)) + { + if(self.aiment.target) + { + oldself = self; + activator = other; + self = self.aiment; + SUB_UseTargets(); + self = oldself; + } + } + else + { + dprint("WARPZONE FAIL AHAHAHAHAH))\n"); + } +} + +float WarpZone_Send(entity to, float sendflags) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE); + + // we need THESE to render the warpzone (and cull properly)... + 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); + + // 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.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); + + return TRUE; +} + +void WarpZone_InitStep_SpawnFunc() +{ + // 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 + + // TODO nexuiz specific + string m; + m = self.model; + EXACTTRIGGER_INIT; + setmodel(self, m); + Net_LinkEntity(self, FALSE, 0, WarpZone_Send); +} + +void WarpZone_InitStep_FindTarget() +{ + entity e; + + if(self.killtarget == "") + { + objerror("Warp zone with no killtarget"); + return; + } + self.aiment = find(world, targetname, self.killtarget); + if(self.aiment == world) + { + objerror("Warp zone with nonexisting killtarget"); + return; + } + + // this way only one of the two ents needs to target + if(self.target != "") + { + e = find(world, targetname, self.target); + if(e) + { + self.enemy = e; + self.enemy.enemy = self; + } + } + + // now enable touch + self.touch = WarpZone_Touch; +} + +void WarpZone_InitStep_UpdateTransform() +{ + if(!self.enemy || self.enemy.enemy != self) + { + objerror("Invalid warp zone detected. Killed."); + 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; +} diff --git a/data/qcsrc/warpzonelib/server.qh b/data/qcsrc/warpzonelib/server.qh new file mode 100644 index 000000000..b92296bf5 --- /dev/null +++ b/data/qcsrc/warpzonelib/server.qh @@ -0,0 +1,10 @@ +void WarpZone_InitStep_SpawnFunc(); +void WarpZone_InitStep_FindTarget(); +void WarpZone_InitStep_UpdateTransform(); + +// 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); + +// server must also define a float called ENT_CLIENT_WARPZONE for the initial byte of WarpZone entities +const float ENT_CLIENT_WARPZONE; diff --git a/data/qcsrc/warpzonelib/util_server.qc b/data/qcsrc/warpzonelib/util_server.qc new file mode 100644 index 000000000..b11b82368 --- /dev/null +++ b/data/qcsrc/warpzonelib/util_server.qc @@ -0,0 +1,55 @@ +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/data/qcsrc/warpzonelib/util_server.qh b/data/qcsrc/warpzonelib/util_server.qh new file mode 100644 index 000000000..48083027f --- /dev/null +++ b/data/qcsrc/warpzonelib/util_server.qh @@ -0,0 +1 @@ +float WarpZoneLib_MoveOutOfSolid(entity e); -- 2.39.2