diff --git a/src/client/entry.c b/src/client/entry.c index fb54c565..baf76588 100644 --- a/src/client/entry.c +++ b/src/client/entry.c @@ -245,6 +245,13 @@ CSQC_UpdateView(float w, float h, float focus) } } + Predict_PostFrame((player)self); + + if (pSeat->pWeaponFX) { + CBaseFX p = (CBaseFX)pSeat->pWeaponFX; + p.Draw(); + } + addentities(MASK_ENGINE); setproperty(VF_MIN, video_mins); setproperty(VF_SIZE, video_res); @@ -322,8 +329,6 @@ CSQC_UpdateView(float w, float h, float focus) CSQC_DrawCenterprint(); } } - - Predict_PostFrame((player)self); } DSP_UpdateListener(); @@ -572,6 +577,14 @@ CSQC_Parse_Event(void) Effect_Impact(iType, vOrigin, vNormal); break; + case EV_ANGLE: + vector a; + a[0] = readfloat(); + a[1] = readfloat(); + a[2] = readfloat(); + setproperty(VF_CL_VIEWANGLES, a); + setproperty(VF_ANGLES, a); + break; default: Game_Parse_Event(fHeader); } diff --git a/src/client/fx.c b/src/client/fx.c new file mode 100644 index 00000000..2c3bb3ea --- /dev/null +++ b/src/client/fx.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016-2019 Marco Hladik + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +class CBaseFX +{ + int m_iBaseJoint; + + void() CBaseFX; + + virtual void() Draw; +}; + +void +CBaseFX::Draw(void) +{ + +} + +void +CBaseFX::CBaseFX(void) +{ + drawmask = MASK_ENGINE; +} diff --git a/src/client/valve/defs.h b/src/client/valve/defs.h index bf013593..42f5dc8b 100644 --- a/src/client/valve/defs.h +++ b/src/client/valve/defs.h @@ -78,6 +78,7 @@ struct int iInputDuck; float fInputSendNext; + entity pWeaponFX; } seats[4], *pSeat; void HUD_DrawAmmo1(void); diff --git a/src/client/view.c b/src/client/view.c index 726ac9f2..a6f197bd 100644 --- a/src/client/view.c +++ b/src/client/view.c @@ -29,6 +29,7 @@ View_Init(void) pSeat->eMuzzleflash = spawn(); pSeat->eMuzzleflash.classname = "mflash"; pSeat->eMuzzleflash.renderflags = RF_ADDITIVE; + pSeat->pWeaponFX = spawn(CBaseFX); } } diff --git a/src/gs-entbase/client.src b/src/gs-entbase/client.src index 47f16195..cc9acad9 100644 --- a/src/gs-entbase/client.src +++ b/src/gs-entbase/client.src @@ -6,6 +6,7 @@ baseentity.h decals.h materials.h +../client/fx.c client/baseentity.cpp client/env_cubemap.cpp client/env_glow.cpp diff --git a/src/server/client.c b/src/server/client.c index 7443707a..6d58ef79 100644 --- a/src/server/client.c +++ b/src/server/client.c @@ -28,3 +28,15 @@ void Client_TriggerCamera(entity target, vector pos, vector end, float wait) msg_entity = target; multicast([0,0,0], MULTICAST_ONE); } + +void Client_FixAngle(entity target, vector ang) +{ + WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); + WriteByte(MSG_MULTICAST, EV_ANGLE); + WriteFloat(MSG_MULTICAST, ang[0]); + WriteFloat(MSG_MULTICAST, ang[1]); + WriteFloat(MSG_MULTICAST, ang[2]); + msg_entity = target; + multicast([0,0,0], MULTICAST_ONE); +} + diff --git a/src/server/cstrike/gamerules.c b/src/server/cstrike/gamerules.c index 1c667d76..786ffc7e 100644 --- a/src/server/cstrike/gamerules.c +++ b/src/server/cstrike/gamerules.c @@ -75,7 +75,6 @@ Gamerules_Spawn(player pl) spot = find(world, classname, "info_player_start"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; } Weapons_RefreshAmmo(pl); } else { @@ -84,6 +83,6 @@ Gamerules_Spawn(player pl) spot = Spawn_SelectRandom("info_player_deathmatch"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; } + Client_FixAngle(pl, pl.angles); } diff --git a/src/server/defs.h b/src/server/defs.h index db19f889..0d614013 100644 --- a/src/server/defs.h +++ b/src/server/defs.h @@ -28,6 +28,7 @@ void TraceAttack_FireBullets(int , vector, int, vector, int); void Damage_Radius( vector, entity, float, float, int, int); void Damage_Apply( entity, entity, float, int, int); void Client_TriggerCamera( entity eTarget, vector vPos, vector vEndPos, float fResetTime ); +void Client_FixAngle(entity, vector); void Game_Input(void); int Rules_IsTeamPlay(void); diff --git a/src/server/gearbox/gamerules.c b/src/server/gearbox/gamerules.c index 5680d849..af04e665 100644 --- a/src/server/gearbox/gamerules.c +++ b/src/server/gearbox/gamerules.c @@ -138,7 +138,6 @@ Gamerules_Spawn(player pl) spot = find(world, classname, "info_player_start"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; } Weapons_RefreshAmmo(pl); } else { @@ -147,11 +146,11 @@ Gamerules_Spawn(player pl) spot = Spawn_SelectRandom("info_player_deathmatch"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; pl.ammo_9mm = 68; Weapons_AddItem(pl, WEAPON_CROWBAR); Weapons_AddItem(pl, WEAPON_GLOCK); pl.g_items |= ITEM_SUIT; } + Client_FixAngle(pl, pl.angles); } diff --git a/src/server/hunger/gamerules.c b/src/server/hunger/gamerules.c index 4591a399..1020cf58 100644 --- a/src/server/hunger/gamerules.c +++ b/src/server/hunger/gamerules.c @@ -115,7 +115,6 @@ Gamerules_Spawn(player pl) spot = find(world, classname, "info_player_start"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; } Weapons_RefreshAmmo(pl); } else { @@ -124,11 +123,11 @@ Gamerules_Spawn(player pl) spot = Spawn_SelectRandom("info_player_deathmatch"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; pl.ammo_9mm = 68; Weapons_AddItem(pl, WEAPON_CROWBAR); Weapons_AddItem(pl, WEAPON_GLOCK); pl.g_items |= ITEM_SUIT; } + Client_FixAngle(pl, pl.angles); } diff --git a/src/server/poke646/gamerules.c b/src/server/poke646/gamerules.c index a70f7cbc..a059759b 100644 --- a/src/server/poke646/gamerules.c +++ b/src/server/poke646/gamerules.c @@ -74,7 +74,6 @@ Gamerules_Spawn(player pl) Gamerules_SetNewParms(); spot = find(world, classname, "info_player_start"); setorigin(pl, spot.origin); - pl.angles = spot.angles; pl.fixangle = TRUE; } } else { @@ -82,9 +81,9 @@ Gamerules_Spawn(player pl) spot = Spawn_SelectRandom("info_player_deathmatch"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; pl.g_items |= ITEM_SUIT; } + Client_FixAngle(pl, pl.angles); } void weaponbox_spawn(player pl) diff --git a/src/server/rewolf/gamerules.c b/src/server/rewolf/gamerules.c index dd81c3fb..e2c64a05 100644 --- a/src/server/rewolf/gamerules.c +++ b/src/server/rewolf/gamerules.c @@ -74,15 +74,14 @@ Gamerules_Spawn(player pl) spot = find(world, classname, "info_player_start"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; } } else { spot = Spawn_SelectRandom("info_player_deathmatch"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; pl.g_items |= ITEM_SUIT; } + Client_FixAngle(pl, pl.angles); } void weaponbox_spawn(player pl) diff --git a/src/server/scihunt/gamerules.c b/src/server/scihunt/gamerules.c index e713e7dc..bce4e901 100644 --- a/src/server/scihunt/gamerules.c +++ b/src/server/scihunt/gamerules.c @@ -75,16 +75,15 @@ Gamerules_Spawn(player pl) spot = find(world, classname, "info_player_start"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; } } else { Gamerules_SetNewParms(); spot = Spawn_SelectRandom("info_player_deathmatch"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; pl.g_items |= ITEM_SUIT; SHData_GetItems(); } + Client_FixAngle(pl, pl.angles); } diff --git a/src/server/valve/gamerules.c b/src/server/valve/gamerules.c index 5c8f62a8..e4a17894 100644 --- a/src/server/valve/gamerules.c +++ b/src/server/valve/gamerules.c @@ -118,7 +118,6 @@ Gamerules_Spawn(player pl) spot = find(world, classname, "info_player_start"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; } Weapons_RefreshAmmo(pl); } else { @@ -127,11 +126,11 @@ Gamerules_Spawn(player pl) spot = Spawn_SelectRandom("info_player_deathmatch"); setorigin(pl, spot.origin); pl.angles = spot.angles; - pl.fixangle = TRUE; pl.ammo_9mm = 68; Weapons_AddItem(pl, WEAPON_CROWBAR); Weapons_AddItem(pl, WEAPON_GLOCK); pl.g_items |= ITEM_SUIT; } + Client_FixAngle(pl, pl.angles); } diff --git a/src/shared/events.h b/src/shared/events.h index 45e972d9..9c27586f 100644 --- a/src/shared/events.h +++ b/src/shared/events.h @@ -23,6 +23,7 @@ enum { EV_WEAPON_SECONDARYATTACK, EV_WEAPON_RELOAD, EV_WEAPON_PICKUP, + EV_ANGLE, EV_IMPACT, EV_GIBHUMAN, EV_BLOOD, diff --git a/src/shared/gearbox/w_grapple.c b/src/shared/gearbox/w_grapple.c index 389ae49b..4d1dd00e 100644 --- a/src/shared/gearbox/w_grapple.c +++ b/src/shared/gearbox/w_grapple.c @@ -123,8 +123,7 @@ grapple_predraw(void) vector col2 = getlight(morg) / 255; makevectors(view_angles); - - + R_BeginPolygon(autocvar_cl_tonguemode == 1 ? "sprites/_tongue.spr_0.tga" : "sprites/tongue.spr_0.tga", 0, 0); R_PolygonVertex(forg + v_right * fsize[0] - v_up * fsize[1], [1,1], col1, 1.0f); diff --git a/src/shared/valve/w_gauss.c b/src/shared/valve/w_gauss.c index 9f6f1529..e60e914a 100644 --- a/src/shared/valve/w_gauss.c +++ b/src/shared/valve/w_gauss.c @@ -23,6 +23,90 @@ Gauss Weapon */ +#ifdef CSQC +#define FXGAUSS_BEAMCOLOR [1,0.5,0] +class FXGauss:CBaseFX +{ + int m_iBeams; + vector m_vecStart; + vector m_vecAngle; + + void() FXGauss; + virtual void() Draw; +}; + +void +FXGauss::Draw(void) +{ + player pl = (player)self; + int iLoop = 6; + vector src, endpos; + vector gunpos = gettaginfo(pSeat->eViewModel, 33); + + if (alpha <= 0.0f) { + return; + } + + src = m_vecStart; + makevectors(m_vecAngle); + vector endpos = src + v_forward * 1024; + traceline(src, endpos, FALSE, pl); + + /* drawing the first bit */ + vector fsize = [3,3]; + makevectors(view_angles); + R_BeginPolygon("sprites/xbeam1.spr_0.tga", 1, 0); + R_PolygonVertex(gunpos + v_right * fsize[0] - v_up * fsize[1], + [1,1], FXGAUSS_BEAMCOLOR, alpha); + R_PolygonVertex(gunpos - v_right * fsize[0] - v_up * fsize[1], + [0,1], FXGAUSS_BEAMCOLOR, alpha); + R_PolygonVertex(trace_endpos - v_right * fsize[0] + v_up * fsize[1], + [0,0], FXGAUSS_BEAMCOLOR, alpha); + R_PolygonVertex(trace_endpos + v_right * fsize[0] + v_up * fsize[1], + [1,0], FXGAUSS_BEAMCOLOR, alpha); + R_EndPolygon(); + + if (m_iBeams == 0) { + alpha -= clframetime * 3; + return; + } + + // reflection equation: + vector x = v_forward; + while (iLoop > 0) { + float n; + vector r; + n = -dotproduct(trace_plane_normal, x); + r = 2 * trace_plane_normal * n + x; + x = r; + src = trace_endpos + (x * 1); + endpos = trace_endpos + (x * 8192); + traceline(src, endpos, FALSE, pl); + + makevectors(view_angles); + R_BeginPolygon("sprites/xbeam1.spr_0.tga", 1, 0); + R_PolygonVertex(src + v_right * fsize[0] - v_up * fsize[1], + [1,1], FXGAUSS_BEAMCOLOR, alpha); + R_PolygonVertex(src - v_right * fsize[0] - v_up * fsize[1], + [0,1], FXGAUSS_BEAMCOLOR, alpha); + R_PolygonVertex(trace_endpos - v_right * fsize[0] + v_up * fsize[1], + [0,0], FXGAUSS_BEAMCOLOR, alpha); + R_PolygonVertex(trace_endpos + v_right * fsize[0] + v_up * fsize[1], + [1,0], FXGAUSS_BEAMCOLOR, alpha); + R_EndPolygon(); + + iLoop--; + } + alpha -= clframetime * 3; +} + +void +FXGauss::FXGauss(void) +{ + CBaseFX::CBaseFX(); +} +#endif + enum { GAUSS_IDLE1, @@ -45,6 +129,7 @@ void w_gauss_precache(void) precache_model("models/p_gauss.mdl"); precache_sound("weapons/gauss2.wav"); precache_model("sprites/yelflare1.spr"); + precache_model("sprites/xbeam1.spr"); precache_sound("weapons/electro4.wav"); precache_sound("weapons/electro5.wav"); precache_sound("weapons/electro6.wav"); @@ -87,6 +172,14 @@ void w_gauss_draw(void) { Weapons_SetModel("models/v_gauss.mdl"); Weapons_ViewAnimation(GAUSS_DRAW); + + /* link the FX class */ +#ifdef CSQC + entity eold = self; + self = pSeat->pWeaponFX; + spawnfunc_FXGauss(); + self = eold; +#endif } void w_gauss_holster(void) @@ -94,71 +187,16 @@ void w_gauss_holster(void) Weapons_ViewAnimation(GAUSS_HOLSTER); } -#ifdef CSQC -void w_gauss_placeorbs(vector org) -{ - static float glow_think(void) { - if (self.alpha <= 0.0f) { - remove(self); - return PREDRAW_NEXT; - } - self.alpha -= (clframetime * 0.25); - addentity(self); - return PREDRAW_NEXT; - } - entity glow = spawn(); - glow.drawmask = MASK_ENGINE; - setmodel(glow, "sprites/yelflare1.spr"); - setsize(glow, [0,0,0], [0,0,0]); - setorigin(glow, org); - glow.predraw = glow_think; - glow.effects = EF_ADDITIVE; - glow.alpha = 1.0f; - glow.scale = 0.25f; - glow.colormod = [255, 255, 0] / 255; - glow.movetype = MOVETYPE_BOUNCE; - glow.velocity[0] = random() - 0.5; - glow.velocity[1] = random() - 0.5; - glow.velocity[2] = random() * 8; - glow.velocity *= 64; -} -void w_gauss_placeimpact(vector org) -{ - static float glow_think(void) { - if (self.alpha <= 0.0f) { - remove(self); - return PREDRAW_NEXT; - } - self.alpha -= (clframetime * 0.5); - dynamiclight_add(self.origin, 256 * self.alpha, self.colormod); - addentity(self); - return PREDRAW_NEXT; - } - entity glow = spawn(); - glow.drawmask = MASK_ENGINE; - setmodel(glow, "sprites/yelflare1.spr"); - setorigin(glow, org); - glow.predraw = glow_think; - glow.effects = EF_ADDITIVE; - glow.alpha = 1.0f; - glow.colormod = [255, 200, 0] / 255; - - for (int i = 0; i < 3; i++) { - w_gauss_placeorbs(org); - } -} -#endif - +#ifdef SSQC void w_gauss_fire(int one) { player pl = (player)self; - int iLoop = 10; + int iLoop = 6; Weapons_MakeVectors(); vector src = Weapons_GetCameraPos(); vector endpos = src + v_forward * 1024; traceline(src, endpos, FALSE, pl); -#ifdef SSQC sound(pl, CHAN_WEAPON, "weapons/gauss2.wav", 1, ATTN_NORM); int iDamage = one ? 20 : 200; @@ -170,15 +208,6 @@ void w_gauss_fire(int one) Damage_Apply(trace_ent, self, iDamage, WEAPON_GAUSS, DMG_ELECTRO); sound(trace_ent, CHAN_ITEM, sprintf("weapons/electro%d.wav", random(0,3)+4), 1, ATTN_NORM); } -#else - te_beam(world, gettaginfo(pSeat->eViewModel, 33), trace_endpos); - - if (getsurfacetexture(trace_ent, getsurfacenearpoint(trace_ent, trace_endpos)) != "sky") { - w_gauss_placeimpact(trace_endpos); - } else { - return; - } -#endif if (one) { return; } else { @@ -203,7 +232,6 @@ void w_gauss_fire(int one) traceline(src, endpos, FALSE, pl); te_beam(world, src, trace_endpos); iLoop--; -#ifdef SSQC if (trace_ent.takedamage == DAMAGE_YES) { Damage_Apply(trace_ent, self, iDamage, WEAPON_GAUSS, DMG_ELECTRO); sound(trace_ent, CHAN_ITEM, sprintf("weapons/electro%d.wav", random(0,3)+4), 1, ATTN_NORM); @@ -214,17 +242,9 @@ void w_gauss_fire(int one) } else { break; } -#else - if (getsurfacetexture(trace_ent, getsurfacenearpoint(trace_ent, trace_endpos)) != "sky") { - te_beam(world, src, trace_endpos); - w_gauss_placeimpact(trace_endpos); - } else { - break; - } -#endif } - } +#endif void w_gauss_primary(void) { @@ -246,11 +266,17 @@ void w_gauss_primary(void) Weapons_ViewAnimation(GAUSS_FIRE2); #ifdef CSQC + FXGauss p = (FXGauss)pSeat->pWeaponFX; + p.m_iBeams = 0; + p.m_vecAngle = input_angles; + p.m_vecStart = pl.net_origin + pl.view_ofs; + p.alpha = 1.0f; pl.a_ammo2 -= 2; + Weapons_ViewPunchAngle([-2,0,0]); #else pl.ammo_uranium -= 2; -#endif w_gauss_fire(1); +#endif pl.w_attack_next = 0.2f; pl.w_idle_next = 2.5f; @@ -330,10 +356,17 @@ void w_gauss_release(void) pl.a_ammo3 = 0; return; } else if (pl.a_ammo3 == 2) { - w_gauss_fire(0); Weapons_ViewAnimation(GAUSS_FIRE1); #ifdef CSQC + FXGauss p = (FXGauss)pSeat->pWeaponFX; + p.m_iBeams = 1; + p.m_vecAngle = input_angles; + p.m_vecStart = pl.net_origin + pl.view_ofs; + p.alpha = 1.0f; soundupdate(pl, CHAN_WEAPON, "", -1, ATTN_NORM, 0, 0, 0); + Weapons_ViewPunchAngle([-5,0,0]); +#else + w_gauss_fire(0); #endif pl.w_attack_next = 1.5f; pl.w_idle_next = 4.0f; diff --git a/src/shared/valve/weapon_common.c b/src/shared/valve/weapon_common.c index 6197ab7d..b1069c54 100644 --- a/src/shared/valve/weapon_common.c +++ b/src/shared/valve/weapon_common.c @@ -76,9 +76,11 @@ void Weapons_Primary(void) { player pl = (player)self; int i = pl.activeweapon; + if (g_weapons[i].primary != __NULL__) { g_weapons[i].primary(); } + #ifdef SSQC if (g_weapons[i].updateammo != __NULL__) { g_weapons[i].updateammo(pl);