diff --git a/dlls/CBaseEntity.cpp b/dlls/CBaseEntity.cpp index 26d997d8..7a7a697d 100644 --- a/dlls/CBaseEntity.cpp +++ b/dlls/CBaseEntity.cpp @@ -406,7 +406,8 @@ int CBaseEntity::DamageDecal(int bitsDamageType) // NOTE: szName must be a pointer to constant memory, e.g. "monster_class" because the entity // will keep a pointer to it after this call. -CBaseEntity* CBaseEntity::Create(const char* szName, const Vector& vecOrigin, const Vector& vecAngles, edict_t* pentOwner, std::unordered_map keys) +CBaseEntity* CBaseEntity::Create(const char* szName, const Vector& vecOrigin, const Vector& vecAngles, + bool spawn, edict_t* pentOwner, std::unordered_map keys) { edict_t* pent; CBaseEntity* pEntity; @@ -431,7 +432,9 @@ CBaseEntity* CBaseEntity::Create(const char* szName, const Vector& vecOrigin, co DispatchKeyValue(pent, &dat); } - DispatchSpawn(pEntity->edict()); + if (spawn) + DispatchSpawn(pEntity->edict()); + return pEntity; } diff --git a/dlls/CBaseEntity.h b/dlls/CBaseEntity.h index 4ed9afe1..71264ea5 100644 --- a/dlls/CBaseEntity.h +++ b/dlls/CBaseEntity.h @@ -308,7 +308,7 @@ class EXPORT CBaseEntity // - static CBaseEntity* Create(const char* szName, const Vector& vecOrigin, const Vector& vecAngles, edict_t* pentOwner = NULL, std::unordered_map keys = std::unordered_map()); + static CBaseEntity* Create(const char* szName, const Vector& vecOrigin, const Vector& vecAngles, bool spawn=true, edict_t* pentOwner = NULL, std::unordered_map keys = std::unordered_map()); virtual BOOL FBecomeProne(void) { return FALSE; }; edict_t* edict() { return ENT(pev); }; diff --git a/dlls/CWorld.cpp b/dlls/CWorld.cpp index 1245850d..c08e0703 100644 --- a/dlls/CWorld.cpp +++ b/dlls/CWorld.cpp @@ -352,7 +352,7 @@ void CWorld::Precache(void) if (pev->netname) { ALERT(at_aiconsole, "Chapter title: %s\n", STRING(pev->netname)); - CBaseEntity* pEntity = CBaseEntity::Create("env_message", g_vecZero, g_vecZero, NULL); + CBaseEntity* pEntity = CBaseEntity::Create("env_message", g_vecZero, g_vecZero); if (pEntity) { pEntity->SetThink(&CBaseEntity::SUB_CallUseToggle); diff --git a/dlls/env/CEnvBeverage.cpp b/dlls/env/CEnvBeverage.cpp index db664bf1..d00284e8 100644 --- a/dlls/env/CEnvBeverage.cpp +++ b/dlls/env/CEnvBeverage.cpp @@ -35,7 +35,7 @@ void CEnvBeverage::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE u return; } - CBaseEntity* pCan = CBaseEntity::Create("item_sodacan", pev->origin, pev->angles, edict()); + CBaseEntity* pCan = CBaseEntity::Create("item_sodacan", pev->origin, pev->angles, true, edict()); if (pev->skin == 6) { diff --git a/dlls/env/CEnvExplosion.cpp b/dlls/env/CEnvExplosion.cpp index d52012c9..0f8831fd 100644 --- a/dlls/env/CEnvExplosion.cpp +++ b/dlls/env/CEnvExplosion.cpp @@ -169,7 +169,7 @@ void CEnvExplosion::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE for (int i = 0; i < sparkCount; i++) { - Create("spark_shower", m_effectOrigin, tr.vecPlaneNormal, NULL); + Create("spark_shower", m_effectOrigin, tr.vecPlaneNormal); } } } @@ -202,7 +202,7 @@ void ExplosionCreate(const Vector& center, const Vector& angles, edict_t* pOwner KeyValueData kvd; char buf[128]; - CBaseEntity* pExplosion = CBaseEntity::Create("env_explosion", center, angles, pOwner); + CBaseEntity* pExplosion = CBaseEntity::Create("env_explosion", center, angles, true, pOwner); snprintf(buf, 128, "%3d", magnitude); kvd.szKeyName = "iMagnitude"; kvd.szValue = buf; diff --git a/dlls/env/CEnvWeather.cpp b/dlls/env/CEnvWeather.cpp index 90eac3b3..a87d190b 100644 --- a/dlls/env/CEnvWeather.cpp +++ b/dlls/env/CEnvWeather.cpp @@ -688,7 +688,7 @@ void CEnvWeather::Spawn(void) // reverse order so fog renders correctly for (int k = FOG_LAYERS - 1; k >= 0; k--) { if (!g_fog_ents[k]) { - g_fog_ents[k] = Create("fog_layer", g_vecZero, g_vecZero, NULL); + g_fog_ents[k] = Create("fog_layer", g_vecZero, g_vecZero); if (!m_isActive) g_fog_ents[k]->pev->effects = EF_NODRAW;; } @@ -982,7 +982,7 @@ void CEnvWeather::WeatherEntsThink() { {"model", weather.model}, }; - CFuncConveyor* ent = (CFuncConveyor*)Create("weather_conveyor", weather.pos, Vector(0, 0, 0), NULL, keys); + CFuncConveyor* ent = (CFuncConveyor*)Create("weather_conveyor", weather.pos, Vector(0, 0, 0), true, NULL, keys); ent->pev->solid = SOLID_NOT; ent->pev->movetype = weather.isFloating ? MOVETYPE_NONE : MOVETYPE_TOSS; ent->pev->rendermode = kRenderTransAdd; diff --git a/dlls/env/CSprite.h b/dlls/env/CSprite.h index 9fc07a61..9bf10938 100644 --- a/dlls/env/CSprite.h +++ b/dlls/env/CSprite.h @@ -38,8 +38,8 @@ class CSprite : public CPointEntity pev->movetype = MOVETYPE_FOLLOW; } } - void TurnOff(void); - void TurnOn(void); + void EXPORT TurnOff(void); + void EXPORT TurnOn(void); inline float Frames(void) { return m_maxFrame; } inline void SetTransparency(int rendermode, int r, int g, int b, int a, int fx) { @@ -68,7 +68,7 @@ class CSprite : public CPointEntity virtual int Save(CSave& save); virtual int Restore(CRestore& restore); static TYPEDESCRIPTION m_SaveData[]; - static CSprite* SpriteCreate(const char* pSpriteName, const Vector& origin, BOOL animate); + static EXPORT CSprite* SpriteCreate(const char* pSpriteName, const Vector& origin, BOOL animate); private: diff --git a/dlls/func/CBreakable.cpp b/dlls/func/CBreakable.cpp index 1d0f8fc5..02a5c386 100644 --- a/dlls/func/CBreakable.cpp +++ b/dlls/func/CBreakable.cpp @@ -743,7 +743,7 @@ void CBreakable::Die() SetThink(&CBreakable::SUB_Remove); pev->nextthink = pev->ltime + 0.1; if (m_iszSpawnObject) - CBaseEntity::Create((char*)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict()); + CBaseEntity::Create((char*)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, true, edict()); if (Explodable()) diff --git a/dlls/func/CFuncTankRocket.cpp b/dlls/func/CFuncTankRocket.cpp index c6a4e693..2d5367d1 100644 --- a/dlls/func/CFuncTankRocket.cpp +++ b/dlls/func/CFuncTankRocket.cpp @@ -31,7 +31,7 @@ void CFuncTankRocket::Fire(const Vector& barrelEnd, const Vector& forward, entva { for (i = 0; i < bulletCount; i++) { - CBaseEntity::Create("rpg_rocket", barrelEnd, pev->angles, edict()); + CBaseEntity::Create("rpg_rocket", barrelEnd, pev->angles, true, edict()); } CFuncTank::Fire(barrelEnd, forward, pev); } diff --git a/dlls/game/game.h b/dlls/game/game.h index 9b05ebae..02426791 100644 --- a/dlls/game/game.h +++ b/dlls/game/game.h @@ -182,6 +182,10 @@ EXPORT extern bool g_cfgsExecuted; // set to true after server and map cfgs are EXPORT extern std::unordered_set g_nomaptrans; // trigger_changelevel disabled for these maps +// lines in the cfg which could possibly be custom weapons. Not known until map plugins are loaded, +// and map plugins aren't known until the cfg finishes parsing +EXPORT extern std::vector> g_unrecognizedCfgEquipment; + // mark a palyer weapon for precaching (alias names are ok) EXPORT void AddPrecacheWeapon(std::string wepName); diff --git a/dlls/game/gamerules.cpp b/dlls/game/gamerules.cpp index c8fd24b8..fa312ea9 100644 --- a/dlls/game/gamerules.cpp +++ b/dlls/game/gamerules.cpp @@ -119,6 +119,38 @@ std::unordered_set timeCriticalCvars = { "mp_skill_allow", }; +std::vector> g_unrecognizedCfgEquipment; +extern int g_mapEquipIdx; + +void AddMapEquipment(std::string name, std::string value) { + if (g_mapEquipIdx >= MAX_EQUIP) { + ALERT(at_error, "Failed to add equipment '%s'. Max equipment reached.\n", name.c_str()); + return; + } + + if (mp_default_medkit.value == 0 && name == "weapon_medkit") { + // don't want medkits by default unless the map specifically places them + // (for a class system or as a special item) + return; + } + + g_mapEquipment[g_mapEquipIdx].itemName = ALLOC_STRING(name.c_str()); + g_mapEquipment[g_mapEquipIdx].count = value.size() ? atoi(value.c_str()) : 1; + + AddPrecacheWeapon(name); + + g_mapEquipIdx++; +} + +void AddMapPluginEquipment() { + for (auto pair : g_unrecognizedCfgEquipment) { + if (g_weaponClassnames.count(pair.first)) { + AddMapEquipment(pair.first, pair.second); + } + } + g_unrecognizedCfgEquipment.clear(); +} + void execMapCfg() { // Map CFGs are low trust so only whitelisted commands are allowed. // Server owners shouldn't have to check each map for things like "rcon_password HAHA_GOT_YOU" @@ -245,7 +277,7 @@ void execMapCfg() { std::stringstream data_stream(cfgFile); string line; - int equipIdx = 0; + g_mapEquipIdx = 0; while (std::getline(data_stream, line)) { @@ -312,24 +344,11 @@ void execMapCfg() { SERVER_COMMAND(UTIL_VarArgs("%s %s\n", name.c_str(), value.c_str())); } - else if (itemNames.find(name) != itemNames.end()) { - if (equipIdx >= MAX_EQUIP) { - ALERT(at_error, "Failed to add equipment '%s'. Max equipment reached.\n", line.c_str()); - continue; - } - - if (mp_default_medkit.value == 0 && name == "weapon_medkit") { - // don't want medkits by default unless the map specifically places them - // (for a class system or as a special item) - continue; - } - - g_mapEquipment[equipIdx].itemName = ALLOC_STRING(name.c_str()); - g_mapEquipment[equipIdx].count = value.size() ? atoi(value.c_str()) : 1; - - AddPrecacheWeapon(name); - - equipIdx++; + else if (itemNames.count(name)) { + AddMapEquipment(name, value); + } + else { + g_unrecognizedCfgEquipment.push_back({ name, value }); } } diff --git a/dlls/game/gamerules.h b/dlls/game/gamerules.h index 9680972e..2d73177b 100644 --- a/dlls/game/gamerules.h +++ b/dlls/game/gamerules.h @@ -401,4 +401,4 @@ class CHalfLifeMultiplay : public CGameRules void SendMOTDToClient( edict_t *client ); }; -extern DLL_GLOBAL CGameRules* g_pGameRules; +EXPORT extern DLL_GLOBAL CGameRules* g_pGameRules; diff --git a/dlls/hooks/PluginHooks.h b/dlls/hooks/PluginHooks.h index 8eddd9be..66a65fc0 100644 --- a/dlls/hooks/PluginHooks.h +++ b/dlls/hooks/PluginHooks.h @@ -5,6 +5,7 @@ #define HLCOOP_API_VERSION 2 +class CBaseEntity; class CBasePlayer; struct HOOK_RETURN_DATA { @@ -164,6 +165,9 @@ struct HLCOOP_PLUGIN_HOOKS { // called before a chat message is sent. Update the message pointer to change the message. HOOK_RETURN_DATA (*pfnChatMessage)(CBasePlayer* plr, const char** message, bool teamOnly); + + // called when an entity is created and keyvalues are applied, but before it spawns + HOOK_RETURN_DATA (*pfnEntityCreated)(CBaseEntity* pEntity); }; // do not call directly, use RegisterPlugin instead diff --git a/dlls/hooks/client_commands.cpp b/dlls/hooks/client_commands.cpp index c3c85a60..a705bf3b 100644 --- a/dlls/hooks/client_commands.cpp +++ b/dlls/hooks/client_commands.cpp @@ -375,7 +375,7 @@ void ClientCommand(edict_t* pEntity) { pPlayer->SelectItem((char*)CMD_ARGV(1)); } - else if (g_weaponClassnames.count(pcmd)) + else if (g_weaponNames.count(pcmd)) { // custom weapon was selected (weapon name includes a folder path to force clients to load HUD files from there) const char* wepCname = pcmd; diff --git a/dlls/hooks/hlds_hooks.cpp b/dlls/hooks/hlds_hooks.cpp index 4b964825..1dd6ac22 100644 --- a/dlls/hooks/hlds_hooks.cpp +++ b/dlls/hooks/hlds_hooks.cpp @@ -61,6 +61,7 @@ void PM_Init(struct playermove_s* ppmove); char PM_FindTextureType(char* name); extern Vector VecBModelOrigin(entvars_t* pevBModel); extern void CopyToBodyQue(entvars_t* pev); +extern void AddMapPluginEquipment(); extern int giPrecacheGrunt; extern int gmsgSayText; extern int g_teamplay; @@ -398,10 +399,10 @@ void ClientPutInServer( edict_t *pEntity ) pPlayer->LoadScore(); pPlayer->m_lastUserInput = g_engfuncs.pfnTime(); - CALL_HOOKS_VOID(pfnClientPutInServer, pPlayer); - // Allocate a CBasePlayer for pev, and call spawn pPlayer->Spawn(); + + CALL_HOOKS_VOID(pfnClientPutInServer, pPlayer); } /* @@ -514,7 +515,9 @@ void ServerDeactivate( void ) g_mapWeapons.clear(); g_wavInfos.clear(); g_weaponClassnames.clear(); + g_weaponNames.clear(); g_nomaptrans.clear(); + g_unrecognizedCfgEquipment.clear(); clearNetworkMessageHistory(); g_mp3Command = ""; g_monstersNerfed = false; @@ -727,6 +730,8 @@ void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) } } + AddMapPluginEquipment(); + PrecacheWeapons(); PrecacheTextureSounds(); @@ -774,7 +779,7 @@ void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) g_tryPrecacheModels.size() + g_bsp.modelCount, g_tryPrecacheModels.size(), g_bsp.modelCount, g_tryPrecacheSounds.size(), g_tryPrecacheGeneric.size(), g_tryPrecacheEvents.size())); - if (g_tryPrecacheModels.size() > g_precachedModels.size()) { + if (g_tryPrecacheModels.size() + g_bsp.entityBspModelCount + 1 > MAX_PRECACHE_MODEL) { ALERT(at_error, "Model precache overflow (%d / %d). The following models were not precached:\n", g_tryPrecacheModels.size() + g_bsp.modelCount, MAX_PRECACHE); @@ -2153,6 +2158,8 @@ edict_t* SpawnEdict(edict_t* pent) { pEntity->pev->absmin = pEntity->pev->origin - Vector(1, 1, 1); pEntity->pev->absmax = pEntity->pev->origin + Vector(1, 1, 1); + CALL_HOOKS(edict_t*, pfnEntityCreated, pEntity); + pEntity->Spawn(); // Try to get the pointer again, in case the spawn function deleted the entity. @@ -2176,16 +2183,27 @@ edict_t* SpawnEdict(edict_t* pent) { { // Already dead? delete if (pGlobal->state == GLOBAL_DEAD) { + // source of bugs + ALERT(at_console, "Removed '%s' (%s) due to global state\n", + STRING(pEntity->pev->targetname), STRING(pEntity->pev->classname)); + REMOVE_ENTITY(pent); return NULL; } - else if (!FStrEq(STRING(gpGlobals->mapname), pGlobal->levelName)) + else if (!FStrEq(STRING(gpGlobals->mapname), pGlobal->levelName)) { + ALERT(at_console, "Hiding '%s' (%s) due to global state\n", + STRING(pEntity->pev->targetname), STRING(pEntity->pev->classname)); + pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive + } // In this level & not dead, continue on as normal } else { + ALERT(at_console, "Activating '%s' (%s) due to global state\n", + STRING(pEntity->pev->targetname), STRING(pEntity->pev->classname)); + // Spawned entities default to 'On' gGlobalState.EntityAdd(pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON); // ALERT( at_console, "Added global entity %s (%s)\n", STRING(pEntity->pev->classname), STRING(pEntity->pev->globalname) ); diff --git a/dlls/monster/CAGrunt.cpp b/dlls/monster/CAGrunt.cpp index 662bc150..041e2ef5 100644 --- a/dlls/monster/CAGrunt.cpp +++ b/dlls/monster/CAGrunt.cpp @@ -390,7 +390,7 @@ void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) WRITE_BYTE( 128 ); // brightness MESSAGE_END(); - CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, UTIL_VecToAngles( vecDirToEnemy ), edict() ); + CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, UTIL_VecToAngles( vecDirToEnemy ), true, edict() ); UTIL_MakeVectors ( pHornet->pev->angles ); pHornet->pev->velocity = gpGlobals->v_forward * 300; diff --git a/dlls/monster/CApache.cpp b/dlls/monster/CApache.cpp index 7e0fe2e4..066e3306 100644 --- a/dlls/monster/CApache.cpp +++ b/dlls/monster/CApache.cpp @@ -826,7 +826,7 @@ void CApache :: FireRocket( void ) WRITE_BYTE( 12 ); // framerate MESSAGE_END(); - CBaseEntity *pRocket = CBaseEntity::Create( "hvr_rocket", vecSrc, pev->angles, edict() ); + CBaseEntity *pRocket = CBaseEntity::Create( "hvr_rocket", vecSrc, pev->angles, true, edict() ); if (pRocket) pRocket->pev->velocity = pev->velocity + gpGlobals->v_forward * 100; diff --git a/dlls/monster/CBaseMonster.cpp b/dlls/monster/CBaseMonster.cpp index 75c94812..340cd006 100644 --- a/dlls/monster/CBaseMonster.cpp +++ b/dlls/monster/CBaseMonster.cpp @@ -3845,7 +3845,7 @@ CBaseEntity* CBaseMonster::DropItem(const char* pszItemName, const Vector& vecPo return NULL; } - CBaseEntity* pItem = CBaseEntity::Create(pszItemName, vecPos, vecAng, edict()); + CBaseEntity* pItem = CBaseEntity::Create(pszItemName, vecPos, vecAng, true, edict()); if (pItem) { diff --git a/dlls/monster/CBigMomma.cpp b/dlls/monster/CBigMomma.cpp index 8fe08e67..56247b5d 100644 --- a/dlls/monster/CBigMomma.cpp +++ b/dlls/monster/CBigMomma.cpp @@ -662,7 +662,7 @@ void CBigMomma :: LayHeadcrab( void ) keys["classify"] = m_Classify; } - CBaseEntity *pChild = CBaseEntity::Create( BIG_CHILDCLASS, pev->origin, pev->angles, edict(), keys ); + CBaseEntity *pChild = CBaseEntity::Create( BIG_CHILDCLASS, pev->origin, pev->angles, true, edict(), keys ); pChild->pev->spawnflags |= SF_MONSTER_FALL_TO_GROUND; diff --git a/dlls/monster/CController.cpp b/dlls/monster/CController.cpp index 20010453..a5a821e2 100644 --- a/dlls/monster/CController.cpp +++ b/dlls/monster/CController.cpp @@ -318,7 +318,7 @@ void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) const char* soundlist = m_soundReplacementPath ? STRING(m_soundReplacementPath) : ""; std::unordered_map keys = { {"soundlist", soundlist} }; - CBaseMonster *pBall = (CBaseMonster*)Create( "controller_head_ball", vecStart, pev->angles, edict(), keys); + CBaseMonster *pBall = (CBaseMonster*)Create( "controller_head_ball", vecStart, pev->angles, true, edict(), keys); pBall->pev->velocity = Vector( 0, 0, 32 ); pBall->m_hEnemy = m_hEnemy; @@ -670,7 +670,7 @@ void CController :: RunTask ( Task_t *pTask ) vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.sk_controller_speedball; vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); - CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, pev->angles, edict() ); + CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, pev->angles, true, edict() ); pBall->pev->velocity = vecDir; if (CBaseEntity::IRelationship(Classify(), CLASS_PLAYER) == R_AL) { diff --git a/dlls/monster/CGargantua.cpp b/dlls/monster/CGargantua.cpp index 19f94ec1..06d76ecb 100644 --- a/dlls/monster/CGargantua.cpp +++ b/dlls/monster/CGargantua.cpp @@ -674,7 +674,7 @@ void CGargantua::DeathEffect( void ) position.z += 15; } - CBaseEntity *pSmoker = CBaseEntity::Create( "env_smoker", pev->origin, g_vecZero, NULL ); + CBaseEntity *pSmoker = CBaseEntity::Create( "env_smoker", pev->origin, g_vecZero ); pSmoker->pev->health = 1; // 1 smoke balls pSmoker->pev->scale = 46; // 4.6X normal size pSmoker->pev->dmg = 0; // 0 radial distribution @@ -1298,7 +1298,7 @@ void SpawnExplosion( Vector center, float randomRange, float time, int magnitude center.x += RANDOM_FLOAT( -randomRange, randomRange ); center.y += RANDOM_FLOAT( -randomRange, randomRange ); - CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, g_vecZero, NULL ); + CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, g_vecZero ); snprintf( buf, 128, "%3d", magnitude ); kvd.szKeyName = "iMagnitude"; kvd.szValue = buf; diff --git a/dlls/monster/CKingpin.cpp b/dlls/monster/CKingpin.cpp index 98119df3..6100957c 100644 --- a/dlls/monster/CKingpin.cpp +++ b/dlls/monster/CKingpin.cpp @@ -525,7 +525,7 @@ void CKingpin::HandleAnimEvent(MonsterEvent_t* pEvent) case KINGPIN_AE_CONJURE_ORB: { if (!m_orb) { Vector orbPosition = pev->origin + Vector(0, 0, 64); - m_orb = Create("kingpin_plasma_ball", orbPosition, g_vecZero, edict()); + m_orb = Create("kingpin_plasma_ball", orbPosition, g_vecZero, true, edict()); m_orb->pev->scale = 0.1f; pev->framerate = 0.3f; // slow down to let the orb grow EMIT_SOUND_DYN(m_orb->edict(), CHAN_WEAPON, ORB_GROW_SOUND, 1.0, ATTN_NORM, 0, RANDOM_LONG(95, 105)); diff --git a/dlls/monster/CNihilanth.cpp b/dlls/monster/CNihilanth.cpp index 1ffc65cf..2de82fcc 100644 --- a/dlls/monster/CNihilanth.cpp +++ b/dlls/monster/CNihilanth.cpp @@ -526,7 +526,7 @@ void CNihilanth :: DyingThink( void ) RGBA(64, 128, 255, 255), 10); GetAttachment( 0, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, true, edict() ); pEntity->pev->velocity = Vector ( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; pEntity->GreenBallInit( ); @@ -601,7 +601,7 @@ void CNihilanth :: ShootBalls( void ) // vecDir = (m_posTarget - vecSrc).Normalize( ); vecDir = (m_posTarget - pev->origin).Normalize( ); vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); - pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, true, edict() ); pEntity->pev->velocity = vecDir * 200.0; pEntity->ZapInit( m_hEnemy ); @@ -610,7 +610,7 @@ void CNihilanth :: ShootBalls( void ) // vecDir = (m_posTarget - vecSrc).Normalize( ); vecDir = (m_posTarget - pev->origin).Normalize( ); vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); - pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, true, edict() ); pEntity->pev->velocity = vecDir * 200.0; pEntity->ZapInit( m_hEnemy ); } @@ -991,7 +991,7 @@ BOOL CNihilanth :: EmitSphere( void ) return FALSE; Vector vecSrc = m_hRecharger->pev->origin; - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, true, edict() ); pEntity->pev->velocity = pev->origin - vecSrc; pEntity->CircleInit( this ); @@ -1064,7 +1064,7 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) Vector vecSrc, vecAngles; GetAttachment( 2, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, true, edict() ); pEntity->pev->velocity = pev->origin - vecSrc; pEntity->TeleportInit( this, m_hEnemy, pTrigger, pTouch ); } @@ -1105,7 +1105,7 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) { Vector vecSrc, vecAngles; GetAttachment( 2, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, true, edict() ); pEntity->pev->velocity = pev->origin - vecSrc; pEntity->ZapInit( m_hEnemy ); } @@ -1114,7 +1114,7 @@ void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) /* Vector vecSrc, vecAngles; GetAttachment( 0, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); + CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, true, edict() ); pEntity->pev->velocity = Vector ( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; pEntity->GreenBallInit( ); */ diff --git a/dlls/monster/COsprey.cpp b/dlls/monster/COsprey.cpp index 99e3b13b..d7420e0e 100644 --- a/dlls/monster/COsprey.cpp +++ b/dlls/monster/COsprey.cpp @@ -328,7 +328,7 @@ CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) keys["is_player_ally"] = "1"; } - pEntity = Create(replenishMonster, vecSrc, pev->angles, NULL, keys); + pEntity = Create(replenishMonster, vecSrc, pev->angles, true, NULL, keys); pGrunt = pEntity->MyMonsterPointer( ); pGrunt->pev->movetype = MOVETYPE_FLY; pGrunt->pev->velocity = Vector( 0, 0, RANDOM_FLOAT( -196, -128 ) ); diff --git a/dlls/player/CBasePlayer.cpp b/dlls/player/CBasePlayer.cpp index 48fe1897..19fe6392 100644 --- a/dlls/player/CBasePlayer.cpp +++ b/dlls/player/CBasePlayer.cpp @@ -766,7 +766,7 @@ void CBasePlayer::PackDeadPlayerItems( void ) static std::unordered_map keys = { {"is_player_ally", "1"} }; Vector angles(0, pev->angles.y, 0); CBaseEntity* pRoach = CBaseEntity::Create("monster_shockroach", - pev->origin + gpGlobals->v_forward * 10, angles, edict(), keys); + pev->origin + gpGlobals->v_forward * 10, angles, true, edict(), keys); pRoach->pev->velocity = pev->velocity * 1.2; } @@ -775,7 +775,7 @@ void CBasePlayer::PackDeadPlayerItems( void ) } // create a box to pack the stuff into. - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin, pev->angles, edict() ); + CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin, pev->angles, true, edict() ); pWeaponBox->pev->angles.x = 0;// don't let weaponbox tilt. pWeaponBox->pev->angles.z = 0; @@ -5218,13 +5218,13 @@ void CBasePlayer::DropPlayerItem ( char *pszItemName ) static std::unordered_map keys = { {"is_player_ally", "1"} }; Vector angles(0, pev->angles.y, 0); CBaseEntity* pRoach = CBaseEntity::Create("monster_shockroach", - pev->origin + gpGlobals->v_forward * 10, angles, edict(), keys); + pev->origin + gpGlobals->v_forward * 10, angles, true, edict(), keys); pRoach->pev->velocity = gpGlobals->v_forward * 400; } return; } - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, edict() ); + CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, true, edict() ); pWeaponBox->pev->angles.x = 0; pWeaponBox->pev->angles.z = 0; pWeaponBox->pev->avelocity = Vector(0, 256, 256); @@ -5327,7 +5327,7 @@ void CBasePlayer::DropAmmo(bool secondary) { string_t model = 0; int body = 0; int sequence = 0; - CBaseEntity* ammoEnt = (CBaseEntity*)CBaseEntity::Create(ammoEntName, pev->origin, pev->angles, edict()); + CBaseEntity* ammoEnt = (CBaseEntity*)CBaseEntity::Create(ammoEntName, pev->origin, pev->angles, true, edict()); if (!ammoEnt) { ALERT(at_console, "Invalid ent in DropAmmo: %s\n", ammoEntName); return; @@ -5337,7 +5337,7 @@ void CBasePlayer::DropAmmo(bool secondary) { body = ammoEnt->pev->body; sequence = ammoEnt->pev->sequence; - CWeaponBox* pWeaponBox = (CWeaponBox*)CBaseEntity::Create("weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, edict()); + CWeaponBox* pWeaponBox = (CWeaponBox*)CBaseEntity::Create("weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, true, edict()); pWeaponBox->pev->angles.x = 0; pWeaponBox->pev->angles.z = 0; pWeaponBox->pev->avelocity = Vector(0, 256, 256); diff --git a/dlls/triggers/CGamePlayerEquip.cpp b/dlls/triggers/CGamePlayerEquip.cpp index 990bfa29..546661de 100644 --- a/dlls/triggers/CGamePlayerEquip.cpp +++ b/dlls/triggers/CGamePlayerEquip.cpp @@ -24,6 +24,7 @@ LINK_ENTITY_TO_CLASS(game_player_equip, CGamePlayerEquip) bool g_mapCfgExists; bool g_noSuit; bool g_noMedkit; +int g_mapEquipIdx; EquipItem g_mapEquipment[MAX_EQUIP]; void CGamePlayerEquip::KeyValue(KeyValueData* pkvd) diff --git a/dlls/triggers/CTriggerCreateEntity.cpp b/dlls/triggers/CTriggerCreateEntity.cpp index 33c0d987..f57797fc 100644 --- a/dlls/triggers/CTriggerCreateEntity.cpp +++ b/dlls/triggers/CTriggerCreateEntity.cpp @@ -166,7 +166,7 @@ void CTriggerCreateEntity::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, US } } - CBaseEntity::Create(STRING(m_childClass), pev->origin, pev->angles, NULL, keys); + CBaseEntity::Create(STRING(m_childClass), pev->origin, pev->angles, true, NULL, keys); if (m_triggerAfterSpawn) { FireLogicTargets(STRING(m_triggerAfterSpawn), USE_TOGGLE, 0); diff --git a/dlls/triggers/CTriggerEntityIterator.cpp b/dlls/triggers/CTriggerEntityIterator.cpp index 7cd6c33b..4c27cb86 100644 --- a/dlls/triggers/CTriggerEntityIterator.cpp +++ b/dlls/triggers/CTriggerEntityIterator.cpp @@ -216,7 +216,7 @@ void CTriggerEntityIterator::Use(CBaseEntity* pActivator, CBaseEntity* pCaller, if (m_run_mode == RUN_MODE_ONCE_MULTITHREADED) { CTriggerEntityIterator* child = (CTriggerEntityIterator*)CBaseEntity::Create( - "trigger_entity_iterator", pev->origin, pev->angles, NULL); + "trigger_entity_iterator", pev->origin, pev->angles); if (child) { child->pev->target = pev->target; diff --git a/dlls/util/Scheduler.h b/dlls/util/Scheduler.h index 0a8c5739..422b6fa6 100644 --- a/dlls/util/Scheduler.h +++ b/dlls/util/Scheduler.h @@ -31,6 +31,8 @@ EXPORT extern unsigned int g_schedule_id; // don't touch this // there should only be one instance of this in the game (g_Scheduler) class Scheduler { public: + static const int REPEAT_INFINITE_TIMES = -1; + std::vector functions; template diff --git a/dlls/util/eng_wrappers.cpp b/dlls/util/eng_wrappers.cpp index 44ebd579..502a8753 100644 --- a/dlls/util/eng_wrappers.cpp +++ b/dlls/util/eng_wrappers.cpp @@ -498,6 +498,10 @@ int PRECACHE_REPLACEMENT_MODEL_ENT(CBaseEntity* ent, const char* path) { return g_engfuncs.pfnPrecacheModel(NOT_PRECACHED_MODEL); } +int PRECACHE_MODEL_NULLENT(const char* path) { + return PRECACHE_MODEL_ENT(NULL, path); +} + int PRECACHE_EVENT(int id, const char* path) { std::string lowerPath = toLowerCase(path); path = lowerPath.c_str(); diff --git a/dlls/util/eng_wrappers.h b/dlls/util/eng_wrappers.h index 55b63fd1..a93360bd 100644 --- a/dlls/util/eng_wrappers.h +++ b/dlls/util/eng_wrappers.h @@ -58,6 +58,7 @@ EXPORT int PRECACHE_GENERIC(const char* path); EXPORT int PRECACHE_SOUND_ENT(CBaseEntity* ent, const char* path); EXPORT int PRECACHE_SOUND_NULLENT(const char* path); EXPORT int PRECACHE_MODEL_ENT(CBaseEntity* ent, const char* model); +EXPORT int PRECACHE_MODEL_NULLENT(const char* model); EXPORT void PRECACHE_MODEL_SEQUENCE(const char* path, int sequence); // precache sounds/sprites used by a single animation EXPORT int PRECACHE_REPLACEMENT_MODEL_ENT(CBaseEntity* ent, const char* model); // only precache the model if it will be replaced EXPORT int PRECACHE_EVENT(int id, const char* path); diff --git a/dlls/util/util.h b/dlls/util/util.h index 7de820ef..136ddd91 100644 --- a/dlls/util/util.h +++ b/dlls/util/util.h @@ -47,7 +47,8 @@ class CBasePlayer; extern EXPORT globalvars_t *gpGlobals; -extern std::unordered_set g_weaponClassnames; +extern std::unordered_set g_weaponNames; // names given by weapons (may have a prefix: "hlcoop/weapon_grapple") +extern std::unordered_set g_weaponClassnames; // valid weapon classnames extern int g_serveractive; // 1 if ServerActivate was called (no longer safe to precache) extern int g_edictsinit; // 1 if all edicts were allocated so that relocations can begin diff --git a/dlls/weapon/CBasePlayerItem.cpp b/dlls/weapon/CBasePlayerItem.cpp index f439c4b8..3557e26e 100644 --- a/dlls/weapon/CBasePlayerItem.cpp +++ b/dlls/weapon/CBasePlayerItem.cpp @@ -160,7 +160,7 @@ CBaseEntity* CBasePlayerItem::Respawn(void) { // make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code // will decide when to make the weapon visible and touchable. - CBaseEntity* pNewWeapon = CBaseEntity::Create((char*)STRING(pev->classname), g_pGameRules->VecWeaponRespawnSpot(this), pev->angles, pev->owner); + CBaseEntity* pNewWeapon = CBaseEntity::Create((char*)STRING(pev->classname), g_pGameRules->VecWeaponRespawnSpot(this), pev->angles, true, pev->owner); if (pNewWeapon) { diff --git a/dlls/weapon/CGrenade.cpp b/dlls/weapon/CGrenade.cpp index 39f0cd7d..27508d8c 100644 --- a/dlls/weapon/CGrenade.cpp +++ b/dlls/weapon/CGrenade.cpp @@ -137,7 +137,7 @@ void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) { int sparkCount = RANDOM_LONG(0,3); for ( int i = 0; i < sparkCount; i++ ) - Create( "spark_shower", m_effectOrigin, pTrace->vecPlaneNormal, NULL ); + Create( "spark_shower", m_effectOrigin, pTrace->vecPlaneNormal ); } } diff --git a/dlls/weapon/CGrenade.h b/dlls/weapon/CGrenade.h index 832c5932..08abf611 100644 --- a/dlls/weapon/CGrenade.h +++ b/dlls/weapon/CGrenade.h @@ -11,13 +11,13 @@ class CGrenade : public CBaseMonster typedef enum { SATCHEL_DETONATE = 0, SATCHEL_RELEASE } SATCHELCODE; - static CGrenade *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time, const char* model=NULL); - static CGrenade *ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - static CGrenade *ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - static void UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ); + EXPORT static CGrenade *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time, const char* model=NULL); + EXPORT static CGrenade *ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); + EXPORT static CGrenade *ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); + EXPORT static void UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ); - void Explode( Vector vecSrc, Vector vecAim ); - virtual void Explode( TraceResult *pTrace, int bitsDamageType ); + void EXPORT Explode( Vector vecSrc, Vector vecAim ); + virtual void EXPORT Explode( TraceResult *pTrace, int bitsDamageType ); void EXPORT Smoke( void ); void EXPORT BounceTouch( CBaseEntity *pOther ); @@ -29,7 +29,7 @@ class CGrenade : public CBaseMonster void EXPORT DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void EXPORT TumbleThink( void ); - virtual void BounceSound( void ); + virtual EXPORT void BounceSound( void ); virtual int BloodColor( void ) { return DONT_BLEED; } virtual void Killed( entvars_t *pevAttacker, int iGib ); virtual const char* GetDeathNoticeWeapon() { return "monster_grenade"; } diff --git a/dlls/weapon/CHgun.cpp b/dlls/weapon/CHgun.cpp index fd08b5f8..14aa8139 100644 --- a/dlls/weapon/CHgun.cpp +++ b/dlls/weapon/CHgun.cpp @@ -163,7 +163,7 @@ void CHgun::PrimaryAttack() #ifndef CLIENT_DLL UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - CBaseEntity *pHornet = CBaseEntity::Create( "hornet", m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); + CBaseEntity *pHornet = CBaseEntity::Create( "hornet", m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12, m_pPlayer->pev->v_angle, true, m_pPlayer->edict() ); pHornet->pev->velocity = gpGlobals->v_forward * 300; m_flRechargeTime = gpGlobals->time + GetRechargeTime(); @@ -261,7 +261,7 @@ void CHgun::SecondaryAttack( void ) break; } - pHornet = CBaseEntity::Create( "hornet", vecSrc, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); + pHornet = CBaseEntity::Create( "hornet", vecSrc, m_pPlayer->pev->v_angle, true, m_pPlayer->edict() ); pHornet->pev->velocity = gpGlobals->v_forward * 1200; pHornet->pev->angles = UTIL_VecToAngles( pHornet->pev->velocity ); diff --git a/dlls/weapon/CSatchel.cpp b/dlls/weapon/CSatchel.cpp index aa8b5a8b..42c8c4d6 100644 --- a/dlls/weapon/CSatchel.cpp +++ b/dlls/weapon/CSatchel.cpp @@ -421,7 +421,7 @@ void CSatchel::Throw( void ) Vector vecThrow = gpGlobals->v_forward * 274 + m_pPlayer->pev->velocity; #ifndef CLIENT_DLL - CBaseEntity *pSatchel = Create( "monster_satchel", vecSrc, Vector( 0, 0, 0), m_pPlayer->edict() ); + CBaseEntity *pSatchel = Create( "monster_satchel", vecSrc, Vector( 0, 0, 0), true, m_pPlayer->edict() ); SET_MODEL(pSatchel->edict(), GetModelW()); pSatchel->pev->velocity = vecThrow; pSatchel->pev->avelocity.y = 400; diff --git a/dlls/weapon/CSqueak.cpp b/dlls/weapon/CSqueak.cpp index d7e5927b..c7aa25c9 100644 --- a/dlls/weapon/CSqueak.cpp +++ b/dlls/weapon/CSqueak.cpp @@ -172,7 +172,7 @@ void CSqueak::PrimaryAttack() m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); #ifndef CLIENT_DLL - CBaseEntity *pSqueak = CBaseEntity::Create( "monster_snark", tr.vecEndPos, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); + CBaseEntity *pSqueak = CBaseEntity::Create( "monster_snark", tr.vecEndPos, m_pPlayer->pev->v_angle, true, m_pPlayer->edict() ); pSqueak->pev->velocity = gpGlobals->v_forward * 200 + m_pPlayer->pev->velocity; #endif diff --git a/dlls/weapon/CTripmine.cpp b/dlls/weapon/CTripmine.cpp index 8770364b..f9a3c019 100644 --- a/dlls/weapon/CTripmine.cpp +++ b/dlls/weapon/CTripmine.cpp @@ -463,7 +463,7 @@ void CTripmine::PrimaryAttack( void ) { Vector angles = UTIL_VecToAngles( tr.vecPlaneNormal ); - CBaseEntity *pEnt = CBaseEntity::Create( "monster_tripmine", tr.vecEndPos + tr.vecPlaneNormal * 8, angles, m_pPlayer->edict() ); + CBaseEntity *pEnt = CBaseEntity::Create( "monster_tripmine", tr.vecEndPos + tr.vecPlaneNormal * 8, angles, true, m_pPlayer->edict() ); SET_MODEL(pEnt->edict(), GetModelW()); m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; diff --git a/dlls/weapon/weapons.cpp b/dlls/weapon/weapons.cpp index b392756b..a5c772d0 100644 --- a/dlls/weapon/weapons.cpp +++ b/dlls/weapon/weapons.cpp @@ -232,7 +232,7 @@ CBaseEntity* ShootMortar(edict_t* pentOwner, Vector vecStart, Vector vecVelocity TraceResult tr; UTIL_TraceLine(vecStart, vecStart + Vector(0, 0, -4096), ignore_monsters, pentOwner, &tr); - CBaseEntity* pMortar = CBaseEntity::Create("monster_mortar", tr.vecEndPos, Vector(0, 0, 0), pentOwner); + CBaseEntity* pMortar = CBaseEntity::Create("monster_mortar", tr.vecEndPos, Vector(0, 0, 0), true, pentOwner); pMortar->pev->nextthink = gpGlobals->time; @@ -275,6 +275,7 @@ void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) bool g_registeringCustomWeps = false; +std::unordered_set g_weaponNames; std::unordered_set g_weaponClassnames; const char* g_filledWeaponSlots[MAX_WEAPON_SLOTS][MAX_WEAPON_POSITIONS]; @@ -369,7 +370,8 @@ ItemInfo UTIL_RegisterWeapon( const char *szClassname ) AddAmmoNameToAmmoRegistry(info.pszAmmo2); } - g_weaponClassnames.insert(info.pszName); + g_weaponNames.insert(info.pszName); + g_weaponClassnames.insert(szClassname); // events must always be precached, and in the correct order, or else // vanilla clients will play the wrong weapon events