From b456cae0c3085b87e6f45a35c6cc827d32ee9644 Mon Sep 17 00:00:00 2001 From: subject9x Date: Tue, 29 Oct 2024 22:39:16 -0400 Subject: [PATCH] fix refactor: game beam handling. + turns out CSQC is kinda flaky on client-side hit detection, possibly through the dozens of addEntity() the game requires, which I think is causing client-side hit-boxes to change-size in almost every frame. + the fix is to rewire beam weapons back to something more like classic quake. Let the server dictate start/end, and target entity. + the only other option would have been dumping start/end for beams into the client's SendEnt func, clunky and spammy. + beam graphics need to generally synchronize with unit attacks, so using Item.SendEnt is kinda out too. + not super happy about this solution. --- client/main/client_parse_funcs.qc | 2 +- client/network/net_general.qc | 14 ++- client/util/headers/particle_sys.qh | 4 +- client/util/particle_sys.qc | 108 ++++++++++++------ common/data/data_values_particles.qc | 5 + common/data/defs/defs_item.qc | 1 + .../data/item/weapon/data_electro_repeater.qc | 77 +++++++------ common/data/item/weapon/data_light_laser.qc | 44 +++---- .../data/item/weapon/data_particle_cannon.qc | 78 +++++++------ main/client_utils.qc | 34 +++--- main/controllers/ctrl_weapon.qc | 2 +- main/headers/client_utils.qh | 2 +- main/headers/utils.qh | 2 +- main/map/map_damage_zone.qc | 2 +- main/utils.qc | 15 ++- 15 files changed, 236 insertions(+), 154 deletions(-) diff --git a/client/main/client_parse_funcs.qc b/client/main/client_parse_funcs.qc index 0d009d29..bf04c27e 100644 --- a/client/main/client_parse_funcs.qc +++ b/client/main/client_parse_funcs.qc @@ -68,7 +68,7 @@ float() CSQC_Parse_TempEntity = return TRUE; case TE_VFX_RAIL: - particle_spawn_beam(ReadByte(), te_read_vector(), te_read_vector(), ReadFloat()); + particle_spawn_beam(ReadByte(), ReadLong(), te_read_vector(), te_read_vector(), ReadFloat(), ReadByte()); return TRUE; case TE_PARTICLE_CUBE: diff --git a/client/network/net_general.qc b/client/network/net_general.qc index 6acdde7e..61589fba 100644 --- a/client/network/net_general.qc +++ b/client/network/net_general.qc @@ -431,8 +431,11 @@ void( float prevShield ) sendevent_shield_explode={ */ void() sendevent_handle_weaponfire={ local entity equip; + local entity unit; local float wepId; - + + unit = self; + particleDraw = vlen(CLIENT_vis_org - self.origin); wepId = 0; @@ -441,8 +444,13 @@ void() sendevent_handle_weaponfire={ equip = sendent_get_weapon( bitshift(1, wepId) ); if( equip ){ - if( (self.attackFlag & equip.w_group) && equip.itemMuzzleFlash ){ - te_weapon_fire_handler(equip); + if( (self.attackFlag & equip.w_group) && equip.beamFlag == FALSE ){ + te_weapon_fire_handler(equip, self); + self = equip; + if(self.itemMuzzleFlash){ + self.itemMuzzleFlash(); + } + self = unit; } } diff --git a/client/util/headers/particle_sys.qh b/client/util/headers/particle_sys.qh index 12cf93ff..1caf9fa7 100644 --- a/client/util/headers/particle_sys.qh +++ b/client/util/headers/particle_sys.qh @@ -183,9 +183,9 @@ void (vector from, vector to, float thickness, string texture, float aspect, flo //ported from effectinfo_api void( vector org, vector windVel ) te_mech_crit; -void( entity item )te_weapon_fire_handler; +void( entity item, entity parent )te_weapon_fire_handler; -void(float beamType, vector particleOrg, vector particleEnd, float width) particle_spawn_beam; +void(float beamType, float entId, vector particleOrg, vector particleEnd, float width, float impactType) particle_spawn_beam; //void() te_explode_mech_piece_th; //void(entity piece) te_explode_mech_piece; diff --git a/client/util/particle_sys.qc b/client/util/particle_sys.qc index 641361b1..cc6aacd8 100644 --- a/client/util/particle_sys.qc +++ b/client/util/particle_sys.qc @@ -242,7 +242,7 @@ void() cl_particles_fogFrame={ localcmd(newFog);*/ }; -void(entity item) te_weapon_fire_handler={ +void(entity item, entity parent) te_weapon_fire_handler={ local entity this; local entity parent; local vector unitOrg; @@ -250,37 +250,35 @@ void(entity item) te_weapon_fire_handler={ local vector adjPartOffset; local vector offset; - view = self.rootAngle; - + view = parent.rootAngle; view_x = 0; makevectors(view); this = self; self = item; util_getPartFromName( self.partParentId, this); + self = this; - if(this.data_type == DATA_VEHC){ - unitOrg = this.cacheGroundPos; + if(parent.data_type == DATA_VEHC){ + unitOrg = parent.cacheGroundPos; } else{ - unitOrg = this.rootOrigin; + unitOrg = parent.rootOrigin; } offset = unitOrg + (v_right * T_PART_PARENT_OFFSET_x) + (v_up * T_PART_PARENT_OFFSET_y) + (v_forward * T_PART_PARENT_OFFSET_z); //FPV z-offset is corrected at the parent-part origin step! - if(this.clientLocalNum == player_localentnum && CLIENT_server_ent.chaseActive == FALSE){ - offset = offset + (v_forward * this.cameraOffset_z); + if(parent.clientLocalNum == player_localentnum && CLIENT_server_ent.chaseActive == FALSE){ + offset = offset + (v_forward * parent.cameraOffset_z); } - adjPartOffset = self.compOffset - T_PART_PARENT_OFFSET; + adjPartOffset = item.compOffset - T_PART_PARENT_OFFSET; view = T_PART_PARENT_ANGL; view_x = view_x *-1; makevectors( view); offset = offset + (v_up * adjPartOffset_y) + (v_right * adjPartOffset_x) + (v_forward * adjPartOffset_z); - self.wepFireOffset = offset + (v_forward * self.wepFireOffsetCache_z) + (v_right * self.wepFireOffsetCache_x) + (v_up * self.wepFireOffsetCache_y); - self.itemMuzzleFlash(); - self = this; + item.wepFireOffset = offset + (v_forward * item.wepFireOffsetCache_z) + (v_right * item.wepFireOffsetCache_x) + (v_up * item.wepFireOffsetCache_y); }; /* @@ -1103,6 +1101,16 @@ void() particle_beam_las_draw={ Draw_CylindricLine(self.beamOrg, self.beamEnd, self.beamWidth, "particles/laserbeam", 0.5, time * (random() * -6), self.drawcolor1, 0.75, DRAWFLAG_NORMAL | DRAWFLAG_MIPMAP, CLIENT_vis_org); }; +void() particle_beam_pac_draw={ + if(vlen(self.beamOrg - CLIENT_vis_org) > PARTICLE_HAZ_DISTANCE){ + return; + } + if(self.beamActive == FALSE){ + return; + } + Draw_CylindricLine(self.beamOrg, self.beamEnd, self.beamWidth, "particles/laserbeam", 0.5, time * (random() * -6), self.drawcolor1, 0.75, DRAWFLAG_NORMAL | DRAWFLAG_MIPMAP, CLIENT_vis_org); +}; + void() particle_beam_lightning_draw={ local float segCount; local vector bAngl; @@ -1146,36 +1154,70 @@ void() particle_beam_lightning_draw={ }; - - //float beamType, vector particleOrg, vector particleEnd, float width, float aspect, float shift, vector colr, float alph -void(float beamType, vector particleOrg, vector particleEnd, float width) particle_spawn_beam={ +void(float beamType, float entId, vector particleOrg, vector particleEnd, float width, float impactType) particle_spawn_beam={ local entity ent; + local entity this; - ent = spawn(); + //'WORLD' beam effects, not bound to weapons + if(entId == 0){ + ent = spawn(); + if(!ent){ + return; + } + if(beamType == BEAM_LAS){ + ent.predraw = particle_beam_las_draw; + ent.nextthink = time + 0.2; + } + else if(beamType == BEAM_ESR){ + ent.predraw = particle_beam_lightning_draw; + ent.nextthink = time + 0.075; + } + else if( beamType == BEAM_PAC){ + ent.predraw = particle_beam_pac_draw; + ent.nextthink = 0.5; + } + else{ + //no-op, bad beam type + return; + } + ent.drawmask = MASK_NORMAL; + ent.origin = particleOrg; + ent.solid = SOLID_NOT; + ent.movetype = MOVETYPE_NONE; + setsize(ent, '-1 -1 -1', '1 1 1'); + setorigin(ent, ent.origin); + ent.beamOrg = particleOrg; + ent.beamEnd = particleEnd; + ent.beamWidth = width; + ent.beamActive = TRUE; + ent.think = particle_beam_th; + return; + } + + //WEAPON beam effects + ent = findfloat(world, entnum, fabs(rint(entId))); if(!ent){ return; } - if(beamType == 0){ - ent.predraw = particle_beam_las_draw; - ent.nextthink = time + 0.2; + if(!ent.owner){ + return; } - else{ - ent.predraw = particle_beam_lightning_draw; - ent.nextthink = time + 0.075; - } - ent.drawmask = MASK_NORMAL; - ent.origin = particleOrg; - ent.solid = SOLID_NOT; - ent.movetype = MOVETYPE_NONE; - setsize(ent, '-1 -1 -1', '1 1 1'); - setorigin(ent, ent.origin); - ent.beamOrg = particleOrg; + if(ent.beamActive){ + return; + } + ent.beamEnd = particleEnd; - ent.beamWidth = width; - ent.beamActive = TRUE; - ent.think = particle_beam_th; + ent.pcl_count = impactType; + + te_weapon_fire_handler(ent, ent.owner); + this = self; + self = ent; + if(self.itemMuzzleFlash){ + self.itemMuzzleFlash(); + } + self = this; }; diff --git a/common/data/data_values_particles.qc b/common/data/data_values_particles.qc index 318b8753..67d60db1 100644 --- a/common/data/data_values_particles.qc +++ b/common/data/data_values_particles.qc @@ -8,6 +8,11 @@ Overview: */ +//BEAMS +#define BEAM_LAS 0 +#define BEAM_ESR 1 +#define BEAM_PAC 2 + //Projectile Impact Events #define IMPACT_SKY 0 #define IMPACT_DIRT 1 diff --git a/common/data/defs/defs_item.qc b/common/data/defs/defs_item.qc index 81fdb8e4..6ef3f8f1 100644 --- a/common/data/defs/defs_item.qc +++ b/common/data/defs/defs_item.qc @@ -32,6 +32,7 @@ Overview .void() itemMuzzleFlash; #endif +.float beamFlag; // .float w_isburst; //ugh .float w_currentammo; .float burstRate; //percentage of reloadRate to use for burst-fire intervals. diff --git a/common/data/item/weapon/data_electro_repeater.qc b/common/data/item/weapon/data_electro_repeater.qc index a14ea906..3a206892 100644 --- a/common/data/item/weapon/data_electro_repeater.qc +++ b/common/data/item/weapon/data_electro_repeater.qc @@ -108,6 +108,7 @@ void() data_ini_attack_electro_repeater_; #ifdef CSQC void() te_beam_esr={ + local float len; local float segCount; local vector bAngl; local float segment; @@ -118,29 +119,36 @@ void() te_beam_esr={ segCount = 6; width = self.beamWidth; - segment = rint(vlen(self.beamEnd - self.wepFireOffset) / segCount); + len = vlen(self.beamEnd - self.wepFireOffset); + segment = rint(len / segCount); segOrg = self.wepFireOffset; bAngl = vectoangles(self.beamEnd - self.wepFireOffset); bAngl_x = bAngl_x * -1; makevectors(bAngl); - nexOrg = self.wepFireOffset + (v_forward * segment) + (v_right * crandom() * 4) + (v_up * crandom() * 6); - Draw_CylindricLine(self.wepFireOffset, nexOrg, width, "particles/electro_beam", 0.1, time * 0.1, '0.17 0.33 1.0', 1.0, DRAWFLAG_NORMAL | DRAWFLAG_MIPMAP, CLIENT_vis_org); - segOrg = nexOrg; - segCount = segCount - 1; + if(len > 100){ + nexOrg = self.wepFireOffset + (v_forward * segment) + (v_right * crandom() * 4) + (v_up * crandom() * 6); + Draw_CylindricLine(self.wepFireOffset, nexOrg, width, "particles/electro_beam", 0.1, time * 0.1, '0.17 0.33 1.0', 1.0, DRAWFLAG_NORMAL | DRAWFLAG_MIPMAP, CLIENT_vis_org); + + + segOrg = nexOrg; + segCount = segCount - 1; - for( itr = segCount; itr < (segment-2); itr = itr + 1){ - nexOrg = self.wepFireOffset + (v_forward * segment * itr) + (v_right * crandom() * 2) + (v_up * crandom() * 4); + for( itr = segCount; itr < (segment-2); itr = itr + 1){ + nexOrg = self.wepFireOffset + (v_forward * segment * itr) + (v_right * crandom() * 2) + (v_up * crandom() * 4); - Draw_CylindricLine(segOrg, nexOrg, width, "particles/electro_beam", 0.1, time * 0.1, '0.17 0.33 1.0', 1.0, DRAWFLAG_NORMAL | DRAWFLAG_MIPMAP, CLIENT_vis_org); - - width = max(1, width - 1); + Draw_CylindricLine(segOrg, nexOrg, width, "particles/electro_beam", 0.1, time * 0.1, '0.17 0.33 1.0', 1.0, DRAWFLAG_NORMAL | DRAWFLAG_MIPMAP, CLIENT_vis_org); + + width = max(1, width - 1); - segOrg = nexOrg; + segOrg = nexOrg; + } + } + else{ + segOrg = self.wepFireOffset; } Draw_CylindricLine(segOrg, self.beamEnd, width, "particles/electro_beam", 0.1, time * 0.1, '0.17 0.33 1.0', 1.0, DRAWFLAG_NORMAL | DRAWFLAG_MIPMAP, CLIENT_vis_org); - }; void() te_muzzle_esr={ local vector startOrg; @@ -149,33 +157,27 @@ void() te_muzzle_esr={ local float impactStyle; startOrg = self.wepFireOffset; - - traceline(startOrg, self.owner.laser_sight_org, FALSE, self.owner); - endOrg = trace_endpos; + endOrg = self.beamEnd; norm = normalize(endOrg - startOrg); sound7(self, CHAN_AUTO, self.fire_sound, 1, ATTN_NORM, (0.5 + (random() * 0.5)) * 175, 0 ); - //trailparticles( world, particleeffectnum("TE_ESR_RAIL"), startOrg, endOrg ); - if( particleDraw < PARTICLE_HAZ_DISTANCE / 2){ pointparticles( particleeffectnum("TE_ESR_MUZZLE"), startOrg, norm* 1, 1); - impactStyle = te_impact_type(endOrg, trace_ent, trace_dphitcontents); - if(impactStyle == IMPACT_ARMOR){ + if(self.pcl_count == IMPACT_ARMOR){ pointparticles( particleeffectnum("TE_ESR_IMPACT_ARMOR"), endOrg, norm * -6, 1); } - if(impactStyle == IMPACT_DIRT){ + if(self.pcl_count == IMPACT_DIRT){ pointparticles( particleeffectnum("TE_ESR_IMPACT_DIRT"), endOrg, norm * -4, 1); pointparticles(PTC_HIT_DIRT_ENE_SML, endOrg, trace_plane_normal * -1, 1); } } - self.beamTime = time + 0.05; + self.beamTime = time + 0.02; self.beamOrg = startOrg; - self.beamEnd = endOrg; self.beamWidth = 4.0; self.beamActive = TRUE; }; @@ -199,6 +201,7 @@ void() data_ini_electro_repeater_={ self.spreadDefault = '0.1 0.1 0'; self.wepFireOffset = '0 0 8'; self.burstRate = 0; + self.beamFlag = TRUE; precache_sound("sound/weapons/esr_ovrht.ogg"); #ifdef CSQC @@ -237,7 +240,7 @@ void() data_ini_electro_repeater_={ #ifdef SSQC void() data_ini_attack_electro_repeater_={ - + local float impactStyle; if( self.owner.energy <= self.energyRate ){ self.wepReloadState = RELOADING; self.w_currentammo = self.reloadMax / 1.125; @@ -271,20 +274,26 @@ void() data_ini_attack_electro_repeater_={ } ctrl_weapon_fireOffset(); + impactStyle = IMPACT_SKY; self.owner.attackFlag = self.owner.attackFlag | self.w_group; - if( (trace_dphitcontents & DPCONTENTS_SKY) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) ){ - return; - } - if( trace_ent.takedamage ){ - if( trace_ent.shield > 0 ){ - t_damage_shield(trace_ent, self, self.owner, self.damageValue * 0.5, FIRE_ENDPOINT, FALSE); - } - else{ - HIT_LOCATION = t_damage(trace_ent, self, self.owner, self.damageValue, FIRE_ENDPOINT, '0 0 0'); - if( HIT_LOCATION && !(self.owner.statTargetHitParts & HIT_LOCATION) ){ - self.owner.statTargetHitParts = self.owner.statTargetHitParts | HIT_LOCATION; + if( !(trace_dphitcontents & DPCONTENTS_SKY) && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) ){ + impactStyle = IMPACT_DIRT; + + if( trace_ent.takedamage ){ + impactStyle = IMPACT_ARMOR; + + if( trace_ent.shield > 0 ){ + t_damage_shield(trace_ent, self, self.owner, self.damageValue * 0.5, FIRE_ENDPOINT, FALSE); + impactStyle = IMPACT_SHIELD; + } + else{ + HIT_LOCATION = t_damage(trace_ent, self, self.owner, self.damageValue, FIRE_ENDPOINT, '0 0 0'); + if( HIT_LOCATION && !(self.owner.statTargetHitParts & HIT_LOCATION) ){ + self.owner.statTargetHitParts = self.owner.statTargetHitParts | HIT_LOCATION; + } } } } + client_send_particle_rail( BEAM_ESR, num_for_edict(self), FIRE_ORIGIN, FIRE_ENDPOINT, 4, impactStyle); }; #endif \ No newline at end of file diff --git a/common/data/item/weapon/data_light_laser.qc b/common/data/item/weapon/data_light_laser.qc index c5593519..11d3c9fc 100644 --- a/common/data/item/weapon/data_light_laser.qc +++ b/common/data/item/weapon/data_light_laser.qc @@ -26,9 +26,7 @@ void() te_muzzle_las={ local vector norm; startOrg = self.wepFireOffset; - - traceline(startOrg, self.owner.laser_sight_org, FALSE, self.owner); - endOrg = trace_endpos; + endOrg = self.beamEnd; norm = normalize(endOrg - startOrg); @@ -41,18 +39,16 @@ void() te_muzzle_las={ self.beamTime = time + 0.2; self.beamOrg = startOrg; - self.beamEnd = endOrg; self.beamWidth = 3.0; self.beamActive = TRUE; //trailparticles( world, particleeffectnum("TE_LAS_RAIL"), startOrg, endOrg ); if( particleDraw < PARTICLE_HAZ_DISTANCE / 2){ - impactStyle = te_impact_type(endOrg, trace_ent, trace_dphitcontents); pointparticles( particleeffectnum("TE_LAS_MUZZLE"), startOrg, norm * -2, 1); - if(impactStyle == IMPACT_ARMOR){ + if(self.pcl_count == IMPACT_ARMOR){ pointparticles(particleeffectnum("TE_LAS_HIT"), endOrg + (norm * -2), norm, 1); } - else if(impactStyle == IMPACT_DIRT){ + else if(self.pcl_count == IMPACT_DIRT){ pointparticles(particleeffectnum("TE_LAS_DIRT"), endOrg + (norm * -2), norm, 1); pointparticles(PTC_HIT_DIRT_ENE_SML, endOrg, trace_plane_normal * -1, 1); } @@ -78,6 +74,7 @@ void() data_ini_light_laser_={ self.spreadDefault = '0.0075 0.0075 0'; self.wepFireOffset = '0 0 3.5'; self.burstRate = 0; + self.beamFlag = TRUE; #ifdef CSQC precache_sound("sound/weapons/laser_fire.ogg"); @@ -102,6 +99,8 @@ void() data_ini_light_laser_={ #ifdef SSQC void() data_ini_attack_laser_={ + local float impactStyle; + if( !ctrl_weapon_checkEnergy() ){ return; } @@ -109,22 +108,27 @@ void() data_ini_attack_laser_={ ctrl_weapon_fireOffset(); ctrl_weapon_updateAmmo( FALSE ); - + impactStyle = IMPACT_SKY; self.owner.attackFlag = self.owner.attackFlag | self.w_group; - if( (trace_dphitcontents & DPCONTENTS_SKY) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) ){ - return; - } - - if( trace_ent.takedamage ){ - if( trace_ent.shield > 0 ){ - t_damage_shield(trace_ent, self,self.owner, self.damageValue * LIGHT_LAS_SHIELD_BONUS, trace_endpos, FALSE); - } - else{ - HIT_LOCATION = t_damage(trace_ent, self, FIRE_ENT, self.damageValue, FIRE_ENDPOINT, '0 0 0'); - if( HIT_LOCATION && !(self.owner.statTargetHitParts & HIT_LOCATION) ){ - self.owner.statTargetHitParts = self.owner.statTargetHitParts | HIT_LOCATION; + + if( !(trace_dphitcontents & DPCONTENTS_SKY) && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) ){ + impactStyle = IMPACT_DIRT; + + if( trace_ent.takedamage ){ + impactStyle = IMPACT_ARMOR; + + if( trace_ent.shield > 0 ){ + t_damage_shield(trace_ent, self,self.owner, self.damageValue * LIGHT_LAS_SHIELD_BONUS, trace_endpos, FALSE); + impactStyle = IMPACT_SHIELD; + } + else{ + HIT_LOCATION = t_damage(trace_ent, self, FIRE_ENT, self.damageValue, FIRE_ENDPOINT, '0 0 0'); + if( HIT_LOCATION && !(self.owner.statTargetHitParts & HIT_LOCATION) ){ + self.owner.statTargetHitParts = self.owner.statTargetHitParts | HIT_LOCATION; + } } } } + client_send_particle_rail( BEAM_LAS, num_for_edict(self), FIRE_ORIGIN, FIRE_ENDPOINT, 4, impactStyle); }; #endif \ No newline at end of file diff --git a/common/data/item/weapon/data_particle_cannon.qc b/common/data/item/weapon/data_particle_cannon.qc index d45736d0..f4be9272 100644 --- a/common/data/item/weapon/data_particle_cannon.qc +++ b/common/data/item/weapon/data_particle_cannon.qc @@ -30,8 +30,7 @@ void() te_muzzle_pac={ local float impactStyle; startOrg = self.wepFireOffset; - traceline(startOrg, self.owner.laser_sight_org, FALSE, self.owner); - endOrg = trace_endpos; + endOrg = self.beamEnd; norm = normalize(endOrg - startOrg); if( vlen(endOrg - startOrg) >= 1500 ){ @@ -46,19 +45,16 @@ void() te_muzzle_pac={ if( particleDraw < PARTICLE_HAZ_DISTANCE / 2){ pointparticles( particleeffectnum("TE_PAC_MUZZLE"), startOrg, norm * 2, 1); - impactStyle = te_impact_type(endOrg, trace_ent, trace_dphitcontents); - - if(impactStyle == IMPACT_ARMOR){ + if(self.pcl_count == IMPACT_ARMOR){ pointparticles( particleeffectnum("TE_PAC_IMPACT_ARMOR"), endOrg, norm * -6, 1); } - else if(impactStyle == IMPACT_DIRT){ + else if(self.pcl_count == IMPACT_DIRT){ pointparticles( particleeffectnum("TE_PAC_IMPACT_GROUND"), endOrg, norm * -4, 1); pointparticles(PTC_HIT_DIRT_ENE_LRG, endOrg, trace_plane_normal * -1, 1); } } self.beamActive = TRUE; - self.beamEnd = endOrg; self.beamWidth = 3.0; self.beamTime = time + 1.0; self.beamAlpha = 0.8; @@ -83,6 +79,7 @@ void() data_ini_particle_cannon_={ self.spreadDefault = '0.0025 0.0025 0'; self.wepFireOffset = '0 0 6.75'; self.burstRate = 0; + self.beamFlag = TRUE; #ifdef CSQC precache_sound("sound/weapons/pac_fire.ogg"); @@ -112,6 +109,7 @@ void() data_ini_attack_particle_cannon_={ local vector strikePoint; local float oldShields; local float dmgArmor, dmgShield; + local float impactStyle; if( !ctrl_weapon_checkEnergy() ){ return; @@ -121,42 +119,50 @@ void() data_ini_attack_particle_cannon_={ ctrl_weapon_updateAmmo( FALSE ); - strikePoint = FIRE_ENDPOINT + (v_forward * -5); - - dmgArmor = self.damageValue; - dmgShield = 0; - if( trace_ent.takedamage ){ + impactStyle = IMPACT_SKY; + if( !(trace_dphitcontents & DPCONTENTS_SKY) && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) ){ + impactStyle = IMPACT_DIRT; - //strike a unit, not a building - if( trace_ent.shield > 0 ){ - if( trace_ent.shield <= (trace_ent.shieldMax * 0.33) ){ - dmgShield = dmgArmor * 0.15; + strikePoint = FIRE_ENDPOINT + (v_forward * -5); + + dmgArmor = self.damageValue; + dmgShield = 0; + if( trace_ent.takedamage ){ + impactStyle = IMPACT_ARMOR; + + //strike a unit, not a building + if( trace_ent.shield > 0 ){ + impactStyle = IMPACT_SHIELD; + if( trace_ent.shield <= (trace_ent.shieldMax * 0.33) ){ + dmgShield = dmgArmor * 0.15; + } + else{ + dmgShield = dmgArmor * 0.25; + } + dmgArmor = dmgArmor - dmgShield; } - else{ - dmgShield = dmgArmor * 0.25; + if( (trace_ent.flags & FL_UNIT) ){ + if( trace_ent.vec_size <= 1 ){ + dmgArmor = dmgArmor * 0.7; + } + else if( trace_ent.vec_size == 2){ + dmgArmor = dmgArmor * 0.85; + } } - dmgArmor = dmgArmor - dmgShield; - } - if( (trace_ent.flags & FL_UNIT) ){ - if( trace_ent.vec_size <= 1 ){ - dmgArmor = dmgArmor * 0.7; + + if( dmgShield ){ + impactStyle = IMPACT_SHIELD; + t_damage_shield(trace_ent, self, FIRE_ENT, dmgShield, FIRE_ENDPOINT + (v_forward*3), FALSE); } - else if( trace_ent.vec_size == 2){ - dmgArmor = dmgArmor * 0.85; + + HIT_LOCATION = t_damage(trace_ent, self, FIRE_ENT, dmgArmor, FIRE_ENDPOINT + (v_forward*3), '0 0 0'); + + if( HIT_LOCATION && (trace_ent.shield < 101 && trace_ent.shield > 0) ){ + self.owner.statTargetHitParts = self.owner.statTargetHitParts | HIT_LOCATION; } } - - if( dmgShield ){ - t_damage_shield(trace_ent, self, FIRE_ENT, dmgShield, FIRE_ENDPOINT + (v_forward*3), FALSE); - } - - HIT_LOCATION = t_damage(trace_ent, self, FIRE_ENT, dmgArmor, FIRE_ENDPOINT + (v_forward*3), '0 0 0'); - - if( HIT_LOCATION && (trace_ent.shield < 101 && trace_ent.shield > 0) ){ - self.owner.statTargetHitParts = self.owner.statTargetHitParts | HIT_LOCATION; - } } - self.owner.attackFlag = self.owner.attackFlag | self.w_group; + client_send_particle_rail( BEAM_PAC, num_for_edict(self), FIRE_ORIGIN, FIRE_ENDPOINT, 4, impactStyle); }; #endif \ No newline at end of file diff --git a/main/client_utils.qc b/main/client_utils.qc index 19daa6c2..3dc37d28 100644 --- a/main/client_utils.qc +++ b/main/client_utils.qc @@ -759,32 +759,34 @@ void( float particleEffectId, vector particleOrg, vector particleVel, float part WriteByte( MSG_BROADCAST, SVC_TEMPENTITY ); WriteByte( MSG_BROADCAST, TE_VFX_POINT ); WriteShort( MSG_BROADCAST, particleEffectId ); - WriteCoord(MSG_BROADCAST, particleOrg_x); - WriteCoord(MSG_BROADCAST, particleOrg_y); - WriteCoord(MSG_BROADCAST, particleOrg_z); + WriteCoord(MSG_BROADCAST, particleOrg_x ); + WriteCoord(MSG_BROADCAST, particleOrg_y ); + WriteCoord(MSG_BROADCAST, particleOrg_z ); - WriteCoord(MSG_BROADCAST, particleVel_x); - WriteCoord(MSG_BROADCAST, particleVel_y); - WriteCoord(MSG_BROADCAST, particleVel_z); + WriteCoord(MSG_BROADCAST, particleVel_x ); + WriteCoord(MSG_BROADCAST, particleVel_y ); + WriteCoord(MSG_BROADCAST, particleVel_z ); - WriteShort(MSG_BROADCAST, particleCount); + WriteShort(MSG_BROADCAST, particleCount ); }; -//void( float entityId, float particleEffectId, vector particleOrg, vector particleEnd ) client_send_particle_rail={ -void(float beamType, vector particleOrg, vector particleEnd, float width) client_send_particle_rail={ + +void(float beamType, float entId, vector particleOrg, vector particleEnd, float width, float impactType) client_send_particle_rail={ WriteByte( MSG_BROADCAST, SVC_TEMPENTITY ); WriteByte( MSG_BROADCAST, TE_VFX_RAIL ); WriteByte( MSG_BROADCAST, beamType ); + WriteLong( MSG_BROADCAST, entId ); - WriteCoord(MSG_BROADCAST, particleOrg_x); - WriteCoord(MSG_BROADCAST, particleOrg_y); - WriteCoord(MSG_BROADCAST, particleOrg_z); + WriteCoord( MSG_BROADCAST, particleOrg_x ); + WriteCoord( MSG_BROADCAST, particleOrg_y ); + WriteCoord( MSG_BROADCAST, particleOrg_z ); - WriteCoord(MSG_BROADCAST, particleEnd_x); - WriteCoord(MSG_BROADCAST, particleEnd_y); - WriteCoord(MSG_BROADCAST, particleEnd_z); + WriteCoord( MSG_BROADCAST, particleEnd_x ); + WriteCoord( MSG_BROADCAST, particleEnd_y ); + WriteCoord( MSG_BROADCAST, particleEnd_z ); - WriteFloat(MSG_BROADCAST, width); + WriteFloat( MSG_BROADCAST, width ); + WriteByte( MSG_BROADCAST, impactType ); }; /* diff --git a/main/controllers/ctrl_weapon.qc b/main/controllers/ctrl_weapon.qc index fd657b1f..0bb6b934 100644 --- a/main/controllers/ctrl_weapon.qc +++ b/main/controllers/ctrl_weapon.qc @@ -155,7 +155,7 @@ void() ctrl_weapon_fireOffset={ FIRE_ORIGIN = FIRE_ENT.origin + (v_forward * FIRE_OFFSET_z) + (v_right * FIRE_OFFSET_x) + (v_up * FIRE_OFFSET_y); } - FIRE_ENDPOINT = util_applySpreadToTrace( FIRE_ENT.v_angle, self.w_range );//becomes 'endpoint' for shot angle + FIRE_ENDPOINT = util_applySpreadToTrace( FIRE_ORIGIN, FIRE_ENT.v_angle, self.w_range );//becomes 'endpoint' for shot angle }; diff --git a/main/headers/client_utils.qh b/main/headers/client_utils.qh index ab4fc923..3c29905e 100644 --- a/main/headers/client_utils.qh +++ b/main/headers/client_utils.qh @@ -52,4 +52,4 @@ void() client_update_faction; void() client_update_losses; void( float particleEffectId, vector particleOrg, vector particleVel, float particleCount ) client_send_particle; -void(float beamType, vector particleOrg, vector particleEnd, float width) client_send_particle_rail; \ No newline at end of file +void(float beamType, float entId, vector particleOrg, vector particleEnd, float width, float impactType) client_send_particle_rail; \ No newline at end of file diff --git a/main/headers/utils.qh b/main/headers/utils.qh index 93067e37..f0db82b9 100644 --- a/main/headers/utils.qh +++ b/main/headers/utils.qh @@ -44,7 +44,7 @@ void(entity ent, vector pnt) util_chekPointToHitDir; float(float numOfSides) util_roll_dice; -vector( vector viewAngle, float idealRange) util_applySpreadToTrace; +vector( vector fireOrg, vector viewAngle, float idealRange) util_applySpreadToTrace; vector( vector start, vector offsets, vector viewAngle) util_getOffsetOfVector; float(float v) anglemod; diff --git a/main/map/map_damage_zone.qc b/main/map/map_damage_zone.qc index d0a6af1e..693705c5 100644 --- a/main/map/map_damage_zone.qc +++ b/main/map/map_damage_zone.qc @@ -181,7 +181,7 @@ void() map_damage_zone_crs_think={ org = self.view_ofs + (randompos(self.maxs, self.mins) * 0.5); hit = unit.origin + (randompos(unit.maxs, unit.mins) * 0.85); traceline(org, hit, MOVE_NORMAL, self); - client_send_particle_rail( 1, org, trace_endpos, 4 ); + client_send_particle_rail( BEAM_ESR, FALSE, org, trace_endpos, 4, 0 ); if( (unit.flags & FL_CLIENT) ){ self.SendFlags = self.SendFlags | SENDFLAG_CRIT; diff --git a/main/utils.qc b/main/utils.qc index 260b34ec..75b50980 100644 --- a/main/utils.qc +++ b/main/utils.qc @@ -127,11 +127,12 @@ vector(vector facing, vector centerpoint, vector sz_max) util_findOpenSpawnArea= //applies 'spread' to the endpos of a previous trace //spread values are taken as cumulatives - add all spread maximums together //vector( vector viewAngle, float idealRange, vector weaponSpread, float playerAcc ) util_applySpreadToTrace={ -vector( vector viewAngle, float idealRange ) util_applySpreadToTrace={ +vector( vector fireOrg, vector viewAngle, float idealRange ) util_applySpreadToTrace={ //local vector direction; //shot dispersion disabled //local vector acc; local vector wepAim; local vector targVel; + local vector endPos; targVel = '0 0 0'; if( (self.owner.enemy.flags & FL_CLIENT) ){ @@ -155,7 +156,7 @@ vector( vector viewAngle, float idealRange ) util_applySpreadToTrace={ } else{ //Player aiming - wepAim = normalize( self.owner.laser_sight_org - FIRE_ORIGIN ); + wepAim = normalize( self.owner.laser_sight_org - fireOrg ); } //08-2020: shot dispersion has been disabled because I can't find a clean/lightweight //means of sending this information over the network @@ -168,11 +169,15 @@ vector( vector viewAngle, float idealRange ) util_applySpreadToTrace={ //acc_y = acc_y * crandom(); //direction = wepAim + (acc_x * v_right) + (acc_y * v_up); - self.owner.dphitcontentsmask = DPCONTENTS_OPAQUE | Q3SURFACEFLAG_SKY | DPCONTENTS_SOLID | DPCONTENTS_BODY ; - traceline (FIRE_ORIGIN, FIRE_ORIGIN + wepAim*idealRange, FALSE, self.owner); + self.owner.dphitcontentsmask = (DPCONTENTS_OPAQUE | Q3SURFACEFLAG_SKY | DPCONTENTS_SOLID | DPCONTENTS_BODY) ; + traceline (fireOrg, fireOrg + (wepAim * idealRange), MOVE_MISSILE, self.owner); self.owner.dphitcontentsmask = 0; - return trace_endpos; + endPos_x = trace_endpos_x; + endPos_y = trace_endpos_y; + endPos_z = trace_endpos_z; + + return endPos; }; //simply returns a vector offset from an origin along a given angle