From 212fb6692646351db02b2299314f0e61d63d1f1f Mon Sep 17 00:00:00 2001 From: jhh8 Date: Thu, 11 Jun 2026 15:55:55 +0300 Subject: [PATCH 1/2] add marineprofile keyvalue to info_player_start marineprofile(choices) : "Marine" : -1 = [ -1 : "Default" 0 : "Sarge" 1 : "Wildcat" 2 : "Faith" 3 : "Crash" 4 : "Jaeger" 5 : "Wolfe" 6 : "Bastille" 7 : "Vegas" ] --- reactivedrop/fgd/base.fgd | 13 ++++ src/game/server/info_player_start.cpp | 31 ++++++++ src/game/server/info_player_start.h | 15 ++++ src/game/server/subs.cpp | 2 - src/game/server/swarm/asw_arena.cpp | 5 +- src/game/server/swarm/asw_player.cpp | 2 +- src/game/server/swarm/asw_player.h | 3 +- .../server/swarm/asw_tutorial_spawning.cpp | 4 +- src/game/server/swarm/asw_tutorial_spawning.h | 4 +- src/game/server/swarm_sdk_server.vcxproj | 2 + src/game/shared/swarm/asw_deathmatch_mode.cpp | 14 ++-- src/game/shared/swarm/asw_gamerules.cpp | 78 ++++++++----------- src/game/shared/swarm/asw_gamerules.h | 7 +- 13 files changed, 114 insertions(+), 66 deletions(-) create mode 100644 src/game/server/info_player_start.cpp create mode 100644 src/game/server/info_player_start.h diff --git a/reactivedrop/fgd/base.fgd b/reactivedrop/fgd/base.fgd index d002539f9..e610fb95a 100644 --- a/reactivedrop/fgd/base.fgd +++ b/reactivedrop/fgd/base.fgd @@ -2654,6 +2654,19 @@ [ 1: "Master (Has priority if multiple info_player_starts exist)" : 0 ] + + marineprofile(choices) : "Marine" : -1 = + [ + -1 : "Default" + 0 : "Sarge" + 1 : "Wildcat" + 2 : "Faith" + 3 : "Crash" + 4 : "Jaeger" + 5 : "Wolfe" + 6 : "Bastille" + 7 : "Vegas" + ] ] @PointClass base(Targetname) size(-1 -1 0, 1 1 1) color(80 150 225) studio("models/editor/overlay_helper.mdl") sphere(fademindist) sphere(fademaxdist) overlay() = info_overlay : diff --git a/src/game/server/info_player_start.cpp b/src/game/server/info_player_start.cpp new file mode 100644 index 000000000..37ae6ad46 --- /dev/null +++ b/src/game/server/info_player_start.cpp @@ -0,0 +1,31 @@ +#include "cbase.h" +#include "info_player_start.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +BEGIN_DATADESC( CBaseStart ) + +DEFINE_KEYFIELD( m_nMarineProfile, FIELD_INTEGER, "marineprofile" ), + +END_DATADESC() + +LINK_ENTITY_TO_CLASS( info_player_start, CBaseStart ); + +CBaseStart::CBaseStart() +{ + m_nMarineProfile = -1; + m_bUsed = false; +} + +bool CBaseStart::KeyValue( const char* szKeyName, const char* szValue ) +{ + if ( FStrEq( szKeyName, "marineprofile" ) ) + { + m_nMarineProfile = atoi( szValue ); + } + else + return BaseClass::KeyValue( szKeyName, szValue ); + + return true; +} \ No newline at end of file diff --git a/src/game/server/info_player_start.h b/src/game/server/info_player_start.h new file mode 100644 index 000000000..de83d9849 --- /dev/null +++ b/src/game/server/info_player_start.h @@ -0,0 +1,15 @@ +#pragma once + +class CBaseStart : public CPointEntity +{ +public: + DECLARE_CLASS( CBaseStart, CPointEntity ); + + CBaseStart(); + virtual bool KeyValue( const char* szKeyName, const char* szValue ); + + DECLARE_DATADESC(); + + int m_nMarineProfile; + bool m_bUsed; +}; \ No newline at end of file diff --git a/src/game/server/subs.cpp b/src/game/server/subs.cpp index c05589093..57ef9e51e 100644 --- a/src/game/server/subs.cpp +++ b/src/game/server/subs.cpp @@ -58,10 +58,8 @@ BEGIN_DATADESC( CBaseDMStart ) END_DATADESC() - // These are the new entry points to entities. LINK_ENTITY_TO_CLASS(info_player_deathmatch,CBaseDMStart); -LINK_ENTITY_TO_CLASS(info_player_start,CPointEntity); LINK_ENTITY_TO_CLASS(info_landmark,CPointEntity); bool CBaseDMStart::IsTriggered( CBaseEntity *pEntity ) diff --git a/src/game/server/swarm/asw_arena.cpp b/src/game/server/swarm/asw_arena.cpp index 67ddf24f8..462d8ac3c 100644 --- a/src/game/server/swarm/asw_arena.cpp +++ b/src/game/server/swarm/asw_arena.cpp @@ -8,6 +8,7 @@ #include "asw_weapon.h" #include "ai_network.h" #include "ai_networkmanager.h" +#include "info_player_start.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -240,7 +241,7 @@ void CASW_Arena::TeleportPlayersToSpawn() if ( !ASWGameRules() ) return; - CBaseEntity *pSpot = NULL; + CBaseStart *pSpot = NULL; CASW_Game_Resource *pGameResource = ASWGameResource(); for (int i=0;iGetMaxMarineResources();i++) { @@ -249,7 +250,7 @@ void CASW_Arena::TeleportPlayersToSpawn() CASW_Marine *pMarine = pGameResource->GetMarineResource(i)->GetMarineEntity(); if ( pMarine->GetHealth() > 0 ) { - pSpot = ASWGameRules()->GetMarineSpawnPoint( pSpot ); + pSpot = ASWGameRules()->GetMarineSpawnPointDM( pSpot ); if ( pSpot ) { pMarine->Teleport( &pSpot->GetAbsOrigin(), &pSpot->GetAbsAngles(), &vec3_origin ); diff --git a/src/game/server/swarm/asw_player.cpp b/src/game/server/swarm/asw_player.cpp index 79c8c3bca..2f43f2825 100644 --- a/src/game/server/swarm/asw_player.cpp +++ b/src/game/server/swarm/asw_player.cpp @@ -372,7 +372,7 @@ void ASW_DrawAwakeAI() } ConVar asw_draw_awake_ai( "asw_draw_awake_ai", "0", FCVAR_CHEAT, "Lists how many of each AI are awake"); -CBaseEntity *CASW_Player::spawn_point = NULL; +CBaseStart *CASW_Player::spawn_point = NULL; CASW_Player::CASW_Player() { diff --git a/src/game/server/swarm/asw_player.h b/src/game/server/swarm/asw_player.h index c875a5566..fc8aa428e 100644 --- a/src/game/server/swarm/asw_player.h +++ b/src/game/server/swarm/asw_player.h @@ -14,6 +14,7 @@ #include "asw_info_message_shared.h" #include "basemultiplayerplayer.h" #include "rd_inventory_shared.h" +#include "info_player_start.h" class CASW_Inhabitable_NPC; class CASW_Marine; @@ -306,7 +307,7 @@ class CASW_Player : public CBaseMultiplayerPlayer, public IASWPlayerAnimStateHel }; CUtlVectorAutoPurge m_InventoryCommands; - static CBaseEntity *spawn_point; + static CBaseStart *spawn_point; bool m_bWelcomed; float m_fLastFragTime; int m_iKillingSpree; diff --git a/src/game/server/swarm/asw_tutorial_spawning.cpp b/src/game/server/swarm/asw_tutorial_spawning.cpp index 16e53eb4a..219196f50 100644 --- a/src/game/server/swarm/asw_tutorial_spawning.cpp +++ b/src/game/server/swarm/asw_tutorial_spawning.cpp @@ -18,12 +18,12 @@ CASW_TutorialStartPoint *CASW_TutorialStartPoint::GetTutorialStartPoint( int iMa if ( iMarineSlot < 0 || iMarineSlot >= 8 ) return NULL; - CASW_TutorialStartPoint *pStartEntity = assert_cast( gEntList.FindEntityByClassname( NULL, "info_tutorial_start" ) ); + CASW_TutorialStartPoint *pStartEntity = dynamic_cast( gEntList.FindEntityByClassname( NULL, "info_tutorial_start" ) ); while ( pStartEntity != NULL ) { if ( pStartEntity->m_iMarineSlot == iMarineSlot && pStartEntity->m_iSaveStage == GetTutorialSaveStage() ) return pStartEntity; - pStartEntity = assert_cast( gEntList.FindEntityByClassname( pStartEntity, "info_tutorial_start" ) ); + pStartEntity = dynamic_cast( gEntList.FindEntityByClassname( dynamic_cast(pStartEntity), "info_tutorial_start" ) ); } return NULL; diff --git a/src/game/server/swarm/asw_tutorial_spawning.h b/src/game/server/swarm/asw_tutorial_spawning.h index 7204360e9..466ed8633 100644 --- a/src/game/server/swarm/asw_tutorial_spawning.h +++ b/src/game/server/swarm/asw_tutorial_spawning.h @@ -4,9 +4,9 @@ #pragma once #endif +#include "info_player_start.h" - -class CASW_TutorialStartPoint : public CPointEntity +class CASW_TutorialStartPoint : public CBaseStart { public: DECLARE_DATADESC(); diff --git a/src/game/server/swarm_sdk_server.vcxproj b/src/game/server/swarm_sdk_server.vcxproj index de742e9f5..ba29ea6bf 100644 --- a/src/game/server/swarm_sdk_server.vcxproj +++ b/src/game/server/swarm_sdk_server.vcxproj @@ -1075,6 +1075,7 @@ exit /b 0 + @@ -2063,6 +2064,7 @@ exit /b 0 + diff --git a/src/game/shared/swarm/asw_deathmatch_mode.cpp b/src/game/shared/swarm/asw_deathmatch_mode.cpp index 2f0970275..57baa66e4 100644 --- a/src/game/shared/swarm/asw_deathmatch_mode.cpp +++ b/src/game/shared/swarm/asw_deathmatch_mode.cpp @@ -708,9 +708,9 @@ void CASW_Deathmatch_Mode::SpawnMarine( CASW_Player *player ) } else { - CASW_Player::spawn_point = ASWGameRules()->GetMarineSpawnPoint( CASW_Player::spawn_point ); + CASW_Player::spawn_point = ASWGameRules()->GetMarineSpawnPointDM( CASW_Player::spawn_point ); if ( !CASW_Player::spawn_point ) - CASW_Player::spawn_point = ASWGameRules()->GetMarineSpawnPoint( NULL ); + CASW_Player::spawn_point = ASWGameRules()->GetMarineSpawnPointDM( NULL ); if ( CASW_Player::spawn_point ) { ASWGameRules()->SpawnMarineAt( pMR, CASW_Player::spawn_point->GetAbsOrigin(), CASW_Player::spawn_point->GetAbsAngles(), false ); @@ -826,10 +826,10 @@ void CASW_Deathmatch_Mode::PrepareMarinesForGunGameOrInstagib( int iWeaponID/* = pMarine->AddSlowHeal( pMarine->GetMaxHealth() - pMarine->GetHealth(), 3, NULL ); // move to spawnpoint - CBaseEntity *( &pSpawnPoint ) = CASW_Player::spawn_point; - pSpawnPoint = ASWGameRules()->GetMarineSpawnPoint( pSpawnPoint ); + CBaseStart *( &pSpawnPoint ) = CASW_Player::spawn_point; + pSpawnPoint = ASWGameRules()->GetMarineSpawnPointDM( pSpawnPoint ); if ( !pSpawnPoint ) - pSpawnPoint = ASWGameRules()->GetMarineSpawnPoint( NULL ); + pSpawnPoint = ASWGameRules()->GetMarineSpawnPointDM( NULL ); if ( pSpawnPoint ) pMarine->Teleport( &pSpawnPoint->GetAbsOrigin(), &pSpawnPoint->GetAbsAngles(), &vec3_origin ); } @@ -1112,10 +1112,10 @@ void CASW_Deathmatch_Mode::DeathmatchThink() continue; } - CASW_Player::spawn_point = ASWGameRules()->GetMarineSpawnPoint( CASW_Player::spawn_point ); + CASW_Player::spawn_point = ASWGameRules()->GetMarineSpawnPointDM( CASW_Player::spawn_point ); if ( !CASW_Player::spawn_point ) { - CASW_Player::spawn_point = ASWGameRules()->GetMarineSpawnPoint( NULL ); + CASW_Player::spawn_point = ASWGameRules()->GetMarineSpawnPointDM( NULL ); } if ( CASW_Player::spawn_point ) diff --git a/src/game/shared/swarm/asw_gamerules.cpp b/src/game/shared/swarm/asw_gamerules.cpp index 1f41e0d03..4a679003d 100644 --- a/src/game/shared/swarm/asw_gamerules.cpp +++ b/src/game/shared/swarm/asw_gamerules.cpp @@ -110,6 +110,7 @@ #include "cdll_int.h" #include "iconsistency.h" #include "rd_crafting_defs.h" + #include "info_player_start.h" #endif #include "fmtstr.h" #include "game_timescale_shared.h" @@ -3647,20 +3648,6 @@ bool CAlienSwarm::SpawnNextMarine() { if (!ASWGameResource()) return false; - - if (m_iMarinesSpawned == 0) - { - if (IsTutorialMap()) - m_pSpawningSpot = CASW_TutorialStartPoint::GetTutorialStartPoint(0); - else - m_pSpawningSpot = GetMarineSpawnPoint(NULL); - } - - if (!m_pSpawningSpot) - { - Msg("Failed to spawn a marine! No more spawn points could be found.\n"); - return false; - } // reactivedrop: security measure, in case players were able to hack and // select more marines than it is allowed by current challenge @@ -3670,28 +3657,23 @@ bool CAlienSwarm::SpawnNextMarine() return false; } - for (int i=m_iMarinesSpawned;iGetMaxMarineResources() && m_pSpawningSpot;i++) + for (int i=m_iMarinesSpawned;iGetMaxMarineResources();i++) { CASW_Marine_Resource* pMR = ASWGameResource()->GetMarineResource(i); if (!pMR) continue; - - if ( !SpawnMarineAt( pMR, m_pSpawningSpot->GetAbsOrigin(), m_pSpawningSpot->GetAbsAngles(), false ) ) - return false; - - m_iMarinesSpawned++; // grab the next spawn spot if (IsTutorialMap()) { - m_pSpawningSpot = CASW_TutorialStartPoint::GetTutorialStartPoint(i+1); + m_pSpawningSpot = dynamic_cast< CBaseStart* >( CASW_TutorialStartPoint::GetTutorialStartPoint(i+1) ); } else { // reactivedrop: if we don't find next spawn point then use the // last one - CBaseEntity *spawn_pt = GetMarineSpawnPoint(m_pSpawningSpot); + CBaseStart* spawn_pt = GetMarineSpawnPoint( pMR->GetProfileIndex() ); if (!spawn_pt) { Warning("Failed to find a pMarine spawn point. Map must " @@ -3702,6 +3684,11 @@ bool CAlienSwarm::SpawnNextMarine() m_pSpawningSpot = spawn_pt; } } + + if ( !SpawnMarineAt( pMR, m_pSpawningSpot->GetAbsOrigin(), m_pSpawningSpot->GetAbsAngles(), false ) ) + return false; + + m_iMarinesSpawned++; } return true; @@ -3831,36 +3818,35 @@ bool CAlienSwarm::SpawnMarineAt( CASW_Marine_Resource * RESTRICT pMR, const Vect return true; } -CBaseEntity* CAlienSwarm::GetMarineSpawnPoint(CBaseEntity *pStartEntity) +CBaseStart* CAlienSwarm::GetMarineSpawnPoint(int nMarineProfile /* = -1 */) { - do + CBaseStart* pStartEntity = NULL; + while ( pStartEntity = dynamic_cast< CBaseStart* >( gEntList.FindEntityByClassname( pStartEntity, "info_player_start" ) ) ) { - pStartEntity = gEntList.FindEntityByClassname( pStartEntity, "info_player_start"); - if (pStartEntity && IsValidMarineStart(pStartEntity)) - return pStartEntity; - } while (pStartEntity!=NULL); + if ( pStartEntity->m_bUsed ) + continue; + + if ( pStartEntity->m_nMarineProfile != -1 && nMarineProfile != pStartEntity->m_nMarineProfile ) + continue; + + pStartEntity->m_bUsed = true; + + return pStartEntity; + } return NULL; } -// make sure this spot doesn't have a marine on it already -bool CAlienSwarm::IsValidMarineStart(CBaseEntity *pSpot) +CBaseStart* CAlienSwarm::GetMarineSpawnPointDM(CBaseStart* pStartEntity) { - //CBaseEntity *ent = NULL; -/* - for ( CEntitySphereQuery sphere( pSpot->GetAbsOrigin(), 128 ); ent = sphere.GetCurrentEntity(); sphere.NextEntity() ) + do { - CASW_Marine* marine; - marine = CASW_Marine::AsMarine( ent ); - if (marine!=NULL) - { - Msg("rejecting this start spot as a marine is nearby\n"); - return false; - } - }*/ + pStartEntity = dynamic_cast(gEntList.FindEntityByClassname(pStartEntity, "info_player_start")); + if (pStartEntity) + return pStartEntity; + } while (pStartEntity != NULL); - //Msg("this start spot is good\n"); - return true; + return NULL; } void CAlienSwarm::StartStim( float duration, CBaseEntity *pSource ) @@ -4300,11 +4286,11 @@ void CAlienSwarm::Resurrect( CASW_Marine_Resource * RESTRICT pMR, CASW_Marine *p // Respawn a dead marine. DEPRECATED, UNUSED void CAlienSwarm::Resurrect( CASW_Marine_Resource * RESTRICT pMR ) { - static CBaseEntity *spawn_spot = NULL; + static CBaseStart *spawn_spot = NULL; - spawn_spot = ASWGameRules()->GetMarineSpawnPoint(spawn_spot); + spawn_spot = ASWGameRules()->GetMarineSpawnPointDM(spawn_spot); if (!spawn_spot) - spawn_spot = ASWGameRules()->GetMarineSpawnPoint(NULL); + spawn_spot = ASWGameRules()->GetMarineSpawnPointDM(NULL); if (!spawn_spot) { Msg( "Failed to find spawn spot" ); diff --git a/src/game/shared/swarm/asw_gamerules.h b/src/game/shared/swarm/asw_gamerules.h index 165896e63..445ee8001 100644 --- a/src/game/shared/swarm/asw_gamerules.h +++ b/src/game/shared/swarm/asw_gamerules.h @@ -85,6 +85,7 @@ class CASW_Player; class CASW_Marine; class CASW_Pickup; class CASW_Powerup; +class CBaseStart; // Faction defines #define FACTION_MARINES ( LAST_SHARED_FACTION + 1 ) @@ -153,8 +154,8 @@ class CAlienSwarm : public CSingleplayRules void AddBonusChargesToPickups(); // spawning/connecting - CBaseEntity* GetMarineSpawnPoint(CBaseEntity *pStartEntity); - bool IsValidMarineStart(CBaseEntity *pSpot); + CBaseStart* GetMarineSpawnPoint(int nMarineProfile = -1); + CBaseStart* GetMarineSpawnPointDM(CBaseStart* pStartEntity); //virtual bool ClientCommand( const char *pcmd, CBaseEntity *pEdict ); virtual void PlayerThink( CBasePlayer *pPlayer ); virtual void PlayerSpawn( CBasePlayer *pPlayer ); @@ -355,7 +356,7 @@ class CAlienSwarm : public CSingleplayRules virtual void VerifySpawnLocation( CASW_Marine *pMarine ); int m_iMarinesSpawned; float m_fNextLaunchingStep; - CBaseEntity* m_pSpawningSpot; + CBaseStart* m_pSpawningSpot; // misc void ExplodedLevel( CBaseEntity *pExploder ); From 0fec884cab55d021bf29f0918ddd7a681a92bb9a Mon Sep 17 00:00:00 2001 From: jhh8 Date: Tue, 16 Jun 2026 13:33:40 +0300 Subject: [PATCH 2/2] tweaks on marineprofile in info_player_start --- reactivedrop/fgd/base.fgd | 2 +- src/game/server/swarm/asw_tutorial_spawning.cpp | 4 ++-- src/game/shared/swarm/asw_gamerules.cpp | 17 ++++++++++++----- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/reactivedrop/fgd/base.fgd b/reactivedrop/fgd/base.fgd index e610fb95a..3c812e60d 100644 --- a/reactivedrop/fgd/base.fgd +++ b/reactivedrop/fgd/base.fgd @@ -2657,7 +2657,7 @@ marineprofile(choices) : "Marine" : -1 = [ - -1 : "Default" + -1 : "Any" 0 : "Sarge" 1 : "Wildcat" 2 : "Faith" diff --git a/src/game/server/swarm/asw_tutorial_spawning.cpp b/src/game/server/swarm/asw_tutorial_spawning.cpp index 219196f50..16e53eb4a 100644 --- a/src/game/server/swarm/asw_tutorial_spawning.cpp +++ b/src/game/server/swarm/asw_tutorial_spawning.cpp @@ -18,12 +18,12 @@ CASW_TutorialStartPoint *CASW_TutorialStartPoint::GetTutorialStartPoint( int iMa if ( iMarineSlot < 0 || iMarineSlot >= 8 ) return NULL; - CASW_TutorialStartPoint *pStartEntity = dynamic_cast( gEntList.FindEntityByClassname( NULL, "info_tutorial_start" ) ); + CASW_TutorialStartPoint *pStartEntity = assert_cast( gEntList.FindEntityByClassname( NULL, "info_tutorial_start" ) ); while ( pStartEntity != NULL ) { if ( pStartEntity->m_iMarineSlot == iMarineSlot && pStartEntity->m_iSaveStage == GetTutorialSaveStage() ) return pStartEntity; - pStartEntity = dynamic_cast( gEntList.FindEntityByClassname( dynamic_cast(pStartEntity), "info_tutorial_start" ) ); + pStartEntity = assert_cast( gEntList.FindEntityByClassname( pStartEntity, "info_tutorial_start" ) ); } return NULL; diff --git a/src/game/shared/swarm/asw_gamerules.cpp b/src/game/shared/swarm/asw_gamerules.cpp index 4a679003d..cf1d4cde9 100644 --- a/src/game/shared/swarm/asw_gamerules.cpp +++ b/src/game/shared/swarm/asw_gamerules.cpp @@ -3820,8 +3820,10 @@ bool CAlienSwarm::SpawnMarineAt( CASW_Marine_Resource * RESTRICT pMR, const Vect CBaseStart* CAlienSwarm::GetMarineSpawnPoint(int nMarineProfile /* = -1 */) { + CBaseStart* pStartEntityCandidate = NULL; + CBaseStart* pStartEntity = NULL; - while ( pStartEntity = dynamic_cast< CBaseStart* >( gEntList.FindEntityByClassname( pStartEntity, "info_player_start" ) ) ) + while ( pStartEntity = assert_cast< CBaseStart* >( gEntList.FindEntityByClassname( pStartEntity, "info_player_start" ) ) ) { if ( pStartEntity->m_bUsed ) continue; @@ -3829,12 +3831,17 @@ CBaseStart* CAlienSwarm::GetMarineSpawnPoint(int nMarineProfile /* = -1 */) if ( pStartEntity->m_nMarineProfile != -1 && nMarineProfile != pStartEntity->m_nMarineProfile ) continue; - pStartEntity->m_bUsed = true; - - return pStartEntity; + if ( !pStartEntityCandidate ) + pStartEntityCandidate = pStartEntity; + + if ( pStartEntity->m_nMarineProfile == nMarineProfile ) + pStartEntityCandidate = pStartEntity; } - return NULL; + if ( pStartEntityCandidate ) + pStartEntityCandidate->m_bUsed = true; + + return pStartEntityCandidate; } CBaseStart* CAlienSwarm::GetMarineSpawnPointDM(CBaseStart* pStartEntity)