mirror of
https://github.com/Gigaslav/HL2Overcharged.git
synced 2026-01-06 10:10:03 +03:00
711 lines
19 KiB
C++
711 lines
19 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_laser.h"
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
#define LASER_AMMOUSING_TIME 0.1
|
|
#define LASER_DAMAGE_TIME 0.02
|
|
#define LASER_BEAM_TEXTURE "effects/Laser/laser.vmt"
|
|
#define LASER_HALO_BEAM_TEXTURE "effects/Laser/laserhalo.vmt"
|
|
#define ADDITIONAL_SPRITE "effects/Laser/aquaDot.vmt"
|
|
#define MAX_BURN_RADIUS 256
|
|
#define RADIUS_GROW_RATE 50.0
|
|
#define LASER_TARGET_INVALID Vector( FLT_MAX, FLT_MAX, FLT_MAX )
|
|
|
|
extern ConVar sk_plr_dmg_laser_wide("sk_plr_dmg_laser_wide", "7");
|
|
ConVar oc_weapon_laser_firewater_frequency("oc_weapon_laser_firewater_frequency", "0", (FCVAR_REPLICATED), "Egon damage.");
|
|
|
|
IMPLEMENT_SERVERCLASS_ST(CWeaponLaser, DT_WeaponLaser)
|
|
END_SEND_TABLE()
|
|
|
|
LINK_ENTITY_TO_CLASS(info_target_laser, CPointEntity);
|
|
LINK_ENTITY_TO_CLASS(weapon_laser, CWeaponLaser);
|
|
PRECACHE_WEAPON_REGISTER(weapon_laser);
|
|
|
|
BEGIN_DATADESC(CWeaponLaser)
|
|
|
|
DEFINE_FIELD(m_bFirstPlay, FIELD_BOOLEAN),
|
|
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_hHaloBeam, FIELD_EHANDLE),
|
|
|
|
END_DATADESC()
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Maps base activities to weapons-specific ones so our characters do the right things.
|
|
//-----------------------------------------------------------------------------
|
|
acttable_t CWeaponLaser::m_acttable[] =
|
|
{
|
|
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PHYSGUN, false },
|
|
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_PHYSGUN, false },
|
|
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PHYSGUN, false },
|
|
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_PHYSGUN, false },
|
|
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PHYSGUN, false },
|
|
{ ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PHYSGUN, false },
|
|
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PHYSGUN, false },
|
|
|
|
{ ACT_IDLE, ACT_IDLE_SMG1, true },
|
|
|
|
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, true },
|
|
{ ACT_RELOAD, ACT_RELOAD_SHOTGUN, false },
|
|
{ ACT_WALK, ACT_WALK_RIFLE, true },
|
|
{ ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SHOTGUN, true },
|
|
|
|
// Readiness activities (not aiming)
|
|
{ ACT_IDLE_RELAXED, ACT_IDLE_SHOTGUN_RELAXED, false },//never aims
|
|
{ ACT_IDLE_STIMULATED, ACT_IDLE_SHOTGUN_STIMULATED, false },
|
|
{ ACT_IDLE_AGITATED, ACT_IDLE_SHOTGUN_AGITATED, false },//always aims
|
|
|
|
{ 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
|
|
|
|
// Readiness activities (aiming)
|
|
{ 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
|
|
//End readiness activities
|
|
|
|
{ ACT_WALK_AIM, ACT_WALK_AIM_SHOTGUN, true },
|
|
{ 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_AIM, ACT_RUN_AIM_SHOTGUN, true },
|
|
{ ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true },
|
|
{ ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true },
|
|
{ ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SHOTGUN, true },
|
|
{ ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_SHOTGUN_LOW, true },
|
|
{ ACT_RELOAD_LOW, ACT_RELOAD_SHOTGUN_LOW, false },
|
|
{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false },
|
|
|
|
//{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SNIPER_RIFLE, true }
|
|
};
|
|
|
|
IMPLEMENT_ACTTABLE(CWeaponLaser);
|
|
|
|
CWeaponLaser::CWeaponLaser(void)
|
|
{
|
|
m_BeamFireState = FIRE_NONE;
|
|
m_bFirstPlay = true;
|
|
m_flChargeTime = gpGlobals->curtime;
|
|
m_flDmgTime = gpGlobals->curtime;
|
|
m_flAmmoTime = gpGlobals->curtime;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWeaponLaser::Precache(void)
|
|
{
|
|
PrecacheMaterial(LASER_BEAM_TEXTURE);
|
|
PrecacheMaterial(LASER_HALO_BEAM_TEXTURE);
|
|
PrecacheMaterial(ADDITIONAL_SPRITE);
|
|
BaseClass::Precache();
|
|
}
|
|
|
|
void CWeaponLaser::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 CWeaponLaser::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 CWeaponLaser::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:
|
|
{
|
|
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;// +GetFireRate();
|
|
|
|
if (pPlayer->GetWaterLevel() != 3)
|
|
{
|
|
if (m_bFirstPlay)
|
|
{
|
|
/*CEffectData Data;
|
|
Data.m_nEntIndex = pPlayer->GetViewModel()->entindex();
|
|
data.m_vOrigin =
|
|
DispatchEffect("LaserSparksMuzzle", Data);*/
|
|
m_flDmgTime = m_flAmmoTime = gpGlobals->curtime + GetFireRate();
|
|
WeaponSound(SINGLE);
|
|
StopWeaponSound(SPECIAL1);
|
|
m_bFirstPlay = 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 CWeaponLaser::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();
|
|
|
|
auto dmgType = tr.m_pEnt->IsCombatCharacter() ? DMG_BURN : DMG_BULLET;
|
|
|
|
if (tr.m_pEnt && tr.m_pEnt->IsAlive() && (tr.m_pEnt->GetFlags() & FL_ONFIRE) == 0)
|
|
{
|
|
CTakeDamageInfo info(this, pPlayer, sk_plr_dmg_laser_wide.GetFloat(), dmgType);
|
|
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_laser_wide.GetFloat(), DMG_BULLET);
|
|
CalculateMeleeDamageForce(&info, vecDir, tr.endpos);
|
|
tr.m_pEnt->DispatchTraceAttack(info, vecDir, &tr);
|
|
ApplyMultiDamage();
|
|
}
|
|
|
|
RadiusDamage(CTakeDamageInfo(this, this, sk_plr_dmg_laser_wide.GetFloat() / 4, dmgType), tr.endpos, 10.0f, CLASS_NONE, NULL);
|
|
}
|
|
|
|
//UTIL_Smoke(tr.endpos, random->RandomInt(5, 10), 10);//Äûì îò ëó÷à
|
|
//UTIL_DecalTrace(&tr, "RedGlowFade");
|
|
UTIL_DecalTrace(&tr, "FadingScorch"); //Ãàðü îò ëó÷à
|
|
//m_flDmgTime = gpGlobals->curtime + LASER_DAMAGE_TIME;
|
|
|
|
ShouldDrawWaterImpacts(tr);
|
|
|
|
m_flDmgTime = gpGlobals->curtime + GetFireRate();
|
|
}
|
|
|
|
}
|
|
|
|
void CWeaponLaser::AmmoUsing()
|
|
{
|
|
// Wide mode uses 10 charges per second in single player
|
|
if (m_flAmmoTime <= gpGlobals->curtime)
|
|
{
|
|
UseAmmo(1);
|
|
m_flAmmoTime = gpGlobals->curtime + LASER_AMMOUSING_TIME;
|
|
}
|
|
}
|
|
|
|
void CWeaponLaser::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);
|
|
|
|
if (tr.allsolid)
|
|
return;
|
|
|
|
/*CEffectData data;
|
|
data.m_vOrigin = tr.endpos + (tr.plane.normal * 1.0f);
|
|
data.m_vNormal = tr.plane.normal;
|
|
DispatchEffect("LaserSparksImpact", data);*/
|
|
|
|
UTIL_ImpactTrace(&tr, GetDamageType(), "LaserSparksImpact");
|
|
|
|
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("LaserWeaponLight", data);
|
|
}
|
|
/*CPASFilter filter(GetAbsOrigin());
|
|
te->DynamicLight(filter, 0.0, &tr.endpos, 0, 213, 255, 0, 250, 0.09, 0);*/
|
|
|
|
//DispatchParticleEffect("ball", tmpSrc, tr.endpos, vec3_angle, NULL);
|
|
//UpdateEffect( tr.endpos );
|
|
//UTIL_ImpactTrace( &tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss" ); // ñëåä íà ñòåíå
|
|
}
|
|
|
|
void CWeaponLaser::UpdateBeam(const Vector &startPoint, const Vector &endPoint, CBasePlayer *pPlayer)
|
|
{
|
|
if (!m_hBeam)
|
|
{
|
|
CreateBeam(pPlayer);
|
|
}
|
|
else
|
|
{
|
|
m_hBeam->SetStartPos(endPoint);
|
|
}
|
|
|
|
if (m_hHaloBeam)
|
|
{
|
|
m_hHaloBeam->SetStartPos(endPoint);
|
|
}
|
|
|
|
if (m_SSprite)
|
|
{
|
|
m_SSprite->SetAbsOrigin(endPoint);
|
|
m_SSprite->SetBrightness(random->RandomFloat(180.f, 255.f));
|
|
m_SSprite->SetScale(random->RandomFloat(1.0f, 2.0f));
|
|
}
|
|
}
|
|
|
|
void CWeaponLaser::CreateBeam(CBasePlayer *pPlayer)
|
|
{
|
|
if (!m_hBeam)
|
|
{
|
|
int width = 2.0f;
|
|
m_hBeam = CBeam::BeamCreate(LASER_BEAM_TEXTURE, width*0.5);
|
|
m_hBeam->SetWidth(width);
|
|
|
|
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->SetScrollRate(950);
|
|
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, 213, 255);
|
|
//m_hBeam->SetHaloTexture(PrecacheModel(LASER_HALO_BEAM_TEXTURE));
|
|
}
|
|
else
|
|
{
|
|
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, 213, 255, 0, 170, 0.12, 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, 213, 255, 0, 170, 0.12, 0);
|
|
}*/
|
|
}
|
|
|
|
if (!m_hHaloBeam)
|
|
{
|
|
int width = 4.0f;
|
|
m_hHaloBeam = CBeam::BeamCreate(LASER_HALO_BEAM_TEXTURE, width*0.5);
|
|
|
|
if (cvar->FindVar("oc_player_draw_body")->GetInt() && cvar->FindVar("oc_player_true_firstperson_vm")->GetInt())
|
|
m_hHaloBeam->PointEntInit(this->GetAbsOrigin(), this);
|
|
else
|
|
m_hHaloBeam->PointEntInit(pPlayer->GetViewModel()->GetAbsOrigin(), pPlayer->GetViewModel());
|
|
|
|
m_hHaloBeam->SetEndWidth(width);
|
|
m_hHaloBeam->SetEndAttachment(1);
|
|
m_hHaloBeam->SetScrollRate(950);
|
|
m_hHaloBeam->AddSpawnFlags(SF_BEAM_TEMPORARY);
|
|
|
|
if (cvar->FindVar("oc_player_draw_body")->GetInt() && cvar->FindVar("oc_player_true_firstperson_vm")->GetInt())
|
|
m_hHaloBeam->SetOwnerEntity(this);
|
|
else
|
|
m_hHaloBeam->SetOwnerEntity(pPlayer);
|
|
|
|
m_hHaloBeam->SetBrightness(50);
|
|
m_hHaloBeam->SetColor(0, 213, 255);
|
|
}
|
|
|
|
if (!m_SSprite)
|
|
{
|
|
m_SSprite = CSprite::SpriteCreate(ADDITIONAL_SPRITE, m_hBeam->GetAbsEndPos(), false);
|
|
m_SSprite->SetParent(m_hBeam);
|
|
m_SSprite->SetScale(1.0);
|
|
m_SSprite->SetColor(0, 213, 255);
|
|
m_SSprite->SetTransparency(kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation);
|
|
m_SSprite->AddSpawnFlags(SF_SPRITE_TEMPORARY);
|
|
}
|
|
}
|
|
|
|
void CWeaponLaser::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)
|
|
{
|
|
//GetParticleSystemIndex("")
|
|
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_hHaloBeam)
|
|
{
|
|
UTIL_Remove(m_hHaloBeam);
|
|
m_hHaloBeam = NULL;
|
|
}
|
|
|
|
if (m_SSprite)
|
|
{
|
|
m_SSprite->Expand(10, 500);
|
|
m_SSprite = NULL;
|
|
}
|
|
}
|
|
|
|
bool CWeaponLaser::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 CWeaponLaser::WeaponLOSCondition(const Vector &ownerPos, const Vector &targetPos, bool bSetConditions)
|
|
{
|
|
CAI_BaseNPC* npcOwner = GetOwner()->MyNPCPointer();
|
|
|
|
if (!npcOwner)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_vecLaserTarget = targetPos;
|
|
return true;
|
|
}
|
|
|
|
|
|
int CWeaponLaser::WeaponRangeAttack1Condition(float flDot, float flDist)
|
|
{
|
|
if (m_flNextPrimaryAttack > gpGlobals->curtime)
|
|
{
|
|
return COND_NONE;
|
|
}
|
|
|
|
if (m_vecLaserTarget == LASER_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 CWeaponLaser::Charge(void)
|
|
{
|
|
|
|
|
|
}
|
|
|
|
void CWeaponLaser::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_hHaloBeam || 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 CWeaponLaser::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;
|
|
} |