Fix shock effect (#9)

* Fix shock effect

* Additional fixes for shock beam
This commit is contained in:
Roman Chistokhodov 2017-09-28 13:19:16 +03:00 committed by Andrey Akhmichin
parent b5f145197d
commit cd0e28488b
9 changed files with 138 additions and 126 deletions

View File

@ -910,7 +910,7 @@ int CBaseMonster::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, f
return 0; return 0;
} }
if( ( bitsDamageType & DMG_ENERGYBEAM ) && FClassnameIs( pevAttacker, "shock" ) ) if( ( bitsDamageType & DMG_ENERGYBEAM ) && FClassnameIs( pevAttacker, "shock_beam" ) )
{ {
GlowShellOn( Vector( 0, 220, 255 ), .5f ); GlowShellOn( Vector( 0, 220, 255 ), .5f );
} }
@ -986,7 +986,7 @@ int CBaseMonster::DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacke
} }
#endif #endif
// kill the corpse if enough damage was done to destroy the corpse and the damage is of a type that is allowed to destroy the corpse. // kill the corpse if enough damage was done to destroy the corpse and the damage is of a type that is allowed to destroy the corpse.
if( (bitsDamageType & DMG_GIB_CORPSE) || (( bitsDamageType & DMG_ENERGYBEAM ) && FClassnameIs( pevAttacker, "shock" )) ) if( (bitsDamageType & DMG_GIB_CORPSE) || (( bitsDamageType & DMG_ENERGYBEAM ) && FClassnameIs( pevInflictor, "shock_beam" )) )
{ {
if( pev->health <= flDamage ) if( pev->health <= flDamage )
{ {

View File

@ -376,7 +376,7 @@ void CGameRules::RefreshSkillData ( void )
gSkillData.plrDmgGrapple = GetSkillCvar( "sk_plr_grapple" ); gSkillData.plrDmgGrapple = GetSkillCvar( "sk_plr_grapple" );
gSkillData.plrDmgEagle = GetSkillCvar( "sk_plr_eagle" ); gSkillData.plrDmgEagle = GetSkillCvar( "sk_plr_eagle" );
gSkillData.plrDmgDisplacer = GetSkillCvar( "sk_plr_displacer_self" ); gSkillData.plrDmgDisplacer = GetSkillCvar( "sk_plr_displacer_self" );
gSkillData.plrDmgShockroach = GetSkillCvar( "sk_plr_shockroachs" ); gSkillData.plrDmgShockroachSingleplayer = GetSkillCvar( "sk_plr_shockroachs" );
gSkillData.plrDmgSpore = GetSkillCvar( "sk_plr_spore" ); gSkillData.plrDmgSpore = GetSkillCvar( "sk_plr_spore" );
gSkillData.plrDmg762 = GetSkillCvar( "sk_plr_762_bullet" ); gSkillData.plrDmg762 = GetSkillCvar( "sk_plr_762_bullet" );
gSkillData.plrDmg556 = GetSkillCvar( "sk_plr_556_bullet" ); gSkillData.plrDmg556 = GetSkillCvar( "sk_plr_556_bullet" );
@ -384,7 +384,7 @@ void CGameRules::RefreshSkillData ( void )
gSkillData.monDmg762 = GetSkillCvar( "sk_plr_762_bullet" ); gSkillData.monDmg762 = GetSkillCvar( "sk_plr_762_bullet" );
gSkillData.monDmg556 = GetSkillCvar( "sk_plr_556_bullet" ); gSkillData.monDmg556 = GetSkillCvar( "sk_plr_556_bullet" );
gSkillData.monDmgDisplacer = GetSkillCvar( "sk_plr_displacer_other" ); gSkillData.monDmgDisplacer = GetSkillCvar( "sk_plr_displacer_other" );
gSkillData.monDmgShockroach = GetSkillCvar( "sk_plr_shockroachm" ); gSkillData.plrDmgShockroachMultiplayer = GetSkillCvar( "sk_plr_shockroachm" );
// HEALTH/CHARGE // HEALTH/CHARGE
gSkillData.suitchargerCapacity = GetSkillCvar( "sk_suitcharger" ); gSkillData.suitchargerCapacity = GetSkillCvar( "sk_suitcharger" );

View File

@ -28,87 +28,93 @@
#include "soundent.h" #include "soundent.h"
#include "game.h" #include "game.h"
#include "weapons.h" #include "weapons.h"
#include "gamerules.h"
#define SHOCK_BEAM_LENGTH 64 #include "customentity.h"
#define SHOCK_BEAM_LENGTH_HALF SHOCK_BEAM_LENGTH * 0.5f
#define SHOCK_BEAM_WIDTH 50
//========================================================= //=========================================================
// Shockrifle projectile // Shockrifle projectile
//========================================================= //=========================================================
class CShock : public CBaseEntity class CShock : public CBaseAnimating
{ {
public: public:
void Spawn(void); void Spawn(void);
void Precache();
static void Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity); static void Shoot(entvars_t *pevOwner, const Vector angles, const Vector vecStart, const Vector vecVelocity);
void Touch(CBaseEntity *pOther); void Touch(CBaseEntity *pOther);
void EXPORT ShockThink(void); void EXPORT FlyThink();
virtual int Save(CSave &save); virtual int Save(CSave &save);
virtual int Restore(CRestore &restore); virtual int Restore(CRestore &restore);
static TYPEDESCRIPTION m_SaveData[]; static TYPEDESCRIPTION m_SaveData[];
void CreateBeam(const Vector& start, const Vector& end, int width); void CreateEffects();
void ClearBeam(); void ClearEffects();
void UpdateBeam(const Vector& start, const Vector& end);
void ComputeBeamPositions(Vector* pos1, Vector* pos2);
CBeam *m_pBeam; CBeam *m_pBeam;
Vector m_vecBeamStart, m_vecBeamEnd; CBeam *m_pNoise;
CSprite *m_pSprite;
}; };
LINK_ENTITY_TO_CLASS(shock, CShock); LINK_ENTITY_TO_CLASS(shock_beam, CShock)
TYPEDESCRIPTION CShock::m_SaveData[] = TYPEDESCRIPTION CShock::m_SaveData[] =
{ {
DEFINE_ARRAY(CShock, m_pBeam, FIELD_CLASSPTR, 1), DEFINE_FIELD(CShock, m_pBeam, FIELD_CLASSPTR),
DEFINE_FIELD(CShock, m_vecBeamStart, FIELD_POSITION_VECTOR), DEFINE_FIELD(CShock, m_pNoise, FIELD_CLASSPTR),
DEFINE_FIELD(CShock, m_vecBeamEnd, FIELD_POSITION_VECTOR), DEFINE_FIELD(CShock, m_pSprite, FIELD_CLASSPTR),
}; };
IMPLEMENT_SAVERESTORE(CShock, CBaseEntity); IMPLEMENT_SAVERESTORE(CShock, CBaseAnimating)
void CShock::Spawn(void) void CShock::Spawn(void)
{ {
Precache();
pev->movetype = MOVETYPE_FLY; pev->movetype = MOVETYPE_FLY;
pev->classname = MAKE_STRING("shock");
pev->solid = SOLID_BBOX; pev->solid = SOLID_BBOX;
pev->rendermode = kRenderTransAdd; pev->classname = MAKE_STRING("shock_beam");
pev->renderamt = 170; SET_MODEL(ENT(pev), "models/shock_effect.mdl");
pev->renderfx = kRenderFxNoDissipation; UTIL_SetOrigin(pev, pev->origin);
SET_MODEL(ENT(pev), "sprites/flare3.spr");
pev->frame = 0;
pev->scale = 0.4;
if ( g_pGameRules->IsMultiplayer() )
pev->dmg = gSkillData.plrDmgShockroachMultiplayer;
else
pev->dmg = gSkillData.plrDmgShockroachSingleplayer;
UTIL_SetSize(pev, Vector(-4, -4, -4), Vector(4, 4, 4)); UTIL_SetSize(pev, Vector(-4, -4, -4), Vector(4, 4, 4));
// Make beam NULL to avoid assertions. CreateEffects();
m_pBeam = 0; SetThink( &CShock::FlyThink );
pev->nextthink = gpGlobals->time;
ComputeBeamPositions(&m_vecBeamStart, &m_vecBeamEnd);
// Create the beam.
//CreateBeam(m_vecBeamStart, m_vecBeamEnd, SHOCK_BEAM_WIDTH);
SetThink(&CShock::ShockThink);
pev->nextthink = gpGlobals->time + 0.1f;
} }
void CShock::ShockThink(void) void CShock::Precache()
{ {
pev->nextthink = gpGlobals->time + 0.01f; PRECACHE_MODEL("sprites/flare3.spr");
PRECACHE_MODEL("sprites/lgtning.spr");
ComputeBeamPositions(&m_vecBeamStart, &m_vecBeamEnd); PRECACHE_MODEL("models/shock_effect.mdl");
PRECACHE_SOUND("weapons/shock_impact.wav");
// Update the beam.
UpdateBeam(m_vecBeamStart, m_vecBeamEnd);
} }
void CShock::Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity) void CShock::FlyThink()
{
if (pev->waterlevel == 3)
{
entvars_t *pevOwner = VARS(pev->owner);
const int iVolume = RANDOM_FLOAT(0.8f, 1);
const int iPitch = RANDOM_FLOAT(80, 110);
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/shock_impact.wav", iVolume, ATTN_NORM, 0, iPitch);
RadiusDamage(pev->origin, pev, pevOwner ? pevOwner : pev, pev->dmg * 3, 144, CLASS_NONE, DMG_SHOCK | DMG_ALWAYSGIB );
ClearEffects();
SetThink( &CBaseEntity::SUB_Remove );
pev->nextthink = gpGlobals->time;
}
else
{
pev->nextthink = gpGlobals->time + 0.05;
}
}
void CShock::Shoot(entvars_t *pevOwner, const Vector angles, const Vector vecStart, const Vector vecVelocity)
{ {
CShock *pShock = GetClassPtr((CShock *)NULL); CShock *pShock = GetClassPtr((CShock *)NULL);
pShock->Spawn(); pShock->Spawn();
@ -116,8 +122,8 @@ void CShock::Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity)
UTIL_SetOrigin(pShock->pev, vecStart); UTIL_SetOrigin(pShock->pev, vecStart);
pShock->pev->velocity = vecVelocity; pShock->pev->velocity = vecVelocity;
pShock->pev->owner = ENT(pevOwner); pShock->pev->owner = ENT(pevOwner);
pShock->pev->angles = angles;
pShock->SetThink(&CShock::ShockThink);
pShock->pev->nextthink = gpGlobals->time; pShock->pev->nextthink = gpGlobals->time;
} }
@ -152,7 +158,7 @@ void CShock::Touch(CBaseEntity *pOther)
WRITE_BYTE( 10 ); // decay * 0.1 WRITE_BYTE( 10 ); // decay * 0.1
MESSAGE_END( ); MESSAGE_END( );
ClearBeam(); ClearEffects();
if (!pOther->pev->takedamage) if (!pOther->pev->takedamage)
{ {
// make a splat on the wall // make a splat on the wall
@ -160,22 +166,29 @@ void CShock::Touch(CBaseEntity *pOther)
int iContents = UTIL_PointContents(pev->origin); int iContents = UTIL_PointContents(pev->origin);
// Create sparks // Create sparks
if (iContents != CONTENTS_WATER) if (iContents != CONTENTS_WATER)
{ {
UTIL_Sparks(tr.vecEndPos); UTIL_Sparks(tr.vecEndPos);
} }
UTIL_Remove(this);
} }
else else
{ {
ClearMultiDamage(); ClearMultiDamage();
entvars_t *pevOwner = VARS(pev->owner); entvars_t *pevOwner = VARS(pev->owner);
float damage = gSkillData.monDmgShockroach; int damageType = DMG_ENERGYBEAM;
if (pevOwner && (pevOwner->flags | FL_CLIENT)) if (pOther->pev->deadflag == DEAD_DEAD)
damage = gSkillData.plrDmgShockroach; {
pOther->TraceAttack(pev, damage, pev->velocity.Normalize(), &tr, DMG_ENERGYBEAM ); damageType |= DMG_ALWAYSGIB;
ApplyMultiDamage(pev, pev); }
else
{
CBaseMonster* pMonster = pOther->MyMonsterPointer();
if (pMonster)
pMonster->GlowShellOn( Vector( 0, 220, 255 ), .5f );
}
pOther->TraceAttack(pev, pev->dmg, pev->velocity.Normalize(), &tr, damageType );
ApplyMultiDamage(pev, pevOwner ? pevOwner : pev);
if (pOther->IsPlayer() && (UTIL_PointContents(pev->origin) != CONTENTS_WATER)) if (pOther->IsPlayer() && (UTIL_PointContents(pev->origin) != CONTENTS_WATER))
{ {
const Vector position = tr.vecEndPos; const Vector position = tr.vecEndPos;
@ -187,69 +200,60 @@ void CShock::Touch(CBaseEntity *pOther)
MESSAGE_END(); MESSAGE_END();
} }
} }
UTIL_Remove(this); SetThink( &CBaseEntity::SUB_Remove );
pev->nextthink = gpGlobals->time;
} }
//========================================================= void CShock::CreateEffects()
// Purpose:
//=========================================================
void CShock::CreateBeam(const Vector& start, const Vector& end, int width)
{ {
m_pSprite = CSprite::SpriteCreate( "sprites/flare3.spr", pev->origin, FALSE );
m_pSprite->SetAttachment( edict(), 0 );
m_pSprite->pev->scale = 0.4;
m_pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 170, kRenderFxNoDissipation );
m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY;
m_pSprite->pev->flags |= FL_SKIPLOCALHOST;
m_pBeam = CBeam::BeamCreate( "sprites/lgtning.spr", 30 );
if (m_pBeam) if (m_pBeam)
{ {
ClearBeam(); m_pBeam->EntsInit( entindex(), entindex() );
} m_pBeam->SetStartAttachment( 1 );
m_pBeam->SetEndAttachment( 2 );
m_pBeam = CBeam::BeamCreate("sprites/lgtning.spr", width); m_pBeam->SetBrightness( 190 );
if (!m_pBeam) m_pBeam->SetScrollRate( 20 );
return; m_pBeam->SetNoise( 20 );
m_pBeam->SetFlags( BEAM_FSHADEOUT );
m_pBeam->PointsInit(start, end); m_pBeam->SetColor( 0, 255, 255 );
m_pBeam->SetColor(140, 255, 220); m_pBeam->pev->spawnflags = SF_BEAM_TEMPORARY;
m_pBeam->SetBrightness(RANDOM_LONG(24, 25) * 10);
m_pBeam->SetFrame(0);
m_pBeam->SetScrollRate(10);
m_pBeam->SetNoise(40);
m_pBeam->SetFlags(SF_BEAM_SHADEIN | SF_BEAM_SHADEOUT);
}
//=========================================================
// Purpose:
//=========================================================
void CShock::ClearBeam()
{
if (m_pBeam)
{
UTIL_Remove(m_pBeam);
m_pBeam = NULL;
}
}
void CShock::UpdateBeam(const Vector& start, const Vector& end)
{
if (!m_pBeam)
{
// Create the beam if not already created.
CreateBeam(start, end, SHOCK_BEAM_WIDTH);
}
else
{
m_pBeam->SetStartPos(start);
m_pBeam->SetEndPos(end);
m_pBeam->RelinkBeam(); m_pBeam->RelinkBeam();
} }
m_pNoise = CBeam::BeamCreate( "sprites/lgtning.spr", 30 );
if (m_pNoise)
{
m_pNoise->EntsInit( entindex(), entindex() );
m_pNoise->SetStartAttachment( 1 );
m_pNoise->SetEndAttachment( 2 );
m_pNoise->SetBrightness( 190 );
m_pNoise->SetScrollRate( 20 );
m_pNoise->SetNoise( 65 );
m_pNoise->SetFlags( BEAM_FSHADEOUT );
m_pNoise->SetColor( 255, 255, 173 );
m_pNoise->pev->spawnflags = SF_BEAM_TEMPORARY;
m_pNoise->RelinkBeam();
}
} }
void CShock::ComputeBeamPositions(Vector* pos1, Vector* pos2) void CShock::ClearEffects()
{ {
const Vector vel = pev->velocity.Normalize(); UTIL_Remove( m_pBeam );
UTIL_MakeVectors( pev->angles ); m_pBeam = NULL;
/* Little aside so beam and sprite won't blend into white ball when looking right into shock beam direction. UTIL_Remove( m_pNoise );
* This should replicate the Opposing Force behavior m_pNoise = NULL;
*/
const Vector origin = pev->origin - gpGlobals->v_right * 6; UTIL_Remove( m_pSprite );
*pos1 = origin + (vel * SHOCK_BEAM_LENGTH_HALF); m_pSprite = NULL;
*pos2 = origin + (vel * -SHOCK_BEAM_LENGTH_HALF/2);
} }

View File

@ -67,7 +67,7 @@ void CShockrifle::Precache(void)
m_usShockFire = PRECACHE_EVENT(1, "events/shock.sc"); m_usShockFire = PRECACHE_EVENT(1, "events/shock.sc");
UTIL_PrecacheOther("shock"); UTIL_PrecacheOther("shock_beam");
} }
int CShockrifle::AddToPlayer(CBasePlayer *pPlayer) int CShockrifle::AddToPlayer(CBasePlayer *pPlayer)
@ -136,7 +136,17 @@ void CShockrifle::PrimaryAttack()
return; return;
} }
if (m_pPlayer->pev->waterlevel == 3)
{
#ifndef CLIENT_DLL #ifndef CLIENT_DLL
RadiusDamage(m_pPlayer->pev->origin, m_pPlayer->pev, m_pPlayer->pev, 300, 144, CLASS_NONE, DMG_SHOCK | DMG_ALWAYSGIB );
#endif
return;
}
#ifndef CLIENT_DLL
Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle;
anglesAim.x = -anglesAim.x;
UTIL_MakeVectors(m_pPlayer->pev->v_angle); UTIL_MakeVectors(m_pPlayer->pev->v_angle);
Vector vecSrc; Vector vecSrc;
@ -146,8 +156,8 @@ void CShockrifle::PrimaryAttack()
vecSrc = vecSrc + gpGlobals->v_right * 8; vecSrc = vecSrc + gpGlobals->v_right * 8;
vecSrc = vecSrc + gpGlobals->v_up * -12; vecSrc = vecSrc + gpGlobals->v_up * -12;
CBaseEntity *pShock = CBaseEntity::Create("shock", vecSrc, m_pPlayer->pev->v_angle, m_pPlayer->edict()); CBaseEntity *pShock = CBaseEntity::Create("shock_beam", vecSrc, anglesAim, m_pPlayer->edict());
pShock->pev->velocity = gpGlobals->v_forward * 900; pShock->pev->velocity = gpGlobals->v_forward * 2000;
m_flRechargeTime = gpGlobals->time + 0.5; m_flRechargeTime = gpGlobals->time + 0.5;
#endif #endif

View File

@ -362,9 +362,10 @@ void CStrooper::HandleAnimEvent(MonsterEvent_t *pEvent)
vecGunAngles = (m_vecEnemyLKP - vecGunPos).Normalize(); vecGunAngles = (m_vecEnemyLKP - vecGunPos).Normalize();
} }
CBaseEntity *pShock = CBaseEntity::Create("shock", vecGunPos, pev->angles, edict()); CBaseEntity *pShock = CBaseEntity::Create("shock_beam", vecGunPos, pev->angles, edict());
vecGunAngles.z += RANDOM_FLOAT( -0.05, 0 ); vecGunAngles.z += RANDOM_FLOAT( -0.05, 0 );
pShock->pev->velocity = vecGunAngles * 900; pShock->pev->velocity = vecGunAngles * 2000;
pShock->pev->nextthink = gpGlobals->time;
// Play fire sound. // Play fire sound.
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/shock_fire.wav", 1, ATTN_NORM); EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/shock_fire.wav", 1, ATTN_NORM);

View File

@ -527,9 +527,8 @@ void CBaseMonster::MonsterThink( void )
{ {
pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking. pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking.
GlowShellUpdate();
RunAI(); RunAI();
GlowShellUpdate();
float flInterval = StudioFrameAdvance( ); // animate float flInterval = StudioFrameAdvance( ); // animate
@ -3429,7 +3428,7 @@ void CBaseMonster::GlowShellUpdate( void )
{ {
if( m_glowShellUpdate ) if( m_glowShellUpdate )
{ {
if( gpGlobals->time > m_glowShellTime ) if( gpGlobals->time > m_glowShellTime || pev->deadflag == DEAD_DEAD )
GlowShellOff(); GlowShellOff();
} }
} }

View File

@ -99,8 +99,6 @@ void CBaseMonster::RunAI( void )
CheckAmmo(); CheckAmmo();
} }
if (m_glowShellUpdate && pev->deadflag == DEAD_DEAD)
GlowShellOff();
FCheckAITrigger(); FCheckAITrigger();
PrescheduleThink(); PrescheduleThink();

View File

@ -196,7 +196,7 @@ void CHalfLifeMultiplay::RefreshSkillData( void )
gSkillData.plrDmgDisplacer = 5; gSkillData.plrDmgDisplacer = 5;
// Shockroach // Shockroach
gSkillData.plrDmgShockroach = 10; gSkillData.plrDmgShockroachSingleplayer = 10;
// Spore // Spore
gSkillData.plrDmgSpore = 50; gSkillData.plrDmgSpore = 50;
@ -217,7 +217,7 @@ void CHalfLifeMultiplay::RefreshSkillData( void )
gSkillData.monDmgDisplacer = 250; gSkillData.monDmgDisplacer = 250;
// Shockroach // Shockroach
gSkillData.monDmgShockroach = 15; gSkillData.plrDmgShockroachMultiplayer = 15;
// Displacer radius // Displacer radius
gSkillData.displacerDmgRadius = 300; gSkillData.displacerDmgRadius = 300;

View File

@ -207,7 +207,7 @@ struct skilldata_t
float plrDmgGrapple; float plrDmgGrapple;
float plrDmgEagle; float plrDmgEagle;
float plrDmgDisplacer; float plrDmgDisplacer;
float plrDmgShockroach; float plrDmgShockroachSingleplayer;
float plrDmgSpore; float plrDmgSpore;
float plrDmg762; float plrDmg762;
float plrDmg556; float plrDmg556;
@ -216,7 +216,7 @@ struct skilldata_t
float monDmg762; float monDmg762;
float monDmg556; float monDmg556;
float monDmgDisplacer; float monDmgDisplacer;
float monDmgShockroach; float plrDmgShockroachMultiplayer;
float displacerDmgRadius; float displacerDmgRadius;
}; };