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;
}
if( ( bitsDamageType & DMG_ENERGYBEAM ) && FClassnameIs( pevAttacker, "shock" ) )
if( ( bitsDamageType & DMG_ENERGYBEAM ) && FClassnameIs( pevAttacker, "shock_beam" ) )
{
GlowShellOn( Vector( 0, 220, 255 ), .5f );
}
@ -986,7 +986,7 @@ int CBaseMonster::DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacke
}
#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.
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 )
{

View File

@ -376,7 +376,7 @@ void CGameRules::RefreshSkillData ( void )
gSkillData.plrDmgGrapple = GetSkillCvar( "sk_plr_grapple" );
gSkillData.plrDmgEagle = GetSkillCvar( "sk_plr_eagle" );
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.plrDmg762 = GetSkillCvar( "sk_plr_762_bullet" );
gSkillData.plrDmg556 = GetSkillCvar( "sk_plr_556_bullet" );
@ -384,7 +384,7 @@ void CGameRules::RefreshSkillData ( void )
gSkillData.monDmg762 = GetSkillCvar( "sk_plr_762_bullet" );
gSkillData.monDmg556 = GetSkillCvar( "sk_plr_556_bullet" );
gSkillData.monDmgDisplacer = GetSkillCvar( "sk_plr_displacer_other" );
gSkillData.monDmgShockroach = GetSkillCvar( "sk_plr_shockroachm" );
gSkillData.plrDmgShockroachMultiplayer = GetSkillCvar( "sk_plr_shockroachm" );
// HEALTH/CHARGE
gSkillData.suitchargerCapacity = GetSkillCvar( "sk_suitcharger" );

View File

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

View File

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

View File

@ -362,9 +362,10 @@ void CStrooper::HandleAnimEvent(MonsterEvent_t *pEvent)
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 );
pShock->pev->velocity = vecGunAngles * 900;
pShock->pev->velocity = vecGunAngles * 2000;
pShock->pev->nextthink = gpGlobals->time;
// Play fire sound.
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.
GlowShellUpdate();
RunAI();
GlowShellUpdate();
float flInterval = StudioFrameAdvance( ); // animate
@ -3429,7 +3428,7 @@ void CBaseMonster::GlowShellUpdate( void )
{
if( m_glowShellUpdate )
{
if( gpGlobals->time > m_glowShellTime )
if( gpGlobals->time > m_glowShellTime || pev->deadflag == DEAD_DEAD )
GlowShellOff();
}
}

View File

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

View File

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

View File

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