Files
HL2Overcharged/game/server/overcharged/weapon_immolator.cpp
2025-05-21 21:20:08 +03:00

754 lines
21 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basehlcombatweapon.h"
#include "basecombatcharacter.h"
#include "player.h"
#include "soundent.h"
#include "te_particlesystem.h"
#include "ndebugoverlay.h"
#include "in_buttons.h"
#include "ai_basenpc.h"
#include "ai_memory.h"
#include "shake.h"
#include "gamerules.h"
#include "te_effect_dispatch.h"
#include "decals.h"
#include "IEffects.h"
#include "AmmoDef.h"
#include "soundenvelope.h"
#include "particle_parse.h"
#include "game.h" // èãðà
#include "NPCevent.h"
#include "weapon_immolator.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//#define IMMOLATOR_CHARGE_TIME 1.2f
#define IMMOLATOR_AMMOUSING_TIME 0.1
#define IMMOLATOR_DAMAGE_TIME 0.02
#define IMMOLATOR_BEAM_TEXTTURE "effects/immolator/laser.vmt"
#define MAX_BURN_RADIUS 256
#define RADIUS_GROW_RATE 50.0
#define IMMOLATOR_TARGET_INVALID Vector( FLT_MAX, FLT_MAX, FLT_MAX )
#define ADDITIONAL_SPRITE "effects/immolator/HitSprite.vmt"
extern ConVar sk_plr_dmg_immolator_wide("sk_plr_dmg_immolator_wide", "7");
ConVar sk_plr_dmg_immolator_radius_dmg("sk_plr_dmg_immolator_radius_dmg", "7");
ConVar oc_weapon_immolator_firewater_frequency("oc_weapon_immolator_firewater_frequency", "0", (FCVAR_REPLICATED), "Egon damage.");
IMPLEMENT_SERVERCLASS_ST(CWeaponImmolator, DT_WeaponImmolator)
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS(info_target_Immolator, CPointEntity);
LINK_ENTITY_TO_CLASS(weapon_Immolator, CWeaponImmolator);
PRECACHE_WEAPON_REGISTER(weapon_Immolator);
BEGIN_DATADESC(CWeaponImmolator)
DEFINE_FIELD(m_bFirstPlay, FIELD_BOOLEAN),
DEFINE_FIELD(m_beamIndex, FIELD_INTEGER),
DEFINE_FIELD(m_flBurnRadius, FIELD_FLOAT),
DEFINE_FIELD(m_vecLaserTarget, FIELD_VECTOR),
DEFINE_FIELD(m_BeamFireState, FIELD_INTEGER),
DEFINE_FIELD(m_SSprite, FIELD_EHANDLE),
DEFINE_FIELD(m_flChargeTime, FIELD_TIME),
DEFINE_FIELD(m_flDmgTime, FIELD_TIME),
DEFINE_FIELD(m_flAmmoTime, FIELD_TIME),
DEFINE_FIELD(m_hBeam, FIELD_EHANDLE),
DEFINE_FIELD(m_hCurveBeam, FIELD_EHANDLE),
DEFINE_FIELD(m_hCurveBeam2, FIELD_EHANDLE),
END_DATADESC()
//-----------------------------------------------------------------------------
// Maps base activities to weapons-specific ones so our characters do the right things.
//-----------------------------------------------------------------------------
acttable_t CWeaponImmolator::m_acttable[] =
{
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_CROSSBOW, false },
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_CROSSBOW, false },
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_CROSSBOW, false },
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_CROSSBOW, false },
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN, false },
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SHOTGUN, false },
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_CROSSBOW, false },
//{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, false }, // END
{ ACT_IDLE_RELAXED, ACT_IDLE_SHOTGUN_RELAXED, false },//never aims
{ ACT_IDLE_STIMULATED, ACT_IDLE_SHOTGUN_STIMULATED, false },
{ ACT_WALK_RELAXED, ACT_WALK_RIFLE_RELAXED, false },//never aims
{ ACT_WALK_STIMULATED, ACT_WALK_RIFLE_STIMULATED, false },
{ ACT_WALK_AGITATED, ACT_WALK_AIM_RIFLE, false },//always aims
{ ACT_RUN_RELAXED, ACT_RUN_RIFLE_RELAXED, false },//never aims
{ ACT_RUN_STIMULATED, ACT_RUN_RIFLE_STIMULATED, false },
{ ACT_RUN_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims
{ ACT_IDLE_AIM_RELAXED, ACT_IDLE_SMG1_RELAXED, false },//never aims
{ ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_RIFLE_STIMULATED, false },
{ ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_SMG1, false },//always aims
{ ACT_WALK_AIM_RELAXED, ACT_WALK_RIFLE_RELAXED, false },//never aims
{ ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_RIFLE_STIMULATED, false },
{ ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_RIFLE, false },//always aims
{ ACT_RUN_AIM_RELAXED, ACT_RUN_RIFLE_RELAXED, false },//never aims
{ ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_RIFLE_STIMULATED, false },
{ ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims
{ ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true },
{ ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true },
{ ACT_RUN, ACT_RUN_RIFLE, true },
{ ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true },
{ ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true },
{ ACT_IDLE, ACT_IDLE_SMG1, true },
{ ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SHOTGUN, true },
{ ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_SHOTGUN, true },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, true },
{ ACT_RELOAD, ACT_RELOAD_SMG1, true },
{ ACT_WALK_AIM, ACT_WALK_AIM_SHOTGUN, true },
{ ACT_RUN_AIM, ACT_RUN_AIM_SHOTGUN, true },
{ ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SHOTGUN, true },
{ ACT_RELOAD_LOW, ACT_RELOAD_SHOTGUN_LOW, false },
{ ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_SHOTGUN_LOW, false },
{ ACT_COVER_LOW, ACT_COVER_SMG1_LOW, false },
{ ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_SMG1_LOW, false },
{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false },
{ ACT_WALK, ACT_WALK_RIFLE, false },
//{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SNIPER_RIFLE, true }
};
IMPLEMENT_ACTTABLE(CWeaponImmolator);
CWeaponImmolator::CWeaponImmolator(void)
{
m_BeamFireState = FIRE_NONE;
m_bFirstPlay = true;
m_flChargeTime = gpGlobals->curtime;
m_flDmgTime = gpGlobals->curtime;
m_flAmmoTime = gpGlobals->curtime;
}
void CWeaponImmolator::Precache(void)
{
m_beamIndex = PrecacheModel(IMMOLATOR_BEAM_TEXTTURE);
PrecacheMaterial(IMMOLATOR_BEAM_TEXTTURE);
PrecacheMaterial(ADDITIONAL_SPRITE);
BaseClass::Precache();
}
void CWeaponImmolator::UseAmmo(int count)
{
CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
if (!pPlayer)
{
return;
}
if (pPlayer->GetAmmoCount(m_iPrimaryAmmoType) >= count)
RemoveAmmo(GetPrimaryAmmoType(), count); //pPlayer->RemoveAmmo(count, m_iPrimaryAmmoType);
else
RemoveAmmo(GetPrimaryAmmoType(), pPlayer->GetAmmoCount(m_iPrimaryAmmoType)); //pPlayer->RemoveAmmo(pPlayer->GetAmmoCount(m_iPrimaryAmmoType), m_iPrimaryAmmoType);
}
Activity CWeaponImmolator::GetPrimaryAttackActivity(void)
{
if (m_BeamFireState == FIRE_STARTUP)
return BaseClass::GetPrimaryAttackActivity();
else if (m_BeamFireState == FIRE_LOOP)
return GetWpnData().animData[m_bFireMode].FirePrimarySpecial;
return BaseClass::GetPrimaryAttackActivity();
}
void CWeaponImmolator::PrimaryAttack(void)
{
CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
if (!pPlayer)
return;
if (pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
{
return;
}
if (GetActivity() != GetPrimaryAttackActivity())
SendWeaponAnim(GetPrimaryAttackActivity());
switch (m_BeamFireState)
{
case FIRE_NONE:
{
//DispatchParticleEffect("Immolator_line01", PATTACH_POINT_FOLLOW, pPlayer->GetViewModel(), "muzzle", false);
DispatchParticleEffect(STRING(GetWpnData().iMuzzleFlashDelayed), PATTACH_POINT_FOLLOW, pPlayer->GetViewModel(), GetWpnData().iAttachment, false);
m_BeamFireState = FIRE_STARTUP;
}
break;
case FIRE_STARTUP:
{
if (m_flNextPrimaryAttack <= gpGlobals->curtime)
{
if (m_BeamFireState == FIRE_STARTUP)
Charge();
WeaponSound(SPECIAL1);
m_BeamFireState = FIRE_LOOP;
m_bFirstPlay = true;
m_flNextSecondaryAttack = m_flNextPrimaryAttack = m_flDmgTime = m_flAmmoTime = gpGlobals->curtime + GetWpnData().mode_fire_rate_automatic_startup_delay;
}
}
break;
case FIRE_LOOP:
{
m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->curtime;
if (pPlayer->GetWaterLevel() != 3)
{
if (m_bFirstPlay)
{
m_flDmgTime = m_flAmmoTime = gpGlobals->curtime + GetFireRate();
WeaponSound(SINGLE);
StopWeaponSound(SPECIAL1);
m_bFirstPlay = false;
//DispatchParticleEffect("Immolator_explodeMain", PATTACH_POINT_FOLLOW, pPlayer->GetViewModel(), "muzzle", false);
//DispatchParticleEffect("Immolator_start", PATTACH_POINT_FOLLOW, pPlayer->GetViewModel(), "muzzle", false);
DispatchParticleEffect(STRING(GetWpnData().iMuzzleFlashShortBurst), PATTACH_POINT_FOLLOW, pPlayer->GetViewModel(), GetWpnData().iAttachment, false);
}
Vector vecAiming = pPlayer->GetAutoaimVector(0);
Vector vecSrc = pPlayer->EyePosition();
Fire(vecSrc, vecAiming, pPlayer);
/*data.m_nEntIndex = pPlayer->GetViewModel()->entindex();
DispatchEffect("MuzzleLight", data);*/
FireClientPrimaryAttack();
}
else
DryFire();
if (GetWpnData().allowLoopSound)
StartLoopSound();
}
break;
case FIRE_END:
{
StopWeaponSound(SPECIAL1);
DestroyBeam();
StopLoopSound();
}
break;
default:
break;
}
/*if (pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
{
// HEV suit - indicate out of ammo condition
pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
}*/
}
void CWeaponImmolator::ApplyDamage(const Vector &vecDir, trace_t &tr, CBasePlayer *pPlayer)
{
if (m_flDmgTime <= gpGlobals->curtime)
{
// wide mode does damage to the ent, and radius damage
if (tr.m_pEnt && tr.m_pEnt->m_takedamage != DAMAGE_NO)
{
ClearMultiDamage();
if (tr.m_pEnt && tr.m_pEnt->IsAlive() && (tr.m_pEnt->GetFlags() & FL_ONFIRE) == 0)
{
CTakeDamageInfo info(this, pPlayer, sk_plr_dmg_immolator_wide.GetFloat(), DMG_BURN);
CalculateMeleeDamageForce(&info, vecDir, tr.endpos);
tr.m_pEnt->DispatchTraceAttack(info, vecDir, &tr);
ApplyMultiDamage();
}
if (tr.m_pEnt && tr.m_pEnt->IsAlive() && (tr.m_pEnt->GetFlags() & FL_ONFIRE) != 0)
{
CTakeDamageInfo info(this, pPlayer, sk_plr_dmg_immolator_wide.GetFloat(), DMG_BULLET);
CalculateMeleeDamageForce(&info, vecDir, tr.endpos);
tr.m_pEnt->DispatchTraceAttack(info, vecDir, &tr);
ApplyMultiDamage();
}
}
RadiusDamage(CTakeDamageInfo(this, this, sk_plr_dmg_immolator_wide.GetFloat() / 4, DMG_BURN | DMG_DISSOLVE), tr.endpos, 10.0f, CLASS_NONE, NULL);
ShouldDrawWaterImpacts(tr);
//UTIL_ImpactTrace(&tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType));
//UTIL_Smoke(tr.endpos, random->RandomInt(5, 10), 10);//Äûì îò ëó÷à
//UTIL_DecalTrace(&tr, "RedGlowFade");
UTIL_DecalTrace( &tr, "FadingScorch" ); //Ãàðü îò ëó÷à
m_flDmgTime = gpGlobals->curtime + GetFireRate();
}
}
void CWeaponImmolator::AmmoUsing()
{
// Wide mode uses 10 charges per second in single player
if (m_flAmmoTime <= gpGlobals->curtime)
{
UseAmmo(1);
m_flAmmoTime = gpGlobals->curtime + IMMOLATOR_AMMOUSING_TIME;
}
}
void CWeaponImmolator::Fire(const Vector &vecOrigSrc, const Vector &vecDir, CBasePlayer *pPlayer)
{
Vector vecDest = vecOrigSrc + (vecDir * MAX_TRACE_LENGTH);
trace_t tr;
UTIL_TraceLine(vecOrigSrc, vecDest, MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr);
ApplyDamage(vecDir, tr, pPlayer);
AmmoUsing();
AddViewKick();
Vector vecUp, vecRight;
QAngle angDir;
VectorAngles(vecDir, angDir);
AngleVectors(angDir, NULL, &vecRight, &vecUp);
Vector tmpSrc = vecOrigSrc + (vecUp * -8) + (vecRight * 3);
UpdateBeam(tmpSrc, tr.endpos, pPlayer);
if (pPlayer)
{
CEffectData data;
data.m_nEntIndex = pPlayer->entindex();
data.m_vOrigin = tr.endpos;
data.m_vStart.x = GetWpnData().iMuzzleFlashLightR;
data.m_vStart.y = GetWpnData().iMuzzleFlashLightG;
data.m_vStart.z = GetWpnData().iMuzzleFlashLightB;
DispatchEffect("ImmolatorWeaponLight", data);
}
if (tr.DidHit())
{
int beams;
/*CPASFilter filter(GetAbsOrigin());
te->DynamicLight(filter, 0.0, &tr.endpos, 0, 255, 0, 0, 280, 0.02, 0);*/
for (beams = 0; beams < 8; beams++)
{
// Vector vecDest;
// Random unit vector
vecDest.x = random->RandomFloat(-1, 1);
vecDest.y = random->RandomFloat(-1, 1);
vecDest.z = random->RandomFloat(-1, 1);
// Push out to radius dist.
vecDest = tr.endpos + vecDest * 55.0f;
UTIL_Beam(tr.endpos,
vecDest,
m_beamIndex,
0, //halo index
0, //frame start
2.0f, //framerate
0.15f, //life
5, // width
1.75, // endwidth
0.75, // fadelength,
15, // noise
0, // red
255, // green
0, // blue,
128, // bright
100 // speed
);
}
}
}
void CWeaponImmolator::UpdateBeam(const Vector &startPoint, const Vector &endPoint, CBasePlayer *pPlayer)
{
if (!m_hBeam && !m_hCurveBeam && !m_hCurveBeam2)
{
CreateBeam(pPlayer);
}
if (m_hBeam)
{
m_hBeam->SetStartPos(endPoint);
}
if (m_hCurveBeam)
{
m_hCurveBeam->SetStartPos(endPoint);
}
if (m_hCurveBeam2)
{
m_hCurveBeam2->SetStartPos(endPoint);
}
if (m_SSprite)
{
m_SSprite->SetAbsOrigin(endPoint);
m_SSprite->SetBrightness(random->RandomFloat(120.f, 255.f));
m_SSprite->SetScale(random->RandomFloat(0.1f, 0.2f));
}
}
void CWeaponImmolator::CreateBeam(CBasePlayer *pPlayer)
{
//DispatchParticleEffect("immolator_normal", PATTACH_POINT_FOLLOW, pPlayer->GetViewModel(), "muzzle", false);
//DispatchParticleEffect("immolator_sparks01", PATTACH_POINT_FOLLOW, pPlayer->GetViewModel(), "muzzle", false);
//DestroyEffect();
if (!m_hBeam)
{
m_hBeam = CBeam::BeamCreate(IMMOLATOR_BEAM_TEXTTURE, 1.5f);
if (cvar->FindVar("oc_player_draw_body")->GetInt() && cvar->FindVar("oc_player_true_firstperson_vm")->GetInt())
m_hBeam->PointEntInit(this->GetAbsOrigin(), this);
else
m_hBeam->PointEntInit(pPlayer->GetViewModel()->GetAbsOrigin(), pPlayer->GetViewModel());
m_hBeam->SetEndAttachment(1);
m_hBeam->AddSpawnFlags(SF_BEAM_TEMPORARY);
if (cvar->FindVar("oc_player_draw_body")->GetInt() && cvar->FindVar("oc_player_true_firstperson_vm")->GetInt())
m_hBeam->SetOwnerEntity(this);
else
m_hBeam->SetOwnerEntity(pPlayer->GetViewModel());
m_hBeam->SetBrightness(2255);
m_hBeam->SetColor(0, 255, 0);
}
if (!m_hCurveBeam)
{
m_hCurveBeam = CBeam::BeamCreate(IMMOLATOR_BEAM_TEXTTURE, 3.0);
if (cvar->FindVar("oc_player_draw_body")->GetInt() && cvar->FindVar("oc_player_true_firstperson_vm")->GetInt())
m_hCurveBeam->PointEntInit(this->GetAbsOrigin(), this);
else
m_hCurveBeam->PointEntInit(pPlayer->GetViewModel()->GetAbsOrigin(), pPlayer->GetViewModel());
m_hCurveBeam->SetEndAttachment(1);
m_hCurveBeam->AddSpawnFlags(SF_BEAM_TEMPORARY);
if (cvar->FindVar("oc_player_draw_body")->GetInt() && cvar->FindVar("oc_player_true_firstperson_vm")->GetInt())
m_hCurveBeam->SetOwnerEntity(this);
else
m_hCurveBeam->SetOwnerEntity(pPlayer->GetViewModel());
m_hCurveBeam->SetBrightness(2255);
m_hCurveBeam->SetColor(0, 255, 0);
m_hCurveBeam->SetNoise(RandomFloat(0.5f, 2.0f));
}
if (!m_hCurveBeam2)
{
m_hCurveBeam2 = CBeam::BeamCreate(IMMOLATOR_BEAM_TEXTTURE, 3.0);
if (cvar->FindVar("oc_player_draw_body")->GetInt() && cvar->FindVar("oc_player_true_firstperson_vm")->GetInt())
m_hCurveBeam2->PointEntInit(this->GetAbsOrigin(), this);
else
m_hCurveBeam2->PointEntInit(pPlayer->GetViewModel()->GetAbsOrigin(), pPlayer->GetViewModel());
m_hCurveBeam2->SetEndAttachment(1);
m_hCurveBeam2->AddSpawnFlags(SF_BEAM_TEMPORARY);
if (cvar->FindVar("oc_player_draw_body")->GetInt() && cvar->FindVar("oc_player_true_firstperson_vm")->GetInt())
m_hCurveBeam2->SetOwnerEntity(this);
else
m_hCurveBeam2->SetOwnerEntity(pPlayer->GetViewModel());
m_hCurveBeam2->SetBrightness(2255);
m_hCurveBeam2->SetColor(0, 255, 0);
m_hCurveBeam2->SetNoise(RandomFloat(0.5f, 2.0f));
}
if (!m_SSprite)
{
m_SSprite = CSprite::SpriteCreate(ADDITIONAL_SPRITE, m_hBeam->GetAbsEndPos(), false);
m_SSprite->SetParent(m_hBeam);
//m_SSprite->SetScale(0.25);
m_SSprite->SetTransparency(kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation);
m_SSprite->AddSpawnFlags(SF_SPRITE_TEMPORARY);
}
/*Vector vForward, vRight, vUp, vThrowPos;
pPlayer->EyeVectors(&vForward, &vRight, &vUp);
vThrowPos = pPlayer->EyePosition();
if (cvar->FindVar("oc_state_IRsight_on")->GetInt() == 1)
{
vThrowPos += vForward * 22.0f;
vThrowPos += vRight * 0.7f;// *1.0f;
vThrowPos += vUp * -3.4f;
CPASFilter filter(GetAbsOrigin());
te->DynamicLight(filter, 0.0, &vThrowPos, 0, 255, 0, 0, 110, 0.01, 0);
}
else if (cvar->FindVar("oc_state_IRsight_on")->GetInt() == 0)
{
vThrowPos += vForward * 22.0f;
vThrowPos += vRight * 5.4f;
vThrowPos += vUp * -3.4f;
CPASFilter filter(GetAbsOrigin());
te->DynamicLight(filter, 0.0, &vThrowPos, 0, 255, 0, 0, 110, 0.01, 0);
}*/
}
void CWeaponImmolator::DestroyBeam(void)
{
m_BeamFireState = FIRE_NONE;
if (m_bFirstPlay)
m_bFirstPlay = false;
m_flNextSecondaryAttack = m_flDmgTime = m_flChargeTime = m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
StopLoopSound();
CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
if (pPlayer)
{
StopParticleEffects(pPlayer->GetViewModel());
if (pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
m_flNextSecondaryAttack = m_flNextPrimaryAttack = gpGlobals->curtime + 0.3f;
}
if (m_hBeam)
{
UTIL_Remove(m_hBeam);
m_hBeam = NULL;
}
if (m_hCurveBeam)
{
UTIL_Remove(m_hCurveBeam);
m_hCurveBeam = NULL;
}
if (m_hCurveBeam2)
{
UTIL_Remove(m_hCurveBeam2);
m_hCurveBeam2 = NULL;
}
if (m_SSprite)
{
m_SSprite->Expand(10, 500);
m_SSprite = NULL;
}
}
bool CWeaponImmolator::Holster(CBaseCombatWeapon *pSwitchingTo)
{
bool bRet;
pSwitchingTo = NULL;
bRet = BaseClass::Holster(pSwitchingTo);
CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
if (!pPlayer)
return false;
StopWeaponSound(SINGLE);
StopWeaponSound(SPECIAL1);
m_BeamFireState = FIRE_NONE;
DestroyBeam();
if (bRet)
{
pSwitchingTo = NULL;
}
return bRet;
}
bool CWeaponImmolator::WeaponLOSCondition(const Vector &ownerPos, const Vector &targetPos, bool bSetConditions)
{
CAI_BaseNPC* npcOwner = GetOwner()->MyNPCPointer();
if (!npcOwner)
{
return false;
}
m_vecLaserTarget = targetPos;
return true;
}
int CWeaponImmolator::WeaponRangeAttack1Condition(float flDot, float flDist)
{
if (m_flNextPrimaryAttack > gpGlobals->curtime)
{
return COND_NONE;
}
if (m_vecLaserTarget == IMMOLATOR_TARGET_INVALID)
{
// No target!
return COND_NONE;
}
if (flDist > m_fMaxRange1)
{
return COND_TOO_FAR_TO_ATTACK;
}
else if (flDot < 0.5f) // UNDONE: Why check this here? Isn't the AI checking this already?
{
return COND_NOT_FACING_ATTACK;
}
return COND_CAN_RANGE_ATTACK1;
}
void CWeaponImmolator::Charge(void)
{
}
void CWeaponImmolator::ItemPostFrame(void)
{
BaseClass::ItemPostFrame();
CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
if (!pPlayer)
return;
if (!m_bReloadComplete &&
!m_bInReload &&
(IsNearWall() ||
GetOwnerIsRunning()))
{
DestroyBeam();
StopWeaponSound(SPECIAL1);
return;
}
if (pPlayer->m_nButtons & IN_ZOOM)
{
if (m_BeamFireState != FIRE_END)
m_BeamFireState = FIRE_END;
}
if (pPlayer->GetWaterLevel() == 3)
{
if (m_BeamFireState != FIRE_END)
m_BeamFireState = FIRE_END;
}
if (pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 && (m_hBeam || m_hCurveBeam || m_hCurveBeam2 || m_SSprite))
{
DestroyBeam();
StopWeaponSound(SPECIAL1);
return;
}
switch (m_BeamFireState)
{
case FIRE_STARTUP:
{
if (pPlayer->m_afButtonReleased & IN_ATTACK)
{
StopWeaponSound(SPECIAL1);
StopLoopSound();
m_BeamFireState = FIRE_END;
}
}
break;
case FIRE_LOOP:
{
if (pPlayer->m_afButtonReleased & IN_ATTACK)
{
StopWeaponSound(SPECIAL1);
StopLoopSound();
m_BeamFireState = FIRE_END;
}
}
break;
case FIRE_END:
{
StopWeaponSound(SPECIAL1);
DestroyBeam();
}
break;
default:
break;
}
/*if (!(pPlayer->m_nButtons & IN_DUCK))
pPlayer->SetMaxSpeed(hl2_normspeed.GetFloat()*0.5f);
else if (pPlayer->m_nButtons & IN_DUCK)
pPlayer->SetMaxSpeed(hl2_normspeed.GetFloat());
else if (pPlayer->GetFlags() & FL_DUCKING)
pPlayer->SetMaxSpeed(hl2_normspeed.GetFloat());
if (pPlayer->m_nButtons & IN_SPEED)
pPlayer->SetMaxSpeed(hl2_normspeed.GetFloat());*/
}
//----------------------------------------------------------------------------------
// Purpose: Check for water
//----------------------------------------------------------------------------------
#define FSetBit(iBitVector, bits) ((iBitVector) |= (bits))
#define FBitSet(iBitVector, bit) ((iBitVector) & (bit))
#define TraceContents( vec ) ( enginetrace->GetPointContents( vec ) )
#define WaterContents( vec ) ( FBitSet( TraceContents( vec ), CONTENTS_WATER|CONTENTS_SLIME ) )
bool CWeaponImmolator::ShouldDrawWaterImpacts(const trace_t &shot_trace)
{
//FIXME: This doesn't handle the case of trying to splash while being underwater, but that's not going to look good
// right now anyway...
// We must start outside the water
if (WaterContents(shot_trace.startpos))
return false;
// We must end inside of water
if (!WaterContents(shot_trace.endpos))
return false;
trace_t waterTrace;
UTIL_TraceLine(shot_trace.startpos, shot_trace.endpos, (CONTENTS_WATER | CONTENTS_SLIME), UTIL_GetLocalPlayer(), COLLISION_GROUP_NONE, &waterTrace);
if (waterTrace.fraction < 1.0f)
{
CEffectData data;
data.m_fFlags = 0;
data.m_vOrigin = waterTrace.endpos;
data.m_vNormal = waterTrace.plane.normal;
data.m_flScale = random->RandomFloat(2.0, 4.0f); // Water effect scale
// See if we hit slime
if (FBitSet(waterTrace.contents, CONTENTS_SLIME))
{
FSetBit(data.m_fFlags, FX_WATER_IN_SLIME);
}
CPASFilter filter(data.m_vOrigin);
te->DispatchEffect(filter, 0.0, data.m_vOrigin, "watersplash", data);
}
return true;
}