]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Experimental view location trigger, new branch as it may interfere with regular modes...
authorMario <zacjardine@y7mail.com>
Thu, 26 Feb 2015 10:24:40 +0000 (21:24 +1100)
committerMario <zacjardine@y7mail.com>
Thu, 26 Feb 2015 10:24:40 +0000 (21:24 +1100)
qcsrc/client/csqcmodel_hooks.qc
qcsrc/client/main.qc
qcsrc/client/progs.src
qcsrc/client/view.qc
qcsrc/common/constants.qh
qcsrc/common/csqcmodel_settings.qh
qcsrc/csqcmodellib/cl_player.qc
qcsrc/server/cl_physics.qc
qcsrc/server/progs.src
qcsrc/server/t_viewloc.qc [new file with mode: 0644]
qcsrc/server/t_viewloc.qh [new file with mode: 0644]

index a262721ff66c2d7b18f9eb9eed500e3487517717..cfadcd0ebc1d57441c14091ac81ecb1eedb6bfa8 100644 (file)
@@ -15,6 +15,8 @@
 
        #include "../warpzonelib/mathlib.qh"
 
+       #include "../server/t_viewloc.qh"
+
        .float death_time;
        .int modelflags;
 #elif defined(MENUQC)
@@ -402,6 +404,12 @@ void CSQCModel_AutoTagIndex_Apply(void)
        if(self.tag_entity && wasfreed(self.tag_entity))
                self.tag_entity = world;
 
+       if(self.viewloc && wasfreed(self.viewloc))
+               self.viewloc = world;
+
+       if(self.viewloc.entnum != self.tag_networkviewloc)
+               self.viewloc = findfloat(world, entnum, self.tag_networkviewloc);
+
        if(self.tag_networkentity)
        {
                // we are ATTACHED!
index 49bdaa0b16298e212d55efdd522e9e91eae6faaa..b00a4c6aae24db8acebc55bfefd23cfc16e9392c 100644 (file)
@@ -13,6 +13,8 @@
 #include "wall.qh"
 #include "waypointsprites.qh"
 
+#include "../server/t_viewloc.qh"
+
 #include "../common/effects.qh"
 
 #include "../common/vehicles/unit/bumblebee.qh"
@@ -1030,6 +1032,8 @@ void CSQC_Ent_Update(float bIsNewEntity)
                case ENT_CLIENT_JAILCAMERA: ent_jailcamera(); break;
                case ENT_CLIENT_MINIGAME: ent_read_minigame(); break;
                case ENT_CLIENT_EFFECT: Read_Effect(bIsNewEntity); break;
+               case ENT_CLIENT_VIEWLOC: ent_viewloc(); break;
+               case ENT_CLIENT_VIEWLOC_TRIGGER: ent_viewloc_trigger(); break;
 
                default:
                        //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype));
index aabcdfa6c84463c678d7cf6bc7dcc58b6ac20bfe..ece5da7b7c1131d3d5f8847bc4fdbfbbb7e6b35f 100644 (file)
@@ -78,6 +78,7 @@ weapons/projectile.qc // TODO
 
 ../server/movelib.qc
 ../server/t_items.qc
+../server/t_viewloc.qc
 
 ../warpzonelib/anglestransform.qc
 ../warpzonelib/client.qc
index 8b36f5c3467d615f2fb3d8bd762041be5d1e8360..99e8ebf4ac51307e6444380decabd9045f37e877 100644 (file)
@@ -224,6 +224,16 @@ vector GetCurrentFov(float fov)
        return '1 0 0' * fovx + '0 1 0' * fovy;
 }
 
+vector GetViewLocationFOV(float fov)
+{
+       float frustumx, frustumy, fovx, fovy;
+       frustumy = tan(fov * M_PI / 360.0) * 0.75;
+       frustumx = frustumy * vid_width / vid_height / vid_pixelheight;
+       fovx = atan2(frustumx, 1) / M_PI * 360.0;
+       fovy = atan2(frustumy, 1) / M_PI * 360.0;
+       return '1 0 0' * fovx + '0 1 0' * fovy;
+}
+
 vector GetOrthoviewFOV(vector ov_worldmin, vector ov_worldmax, vector ov_mid, vector ov_org)
 {
        float fovx, fovy;
@@ -420,6 +430,8 @@ float WantEventchase()
                return false;
        if(intermission)
                return true;
+       if(self.viewloc)
+               return true;
        if(spectatee_status >= 0)
        {
                if(hud != HUD_NORMAL && (autocvar_cl_eventchase_vehicle || spectatee_status > 0))
@@ -553,7 +565,7 @@ void UpdateCrosshair()
        float tempcamera = (gametype == MAPINFO_TYPE_JAILBREAK && spectatee_status >= 0 && getstati(STAT_ROUNDLOST) && !getstati(STAT_PRISONED));
 
        // crosshair goes VERY LAST
-       if(!scoreboard_active && !camera_active && intermission != 2 && 
+       if(!scoreboard_active && !csqcplayer.viewloc && !camera_active && intermission != 2 && 
                spectatee_status != -1 && hud == HUD_NORMAL && autocvar_chase_active >= 0 && 
                !HUD_QuickMenu_IsOpened() && !tempcamera && !HUD_MinigameMenu_IsOpened() )
        {
@@ -1213,6 +1225,7 @@ void CSQC_UpdateView(float w, float h)
                        WarpZone_TraceBox(current_view_origin, autocvar_cl_eventchase_mins, autocvar_cl_eventchase_maxs, eventchase_target_origin, MOVE_WORLDONLY, self);
 
                        // If the boxtrace fails, revert back to line tracing.
+                       if(!self.viewloc)
                        if(trace_startsolid)
                        {
                                eventchase_target_origin = (current_view_origin - (v_forward * eventchase_current_distance));
@@ -1221,7 +1234,8 @@ void CSQC_UpdateView(float w, float h)
                        }
                        else { setproperty(VF_ORIGIN, trace_endpos); }
 
-                       setproperty(VF_ANGLES, WarpZone_TransformVAngles(WarpZone_trace_transform, view_angles));
+                       if(!self.viewloc)
+                               setproperty(VF_ANGLES, WarpZone_TransformVAngles(WarpZone_trace_transform, view_angles));
                }
                else if(autocvar_chase_active < 0) // time to disable chase_active if it was set by this code
                {
@@ -1453,6 +1467,7 @@ void CSQC_UpdateView(float w, float h)
                fovlock = -1;
 
        if(autocvar_cl_orthoview) { setproperty(VF_FOV, GetOrthoviewFOV(ov_worldmin, ov_worldmax, ov_mid, ov_org)); }
+       else if(csqcplayer.viewloc) { setproperty(VF_FOV, GetViewLocationFOV(110)); } // enforce 110 fov, so things dont look odd
        else if(fovlock > 0 && autocvar_cl_specfov) { setproperty(VF_FOV, GetCurrentFov(fovlock)); }
        else { setproperty(VF_FOV, GetCurrentFov(fov)); }
 
index 9691d222b30793e9e5d254567136cef78e781c6c..b795a0f417f12f277d91a550de235e34f44645ac 100644 (file)
@@ -85,6 +85,8 @@ const int ENT_CLIENT_JAILCAMERA = 72;
 const int ENT_CLIENT_EFFECT = 73;
 const int ENT_CLIENT_CONQUEST_CONTROLPOINT = 74;
 const int ENT_CLIENT_MINIGAME = 75;
+const int ENT_CLIENT_VIEWLOC = 76;
+const int ENT_CLIENT_VIEWLOC_TRIGGER = 77;
 
 const int ENT_CLIENT_HEALING_ORB = 80;
 
index af693c29880a74c37319a0b3191a3bc546105023..58ff0e3ba94b2df924384dcf67344cb37bbe043c 100644 (file)
 # define TAG_ENTITY_NAME tag_networkentity
 # define TAG_ENTITY_TYPE float
 .float tag_networkentity;
+
+# define TAG_VIEWLOC_NAME tag_networkviewloc
+# define TAG_VIEWLOC_TYPE int
+.float tag_networkviewloc;
 #else
 # define TAG_ENTITY_NAME tag_entity
 # define TAG_ENTITY_TYPE entity
+
+# define TAG_VIEWLOC_NAME viewloc
+# define TAG_VIEWLOC_TYPE entity
 #endif
 
 // new fields
@@ -52,7 +59,8 @@
                CSQCMODEL_PROPERTY(512, float, ReadApproxPastTime, WriteApproxPastTime, anim_upper_time) \
        CSQCMODEL_ENDIF \
        CSQCMODEL_PROPERTY(1024, float, ReadAngle, WriteAngle, v_angle_x) \
-       CSQCMODEL_PROPERTY_SCALED(4096, float, ReadByte, WriteByte, scale, 16, 0, 255)
+       CSQCMODEL_PROPERTY_SCALED(4096, float, ReadByte, WriteByte, scale, 16, 0, 255) \
+       CSQCMODEL_PROPERTY(8192, TAG_VIEWLOC_TYPE, ReadShort, WriteEntity, TAG_VIEWLOC_NAME)
 // TODO get rid of colormod/glowmod here, find good solution for vortex charge glowmod hack; also get rid of some useless properties on non-players that only exist for CopyBody
 
 // add hook function calls here
index 0c740a253c936390f860b5f0c32175d741ad7ee0..549ebca26801f6529d60df5a18fe0e2d6c0ae255 100644 (file)
@@ -30,6 +30,7 @@
        #include "common.qh"
        #include "cl_model.qh"
        #include "cl_player.qh"
+       #include "../server/t_viewloc.qh"
 #elif defined(MENUQC)
 #elif defined(SVQC)
 #endif
@@ -177,11 +178,88 @@ void CSQCPlayer_PredictTo(float endframe, float apply_error)
        input_angles = view_angles;
 }
 
-float CSQCPlayer_IsLocalPlayer()
+bool CSQCPlayer_IsLocalPlayer()
 {
        return (self == csqcplayer);
 }
 
+void CSQCPlayer_SetViewLocation(int refdefflags)
+{
+       entity view = CSQCModel_server2csqc(player_localentnum);
+       if(!view) { return; }
+
+       if(view.viewloc && !wasfreed(view.viewloc) && view.viewloc.enemy && view.viewloc.goalentity)
+       {
+               vector level_start, level_end, camera_rail, camera_angle;
+               vector forward, backward;
+
+               level_start = view.viewloc.enemy.origin;
+               level_end = view.viewloc.goalentity.origin;
+
+               // there may already be a function for bouning a vector in this manner, however my very quick search did not reveal one -- Player_2
+
+               //bound the x axis
+               if (view.origin.x < min(level_start.x, level_end.x))
+                       camera_rail.x = min(level_start.x, level_end.x);
+               else if (view.origin.x > max(level_start.x, level_end.x))
+                       camera_rail.x = max(level_start.x, level_end.x);
+               else
+                       camera_rail.x = view.origin.x;
+               
+               //bound the y axis
+               if (view.origin.y < min(level_start.y, level_end.y))
+                       camera_rail.y = min(level_start.y, level_end.y);
+               else if (view.origin.y > max(level_start.y, level_end.y))
+                       camera_rail.y = max(level_start.y, level_end.y);
+               else
+                       camera_rail.y = view.origin.y;
+               
+               //bound the z axis
+               if (view.origin.z < min(level_start.z, level_end.z))
+                       camera_rail.z = min(level_start.z, level_end.z);
+               else if (view.origin.z > max(level_start.z, level_end.z))
+                       camera_rail.z = max(level_start.z, level_end.z);
+               else
+                       camera_rail.z = view.origin.z;
+
+               //we float around x and y, but rotate around z
+               camera_angle.x = view.origin.x - camera_rail.x;
+               camera_angle.y = view.origin.y - camera_rail.y;
+               //camera_angle.z = camera_rail.z - view.origin.z;
+
+               //camera_angle.y = view.viewloc.enemy.angles_y;
+               camera_angle.z = view.viewloc.enemy.angles_z;
+               
+               //get the angles actual
+               camera_angle = vectoangles(normalize(camera_angle));
+
+               //dprint(vtos(camera_rail), "\n");
+
+               freeze_org = getpropertyvec(VF_ORIGIN);
+               freeze_ang = getpropertyvec(VF_ANGLES);
+               setproperty(VF_ORIGIN, camera_rail);
+               setproperty(VF_ANGLES, camera_angle);
+
+               forward = vectoangles(normalize(level_end - level_start));
+               backward = vectoangles(normalize(level_start - level_end));
+
+               if(input_movevalues_y < 0) // left
+                       view.angles = backward;
+               if(input_movevalues_y > 0) // favour right
+                       view.angles = forward;
+
+               /*if(input_buttons & 512) // left
+                       view.angles = backward;
+               else //if(input_buttons & 1024) // right
+                       view.angles = forward;*/
+
+               if(input_buttons & 256) // forward
+                       view.v_angle_x = view.angles_x = -50;
+
+               setproperty(VF_CL_VIEWANGLES, view.angles);
+       }
+}
+
 void CSQCPlayer_SetCamera()
 {
        vector v0;
@@ -302,6 +380,8 @@ void CSQCPlayer_SetCamera()
                        refdefflags |= REFDEFFLAG_INTERMISSION;
 
                V_CalcRefdef(view, refdefflags);
+
+               CSQCPlayer_SetViewLocation(refdefflags);
        }
        else
        {
index c0b7d3e336b2bcf7ea0035ef909c4393eb204220..db4eed221015dc39195c2bf1d9ea4e6f08e50e77 100644 (file)
@@ -24,6 +24,7 @@
     #include "g_hook.qh"
     #include "race.qh"
     #include "playerdemo.qh"
+       #include "t_viewloc.qh"
 #endif
 
 .float race_penalty;
@@ -862,6 +863,35 @@ void SV_PlayerPhysics()
        if(time < self.ladder_time)
                self.disableclientprediction = 1;
 
+       if(self.viewloc)
+       {
+               self.disableclientprediction = 1;
+               vector oldmovement = self.movement;
+               self.movement_x = oldmovement_y;
+               self.movement_y = 0;
+
+               if(self.movement_x < 0)
+                       self.movement_x = -self.movement_x;
+
+               vector level_start, level_end;
+               level_start = self.viewloc.enemy.origin;
+               level_end = self.viewloc.goalentity.origin;
+               vector forward, backward;
+               forward = vectoangles(normalize(level_end - level_start));
+               backward = vectoangles(normalize(level_start - level_end));
+
+               if(self.movement_x < 0) // left
+                       self.angles = backward;
+               if(self.movement_x > 0) // right
+                       self.angles = forward;
+
+               if(oldmovement_x > 0)
+                       self.v_angle_x = self.angles_x = -50;
+               
+               if(!self.BUTTON_CROUCH)
+                       self.BUTTON_CROUCH = (oldmovement_x < 0);
+       }
+
        if(self.frozen)
        {
                if(autocvar_sv_dodging_frozen && IS_REAL_CLIENT(self))
index 3ce98cebf69ceeaac67ca711d5d6ac6b3a7e0f91..848c49d44772a832eae5276b7019c31da6b504b8 100644 (file)
@@ -60,6 +60,7 @@ t_quake3.qc
 t_quake.qc
 t_swamp.qc
 t_teleporters.qc
+t_viewloc.qc
 waypointsprites.qc
 
 bot/bot.qc
diff --git a/qcsrc/server/t_viewloc.qc b/qcsrc/server/t_viewloc.qc
new file mode 100644 (file)
index 0000000..4d59406
--- /dev/null
@@ -0,0 +1,180 @@
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+       #include "../dpdefs/progsdefs.qh"
+    #include "../warpzonelib/util_server.qh"
+    #include "defs.qh"
+       #include "t_viewloc.qh"
+#endif
+
+#ifdef SVQC
+
+void viewloc_think()
+{
+       entity e;
+
+       // set myself as current viewloc where possible
+       for(e = world; (e = findentity(e, viewloc, self)); )
+               e.viewloc = world;
+
+               for(e = findradius((self.absmin + self.absmax) * 0.5, vlen(self.absmax - self.absmin) * 0.5 + 1); e; e = e.chain)
+                       if(!e.viewloc)
+                               if(IS_PLAYER(e)) // should we support non-player entities with this?
+                               if(e.deadflag == DEAD_NO) // death view is handled separately, we can't override this just yet
+                               {
+                                       vector emin = e.absmin;
+                                       vector emax = e.absmax;
+                                       if(self.solid == SOLID_BSP)
+                                       {
+                                               emin -= '1 1 1';
+                                               emax += '1 1 1';
+                                       }
+                                       if(boxesoverlap(emin, emax, self.absmin, self.absmax)) // quick
+                                               if(WarpZoneLib_BoxTouchesBrush(emin, emax, self, e)) // accurate
+                                                       e.viewloc = self;
+                               }
+
+       self.nextthink = time;
+}
+
+bool trigger_viewloc_send(entity to, int sf)
+{
+       // CSQC doesn't need to know our origin (yet), as we're only available for referencing
+       WriteByte(MSG_ENTITY, ENT_CLIENT_VIEWLOC_TRIGGER);
+
+       WriteEntity(MSG_ENTITY, self.enemy);
+       WriteEntity(MSG_ENTITY, self.goalentity);
+
+       WriteCoord(MSG_ENTITY, self.origin_x);
+       WriteCoord(MSG_ENTITY, self.origin_y);
+       WriteCoord(MSG_ENTITY, self.origin_z);
+
+       return true;
+}
+
+void viewloc_init()
+{
+       entity e;
+       for(e = world; (e = find(e, targetname, self.target)); )
+               if(e.classname == "target_viewlocation_start")
+               {
+                       self.enemy = e;
+                       break;
+               }
+       for(e = world; (e = find(e, targetname, self.target2)); )
+               if(e.classname == "target_viewlocation_end")
+               {
+                       self.goalentity = e;
+                       break;
+               }
+
+       if(!self.enemy) { print("^1FAIL!\n"); remove(self); return; }
+
+       if(!self.goalentity)
+               self.goalentity = self.enemy; // make them match so CSQC knows what to do
+
+       Net_LinkEntity(self, false, 0, trigger_viewloc_send);
+
+       self.think = viewloc_think;
+       self.nextthink = time;
+}
+
+void spawnfunc_trigger_viewlocation()
+{
+       // we won't check target2 here yet, as it may not even need to exist
+       if(self.target == "") { print("^1FAIL!\n"); remove(self); return; }
+
+       EXACTTRIGGER_INIT;
+       InitializeEntity(self, viewloc_init, INITPRIO_FINDTARGET);
+}
+
+bool viewloc_send(entity to, int sf)
+{
+       WriteByte(MSG_ENTITY, ENT_CLIENT_VIEWLOC);
+
+       WriteByte(MSG_ENTITY, self.cnt);
+
+       WriteCoord(MSG_ENTITY, self.origin_x);
+       WriteCoord(MSG_ENTITY, self.origin_y);
+       WriteCoord(MSG_ENTITY, self.origin_z);
+
+       WriteCoord(MSG_ENTITY, self.angles_x);
+       WriteCoord(MSG_ENTITY, self.angles_y);
+       WriteCoord(MSG_ENTITY, self.angles_z);
+
+       return true;
+}
+
+.float angle;
+void viewloc_link()
+{
+       if(self.angle)
+               self.angles_y = self.angle;
+       Net_LinkEntity(self, false, 0, viewloc_send);
+}
+
+void spawnfunc_target_viewlocation_start()
+{
+       self.classname = "target_viewlocation_start";
+       self.cnt = 1;
+       viewloc_link();
+}
+void spawnfunc_target_viewlocation_end()
+{
+       self.classname = "target_viewlocation_end";
+       self.cnt = 2;
+       viewloc_link();
+}
+
+// compatibility
+void spawnfunc_target_viewlocation() { spawnfunc_target_viewlocation_start(); }
+
+#elif defined(CSQC)
+
+void trigger_viewloc_updatelink()
+{
+       self.enemy = findfloat(world, entnum, self.cnt);
+       self.goalentity = findfloat(world, entnum, self.count);
+}
+
+void ent_viewloc_trigger()
+{
+       float point1 = ReadShort();
+       float point2 = ReadShort();
+
+       self.enemy = findfloat(world, entnum, point1);
+       self.goalentity = findfloat(world, entnum, point2);
+
+       self.origin_x = ReadCoord();
+       self.origin_y = ReadCoord();
+       self.origin_z = ReadCoord();
+       setorigin(self, self.origin);
+
+       self.cnt = point1;
+       self.count = point2;
+
+       self.think = trigger_viewloc_updatelink;
+       self.nextthink = time + 1; // we need to delay this or else
+
+       self.classname = "trigger_viewlocation";
+       self.drawmask = MASK_NORMAL; // not so concerned, but better keep it alive
+}
+
+void ent_viewloc()
+{
+       self.cnt = ReadByte();
+
+       self.origin_x = ReadCoord();
+       self.origin_y = ReadCoord();
+       self.origin_z = ReadCoord();
+       setorigin(self, self.origin);
+
+       self.movedir_x = ReadCoord();
+       self.movedir_y = ReadCoord();
+       self.movedir_z = ReadCoord();
+
+       self.classname = ((self.cnt == 2) ? "target_viewlocation_end" : "target_viewlocation_start");
+       self.drawmask = MASK_NORMAL; // don't cull it
+}
+
+#endif
diff --git a/qcsrc/server/t_viewloc.qh b/qcsrc/server/t_viewloc.qh
new file mode 100644 (file)
index 0000000..c7fd150
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef T_VIEWLOC_H
+#define T_VIEWLOC_H
+
+.entity viewloc;
+
+#ifdef CSQC
+.entity goalentity;
+.entity enemy;
+.vector movedir;
+
+void ent_viewloc();
+void ent_viewloc_trigger();
+#endif
+
+#endif
\ No newline at end of file