/*** * * Copyright (c) 1996-2001, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. * All Rights Reserved. * * Use, distribution, and modification of this source code and/or resulting * object code is restricted to non-commercial enhancements to products from * Valve LLC. All other use, distribution, or modification is prohibited * without written permission from Valve LLC. * ****/ #include "extdll.h" #include "util.h" #include "cbase.h" #include "monsters.h" #include "weapons.h" #include "nodes.h" #include "player.h" #include "soundent.h" #include "gamerules.h" #include "decals.h" #include "sporegrenade.h" LINK_ENTITY_TO_CLASS(spore, CSpore) TYPEDESCRIPTION CSpore::m_SaveData[] = { DEFINE_FIELD(CSpore, m_SporeType, FIELD_INTEGER), DEFINE_FIELD(CSpore, m_flIgniteTime, FIELD_TIME), DEFINE_FIELD(CSpore, m_bIsAI, FIELD_BOOLEAN), DEFINE_FIELD(CSpore, m_hSprite, FIELD_EHANDLE) }; IMPLEMENT_SAVERESTORE(CSpore, CGrenade) int gSporeExplode, gSporeExplodeC; void CSpore::Precache(void) { PRECACHE_MODEL("models/spore.mdl"); PRECACHE_MODEL("sprites/glow01.spr"); m_iBlow = PRECACHE_MODEL("sprites/spore_exp_01.spr"); m_iBlowSmall = PRECACHE_MODEL("sprites/spore_exp_c_01.spr"); m_iSpitSprite = m_iTrail = PRECACHE_MODEL("sprites/tinyspit.spr"); PRECACHE_SOUND("weapons/splauncher_bounce.wav"); PRECACHE_SOUND("weapons/splauncher_impact.wav"); } void CSpore::Spawn() { Precache(); if (m_SporeType == GRENADE) pev->movetype = MOVETYPE_BOUNCE; else pev->movetype = MOVETYPE_FLY; pev->solid = SOLID_BBOX; SET_MODEL(edict(), "models/spore.mdl"); UTIL_SetSize(pev, g_vecZero, g_vecZero); UTIL_SetOrigin(pev, pev->origin); SetThink(&CSpore::FlyThink); if (m_SporeType == GRENADE) { SetTouch(&CSpore::MyBounceTouch); if (!m_bPuked) { pev->angles.x -= RANDOM_LONG(-5, 5) + 30; } } else { SetTouch(&CSpore::RocketTouch); } UTIL_MakeVectors(pev->angles); if (!m_bIsAI) { if (m_SporeType != GRENADE) { pev->velocity = gpGlobals->v_forward * 1200; } pev->gravity = 1; } else { pev->gravity = 0.5; pev->friction = 0.7; } pev->dmg = gSkillData.plrDmgSpore; m_flIgniteTime = gpGlobals->time; pev->nextthink = gpGlobals->time + 0.01; CSprite* sprite = CSprite::SpriteCreate("sprites/glow01.spr", pev->origin, false); if (sprite) { sprite->SetTransparency(kRenderTransAdd, 180, 180, 40, 100, kRenderFxDistort); sprite->SetScale(0.8); sprite->SetAttachment(edict(), 0); m_hSprite = sprite; } m_fRegisteredSound = false; m_flSoundDelay = gpGlobals->time; } void CSpore::BounceSound() { //Nothing } void CSpore::IgniteThink() { SetThink(NULL); SetTouch(NULL); if (m_hSprite) { UTIL_Remove(m_hSprite); m_hSprite = 0; } EMIT_SOUND(edict(), CHAN_WEAPON, "weapons/splauncher_impact.wav", VOL_NORM, ATTN_NORM); const Vector vecDir = pev->velocity.Normalize(); TraceResult tr; UTIL_TraceLine( pev->origin, pev->origin + vecDir * (m_SporeType == GRENADE ? 64 : 32), dont_ignore_monsters, edict(), &tr); UTIL_DecalTrace(&tr, DECAL_SPR_SPLT1 + RANDOM_LONG(0, 2)); MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin); WRITE_BYTE(TE_SPRITE_SPRAY); WRITE_COORD( pev->origin.x ); WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); WRITE_COORD( tr.vecPlaneNormal.x ); WRITE_COORD( tr.vecPlaneNormal.y ); WRITE_COORD( tr.vecPlaneNormal.z ); WRITE_SHORT(m_iSpitSprite); WRITE_BYTE(100); WRITE_BYTE(40); WRITE_BYTE(180); MESSAGE_END(); MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin); WRITE_BYTE(TE_DLIGHT); WRITE_COORD( pev->origin.x ); WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); WRITE_BYTE(10); WRITE_BYTE(15); WRITE_BYTE(220); WRITE_BYTE(40); WRITE_BYTE(5); WRITE_BYTE(10); MESSAGE_END(); MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin); WRITE_BYTE(TE_SPRITE); WRITE_COORD( pev->origin.x ); WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); WRITE_SHORT(RANDOM_LONG(0, 1) ? m_iBlow : m_iBlowSmall); WRITE_BYTE(20); WRITE_BYTE(128); MESSAGE_END(); MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin); WRITE_BYTE(TE_SPRITE_SPRAY); WRITE_COORD( pev->origin.x ); WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); WRITE_COORD(RANDOM_FLOAT(-1, 1)); WRITE_COORD(1); WRITE_COORD(RANDOM_FLOAT(-1, 1)); WRITE_SHORT(m_iTrail); WRITE_BYTE(2); WRITE_BYTE(20); WRITE_BYTE(80); MESSAGE_END(); ::RadiusDamage(pev->origin, pev, VARS(pev->owner), pev->dmg, 200, CLASS_NONE, DMG_ALWAYSGIB | DMG_BLAST); SetThink(&CSpore::SUB_Remove); pev->nextthink = gpGlobals->time; } void CSpore::FlyThink() { const float flDelay = m_bIsAI ? 4.0 : 2.0; if (m_SporeType != GRENADE || (gpGlobals->time <= m_flIgniteTime + flDelay)) { Vector velocity = pev->velocity.Normalize(); MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin); WRITE_BYTE(TE_SPRITE_SPRAY); WRITE_COORD( pev->origin.x ); WRITE_COORD( pev->origin.y ); WRITE_COORD( pev->origin.z ); WRITE_COORD( velocity.x ); WRITE_COORD( velocity.y ); WRITE_COORD( velocity.z ); WRITE_SHORT(m_iTrail); WRITE_BYTE(2); WRITE_BYTE(20); WRITE_BYTE(80); MESSAGE_END(); } else { SetThink(&CSpore::IgniteThink); } pev->nextthink = gpGlobals->time + 0.03; } void CSpore::GibThink() { //Nothing } void CSpore::RocketTouch(CBaseEntity* pOther) { if (pOther->pev->takedamage != DAMAGE_NO) { pOther->TakeDamage(pev, VARS(pev->owner), gSkillData.plrDmgSpore, DMG_GENERIC); } IgniteThink(); } void CSpore::MyBounceTouch(CBaseEntity* pOther) { if (pOther->pev->takedamage == DAMAGE_NO) { if (pOther->edict() != pev->owner) { if (gpGlobals->time > m_flSoundDelay) { CSoundEnt::InsertSound(bits_SOUND_DANGER, pev->origin, (int)(pev->dmg * 2.5f), 0.3); m_flSoundDelay = gpGlobals->time + 1.0; } if ((pev->flags & FL_ONGROUND) != 0) { pev->velocity = pev->velocity * 0.5; } else { EMIT_SOUND_DYN(edict(), CHAN_VOICE, "weapons/splauncher_bounce.wav", 0.25, ATTN_NORM, 0, PITCH_NORM); } } } else { pOther->TakeDamage(pev, VARS(pev->owner), gSkillData.plrDmgSpore, DMG_GENERIC); IgniteThink(); } } CSpore* CSpore::CreateSpore(const Vector& vecOrigin, const Vector& vecAngles, CBaseEntity* pOwner, SporeType sporeType, bool bIsAI, bool bPuked) { CSpore* pSpore = GetClassPtr(NULL); UTIL_SetOrigin(pSpore->pev, vecOrigin); pSpore->m_SporeType = sporeType; if (bIsAI) { pSpore->pev->velocity = vecAngles; pSpore->pev->angles = UTIL_VecToAngles(vecAngles); } else { pSpore->pev->angles = vecAngles; } pSpore->m_bIsAI = bIsAI; pSpore->m_bPuked = bPuked; pSpore->Spawn(); pSpore->pev->owner = pOwner->edict(); pSpore->pev->classname = MAKE_STRING("spore"); return pSpore; } void CSpore::UpdateOnRemove() { CGrenade::UpdateOnRemove(); if (m_hSprite) { UTIL_Remove(m_hSprite); m_hSprite = 0; } }