warpzonelib - the beginning
authordiv0 <div0@f962a42d-fe04-0410-a3ab-8c8b0445ebaa>
Sun, 28 Feb 2010 19:42:26 +0000 (19:42 +0000)
committerdiv0 <div0@f962a42d-fe04-0410-a3ab-8c8b0445ebaa>
Sun, 28 Feb 2010 19:42:26 +0000 (19:42 +0000)
NOTE: this patch breaks something on CLIENT side.

git-svn-id: svn://svn.icculus.org/nexuiz/trunk@8687 f962a42d-fe04-0410-a3ab-8c8b0445ebaa

21 files changed:
data/qcsrc/client/Main.qc
data/qcsrc/client/View.qc
data/qcsrc/client/progs.src
data/qcsrc/common/util.qc
data/qcsrc/common/util.qh
data/qcsrc/server/miscfunctions.qc
data/qcsrc/server/portals.qc
data/qcsrc/server/progs.src
data/qcsrc/server/t_teleporters.qc
data/qcsrc/server/w_campingrifle.qc
data/qcsrc/warpzonelib/COPYING [new file with mode: 0644]
data/qcsrc/warpzonelib/anglestransform.qc [new file with mode: 0644]
data/qcsrc/warpzonelib/anglestransform.qh [new file with mode: 0644]
data/qcsrc/warpzonelib/client.qc [new file with mode: 0644]
data/qcsrc/warpzonelib/client.qh [new file with mode: 0644]
data/qcsrc/warpzonelib/common.qc [new file with mode: 0644]
data/qcsrc/warpzonelib/common.qh [new file with mode: 0644]
data/qcsrc/warpzonelib/server.qc [new file with mode: 0644]
data/qcsrc/warpzonelib/server.qh [new file with mode: 0644]
data/qcsrc/warpzonelib/util_server.qc [new file with mode: 0644]
data/qcsrc/warpzonelib/util_server.qh [new file with mode: 0644]

index 3fcce30..44d37ec 100644 (file)
@@ -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;
index 70105a7..c42512a 100644 (file)
@@ -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)
index 61c0d99..989fc31 100644 (file)
@@ -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
index 8d2b111..afbc368 100644 (file)
@@ -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)
index 3608443..9b863fe 100644 (file)
@@ -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);
index 7443684..14813ee 100644 (file)
@@ -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";
index cedf344..4fd11ae 100644 (file)
@@ -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;
index 741c39b..37b0920 100644 (file)
@@ -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
index 1a5240b..e80e44e 100644 (file)
@@ -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);
 }
index e831376..39e2718 100644 (file)
@@ -239,3 +239,84 @@ float w_campingrifle(float req)
        return TRUE;
 };
 #endif
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Ç[\7f\90Kg|º^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
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\11\87\vío¸?~á\85\17Ñ  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
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
\ No newline at end of file
diff --git a/data/qcsrc/warpzonelib/COPYING b/data/qcsrc/warpzonelib/COPYING
new file mode 100644 (file)
index 0000000..0e432c9
--- /dev/null
@@ -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 (file)
index 0000000..9751067
--- /dev/null
@@ -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 (file)
index 0000000..fb2b99d
--- /dev/null
@@ -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 (file)
index 0000000..677cb78
--- /dev/null
@@ -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 (file)
index 0000000..9c0f8fe
--- /dev/null
@@ -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 (file)
index 0000000..772765a
--- /dev/null
@@ -0,0 +1 @@
+// empty yet
diff --git a/data/qcsrc/warpzonelib/common.qh b/data/qcsrc/warpzonelib/common.qh
new file mode 100644 (file)
index 0000000..8b1a393
--- /dev/null
@@ -0,0 +1 @@
+// empty
diff --git a/data/qcsrc/warpzonelib/server.qc b/data/qcsrc/warpzonelib/server.qc
new file mode 100644 (file)
index 0000000..19709f8
--- /dev/null
@@ -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 (file)
index 0000000..b92296b
--- /dev/null
@@ -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 (file)
index 0000000..b11b823
--- /dev/null
@@ -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 (file)
index 0000000..4808302
--- /dev/null
@@ -0,0 +1 @@
+float WarpZoneLib_MoveOutOfSolid(entity e);