]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Build new drawing method into client code for Arc effects
authorSamual Lenks <samual@xonotic.org>
Tue, 18 Feb 2014 05:36:13 +0000 (00:36 -0500)
committerSamual Lenks <samual@xonotic.org>
Tue, 18 Feb 2014 05:36:13 +0000 (00:36 -0500)
Note that this is NOT the larger change I intend to do at a later point,
but just a "temporary" one which draws a visual effect for the gun for
now.

qcsrc/client/Main.qc
qcsrc/client/particles.qc
qcsrc/common/weapons/w_arc.qc

index d49616d3124656431742a888dbe6f5aa8d7e1500..0ccb68a7f4edb2ab437815daf19bf719f1a37a97 100644 (file)
@@ -818,7 +818,7 @@ void CSQC_Ent_Update(float bIsNewEntity)
                case ENT_CLIENT_WARPZONE_TELEPORTED: WarpZone_Teleported_Read(bIsNewEntity); break;
                case ENT_CLIENT_TRIGGER_MUSIC: Ent_ReadTriggerMusic(); break;
                case ENT_CLIENT_HOOK: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_HOOK); break;
-               case ENT_CLIENT_ARC_BEAM: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_ARC_BEAM); break;
+               case ENT_CLIENT_ARC_BEAM: Ent_ReadArcBeam(bIsNewEntity); break;
                case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break;
                case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break;
                case ENT_CLIENT_TURRET: ent_turret(); break;
index 857e182f6604c4aeb5f13df02dae2df954211c0d..e1de39c93f3bf85d6999bf0b9a31df1921cbcf95 100644 (file)
@@ -362,3 +362,258 @@ void Net_ReadShockwaveParticle()
        shockwave.sw_time = time;
 }
 
+.float beam_usevieworigin;
+.float beam_initialized;
+.vector beam_shotorigin;
+.vector beam_dir;
+void Draw_ArcBeam()
+{
+       if(self.teleport_time)
+       if(time > self.teleport_time)
+       {
+               sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, ATTEN_NORM); // safeguard
+               self.teleport_time = 0;
+       }
+
+       InterpolateOrigin_Do();
+
+       // origin = beam starting origin
+       // v_angle = wanted/aim direction
+       // angles = current direction of beam
+
+       vector beamdir; //= self.beam_dir;
+       vector wantdir; //= view_forward;
+
+       vector start_pos;
+
+       if(self.beam_usevieworigin)
+       {
+               makevectors(view_angles);
+
+               if(!self.beam_initialized)
+               {
+                       self.beam_dir = view_forward;
+                       self.beam_initialized = TRUE;
+               }
+
+               if(self.beam_dir != view_forward)
+               {
+                       float angle = ceil(vlen(view_forward - self.beam_dir) * RAD2DEG);
+                       float anglelimit;
+                       if(angle && (angle > cvar("g_balance_arc_beam_maxangle")))
+                       {
+                               // if the angle is greater than maxangle, force the blendfactor to make this the maximum factor
+                               anglelimit = min(cvar("g_balance_arc_beam_maxangle") / angle, 1);
+                       }
+                       else
+                       {
+                               // the radius is not too far yet, no worries :D
+                               anglelimit = 1;
+                       }
+
+                       // calculate how much we're going to move the end of the beam to the want position
+                       float blendfactor = bound(0, anglelimit * (1 - (cvar("g_balance_arc_beam_returnspeed") * frametime)), 1);
+                       self.beam_dir = normalize((view_forward * (1 - blendfactor)) + (self.beam_dir * blendfactor));
+               }
+
+               beamdir = self.beam_dir;
+               wantdir = view_forward;
+
+               vector origin_offset = view_forward * self.beam_shotorigin_x + view_right * -self.beam_shotorigin_y + view_up * self.beam_shotorigin_z;
+               if(self.beam_usevieworigin == 2)
+                       { start_pos = view_origin + origin_offset; }
+               else
+                       { start_pos = self.origin + origin_offset; }
+       }
+       else
+       {
+               beamdir = self.angles;
+               wantdir = self.v_angle;
+               start_pos = self.origin;
+       }
+
+       setorigin(self, start_pos);
+
+       float i;
+       float segments = 20; // todo: calculate this in a similar way to server does
+
+       vector beam_endpos_estimate = (start_pos + (beamdir * cvar("g_balance_arc_beam_range")));
+
+       //vector axis = normalize(last_origin - new_origin);
+       vector thickdir = normalize(cross(beamdir, view_origin - start_pos));
+
+       vector last_origin = start_pos;
+       
+       vector last_top = start_pos + (thickdir * 0);
+       vector last_bottom = start_pos - (thickdir * 0);
+
+       for(i = 1; i <= segments; ++i)
+       {
+               // calculate this on every segment to ensure that we always reach the full length of the attack
+               float segmentblend = (i/segments);
+               float segmentdist = vlen(beam_endpos_estimate - last_origin) * (i/segments);
+
+               vector new_dir = normalize( (wantdir * (1 - segmentblend)) + (normalize(beam_endpos_estimate - last_origin) * segmentblend) );
+               vector new_origin = last_origin + (new_dir * segmentdist);
+
+               WarpZone_TraceLine(
+                       last_origin,
+                       new_origin,
+                       MOVE_NORMAL,
+                       self
+               );
+
+               vector hitorigin;
+
+               // draw segment
+               if(trace_fraction != 1)
+               {
+                       // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
+                       hitorigin = last_origin + (new_dir * segmentdist * trace_fraction);
+               }
+               else
+               {
+                       hitorigin = new_origin;
+               }
+
+               #if 0
+               float falloff = ExponentialFalloff(
+                       WEP_CVAR(arc, beam_falloff_mindist),
+                       WEP_CVAR(arc, beam_falloff_maxdist),
+                       WEP_CVAR(arc, beam_falloff_halflifedist),
+                       vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, hitorigin) - start_pos)
+               );
+               #else
+               //float falloff = 1;
+               #endif
+
+               vector top    = hitorigin + (thickdir * 1);
+               vector bottom = hitorigin - (thickdir * 1);
+
+               R_BeginPolygon("", DRAWFLAG_NORMAL);
+               R_PolygonVertex(top,         '0 1 0', '1 0 0', 0.5);
+               R_PolygonVertex(last_top,    '0 1 0', '1 0 0', 0.5);
+               R_PolygonVertex(last_bottom, '0 0 0', '1 0 0', 0.5);
+               R_PolygonVertex(bottom,      '0 0 0', '1 0 0', 0.5);
+               R_EndPolygon();
+
+               // draw collision effect
+               if(trace_fraction != 1)
+               {
+                       switch(self.beam_type)
+                       {
+                               //case ARC_BT_MISS: te_customflash(hitorigin, 40, 5, '1 1 0'); break;
+                               case ARC_BT_WALL: te_customflash(hitorigin, 40, 2, '0 0 1'); break;
+                               case ARC_BT_HIT:  te_customflash(hitorigin, 80, 5, '1 0 0'); break;
+                               //case ARC_BT_MISS: te_customflash(hitorigin, 80, 5, '0 1 0'); break;
+                               default: te_customflash(hitorigin, 40, 2, '0 1 0'); break;
+                       }
+                       break; // we're done with drawing this frame
+               }
+               else
+               {
+                       last_origin = new_origin; // continue onto the next segment
+                       last_top = top;
+                       last_bottom = bottom;
+               }
+       }
+
+       if(trace_fraction == 1)
+       {
+               // do end of beam effect here
+       }
+}
+
+void Remove_ArcBeam(void)
+{
+       sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, ATTEN_NORM);
+}
+
+void Ent_ReadArcBeam(float isnew)
+{
+       // don't send group 1 if this beam is for the local player
+       //if(to == self.owner) { sf |= 1; }
+       //WriteByte(MSG_ENTITY, sf);
+       float sf = ReadByte();
+
+       // self.iflags = IFLAG_ORIGIN | IFLAG_ANGLES | IFLAG_V_ANGLE; // why doesn't this work?
+       self.iflags = IFLAG_ORIGIN;
+
+       InterpolateOrigin_Undo();
+
+       if(sf & 1) // starting location // not sent if beam is for owner
+       {
+               //WriteByte(MSG_ENTITY, num_for_edict(self.owner));
+               self.origin_x = ReadCoord();
+               self.origin_y = ReadCoord();
+               self.origin_z = ReadCoord();
+               setorigin(self, self.origin);
+               self.beam_usevieworigin = 0;
+               //WriteCoord(MSG_ENTITY, WEP_CVAR(arc, beam_range));
+       }
+       else // infer the location from player location
+       {
+               //origin_offset = view_forward * origin_offset_x + view_right * -origin_offset_y + view_up * origin_offset_z;
+
+               if(autocvar_chase_active) // use player origin so that third person display still works
+               {
+                       self.beam_usevieworigin = 1;
+                       self.origin = getplayerorigin(player_localnum) + ('0 0 1' * getstati(STAT_VIEWHEIGHT));
+               }
+               else // use view origin
+               {
+                       self.beam_usevieworigin = 2;
+               }
+               setorigin(self, self.origin);
+       }
+
+       float gunalign = autocvar_cl_gunalign;
+       if(gunalign != 1 && gunalign != 2 && gunalign != 4)
+               gunalign = 3; // default value
+       --gunalign;
+
+       self.beam_shotorigin = arc_shotorigin[gunalign];
+
+       //origin_offset = view_forward * self.beam_shotorigin_x + view_right * -self.beam_shotorigin_y + view_up * self.beam_shotorigin_z;
+       
+       if(sf & 2) // want/aim direction
+       {
+               self.v_angle_x = ReadCoord();
+               self.v_angle_y = ReadCoord();
+               self.v_angle_z = ReadCoord();
+       }
+       if(sf & 4) // beam direction
+       {
+               self.angles_x = ReadCoord();
+               self.angles_y = ReadCoord();
+               self.angles_z = ReadCoord();
+       }
+       if(sf & 8) // beam type
+       {
+               self.beam_type = ReadByte();
+       }
+
+       InterpolateOrigin_Note();
+
+       if(isnew || !self.teleport_time)
+       {
+               self.draw = Draw_ArcBeam;
+               self.entremove = Remove_ArcBeam;
+               sound(self, CH_SHOTS_SINGLE, "weapons/lgbeam_fly.wav", VOL_BASE, ATTEN_NORM);
+       }
+
+       self.teleport_time = time + 10;
+
+       #if 0
+       printf(
+               "Ent_ReadArcBeam(%d): sf = %d, start = %s, want = %s, dir = %s, type = %d\n",
+               isnew,
+               sf,
+               vtos(self.beam_start),
+               vtos(self.v_angle),
+               vtos(self.angles),
+               self.beam_type
+       );
+       #endif
+}
+
index d1c8ff2ec5ff33f864f8101e06693926c6b94111..759eafa99328401d96248e74ec852dc457623dba 100644 (file)
@@ -42,6 +42,10 @@ REGISTER_WEAPON(
 
 #ifndef MENUQC
 vector arc_shotorigin[4];
+.vector beam_start;
+.vector beam_dir;
+.vector beam_wantdir;
+.float beam_type;
 #define ARC_BT_MISS        0
 #define ARC_BT_WALL        1
 #define ARC_BT_HEAL        2
@@ -59,14 +63,10 @@ void ArcInit(void);
 .entity arc_beam; // used for beam
 .float BUTTON_ATCK_prev; // for better animation control
 .float lg_fire_prev; // for better animation control
-#define ARC_DEBUG
 #ifdef ARC_DEBUG
 .entity lg_ents[ARC_MAX_SEGMENTS]; // debug
 #endif
-.vector beam_dir;
-.vector beam_wantdir;
 .float beam_initialized;
-.float beam_type;
 #endif
 #else
 #ifdef SVQC
@@ -75,14 +75,18 @@ void spawnfunc_weapon_arc(void) { weapon_defaultspawnfunc(WEP_ARC); }
 float W_Arc_Beam_Send(entity to, float sf)
 {
        WriteByte(MSG_ENTITY, ENT_CLIENT_ARC_BEAM);
-       sf = sf & 0x7F;
-       if(sound_allowed(MSG_BROADCAST, self.owner))
-               sf |= 0x80;
+
+       // don't send group 1, 2, or 3 if this beam is for the local player
+       if(to == self.owner) { sf &= ~7; }
        WriteByte(MSG_ENTITY, sf);
-       if(sf & 1) // main information
+       
+       if(sf & 1) // starting location // not sent if beam is for owner
        {
-               WriteByte(MSG_ENTITY, num_for_edict(self.owner));
-               WriteCoord(MSG_ENTITY, WEP_CVAR(arc, beam_range));
+               //WriteByte(MSG_ENTITY, num_for_edict(self.owner));
+               WriteCoord(MSG_ENTITY, self.beam_start_x);
+               WriteCoord(MSG_ENTITY, self.beam_start_y);
+               WriteCoord(MSG_ENTITY, self.beam_start_z);
+               //WriteCoord(MSG_ENTITY, WEP_CVAR(arc, beam_range));
        }
        if(sf & 2) // want/aim direction
        {
@@ -102,6 +106,7 @@ float W_Arc_Beam_Send(entity to, float sf)
        }
        return TRUE;
 }
+
 void W_Arc_Beam_Think(void)
 {
        float i, burst = TRUE;
@@ -153,7 +158,12 @@ void W_Arc_Beam_Think(void)
 
        W_SetupShot_Range(self.owner, TRUE, 0, "", 0, WEP_CVAR(arc, beam_damage) * dt, WEP_CVAR(arc, beam_range));
 
-       // network information: want/aim direction
+       // network information: shot origin and want/aim direction
+       if(self.beam_start != w_shotorg)
+       {
+               self.SendFlags |= 1;
+               self.beam_start = w_shotorg;
+       }
        if(self.beam_wantdir != w_shotdir)
        {
                self.SendFlags |= 2;
@@ -191,6 +201,10 @@ void W_Arc_Beam_Think(void)
                float blendfactor = bound(0, anglelimit * (1 - (WEP_CVAR(arc, beam_returnspeed) * dt)), 1);
                self.beam_dir = normalize((w_shotdir * (1 - blendfactor)) + (self.beam_dir * blendfactor));
 
+               // todo: figure out a way so that blendfactor becomes 0 at some point,
+               // currently self.beam_dir and w_shotdir never really become equal as there is no rounding/snapping point
+               // printf("blendfactor = %f\n", blendfactor);
+
                // network information: beam direction
                self.SendFlags |= 4;
 
@@ -410,7 +424,7 @@ void W_Arc_Beam(void)
        beam.shot_spread = 1;
        beam.bot_dodge = TRUE;
        beam.bot_dodgerating = WEP_CVAR(arc, beam_damage);
-       //Net_LinkEntity(beam, FALSE, 0, W_Arc_Beam_Send);
+       Net_LinkEntity(beam, FALSE, 0, W_Arc_Beam_Send);
 
        oldself = self;
        self = beam;