|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Precaches and defs for entities and other data that must always be available.
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "soundent.h"
#include "client.h"
#include "decals.h"
#include "EnvMessage.h"
#include "player.h"
#include "gamerules.h"
#include "teamplay_gamerules.h"
#include "physics.h"
#include "isaverestore.h"
#include "activitylist.h"
#include "eventlist.h"
#include "eventqueue.h"
#include "ai_network.h"
#include "ai_schedule.h"
#include "ai_networkmanager.h"
#include "ai_utils.h"
#include "basetempentity.h"
#include "world.h"
#include "mempool.h"
#include "igamesystem.h"
#include "engine/IEngineSound.h"
#include "globals.h"
#include "engine/IStaticPropMgr.h"
#include "particle_parse.h"
#include "globalstate.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern CBaseEntity *g_pLastSpawn; void InitBodyQue(void); extern void W_Precache(void); extern void ActivityList_Free( void ); extern CUtlMemoryPool g_EntityListPool;
#define SF_DECAL_NOTINDEATHMATCH 2048
class CDecal : public CPointEntity { public: DECLARE_CLASS( CDecal, CPointEntity );
void Spawn( void ); bool KeyValue( const char *szKeyName, const char *szValue );
// Need to apply static decals here to get them into the signon buffer for the server appropriately
virtual void Activate();
void TriggerDecal( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
// Input handlers.
void InputActivate( inputdata_t &inputdata );
DECLARE_DATADESC();
public: int m_nTexture; bool m_bLowPriority;
private:
void StaticDecal( void ); };
BEGIN_DATADESC( CDecal )
DEFINE_FIELD( m_nTexture, FIELD_INTEGER ), DEFINE_KEYFIELD( m_bLowPriority, FIELD_BOOLEAN, "LowPriority" ), // Don't mark as FDECAL_PERMANENT so not save/restored and will be reused on the client preferentially
// Function pointers
DEFINE_FUNCTION( StaticDecal ), DEFINE_FUNCTION( TriggerDecal ),
DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( infodecal, CDecal );
// UNDONE: These won't get sent to joining players in multi-player
void CDecal::Spawn( void ) { if ( m_nTexture < 0 || (gpGlobals->deathmatch && HasSpawnFlags( SF_DECAL_NOTINDEATHMATCH )) ) { UTIL_Remove( this ); return; } }
void CDecal::Activate() { BaseClass::Activate();
if ( !GetEntityName() ) { StaticDecal(); } else { // if there IS a targetname, the decal sprays itself on when it is triggered.
SetThink ( &CDecal::SUB_DoNothing ); SetUse(&CDecal::TriggerDecal); } }
void CDecal::TriggerDecal ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { // this is set up as a USE function for info_decals that have targetnames, so that the
// decal doesn't get applied until it is fired. (usually by a scripted sequence)
trace_t trace; int entityIndex;
UTIL_TraceLine( GetAbsOrigin() - Vector(5,5,5), GetAbsOrigin() + Vector(5,5,5), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trace );
entityIndex = trace.m_pEnt ? trace.m_pEnt->entindex() : 0;
CBroadcastRecipientFilter filter;
te->BSPDecal( filter, 0.0, &GetAbsOrigin(), entityIndex, m_nTexture );
SetThink( &CDecal::SUB_Remove ); SetNextThink( gpGlobals->curtime + 0.1f ); }
void CDecal::InputActivate( inputdata_t &inputdata ) { TriggerDecal( inputdata.pActivator, inputdata.pCaller, USE_ON, 0 ); }
void CDecal::StaticDecal( void ) { class CTraceFilterValidForDecal : public CTraceFilterSimple { public: CTraceFilterValidForDecal(const IHandleEntity *passentity, int collisionGroup ) : CTraceFilterSimple( passentity, collisionGroup ) { }
virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) { static const char *ppszIgnoredClasses[] = { "weapon_*", "item_*", "prop_ragdoll", "prop_dynamic", "prop_static", "prop_physics", "npc_bullseye", // Tracker 15335
};
CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
// Tracker 15335: Never impact decals against entities which are not rendering, either.
if ( pEntity->IsEffectActive( EF_NODRAW ) ) return false;
for ( int i = 0; i < ARRAYSIZE(ppszIgnoredClasses); i++ ) { if ( pEntity->ClassMatches( ppszIgnoredClasses[i] ) ) return false; }
return CTraceFilterSimple::ShouldHitEntity( pServerEntity, contentsMask ); } };
trace_t trace; CTraceFilterValidForDecal traceFilter( this, COLLISION_GROUP_NONE ); int entityIndex, modelIndex = 0;
Vector position = GetAbsOrigin(); UTIL_TraceLine( position - Vector(5,5,5), position + Vector(5,5,5), MASK_SOLID, &traceFilter, &trace );
bool canDraw = true;
entityIndex = trace.m_pEnt ? (short)trace.m_pEnt->entindex() : 0; if ( entityIndex ) { CBaseEntity *ent = trace.m_pEnt; if ( ent ) { modelIndex = ent->GetModelIndex(); VectorITransform( GetAbsOrigin(), ent->EntityToWorldTransform(), position );
canDraw = ( modelIndex != 0 ); if ( !canDraw ) { Warning( "Suppressed StaticDecal which would have hit entity %i (class:%s, name:%s) with modelindex = 0\n", ent->entindex(), ent->GetClassname(), STRING( ent->GetEntityName() ) ); } } }
if ( canDraw ) { engine->StaticDecal( position, m_nTexture, entityIndex, modelIndex, m_bLowPriority ); }
SUB_Remove(); }
bool CDecal::KeyValue( const char *szKeyName, const char *szValue ) { if (FStrEq(szKeyName, "texture")) { // FIXME: should decals all be preloaded?
m_nTexture = UTIL_PrecacheDecal( szValue, true ); // Found
if (m_nTexture >= 0 ) return true; Warning( "Can't find decal %s\n", szValue ); } else { return BaseClass::KeyValue( szKeyName, szValue ); }
return true; }
//-----------------------------------------------------------------------------
// Purpose: Projects a decal against a prop
//-----------------------------------------------------------------------------
class CProjectedDecal : public CPointEntity { public: DECLARE_CLASS( CProjectedDecal, CPointEntity );
void Spawn( void ); bool KeyValue( const char *szKeyName, const char *szValue );
// Need to apply static decals here to get them into the signon buffer for the server appropriately
virtual void Activate();
void TriggerDecal( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
// Input handlers.
void InputActivate( inputdata_t &inputdata );
DECLARE_DATADESC();
public: int m_nTexture; float m_flDistance;
private: void ProjectDecal( CRecipientFilter& filter );
void StaticDecal( void ); };
BEGIN_DATADESC( CProjectedDecal )
DEFINE_FIELD( m_nTexture, FIELD_INTEGER ),
DEFINE_KEYFIELD( m_flDistance, FIELD_FLOAT, "Distance" ),
// Function pointers
DEFINE_FUNCTION( StaticDecal ), DEFINE_FUNCTION( TriggerDecal ),
DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( info_projecteddecal, CProjectedDecal );
// UNDONE: These won't get sent to joining players in multi-player
void CProjectedDecal::Spawn( void ) { if ( m_nTexture < 0 || (gpGlobals->deathmatch && HasSpawnFlags( SF_DECAL_NOTINDEATHMATCH )) ) { UTIL_Remove( this ); return; } }
void CProjectedDecal::Activate() { BaseClass::Activate();
if ( !GetEntityName() ) { StaticDecal(); } else { // if there IS a targetname, the decal sprays itself on when it is triggered.
SetThink ( &CProjectedDecal::SUB_DoNothing ); SetUse(&CProjectedDecal::TriggerDecal); } }
void CProjectedDecal::InputActivate( inputdata_t &inputdata ) { TriggerDecal( inputdata.pActivator, inputdata.pCaller, USE_ON, 0 ); }
void CProjectedDecal::ProjectDecal( CRecipientFilter& filter ) { te->ProjectDecal( filter, 0.0, &GetAbsOrigin(), &GetAbsAngles(), m_flDistance, m_nTexture ); }
void CProjectedDecal::TriggerDecal ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { CBroadcastRecipientFilter filter;
ProjectDecal( filter );
SetThink( &CProjectedDecal::SUB_Remove ); SetNextThink( gpGlobals->curtime + 0.1f ); }
void CProjectedDecal::StaticDecal( void ) { CBroadcastRecipientFilter initFilter; initFilter.MakeInitMessage();
ProjectDecal( initFilter );
SUB_Remove(); }
bool CProjectedDecal::KeyValue( const char *szKeyName, const char *szValue ) { if (FStrEq(szKeyName, "texture")) { // FIXME: should decals all be preloaded?
m_nTexture = UTIL_PrecacheDecal( szValue, true ); // Found
if (m_nTexture >= 0 ) return true; Warning( "Can't find decal %s\n", szValue ); } else { return BaseClass::KeyValue( szKeyName, szValue ); }
return true; }
//=======================
// CWorld
//
// This spawns first when each level begins.
//=======================
LINK_ENTITY_TO_CLASS( worldspawn, CWorld );
BEGIN_DATADESC( CWorld )
DEFINE_FIELD( m_flWaveHeight, FIELD_FLOAT ),
// keyvalues are parsed from map, but not saved/loaded
DEFINE_KEYFIELD( m_iszChapterTitle, FIELD_STRING, "chaptertitle" ), DEFINE_KEYFIELD( m_bStartDark, FIELD_BOOLEAN, "startdark" ), DEFINE_KEYFIELD( m_bDisplayTitle, FIELD_BOOLEAN, "gametitle" ), DEFINE_FIELD( m_WorldMins, FIELD_VECTOR ), DEFINE_FIELD( m_WorldMaxs, FIELD_VECTOR ), #ifdef _X360
DEFINE_KEYFIELD( m_flMaxOccludeeArea, FIELD_FLOAT, "maxoccludeearea_x360" ), DEFINE_KEYFIELD( m_flMinOccluderArea, FIELD_FLOAT, "minoccluderarea_x360" ), #else
DEFINE_KEYFIELD( m_flMaxOccludeeArea, FIELD_FLOAT, "maxoccludeearea" ), DEFINE_KEYFIELD( m_flMinOccluderArea, FIELD_FLOAT, "minoccluderarea" ), #endif
DEFINE_KEYFIELD( m_flMaxPropScreenSpaceWidth, FIELD_FLOAT, "maxpropscreenwidth" ), DEFINE_KEYFIELD( m_flMinPropScreenSpaceWidth, FIELD_FLOAT, "minpropscreenwidth" ), DEFINE_KEYFIELD( m_iszDetailSpriteMaterial, FIELD_STRING, "detailmaterial" ), DEFINE_KEYFIELD( m_bColdWorld, FIELD_BOOLEAN, "coldworld" ),
END_DATADESC()
// SendTable stuff.
IMPLEMENT_SERVERCLASS_ST(CWorld, DT_WORLD) SendPropFloat (SENDINFO(m_flWaveHeight), 8, SPROP_ROUNDUP, 0.0f, 8.0f), SendPropVector (SENDINFO(m_WorldMins), -1, SPROP_COORD), SendPropVector (SENDINFO(m_WorldMaxs), -1, SPROP_COORD), SendPropInt (SENDINFO(m_bStartDark), 1, SPROP_UNSIGNED ), SendPropFloat (SENDINFO(m_flMaxOccludeeArea), 0, SPROP_NOSCALE ), SendPropFloat (SENDINFO(m_flMinOccluderArea), 0, SPROP_NOSCALE ), SendPropFloat (SENDINFO(m_flMaxPropScreenSpaceWidth), 0, SPROP_NOSCALE ), SendPropFloat (SENDINFO(m_flMinPropScreenSpaceWidth), 0, SPROP_NOSCALE ), SendPropStringT (SENDINFO(m_iszDetailSpriteMaterial) ), SendPropInt (SENDINFO(m_bColdWorld), 1, SPROP_UNSIGNED ), END_SEND_TABLE()
//
// Just to ignore the "wad" field.
//
bool CWorld::KeyValue( const char *szKeyName, const char *szValue ) { if ( FStrEq(szKeyName, "skyname") ) { // Sent over net now.
ConVarRef skyname( "sv_skyname" ); skyname.SetValue( szValue ); } else if ( FStrEq(szKeyName, "newunit") ) { // Single player only. Clear save directory if set
if ( atoi(szValue) ) { extern void Game_SetOneWayTransition(); Game_SetOneWayTransition(); } } else if ( FStrEq(szKeyName, "world_mins") ) { Vector vec; sscanf( szValue, "%f %f %f", &vec.x, &vec.y, &vec.z ); m_WorldMins = vec; } else if ( FStrEq(szKeyName, "world_maxs") ) { Vector vec; sscanf( szValue, "%f %f %f", &vec.x, &vec.y, &vec.z ); m_WorldMaxs = vec; } else return BaseClass::KeyValue( szKeyName, szValue );
return true; }
extern bool g_fGameOver; static CWorld *g_WorldEntity = NULL;
CWorld* GetWorldEntity() { return g_WorldEntity; }
CWorld::CWorld( ) { AddEFlags( EFL_NO_AUTO_EDICT_ATTACH | EFL_KEEP_ON_RECREATE_ENTITIES ); NetworkProp()->AttachEdict( INDEXENT(RequiredEdictIndex()) ); ActivityList_Init(); EventList_Init(); SetSolid( SOLID_BSP ); SetMoveType( MOVETYPE_NONE );
m_bColdWorld = false; }
CWorld::~CWorld( ) { EventList_Free(); ActivityList_Free(); if ( g_pGameRules ) { g_pGameRules->LevelShutdown(); delete g_pGameRules; g_pGameRules = NULL; } g_WorldEntity = NULL; }
//------------------------------------------------------------------------------
// Purpose : Add a decal to the world
// Input :
// Output :
//------------------------------------------------------------------------------
void CWorld::DecalTrace( trace_t *pTrace, char const *decalName) { int index = decalsystem->GetDecalIndexForName( decalName ); if ( index < 0 ) return;
CBroadcastRecipientFilter filter; if ( pTrace->hitbox != 0 ) { te->Decal( filter, 0.0f, &pTrace->endpos, &pTrace->startpos, 0, pTrace->hitbox, index ); } else { te->WorldDecal( filter, 0.0, &pTrace->endpos, index ); } }
void CWorld::RegisterSharedActivities( void ) { ActivityList_RegisterSharedActivities(); }
void CWorld::RegisterSharedEvents( void ) { EventList_RegisterSharedEvents(); }
void CWorld::Spawn( void ) { SetLocalOrigin( vec3_origin ); SetLocalAngles( vec3_angle ); // NOTE: SHOULD NEVER BE ANYTHING OTHER THAN 1!!!
SetModelIndex( 1 ); // world model
SetModelName( AllocPooledString( modelinfo->GetModelName( GetModel() ) ) ); AddFlag( FL_WORLDBRUSH );
g_EventQueue.Init(); Precache( ); GlobalEntity_Add( "is_console", STRING(gpGlobals->mapname), ( IsConsole() ) ? GLOBAL_ON : GLOBAL_OFF ); GlobalEntity_Add( "is_pc", STRING(gpGlobals->mapname), ( !IsConsole() ) ? GLOBAL_ON : GLOBAL_OFF ); }
static const char *g_DefaultLightstyles[] = { // 0 normal
"m", // 1 FLICKER (first variety)
"mmnmmommommnonmmonqnmmo", // 2 SLOW STRONG PULSE
"abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba", // 3 CANDLE (first variety)
"mmmmmaaaaammmmmaaaaaabcdefgabcdefg", // 4 FAST STROBE
"mamamamamama", // 5 GENTLE PULSE 1
"jklmnopqrstuvwxyzyxwvutsrqponmlkj", // 6 FLICKER (second variety)
"nmonqnmomnmomomno", // 7 CANDLE (second variety)
"mmmaaaabcdefgmmmmaaaammmaamm", // 8 CANDLE (third variety)
"mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa", // 9 SLOW STROBE (fourth variety)
"aaaaaaaazzzzzzzz", // 10 FLUORESCENT FLICKER
"mmamammmmammamamaaamammma", // 11 SLOW PULSE NOT FADE TO BLACK
"abcdefghijklmnopqrrqponmlkjihgfedcba", // 12 UNDERWATER LIGHT MUTATION
// this light only distorts the lightmap - no contribution
// is made to the brightness of affected surfaces
"mmnnmmnnnmmnn", };
const char *GetDefaultLightstyleString( int styleIndex ) { if ( styleIndex < ARRAYSIZE(g_DefaultLightstyles) ) { return g_DefaultLightstyles[styleIndex]; } return "m"; }
void CWorld::Precache( void ) { g_WorldEntity = this; g_fGameOver = false; g_pLastSpawn = NULL;
ConVarRef stepsize( "sv_stepsize" ); stepsize.SetValue( 18 );
ConVarRef roomtype( "room_type" ); roomtype.SetValue( 0 );
// Set up game rules
Assert( !g_pGameRules ); if (g_pGameRules) { delete g_pGameRules; }
InstallGameRules(); Assert( g_pGameRules ); g_pGameRules->Init();
CSoundEnt::InitSoundEnt();
// Only allow precaching between LevelInitPreEntity and PostEntity
CBaseEntity::SetAllowPrecache( true ); IGameSystem::LevelInitPreEntityAllSystems( STRING( GetModelName() ) );
// Create the player resource
g_pGameRules->CreateStandardEntities();
// UNDONE: Make most of these things server systems or precache_registers
// =================================================
// Activities
// =================================================
ActivityList_Free(); RegisterSharedActivities();
EventList_Free(); RegisterSharedEvents();
InitBodyQue(); // init sentence group playback stuff from sentences.txt.
// ok to call this multiple times, calls after first are ignored.
SENTENCEG_Init();
// Precache standard particle systems
PrecacheStandardParticleSystems( );
// the area based ambient sounds MUST be the first precache_sounds
// player precaches
W_Precache (); // get weapon precaches
ClientPrecache(); g_pGameRules->Precache(); // precache all temp ent stuff
CBaseTempEntity::PrecacheTempEnts();
g_Language.SetValue( LANGUAGE_ENGLISH ); // TODO use VGUI to get current language
if ( g_Language.GetInt() == LANGUAGE_GERMAN ) { PrecacheModel( "models/germangibs.mdl" ); } else { PrecacheModel( "models/gibs/hgibs.mdl" ); }
PrecacheScriptSound( "BaseEntity.EnterWater" ); PrecacheScriptSound( "BaseEntity.ExitWater" );
//
// Setup light animation tables. 'a' is total darkness, 'z' is maxbright.
//
for ( int i = 0; i < ARRAYSIZE(g_DefaultLightstyles); i++ ) { engine->LightStyle( i, GetDefaultLightstyleString(i) ); }
// styles 32-62 are assigned by the light program for switchable lights
// 63 testing
engine->LightStyle(63, "a");
// =================================================
// Load and Init AI Networks
// =================================================
CAI_NetworkManager::InitializeAINetworks(); // =================================================
// Load and Init AI Schedules
// =================================================
g_AI_SchedulesManager.LoadAllSchedules(); // =================================================
// Initialize NPC Relationships
// =================================================
g_pGameRules->InitDefaultAIRelationships(); CBaseCombatCharacter::InitInteractionSystem();
// Call all registered precachers.
CPrecacheRegister::Precache();
if ( m_iszChapterTitle != NULL_STRING ) { DevMsg( 2, "Chapter title: %s\n", STRING(m_iszChapterTitle) ); CMessage *pMessage = (CMessage *)CBaseEntity::Create( "env_message", vec3_origin, vec3_angle, NULL ); if ( pMessage ) { pMessage->SetMessage( m_iszChapterTitle ); m_iszChapterTitle = NULL_STRING;
// send the message entity a play message command, delayed by 1 second
pMessage->AddSpawnFlags( SF_MESSAGE_ONCE ); pMessage->SetThink( &CMessage::SUB_CallUseToggle ); pMessage->SetNextThink( gpGlobals->curtime + 1.0f ); } }
g_iszFuncBrushClassname = AllocPooledString("func_brush"); }
//-----------------------------------------------------------------------------
// Purpose:
// Output : float
//-----------------------------------------------------------------------------
float GetRealTime() { return engine->Time(); }
bool CWorld::GetDisplayTitle() const { return m_bDisplayTitle; }
bool CWorld::GetStartDark() const { return m_bStartDark; }
void CWorld::SetDisplayTitle( bool display ) { m_bDisplayTitle = display; }
void CWorld::SetStartDark( bool startdark ) { m_bStartDark = startdark; }
bool CWorld::IsColdWorld( void ) { return m_bColdWorld; }
|