You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
618 lines
14 KiB
618 lines
14 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// |
|
//=====================================================================================// |
|
|
|
#include "cbase.h" // for pch |
|
#include "props.h" |
|
#include "filters.h" |
|
#include "achievementmgr.h" |
|
|
|
extern CAchievementMgr g_AchievementMgrPortal; |
|
|
|
#define RADIO_MODEL_NAME "models/props/radio_reference.mdl" |
|
//#define RADIO_DEBUG_SERVER |
|
|
|
class CDinosaurSignal : public CBaseEntity |
|
{ |
|
public: |
|
DECLARE_DATADESC(); |
|
DECLARE_SERVERCLASS(); |
|
DECLARE_CLASS( CDinosaurSignal, CBaseEntity ); |
|
void Spawn(); |
|
int UpdateTransmitState(); |
|
#if RADIO_DEBUG_SERVER |
|
int DrawDebugTextOverlays( void ); |
|
#endif |
|
|
|
CNetworkString( m_szSoundName, 128 ); |
|
CNetworkVar( float, m_flInnerRadius ); |
|
CNetworkVar( float, m_flOuterRadius ); |
|
CNetworkVar( int, m_nSignalID ); |
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS( updateitem1, CDinosaurSignal ); |
|
|
|
BEGIN_DATADESC( CDinosaurSignal ) |
|
DEFINE_AUTO_ARRAY( m_szSoundName, FIELD_CHARACTER ), |
|
DEFINE_FIELD( m_flOuterRadius, FIELD_FLOAT ), |
|
DEFINE_FIELD( m_flInnerRadius, FIELD_FLOAT ), |
|
DEFINE_FIELD( m_nSignalID, FIELD_INTEGER ), |
|
END_DATADESC() |
|
|
|
IMPLEMENT_SERVERCLASS_ST( CDinosaurSignal, DT_DinosaurSignal ) |
|
SendPropString( SENDINFO(m_szSoundName) ), |
|
SendPropFloat( SENDINFO(m_flOuterRadius) ), |
|
SendPropFloat( SENDINFO(m_flInnerRadius) ), |
|
SendPropInt( SENDINFO(m_nSignalID) ), |
|
END_SEND_TABLE() |
|
|
|
void CDinosaurSignal::Spawn() |
|
{ |
|
PrecacheScriptSound( m_szSoundName.Get() ); |
|
BaseClass::Spawn(); |
|
SetTransmitState( FL_EDICT_ALWAYS ); |
|
} |
|
|
|
int CDinosaurSignal::UpdateTransmitState() |
|
{ |
|
// ALWAYS transmit to all clients. |
|
return SetTransmitState( FL_EDICT_ALWAYS ); |
|
} |
|
|
|
#if RADIO_DEBUG_SERVER |
|
int CDinosaurSignal::DrawDebugTextOverlays( void ) |
|
{ |
|
int text_offset = BaseClass::DrawDebugTextOverlays(); |
|
if (m_debugOverlays & OVERLAY_TEXT_BIT) |
|
{ |
|
NDebugOverlay::Sphere( GetAbsOrigin(), GetAbsAngles(), m_flInnerRadius, 255, 0, 0, 64, false, 0.1f ); |
|
NDebugOverlay::Sphere( GetAbsOrigin(), GetAbsAngles(), m_flOuterRadius, 0, 255, 0, 64, false, 0.1f ); |
|
} |
|
return text_offset; |
|
} |
|
#endif |
|
|
|
|
|
class CPortal_Dinosaur : public CPhysicsProp |
|
{ |
|
public: |
|
DECLARE_CLASS( CPortal_Dinosaur, CPhysicsProp ); |
|
DECLARE_DATADESC(); |
|
DECLARE_SERVERCLASS(); |
|
|
|
virtual void Spawn(); |
|
virtual void Precache(); |
|
virtual QAngle PreferredCarryAngles( void ) { return QAngle( 0, 180, 0 ); } |
|
virtual bool HasPreferredCarryAnglesForPlayer( CBasePlayer *pPlayer ) { return true; } |
|
virtual void Activate(); |
|
|
|
|
|
CNetworkHandle( CDinosaurSignal, m_hDinosaur_Signal ); |
|
CNetworkVar( bool, m_bAlreadyDiscovered ); |
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS( updateitem2, CPortal_Dinosaur ); |
|
|
|
BEGIN_DATADESC( CPortal_Dinosaur ) |
|
DEFINE_FIELD( m_hDinosaur_Signal, FIELD_EHANDLE ), |
|
DEFINE_FIELD( m_bAlreadyDiscovered, FIELD_BOOLEAN ), |
|
END_DATADESC() |
|
|
|
IMPLEMENT_SERVERCLASS_ST( CPortal_Dinosaur, DT_PropDinosaur ) |
|
SendPropEHandle( SENDINFO( m_hDinosaur_Signal ) ), |
|
SendPropBool( SENDINFO( m_bAlreadyDiscovered ) ), |
|
END_SEND_TABLE() |
|
|
|
void CPortal_Dinosaur::Precache() |
|
{ |
|
PrecacheModel( RADIO_MODEL_NAME ); |
|
|
|
PrecacheScriptSound( "Portal.room1_radio" ); |
|
PrecacheScriptSound( "UpdateItem.Static" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur01" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur02" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur03" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur04" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur05" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur06" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur07" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur08" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur09" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur10" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur11" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur12" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur13" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur14" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur15" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur16" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur17" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur18" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur19" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur20" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur21" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur22" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur23" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur24" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur25" ); |
|
PrecacheScriptSound( "UpdateItem.Dinosaur26" ); |
|
|
|
PrecacheScriptSound( "UpdateItem.Fizzle" ); |
|
} |
|
|
|
|
|
void CPortal_Dinosaur::Spawn() |
|
{ |
|
Precache(); |
|
KeyValue( "model", RADIO_MODEL_NAME ); |
|
m_spawnflags |= SF_PHYSPROP_START_ASLEEP; |
|
BaseClass::Spawn(); |
|
} |
|
|
|
void CPortal_Dinosaur::Activate( void ) |
|
{ |
|
// Find the current completion status of the dinosaurs |
|
uint64 fStateFlags = 0; |
|
CBaseAchievement *pTransmissionRecvd = dynamic_cast<CBaseAchievement *>(g_AchievementMgrPortal.GetAchievementByName("PORTAL_TRANSMISSION_RECEIVED")); |
|
if ( pTransmissionRecvd ) |
|
{ |
|
fStateFlags = pTransmissionRecvd->GetComponentBits(); |
|
} |
|
|
|
if ( m_hDinosaur_Signal != NULL ) |
|
{ |
|
uint64 nId = m_hDinosaur_Signal.Get()->m_nSignalID; |
|
// See if we're already tripped |
|
if ( fStateFlags & ((uint64)1<<nId) ) |
|
{ |
|
m_bAlreadyDiscovered = true; |
|
} |
|
} |
|
|
|
BaseClass::Activate(); |
|
} |
|
|
|
struct radiolocs |
|
{ |
|
const char *mapname; |
|
const char *soundname; |
|
int id; |
|
float radiopos[3]; |
|
float radioang[3]; |
|
float soundpos[3]; |
|
float soundouterrad; |
|
float soundinnerrad; |
|
}; |
|
static const radiolocs s_radiolocs[] = |
|
{ |
|
{ |
|
"testchmb_a_00", |
|
"UpdateItem.Dinosaur01", |
|
0, |
|
{ 0, 0, 0 }, |
|
{ 0, 0, 0 }, |
|
{ -506, -924, 161 }, |
|
200, |
|
64 |
|
}, |
|
{ |
|
"testchmb_a_00", |
|
"UpdateItem.Dinosaur02", |
|
1, |
|
{ -960, -634, 783 }, |
|
{ 0, 90, 0 }, |
|
{ -926.435, -256.323, 583 }, |
|
200, |
|
64, |
|
}, |
|
{ |
|
"testchmb_a_01", |
|
"UpdateItem.Dinosaur03", |
|
2, |
|
{ 233, 393, 130 }, |
|
{ 0, 225, 0 }, |
|
{ 96, 160, -108 }, |
|
224, |
|
128, |
|
}, |
|
{ |
|
"testchmb_a_01", |
|
"UpdateItem.Dinosaur04", |
|
3, |
|
{ -1439.89, 1076.04, 779.102 }, |
|
{ 0, 270, 0 }, |
|
{ -731, 735, 888 }, |
|
400, |
|
64, |
|
}, |
|
{ |
|
// new entry |
|
"testchmb_a_02", |
|
"UpdateItem.Dinosaur05", |
|
4, |
|
{ 2, 65, 390 }, |
|
{ 0, 270, 0 }, |
|
{ -864, 192, 64}, |
|
192, |
|
96, |
|
}, |
|
{ |
|
"testchmb_a_02", |
|
"UpdateItem.Dinosaur06", |
|
21, |
|
{ 111, 832, 577 }, |
|
{ 0, 0, 0 }, |
|
{ 918, 831, 512}, |
|
192, |
|
96, |
|
}, |
|
{ |
|
"testchmb_a_03", |
|
"UpdateItem.Dinosaur07", |
|
5, |
|
{ -53.2337, 78.181, 236 }, |
|
{ 0, 225, 0 }, |
|
{ 304, 0, -96 }, |
|
256, |
|
128 |
|
}, |
|
// new entry |
|
{ |
|
"testchmb_a_03", |
|
"UpdateItem.Dinosaur08", |
|
6, |
|
{ 428.112, 0.22326, 1201 }, |
|
{ 0, 180, 0 }, |
|
{ -581.096, 193.694, 1351 }, |
|
165, |
|
128 |
|
}, |
|
{ |
|
"testchmb_a_04", |
|
"UpdateItem.Dinosaur09", |
|
7, |
|
{ 118, -56.6, -38.8 }, |
|
{ 0, 180, 0 }, |
|
{ -640, 256, 8 }, |
|
512, |
|
128 |
|
}, |
|
// new entry |
|
{ |
|
"testchmb_a_05", |
|
"UpdateItem.Dinosaur10", |
|
8, |
|
{ 64, 144, 160 }, |
|
{ 0, 270, 0 }, |
|
{ 64, 740, 7 }, |
|
350, |
|
128 |
|
}, |
|
{ |
|
"testchmb_a_06", |
|
"UpdateItem.Dinosaur11", |
|
9, |
|
{ 529, 315, 320 }, |
|
{ 0, 270, 0 }, |
|
{ 608, 128, -184 }, |
|
384, |
|
160 |
|
}, |
|
{ |
|
"testchmb_a_07", |
|
"UpdateItem.Dinosaur12", |
|
10, |
|
{ 192, -1546, 1425 }, |
|
{ 0, 113, 0 }, |
|
{ 272, -496, 1328 }, |
|
432, |
|
88 |
|
}, |
|
// new entry |
|
{ |
|
"testchmb_a_07", |
|
"UpdateItem.Dinosaur13", |
|
11, |
|
{ -144, -768, 256 }, |
|
{ 0, 90, 0 }, |
|
{ -192, -384, 176 }, |
|
256, |
|
128 |
|
}, |
|
{ |
|
"testchmb_a_08", |
|
"UpdateItem.Dinosaur14", |
|
12, |
|
{ 267, -378, 256 }, |
|
{ 0, 90, 0 }, |
|
{ -560, 96, 320 }, |
|
288, |
|
128, |
|
}, |
|
{ |
|
"testchmb_a_09", |
|
"UpdateItem.Dinosaur15", |
|
13, |
|
{ 634, 1308, 256 }, |
|
{ 0, 180, 0 }, |
|
{ 386.699, 1792.43, 7}, |
|
548, |
|
64 |
|
}, |
|
{ |
|
"testchmb_a_10", |
|
"UpdateItem.Dinosaur16", |
|
14, |
|
{ -1420, -2752, 76 }, |
|
{ 0, 0, 0 }, |
|
{ -1968, -2880, -334 }, |
|
448, |
|
196, |
|
}, |
|
// new entry |
|
{ |
|
"testchmb_a_10", |
|
"UpdateItem.Dinosaur17", |
|
15, |
|
{ 112, 1392, -63 }, |
|
{ 0, 260, 0 }, |
|
{ -189, 1220, 65 }, |
|
192, |
|
128, |
|
}, |
|
{ |
|
"testchmb_a_11", |
|
"UpdateItem.Dinosaur18", |
|
16, |
|
{0,0,0}, |
|
{0,0,0}, |
|
{-512,644,64}, |
|
192, |
|
96, |
|
}, |
|
{ |
|
"testchmb_a_13", |
|
"UpdateItem.Dinosaur19", |
|
17, |
|
{955,931,-267}, |
|
{-90,0,0}, |
|
{1472,-191,-12}, |
|
256, |
|
128, |
|
}, |
|
{ |
|
"testchmb_a_14", |
|
"UpdateItem.Dinosaur20", |
|
18, |
|
{0,0,0}, |
|
{0,0,0}, |
|
{144,192,1288}, |
|
807, |
|
128, |
|
}, |
|
{ |
|
"testchmb_a_14", |
|
"UpdateItem.Dinosaur21", |
|
22, |
|
{1285, 1344, 1412}, |
|
{0,0,0}, |
|
{2712, 894, 1011}, |
|
200, |
|
120, |
|
}, |
|
{ |
|
"testchmb_a_14", |
|
"UpdateItem.Dinosaur22", |
|
23, |
|
{-952, 336, -256}, |
|
{0,0,0}, |
|
{-1144, -249, 3336}, |
|
400, |
|
128, |
|
}, |
|
{ |
|
"testchmb_a_15", |
|
"UpdateItem.Dinosaur23", |
|
19, |
|
{-1529,293,-283}, |
|
{0,90,0}, |
|
{761,443,810}, |
|
256, |
|
128, |
|
}, |
|
{ |
|
"escape_00", |
|
"UpdateItem.Dinosaur24", |
|
24, |
|
{192, -1344, -832}, |
|
{0, 135, 0}, |
|
{891, 322, -184}, |
|
285, |
|
150, |
|
}, |
|
{ |
|
"escape_01", |
|
"UpdateItem.Dinosaur25", |
|
20, |
|
{0,0,0}, |
|
{0,0,0}, |
|
{-624, 1440, -464}, |
|
512, |
|
128, |
|
}, |
|
{ |
|
"escape_02", |
|
"UpdateItem.Dinosaur26", |
|
25, |
|
{5504, 131, -1422}, |
|
{0, 90, 0}, |
|
{4218, 674, 8}, |
|
300, |
|
100, |
|
}, |
|
}; |
|
|
|
class CSpawnDinosaurHack : CAutoGameSystem |
|
{ |
|
public: |
|
virtual void LevelInitPreEntity(); |
|
virtual void LevelInitPostEntity(); |
|
|
|
CPortal_Dinosaur *SpawnDinosaur( radiolocs& loc ); |
|
CDinosaurSignal *SpawnSignal( radiolocs& loc ); |
|
|
|
void ApplyMapSpecificHacks(); |
|
}; |
|
|
|
static CSpawnDinosaurHack g_SpawnRadioHack; |
|
|
|
void CSpawnDinosaurHack::LevelInitPreEntity() |
|
{ |
|
UTIL_PrecacheOther( "updateitem2", RADIO_MODEL_NAME ); |
|
|
|
ApplyMapSpecificHacks(); |
|
} |
|
|
|
// Spawn all the Dinosaurs and sstv images |
|
void CSpawnDinosaurHack::LevelInitPostEntity() |
|
{ |
|
if ( gpGlobals->eLoadType == MapLoad_LoadGame ) |
|
{ |
|
#if defined ( RADIO_DEBUG_SERVER ) |
|
Msg( "Not spawning any Dinosaurs: Detected a map load\n" ); |
|
#endif |
|
|
|
return; |
|
} |
|
|
|
IAchievement *pHeartbreaker = g_AchievementMgrPortal.GetAchievementByName("PORTAL_BEAT_GAME"); |
|
if ( pHeartbreaker == NULL || pHeartbreaker->IsAchieved() == false ) |
|
{ |
|
#if defined ( RADIO_DEBUG_SERVER ) |
|
Msg( "Not spawning any Dinosaurs: Player has not beat the game, or failed to get heartbreaker achievement from mgr\n" ); |
|
#endif |
|
|
|
return; |
|
} |
|
|
|
for ( int i = 0; i < ARRAYSIZE( s_radiolocs ); ++i ) |
|
{ |
|
radiolocs loc = s_radiolocs[i]; |
|
if ( V_strcmp( STRING(gpGlobals->mapname), loc.mapname ) == 0 ) |
|
{ |
|
#if defined ( RADIO_DEBUG_SERVER ) |
|
Msg( "Found Dinosaur and signal info for %s, spawning.\n", loc.mapname ); |
|
Msg( "Dinosaur pos: %f %f %f, ang: %f %f %f\n", loc.radiopos[0], loc.radiopos[1], loc.radiopos[2], loc.radioang[0], loc.radioang[1], loc.radioang[2] ); |
|
Msg( "Signal pos: %f %f %f, inner rad: %f, outter rad: %f\n", loc.soundpos[0], loc.soundpos[1], loc.soundpos[2], loc.soundinnerrad, loc.soundouterrad ); |
|
#endif |
|
|
|
CPortal_Dinosaur *pDinosaur = SpawnDinosaur( loc ); |
|
CDinosaurSignal *pSignal = SpawnSignal( loc ); |
|
|
|
Assert ( pDinosaur && pSignal ); |
|
if ( pDinosaur && pSignal ) |
|
{ |
|
#if defined ( RADIO_DEBUG_SERVER ) |
|
Msg( "SUCCESS: Spawned Dinosaur and signal and linked them.\n" ); |
|
#endif |
|
// OK, so these really could have been the same class... not worth changing it now though. |
|
pDinosaur->m_hDinosaur_Signal.Set( pSignal ); |
|
pDinosaur->Activate(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
CPortal_Dinosaur *CSpawnDinosaurHack::SpawnDinosaur( radiolocs& loc ) |
|
{ |
|
Vector vSpawnPos ( loc.radiopos[0], loc.radiopos[1], loc.radiopos[2] ); |
|
QAngle vSpawnAng ( loc.radioang[0], loc.radioang[1], loc.radioang[2] ); |
|
|
|
// origin and angles of zero means skip this Dinosaur creation and look for an existing radio |
|
if ( loc.radiopos[0] == 0 && |
|
loc.radiopos[1] == 0 && |
|
loc.radiopos[2] == 0 && |
|
loc.radioang[0] == 0 && |
|
loc.radioang[1] == 0 && |
|
loc.radioang[2] == 0 ) |
|
{ |
|
|
|
#if defined ( RADIO_DEBUG_SERVER ) |
|
Msg( "Dinosaur found with zero angles and origin. Replacing existing radio.\n" ); |
|
#endif |
|
// Find existing Dinosaur, kill it and spawn at its position |
|
CPhysicsProp *pOldDinosaur = (CPhysicsProp*)gEntList.FindEntityByClassname( NULL, "prop_physics" ); |
|
while ( pOldDinosaur ) |
|
{ |
|
if ( V_strcmp( STRING( pOldDinosaur->GetModelName() ), RADIO_MODEL_NAME ) == 0 ) |
|
{ |
|
vSpawnPos = pOldDinosaur->GetAbsOrigin(); |
|
vSpawnAng = pOldDinosaur->GetAbsAngles(); |
|
|
|
UTIL_Remove( pOldDinosaur ); |
|
|
|
#if defined ( RADIO_DEBUG_SERVER ) |
|
Msg( "Found Dinosaur exiting in level, replacing with %f, %f %f and %f %f %f.\n", XYZ(vSpawnPos), XYZ(vSpawnAng) ); |
|
#endif |
|
break; |
|
} |
|
|
|
pOldDinosaur = (CPhysicsProp*)gEntList.FindEntityByClassname( pOldDinosaur, "prop_physics" ); |
|
} |
|
} |
|
|
|
Assert( vSpawnPos != vec3_origin ); |
|
|
|
CPortal_Dinosaur *pDinosaur = (CPortal_Dinosaur*)CreateEntityByName( "updateitem2" ); |
|
Assert ( pDinosaur ); |
|
if ( pDinosaur ) |
|
{ |
|
pDinosaur->SetAbsOrigin( vSpawnPos ); |
|
pDinosaur->SetAbsAngles( vSpawnAng ); |
|
DispatchSpawn( pDinosaur ); |
|
} |
|
|
|
return pDinosaur; |
|
} |
|
|
|
CDinosaurSignal *CSpawnDinosaurHack::SpawnSignal( radiolocs& loc ) |
|
{ |
|
CDinosaurSignal *pSignal = (CDinosaurSignal*)CreateEntityByName( "updateitem1" ); |
|
Assert ( pSignal ); |
|
if ( pSignal ) |
|
{ |
|
#if defined ( RADIO_DEBUG_SERVER ) |
|
if ( loc.soundinnerrad > loc.soundouterrad ) |
|
{ |
|
Assert( 0 ); |
|
Warning( "Dinosaur BUG: Inner radius is greater than outer radius. Will swap them.\n" ); |
|
swap( loc.soundinnerrad, loc.soundouterrad ); |
|
} |
|
#endif |
|
pSignal->SetAbsOrigin( Vector( loc.soundpos[0], loc.soundpos[1], loc.soundpos[2] ) ); |
|
pSignal->m_flInnerRadius = loc.soundinnerrad; |
|
pSignal->m_flOuterRadius = loc.soundouterrad; |
|
V_strncpy( pSignal->m_szSoundName.GetForModify(), loc.soundname, 128 ); |
|
pSignal->m_nSignalID = loc.id; |
|
DispatchSpawn( pSignal ); |
|
} |
|
|
|
return pSignal; |
|
} |
|
|
|
|
|
void CSpawnDinosaurHack::ApplyMapSpecificHacks() |
|
{ |
|
if ( V_strcmp( STRING(gpGlobals->mapname), "testchmb_a_02" ) == 0 ) |
|
{ |
|
CBaseEntity *pFilter = CreateEntityByName( "filter_activator_name" ); |
|
Assert( pFilter ); |
|
if ( pFilter ) |
|
{ |
|
pFilter->KeyValue( "filtername", "box_2" ); |
|
pFilter->KeyValue( "targetname", "filter_weight_box" ); |
|
DispatchSpawn( pFilter ); |
|
} |
|
} |
|
} |
|
|
|
|