From a0aacf06bea12f7e45e0b1cb52beb75bdcf9f557 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 2 Jan 2025 23:30:18 +0000 Subject: [PATCH] Add support for networked effect colors --- qcsrc/common/effects/all.qc | 73 +++++++++++++++++--- qcsrc/common/effects/all.qh | 2 +- qcsrc/common/effects/effect.qh | 2 + qcsrc/common/mutators/mutator/nades/nades.qc | 62 +++++++++-------- qcsrc/common/weapons/all.qc | 2 +- 5 files changed, 102 insertions(+), 39 deletions(-) diff --git a/qcsrc/common/effects/all.qc b/qcsrc/common/effects/all.qc index d3a144620..47af03cb7 100644 --- a/qcsrc/common/effects/all.qc +++ b/qcsrc/common/effects/all.qc @@ -1,5 +1,10 @@ #include "all.qh" +const int EFF_NET_VELOCITY = BIT(0); +const int EFF_NET_COLOR_MIN = BIT(1); +const int EFF_NET_COLOR_MAX = BIT(2); +const int EFF_NET_COLOR_SAME = BIT(3); // optimisation bit for sending only one color + REGISTER_NET_TEMP(net_effect) #ifdef CSQC NET_HANDLE(net_effect, bool isNew) @@ -10,20 +15,41 @@ NET_HANDLE(net_effect, bool isNew) vector vel = '0 0 0'; int eff_cnt = 1; + int eff_flags = 0; bool eff_trail = eff.eent_eff_trail; vector v = ReadVector(); + int extraflags = ReadByte(); + + particles_colormin = particles_colormax = '0 0 0'; - bool use_vel = ReadByte(); - if(use_vel) + if(extraflags & EFF_NET_VELOCITY) vel = ReadVector(); + if(extraflags & EFF_NET_COLOR_MIN) + { + particles_colormin.x = ReadByte() / 16; + particles_colormin.y = ReadByte() / 16; + particles_colormin.z = ReadByte() / 16; + eff_flags |= PARTICLES_USECOLOR; + } + + if(extraflags & EFF_NET_COLOR_MAX) + { + particles_colormax.x = ReadByte() / 16; + particles_colormax.y = ReadByte() / 16; + particles_colormax.z = ReadByte() / 16; + eff_flags |= PARTICLES_USECOLOR; + } + else if(extraflags & EFF_NET_COLOR_SAME) + particles_colormax = particles_colormin; + if(!eff_trail) eff_cnt = ReadByte(); if(eff_trail) - WarpZone_TrailParticles(NULL, particleeffectnum(eff), v, vel); + WarpZone_TrailParticles_WithMultiplier(NULL, particleeffectnum(eff), v, vel, 1, eff_flags); else - pointparticles(eff, v, vel, eff_cnt); + boxparticles(particleeffectnum(eff), NULL, v, v, vel, vel, 1, eff_flags); return true; } #endif @@ -39,19 +65,44 @@ bool Net_Write_Effect(entity this, entity client, int sf) : WriteByte(channel, this.m_id); WriteVector(channel, this.eent_net_location); + int extraflags = 0; + if(this.eent_net_velocity != '0 0 0') + extraflags |= EFF_NET_VELOCITY; + if(this.eent_net_color_min != '0 0 0') + extraflags |= EFF_NET_COLOR_MIN; + // optimisation: only send one color if the min and max match + if(this.eent_net_color_min != '0 0 0' && this.eent_net_color_min == this.eent_net_color_max) + extraflags |= EFF_NET_COLOR_SAME; + else if(this.eent_net_color_max != '0 0 0') + extraflags |= EFF_NET_COLOR_MAX; + + WriteByte(channel, extraflags); + // attempt to save a tiny bit more bandwidth by not sending velocity if it isn't set - if(this.eent_net_velocity) - { - WriteByte(channel, true); + if(extraflags & EFF_NET_VELOCITY) WriteVector(channel, this.eent_net_velocity); + + if(extraflags & EFF_NET_COLOR_MIN) + { + vector col = this.eent_net_color_min; + WriteByte(channel, rint(bound(0, 16 * col.x, 255))); + WriteByte(channel, rint(bound(0, 16 * col.y, 255))); + WriteByte(channel, rint(bound(0, 16 * col.z, 255))); + } + + if(extraflags & EFF_NET_COLOR_MAX) + { + vector col = this.eent_net_color_max; + WriteByte(channel, rint(bound(0, 16 * col.x, 255))); + WriteByte(channel, rint(bound(0, 16 * col.y, 255))); + WriteByte(channel, rint(bound(0, 16 * col.z, 255))); } - else { WriteByte(channel, false); } if(!this.eent_eff_trail) { WriteByte(channel, this.eent_net_count); } return true; } -void Send_Effect_Except(entity eff, vector eff_loc, vector eff_vel, int eff_cnt, entity ignore) +void Send_Effect_Except(entity eff, vector eff_loc, vector eff_vel, int eff_cnt, vector eff_col_min, vector eff_col_max, entity ignore) { if(!eff) { return; } if(!eff.eent_eff_trail && !eff_cnt) { return; } // effect has no count! @@ -63,6 +114,8 @@ void Send_Effect_Except(entity eff, vector eff_loc, vector eff_vel, int eff_cnt, net_eff.eent_net_location = eff_loc; net_eff.eent_net_count = eff_cnt; net_eff.eent_eff_trail = eff.eent_eff_trail; + net_eff.eent_net_color_min = eff_col_min; + net_eff.eent_net_color_max = eff_col_max; FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != ignore && !(IS_SPEC(it) && it.enemy && it.enemy == ignore), Net_Write_Effect(net_eff, it, 0)); delete(net_eff); @@ -70,7 +123,7 @@ void Send_Effect_Except(entity eff, vector eff_loc, vector eff_vel, int eff_cnt, void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt) { - Send_Effect_Except(eff, eff_loc, eff_vel, eff_cnt, NULL); + Send_Effect_Except(eff, eff_loc, eff_vel, eff_cnt, '0 0 0', '0 0 0', NULL); } void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt) diff --git a/qcsrc/common/effects/all.qh b/qcsrc/common/effects/all.qh index 525336377..8987437bb 100644 --- a/qcsrc/common/effects/all.qh +++ b/qcsrc/common/effects/all.qh @@ -3,7 +3,7 @@ #include "effect.qh" #ifdef SVQC -void Send_Effect_Except(entity eff, vector eff_loc, vector eff_vel, int eff_cnt, entity ignore); +void Send_Effect_Except(entity eff, vector eff_loc, vector eff_vel, int eff_cnt, vector eff_col_min, vector eff_col_max, entity ignore); void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt); void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt); #endif diff --git a/qcsrc/common/effects/effect.qh b/qcsrc/common/effects/effect.qh index 7802f0a91..db43426b4 100644 --- a/qcsrc/common/effects/effect.qh +++ b/qcsrc/common/effects/effect.qh @@ -22,6 +22,8 @@ .vector eent_net_location; .vector eent_net_velocity; +.vector eent_net_color_min; +.vector eent_net_color_max; .int eent_net_count; entity Create_Effect_Entity(string eff_name, bool eff_trail) diff --git a/qcsrc/common/mutators/mutator/nades/nades.qc b/qcsrc/common/mutators/mutator/nades/nades.qc index 323c14d98..7eb61fd3e 100644 --- a/qcsrc/common/mutators/mutator/nades/nades.qc +++ b/qcsrc/common/mutators/mutator/nades/nades.qc @@ -193,6 +193,15 @@ void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expan .entity nade_spawnloc; +vector nades_PlayerColor(entity this, bool isPants) +{ + if(teamplay) + return Team_ColorRGB(this.team); + + // logic copied from Scoreboard_GetName + int col = (this.colormap >= 1024) ? this.colormap - 1024 : this.clientcolors; + return (isPants) ? colormapPaletteColor(col % 16, true) : colormapPaletteColor(floor(col / 16), false); +} void nade_timer_think(entity this) { @@ -433,8 +442,10 @@ void nade_ice_think(entity this) { if ( autocvar_g_nades_ice_explode ) { - entity expef = EFFECT_NADE_EXPLODE(this.realowner.team); - Send_Effect(expef, this.origin + '0 0 1', '0 0 0', 1); + vector expcol_min = nades_PlayerColor(this.realowner, false); + vector expcol_max = nades_PlayerColor(this.realowner, true); + entity expef = EFFECT_NADE_EXPLODE_NEUTRAL; + Send_Effect_Except(expef, this.origin + '0 0 1', '0 0 0', 1, expcol_min, expcol_max, NULL); sound(this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM); normal_nade_boom(this); @@ -806,8 +817,10 @@ void nade_darkness_think(entity this) { if ( autocvar_g_nades_darkness_explode ) { - entity expef = EFFECT_NADE_EXPLODE(this.realowner.team); - Send_Effect(expef, this.origin + '0 0 1', '0 0 0', 1); + vector expcol_min = nades_PlayerColor(this.realowner, false); + vector expcol_max = nades_PlayerColor(this.realowner, true); + entity expef = EFFECT_NADE_EXPLODE_NEUTRAL; + Send_Effect_Except(expef, this.origin + '0 0 1', '0 0 0', 1, expcol_min, expcol_max, NULL); sound(this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM); normal_nade_boom(this); @@ -898,40 +911,35 @@ void nade_boom(entity this) { entity expef = NULL; bool nade_blast = true; + vector expcol_min = '0 0 0', expcol_max = '0 0 0'; -#define GET_NADE_TYPE_SPAWN_EFFECT(team_owner) \ - ((team_owner) == NUM_TEAM_1 ? EFFECT_SPAWN_RED : \ - ((team_owner) == NUM_TEAM_2 ? EFFECT_SPAWN_BLUE : \ - ((team_owner) == NUM_TEAM_3 ? EFFECT_SPAWN_YELLOW : \ - ((team_owner) == NUM_TEAM_4 ? EFFECT_SPAWN_PINK : \ - EFFECT_SPAWN_NEUTRAL)))) - -#define SET_NADE_EFFECT(nade_type, blast, exp_effect) \ +#define SET_NADE_EFFECT(nade_type, blast, exp_effect, exp_color_min, exp_color_max) \ case nade_type: \ nade_blast = blast; \ expef = exp_effect; \ + expcol_min = exp_color_min; \ + expcol_max = exp_color_max; \ break switch ( REGISTRY_GET(Nades, STAT(NADE_BONUS_TYPE, this)) ) { - SET_NADE_EFFECT(NADE_TYPE_NAPALM, autocvar_g_nades_napalm_blast, EFFECT_EXPLOSION_MEDIUM); - SET_NADE_EFFECT(NADE_TYPE_ICE, false, EFFECT_ELECTRO_COMBO /* hookbomb_explode electro_combo bigplasma_impact */); - SET_NADE_EFFECT(NADE_TYPE_TRANSLOCATE, false, NULL); - SET_NADE_EFFECT(NADE_TYPE_MONSTER, true, (!autocvar_g_monsters) ? EFFECT_NADE_EXPLODE(this.realowner.team) : NULL); - SET_NADE_EFFECT(NADE_TYPE_SPAWN, false, GET_NADE_TYPE_SPAWN_EFFECT(this.realowner.team)); - SET_NADE_EFFECT(NADE_TYPE_HEAL, false, EFFECT_SPAWN_RED); - SET_NADE_EFFECT(NADE_TYPE_ENTRAP, false, EFFECT_SPAWN_YELLOW); - SET_NADE_EFFECT(NADE_TYPE_VEIL, false, EFFECT_SPAWN_NEUTRAL); - SET_NADE_EFFECT(NADE_TYPE_AMMO, false, EFFECT_SPAWN_BROWN); - SET_NADE_EFFECT(NADE_TYPE_DARKNESS, false, EFFECT_EXPLOSION_MEDIUM); - SET_NADE_EFFECT(NADE_TYPE_NORMAL, true, EFFECT_NADE_EXPLODE(this.realowner.team)); - default: expef = EFFECT_NADE_EXPLODE(this.realowner.team); break; - } -#undef GET_NADE_TYPE_SPAWN_EFFECT + SET_NADE_EFFECT(NADE_TYPE_NAPALM, autocvar_g_nades_napalm_blast, EFFECT_EXPLOSION_MEDIUM, '0 0 0', '0 0 0'); + SET_NADE_EFFECT(NADE_TYPE_ICE, false, EFFECT_ELECTRO_COMBO, '0 0 0', '0 0 0'); + SET_NADE_EFFECT(NADE_TYPE_TRANSLOCATE, false, NULL, '0 0 0', '0 0 0'); + SET_NADE_EFFECT(NADE_TYPE_MONSTER, true, (!autocvar_g_monsters) ? EFFECT_NADE_EXPLODE_NEUTRAL : NULL, nades_PlayerColor(this.realowner, false), nades_PlayerColor(this.realowner, true)); + SET_NADE_EFFECT(NADE_TYPE_SPAWN, false, EFFECT_SPAWN_NEUTRAL, nades_PlayerColor(this.realowner, false), nades_PlayerColor(this.realowner, true)); + SET_NADE_EFFECT(NADE_TYPE_HEAL, false, EFFECT_SPAWN_NEUTRAL, '1 0 0', '1 0 0'); + SET_NADE_EFFECT(NADE_TYPE_ENTRAP, false, EFFECT_SPAWN_NEUTRAL, '1 1 0', '1 1 0'); + SET_NADE_EFFECT(NADE_TYPE_VEIL, false, EFFECT_SPAWN_NEUTRAL, '0 0 0', '0 0 0'); + SET_NADE_EFFECT(NADE_TYPE_AMMO, false, EFFECT_SPAWN_NEUTRAL, '0.66 0.33 0', '0.66 0.33 0'); + SET_NADE_EFFECT(NADE_TYPE_DARKNESS, false, EFFECT_EXPLOSION_MEDIUM, '0 0 0', '0 0 0'); + SET_NADE_EFFECT(NADE_TYPE_NORMAL, true, EFFECT_NADE_EXPLODE_NEUTRAL, nades_PlayerColor(this.realowner, false), nades_PlayerColor(this.realowner, true)); + default: expef = EFFECT_NADE_EXPLODE_NEUTRAL; expcol_min = nades_PlayerColor(this.realowner, false); expcol_max = nades_PlayerColor(this.realowner, true); break; + } #undef SET_NADE_EFFECT if(expef) - Send_Effect(expef, findbetterlocation(this.origin, 8), '0 0 0', 1); + Send_Effect_Except(expef, findbetterlocation(this.origin, 8), '0 0 0', 1, expcol_min, expcol_max, NULL); sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, ATTEN_NORM); sound(this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM); diff --git a/qcsrc/common/weapons/all.qc b/qcsrc/common/weapons/all.qc index 66735dd2f..5dcb0756e 100644 --- a/qcsrc/common/weapons/all.qc +++ b/qcsrc/common/weapons/all.qc @@ -720,7 +720,7 @@ void W_MuzzleFlash(Weapon thiswep, entity actor, .entity weaponentity, vector sh // don't show an exterior muzzle effect for the off-hand if(weaponslot(weaponentity) == 0) { - Send_Effect_Except(thiswep.m_muzzleeffect, shotorg, shotdir * 1000, 1, actor); + Send_Effect_Except(thiswep.m_muzzleeffect, shotorg, shotdir * 1000, 1, '0 0 0', '0 0 0', actor); if(thiswep.m_muzzlemodel != MDL_Null) { -- 2.39.5