This commit is contained in:
mv 2024-08-30 03:12:35 +03:00
parent 1d38da55e4
commit e165a8b786
58 changed files with 1442 additions and 205 deletions

View File

@ -4793,8 +4793,8 @@
0 : "No"
1 : "Yes"
]
MinSkillLevel(integer) : "Min Skill Level" : 0 : "The minimum skill level for this spawner to function. Skill levels are: 1=easy 2=normal 3=hard 4=insane"
MaxSkillLevel(integer) : "Max Skill Level" : 0 : "The maximum skill level for this spawner to function. Skill levels are: 1=easy 2=normal 3=hard 4=insane"
MinSkillLevel(integer) : "Min Skill Level" : 0 : "The minimum skill level for this spawner to function. Skill levels are: 1=easy 2=normal 3=hard 4=insane 5=imba"
MaxSkillLevel(integer) : "Max Skill Level" : 0 : "The maximum skill level for this spawner to function. Skill levels are: 1=easy 2=normal 3=hard 4=insane 5=imba"
output OnSpawned(string) : "Fires when an alien is spawned. The activator is the alien, and the string is the name of the alien."

View File

@ -11,6 +11,7 @@
#include <vgui/ILocalize.h>
#include "asw_shareddefs.h"
#include "c_asw_marine_resource.h"
#include "c_asw_campaign_save.h"
CASW_Steamstats g_ASW_Steamstats;
@ -39,15 +40,56 @@ namespace
const char* szShotsTotal = ".shotsfired.total";
const char* szShotsHit = ".shotshit.total";
const char* szHealingTotal = ".healing.total";
const char* szTimeTotal = ".time.total";
const char* szKillsAvg = ".kills.avg";
const char* szDamageAvg = ".damage.avg";
const char* szFFAvg = ".ff.avg";
const char* szTimeAvg = ".time.avg";
const char* szBestDifficulty = ".difficulty.best";
const char* szBestTime = ".time.best";
const char* szBestSpeedrunDifficulty = ".time.best.difficulty";
// difficulty names used when fetching steam stats
const char* g_szDifficulties[] =
{
"Easy",
"Normal",
"Hard",
"Insane"
"Insane",
"imba"
};
const char *g_OfficialMaps[] =
{
"asi-jac1-landingbay_01",
"asi-jac1-landingbay_02",
"asi-jac2-deima",
"asi-jac3-rydberg",
"asi-jac4-residential",
"asi-jac6-sewerjunction",
"asi-jac7-timorstation"
};
}
bool IsOfficialCampaign()
{
if( !ASWGameRules()->IsCampaignGame() )
return false;
CASW_Campaign_Save *pCampaign = ASWGameRules()->GetCampaignSave();
const char *szMapName = engine->GetLevelNameShort();
const char *szCampaignName = pCampaign->GetCampaignName();
if( FStrEq( szCampaignName, "jacob" ) )
{
for( int i=0; i < ARRAYSIZE( g_OfficialMaps ); ++i )
{
if( FStrEq( szMapName, g_OfficialMaps[i] ) )
return true;
}
}
return false;
}
bool IsDamagingWeapon( const char* szWeaponName, bool bIsExtraEquip )
@ -149,6 +191,10 @@ bool CASW_Steamstats::FetchStats( CSteamID playerSteamID, CASW_Player *pPlayer )
m_DifficultyCounts.Purge();
m_WeaponStats.Purge();
// Returns true so we don't re-fetch stats
if( !IsOfficialCampaign() )
return true;
// Fetch the player's overall stats
FETCH_STEAM_STATS( "iTotalKills", m_iTotalKills );
FETCH_STEAM_STATS( "fAccuracy", m_fAccuracy );
@ -253,7 +299,7 @@ bool CASW_Steamstats::FetchStats( CSteamID playerSteamID, CASW_Player *pPlayer )
}
// Get difficulty counts
for( int i=0; i < 4; ++i )
for( int i=0; i < 5; ++i )
{
int32 iTempCount;
FETCH_STEAM_STATS( CFmtStr( "%s.games.total", g_szDifficulties[ i ] ), iTempCount );
@ -275,7 +321,13 @@ void CASW_Steamstats::PrepStatsForSend( CASW_Player *pPlayer )
return;
// Update stats from the briefing screen
if( !GetDebriefStats() || !ASWGameResource() )
if( !GetDebriefStats()
|| !ASWGameResource()
|| !IsOfficialCampaign()
#ifndef DEBUG
|| ASWGameRules()->m_bCheated
#endif
)
return;
if( m_MarineSelectionCounts.Count() == 0 ||
@ -386,7 +438,10 @@ void CASW_Steamstats::PrepStatsForSend( CASW_Player *pPlayer )
SEND_STEAM_STATS( CFmtStr( "marines.%i.total", iMarineProfileIndex ), m_MarineSelectionCounts[iMarineProfileIndex] );
int iLevel = pPlayer->GetLevel();
SEND_STEAM_STATS( "level", iLevel );
SEND_STEAM_STATS( "level.xprequired", ( iLevel == NELEMS( g_iLevelExperience ) ) ? 0 : g_iLevelExperience[ iLevel ] );
int iPromotion = pPlayer->GetPromotion();
float flXPRequired = ( iLevel == NELEMS( g_iLevelExperience ) ) ? 0 : g_iLevelExperience[ iLevel ];
flXPRequired *= g_flPromotionXPScale[ iPromotion ];
SEND_STEAM_STATS( "level.xprequired", (int) flXPRequired );
// Send favorite equip info
SEND_STEAM_STATS( "equips.primary.fav", GetFavoriteEquip(0) );
@ -560,6 +615,8 @@ bool DifficultyStats_t::FetchDifficultyStats( CSteamAPIContext * pSteamContext,
break;
case 4: szDifficulty = "insane";
break;
case 5: szDifficulty = "imba";
break;
}
if( szDifficulty )
{
@ -618,6 +675,8 @@ void DifficultyStats_t::PrepStatsForSend( CASW_Player *pPlayer )
break;
case 4: szDifficulty = "insane";
break;
case 5: szDifficulty = "imba";
break;
}
if( szDifficulty )
{
@ -652,6 +711,12 @@ bool MissionStats_t::FetchMissionStats( CSteamAPIContext * pSteamContext, CSteam
FETCH_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szKillsTotal ), m_iKillsTotal );
FETCH_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szDamageTotal ), m_iDamageTotal );
FETCH_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szFFTotal ), m_iFFTotal );
FETCH_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szTimeTotal ), m_iTimeTotal );
FETCH_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szBestDifficulty ), m_iHighestDifficulty );
for( int i=0; i<5; ++i )
{
FETCH_STEAM_STATS( CFmtStr( "%s%s.%s", szLevelName, szBestTime, g_szDifficulties[i] ), m_iBestSpeedrunTimes[i] );
}
return bOK;
}
@ -663,6 +728,7 @@ void MissionStats_t::PrepStatsForSend( CASW_Player *pPlayer )
return;
CASW_Marine_Resource *pMR = ASWGameResource()->GetFirstMarineResourceForPlayer( pPlayer );
int iDifficulty = ASWGameRules()->GetSkillLevel();
if ( pMR )
{
int iMarineIndex = ASWGameResource()->GetMarineResourceIndex( pMR );
@ -674,6 +740,24 @@ void MissionStats_t::PrepStatsForSend( CASW_Player *pPlayer )
m_iGamesTotal++;
m_iGamesSuccess += ASWGameRules()->GetMissionSuccess() ? 1 : 0;
m_fGamesSuccessPercent = m_iGamesSuccess / (float)m_iGamesTotal * 100.0f;
m_iTimeTotal += GetDebriefStats()->m_fTimeTaken;
if( ASWGameRules()->GetMissionSuccess() )
{
if( iDifficulty > m_iHighestDifficulty )
m_iHighestDifficulty = iDifficulty;
if( (unsigned int)m_iBestSpeedrunTimes[ iDifficulty - 1 ] > GetDebriefStats()->m_fTimeTaken )
{
m_iBestSpeedrunTimes[ iDifficulty - 1 ] = GetDebriefStats()->m_fTimeTaken;
}
}
// Safely compute averages
m_fKillsAvg = m_iKillsTotal / (float)m_iGamesTotal;
m_fFFAvg = m_iFFTotal / (float)m_iGamesTotal;
m_fDamageAvg = m_iDamageTotal / (float)m_iGamesTotal;
m_iTimeAvg = m_iTimeTotal / (float)m_iGamesTotal;
}
}
@ -692,7 +776,13 @@ void MissionStats_t::PrepStatsForSend( CASW_Player *pPlayer )
SEND_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szKillsTotal ), m_iKillsTotal );
SEND_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szDamageTotal ), m_iDamageTotal );
SEND_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szFFTotal ), m_iFFTotal );
SEND_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szTimeTotal ), m_iTimeTotal );
SEND_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szKillsAvg ), m_fKillsAvg );
SEND_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szDamageAvg ), m_fDamageAvg );
SEND_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szFFAvg ), m_fFFAvg );
SEND_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szTimeAvg ), m_iTimeAvg );
SEND_STEAM_STATS( CFmtStr( "%s%s", szLevelName, szBestDifficulty ), m_iHighestDifficulty );
SEND_STEAM_STATS( CFmtStr( "%s%s.%s", szLevelName, szBestTime, g_szDifficulties[ iDifficulty - 1 ] ), m_iBestSpeedrunTimes[ iDifficulty - 1 ] );
}
bool WeaponStats_t::FetchWeaponStats( CSteamAPIContext * pSteamContext, CSteamID playerSteamID, const char *szClassName )

View File

@ -34,9 +34,13 @@ struct MissionStats_t
int32 m_iKillsTotal;
int32 m_iDamageTotal;
int32 m_iFFTotal;
int32 m_iKillsAvg;
int32 m_iDamageAvg;
int32 m_iFFAvg;
float32 m_fKillsAvg;
float32 m_fDamageAvg;
float32 m_fFFAvg;
int32 m_iTimeTotal;
int32 m_iTimeAvg;
int32 m_iHighestDifficulty;
int32 m_iBestSpeedrunTimes[5];
};
struct WeaponStats_t
@ -105,7 +109,7 @@ private:
StatList_Int_t m_MarineSelectionCounts;
StatList_Int_t m_DifficultyCounts;
DifficultyStats_t m_DifficultyStats[4];
DifficultyStats_t m_DifficultyStats[5];
MissionStats_t m_MissionStats;
WeaponStatList_t m_WeaponStats;

View File

@ -58,6 +58,7 @@ public:
FooterFormat_t GetFormat();
bool GetHelpTextEnabled();
void SetHelpText( const char *text );
const char * GetHelpText() { return m_HelpText; }
void FadeHelpText( void );
void GetPosition( int &x, int &y );
bool HasContent( void );

View File

@ -966,7 +966,7 @@ FoundGames::FoundGames( Panel *parent, const char *panelName ):
m_pHeaderFooter->SetHeaderEnabled( false );
m_pHeaderFooter->SetFooterEnabled( true );
m_pHeaderFooter->SetGradientBarEnabled( true );
m_pHeaderFooter->SetGradientBarPos( 80, 300 );
m_pHeaderFooter->SetGradientBarPos( 80, 315 );
m_pTitle = new vgui::Label( this, "Title", "" );

View File

@ -29,6 +29,7 @@ using namespace BaseModUI;
//=============================================================================
static ConVar ui_public_lobby_filter_difficulty2( "ui_public_lobby_filter_difficulty2", "", FCVAR_ARCHIVE, "Filter type for difficulty on the public lobby display" );
static ConVar ui_public_lobby_filter_onslaught( "ui_public_lobby_filter_onslaught", "", FCVAR_ARCHIVE, "Filter type for Onslaught mode on the public lobby display");
ConVar ui_public_lobby_filter_campaign( "ui_public_lobby_filter_campaign", "", FCVAR_ARCHIVE, "Filter type for campaigns on the public lobby display" );
ConVar ui_public_lobby_filter_status( "ui_public_lobby_filter_status", "", FCVAR_ARCHIVE, "Filter type for game status on the public lobby display" );
@ -38,6 +39,7 @@ FoundPublicGames::FoundPublicGames( Panel *parent, const char *panelName ) :
m_pSearchManager( NULL )
{
m_drpDifficulty = NULL;
m_drpOnslaught = NULL;
m_drpGameStatus = NULL;
m_drpCampaign = NULL;
@ -92,6 +94,7 @@ void FoundPublicGames::ApplySchemeSettings( IScheme *pScheme )
BaseClass::ApplySchemeSettings( pScheme );
m_drpDifficulty = dynamic_cast< DropDownMenu* >( FindChildByName( "DrpFilterDifficulty" ) );
m_drpOnslaught = dynamic_cast< DropDownMenu* >( FindChildByName( "DrpFilterOnslaught" ) );
m_drpGameStatus = dynamic_cast< DropDownMenu* >( FindChildByName( "DrpFilterGameStatus" ) );
m_drpCampaign = dynamic_cast< DropDownMenu* >( FindChildByName( "DrpFilterCampaign" ) );
m_btnFilters = dynamic_cast< BaseModUI::BaseModHybridButton* >( FindChildByName( "BtnFilters" ) );
@ -168,6 +171,10 @@ void FoundPublicGames::StartSearching( void )
if ( szDifficulty && *szDifficulty && GameModeHasDifficulty( szGameMode ) )
pKeyValuesSearch->SetString( "game/difficulty", szDifficulty );
char const *szOnslaught = ui_public_lobby_filter_onslaught.GetString();
if ( szOnslaught && *szOnslaught )
pKeyValuesSearch->SetInt( "game/onslaught", 1 );
char const *szStatus = ui_public_lobby_filter_status.GetString();
if ( szStatus && *szStatus )
pKeyValuesSearch->SetString( "game/state", szStatus );
@ -501,6 +508,11 @@ void FoundPublicGames::OnCommand( const char *command )
ui_public_lobby_filter_difficulty2.SetValue( filterDifficulty );
StartSearching();
}
else if ( char const *filterOnslaught = StringAfterPrefix( command, "filter_onslaught_" ) )
{
ui_public_lobby_filter_onslaught.SetValue( filterOnslaught );
StartSearching();
}
else if ( char const *filterCampaign = StringAfterPrefix( command, "filter_campaign_" ) )
{
ui_public_lobby_filter_campaign.SetValue( filterCampaign );
@ -544,6 +556,11 @@ void FoundPublicGames::Activate()
m_drpDifficulty->SetCurrentSelection( CFmtStr( "filter_difficulty_%s", ui_public_lobby_filter_difficulty2.GetString() ) );
}
if ( m_drpOnslaught )
{
m_drpOnslaught->SetCurrentSelection( CFmtStr( "filter_onslaught_%s", ui_public_lobby_filter_onslaught.GetString() ) );
}
if ( m_drpGameStatus )
{
m_drpGameStatus->SetCurrentSelection( CFmtStr( "filter_status_%s", ui_public_lobby_filter_status.GetString() ) );

View File

@ -55,6 +55,7 @@ namespace BaseModUI {
#endif
DropDownMenu* m_drpDifficulty;
DropDownMenu* m_drpOnslaught;
DropDownMenu* m_drpGameStatus;
DropDownMenu* m_drpCampaign;
BaseModUI::BaseModHybridButton *m_btnFilters;

View File

@ -55,13 +55,15 @@ GameSettings::GameSettings( vgui::Panel *parent, const char *panelName ):
m_drpStartingMission( NULL ),
m_bEditingSession( false ),
m_bAllowChangeToCustomCampaign( true ),
m_bPreventSessionModifications( false )
m_bPreventSessionModifications( false ),
m_drpFriendlyFire( NULL ),
m_drpOnslaught( NULL )
{
m_pHeaderFooter = new CNB_Header_Footer( this, "HeaderFooter" );
m_pHeaderFooter->SetTitle( "" );
m_pHeaderFooter->SetHeaderEnabled( false );
m_pHeaderFooter->SetGradientBarEnabled( true );
m_pHeaderFooter->SetGradientBarPos( 150, 170 );
m_pHeaderFooter->SetGradientBarPos( 140, 190 );
m_pTitle = new vgui::Label( this, "Title", "" );
SetDeleteSelfOnClose(true);
SetProportional( true );
@ -206,6 +208,36 @@ void GameSettings::Activate()
flyout->CloseMenu( NULL );
}
if ( m_drpFriendlyFire )
{
if ( m_pSettings->GetInt( "game/hardcoreFF", 0 ) == 1 )
{
m_drpFriendlyFire->SetCurrentSelection( "#L4D360UI_HardcoreFF" );
}
else
{
m_drpFriendlyFire->SetCurrentSelection( "#L4D360UI_RegularFF" );
}
if ( FlyoutMenu* flyout = m_drpFriendlyFire->GetCurrentFlyout() )
flyout->CloseMenu( NULL );
}
if ( m_drpOnslaught )
{
if ( m_pSettings->GetInt( "game/onslaught", 0 ) == 1 )
{
m_drpOnslaught->SetCurrentSelection( "#L4D360UI_OnslaughtEnabled" );
}
else
{
m_drpOnslaught->SetCurrentSelection( "#L4D360UI_OnslaughtDisabled" );
}
if ( FlyoutMenu* flyout = m_drpOnslaught->GetCurrentFlyout() )
flyout->CloseMenu( NULL );
}
// If we have an active control, navigate from it since we'll be setting a new one
if ( m_ActiveControl )
{
@ -581,6 +613,94 @@ void GameSettings::OnCommand(const char *command)
pFlyout->SetListener( this );
}
}
else if ( !Q_strcmp( command, "#L4D360UI_RegularFF" ) )
{
KeyValues *pSettings = KeyValues::FromString(
"update",
" update { "
" game { "
" hardcoreFF = "
" } "
" } "
);
KeyValues::AutoDelete autodelete( pSettings );
pSettings->SetInt( "update/game/hardcoreFF", 0 );
UpdateSessionSettings( pSettings );
if( m_drpFriendlyFire )
{
if ( FlyoutMenu* pFlyout = m_drpFriendlyFire->GetCurrentFlyout() )
pFlyout->SetListener( this );
}
}
else if ( !Q_strcmp( command, "#L4D360UI_HardcoreFF" ) )
{
KeyValues *pSettings = KeyValues::FromString(
"update",
" update { "
" game { "
" hardcoreFF = "
" } "
" } "
);
KeyValues::AutoDelete autodelete( pSettings );
pSettings->SetInt( "update/game/hardcoreFF", 1 );
UpdateSessionSettings( pSettings );
if( m_drpFriendlyFire )
{
if ( FlyoutMenu* pFlyout = m_drpFriendlyFire->GetCurrentFlyout() )
pFlyout->SetListener( this );
}
}
else if ( !Q_strcmp( command, "#L4D360UI_OnslaughtDisabled" ) )
{
KeyValues *pSettings = KeyValues::FromString(
"update",
" update { "
" game { "
" onslaught = "
" } "
" } "
);
KeyValues::AutoDelete autodelete( pSettings );
pSettings->SetInt( "update/game/onslaught", 0 );
UpdateSessionSettings( pSettings );
if( m_drpOnslaught )
{
if ( FlyoutMenu* pFlyout = m_drpOnslaught->GetCurrentFlyout() )
pFlyout->SetListener( this );
}
}
else if ( !Q_strcmp( command, "#L4D360UI_OnslaughtEnabled" ) )
{
KeyValues *pSettings = KeyValues::FromString(
"update",
" update { "
" game { "
" onslaught = "
" } "
" } "
);
KeyValues::AutoDelete autodelete( pSettings );
pSettings->SetInt( "update/game/onslaught", 1 );
UpdateSessionSettings( pSettings );
if( m_drpOnslaught )
{
if ( FlyoutMenu* pFlyout = m_drpOnslaught->GetCurrentFlyout() )
pFlyout->SetListener( this );
}
}
else if ( const char *szRoundLimitValue = StringAfterPrefix( command, "#L4D360UI_RoundLimit_" ) )
{
KeyValues *pSettings = new KeyValues( "update" );
@ -654,6 +774,8 @@ void GameSettings::ApplySchemeSettings( vgui::IScheme *pScheme )
m_drpDifficulty = dynamic_cast< DropDownMenu* >( FindChildByName( "DrpDifficulty" ) );
m_drpGameType = dynamic_cast< DropDownMenu* >( FindChildByName( "DrpGameType" ) );
m_drpFriendlyFire = dynamic_cast< DropDownMenu* >( FindChildByName( "DrpFriendlyFire" ) );
m_drpOnslaught = dynamic_cast< DropDownMenu* >( FindChildByName( "DrpOnslaught" ) );
m_drpGameAccess = dynamic_cast< DropDownMenu* >( FindChildByName( "DrpGameAccess" ) );
if ( m_drpGameAccess )
@ -710,6 +832,12 @@ void GameSettings::OnClose()
if( m_drpGameType )
m_drpGameType->CloseDropDown();
if( m_drpFriendlyFire )
m_drpFriendlyFire->CloseDropDown();
if( m_drpOnslaught )
m_drpOnslaught->CloseDropDown();
m_pSettings = NULL; // NULL out settings in case we get some calls
// after we are closed
if ( m_bCloseSessionOnClose )

View File

@ -73,6 +73,8 @@ private:
DropDownMenu* m_drpGameAccess;
DropDownMenu* m_drpServerType;
DropDownMenu* m_drpStartingMission;
DropDownMenu* m_drpFriendlyFire;
DropDownMenu* m_drpOnslaught;
CNB_Header_Footer *m_pHeaderFooter;
vgui::Label *m_pTitle;

View File

@ -92,7 +92,8 @@ void InGameDifficultySelect::OnCommand(const char *command)
if ( !Q_strcmp( command, "Easy" ) ||
!Q_strcmp( command, "Normal" ) ||
!Q_strcmp( command, "Hard" ) ||
!Q_strcmp( command, "Insane" ) )
!Q_strcmp( command, "Insane" ) ||
!Q_strcmp( command, "Imba" ) )
{
CGameUIConVarRef z_difficulty("z_difficulty");

View File

@ -140,6 +140,7 @@ CASW_Difficulty_Entry::CASW_Difficulty_Entry( vgui::Panel *pParent, const char *
case 2: m_pDifficultyLabel->SetText("#asw_difficulty_chooser_normal"); break;
case 3: m_pDifficultyLabel->SetText("#asw_difficulty_chooser_hard"); break;
case 4: m_pDifficultyLabel->SetText("#asw_difficulty_chooser_insane"); break;
case 5: m_pDifficultyLabel->SetText("#asw_difficulty_chooser_imba"); break;
default: m_pDifficultyLabel->SetText("???"); break;
}
@ -149,6 +150,7 @@ CASW_Difficulty_Entry::CASW_Difficulty_Entry( vgui::Panel *pParent, const char *
case 2: m_pDifficultyDescriptionLabel->SetText("#asw_difficulty_chooser_normald"); break;
case 3: m_pDifficultyDescriptionLabel->SetText("#asw_difficulty_chooser_hardd"); break;
case 4: m_pDifficultyDescriptionLabel->SetText("#asw_difficulty_chooser_insaned"); break;
case 5: m_pDifficultyDescriptionLabel->SetText("#asw_difficulty_chooser_imbad"); break;
default: m_pDifficultyDescriptionLabel->SetText("???"); break;
}
@ -158,6 +160,7 @@ CASW_Difficulty_Entry::CASW_Difficulty_Entry( vgui::Panel *pParent, const char *
case 2: m_pImagePanel->SetImage("swarm/MissionPics/DifficultyPicNormal"); break;
case 3: m_pImagePanel->SetImage("swarm/MissionPics/DifficultyPicHard"); break;
case 4: m_pImagePanel->SetImage("swarm/MissionPics/DifficultyPicInsane"); break;
case 5: m_pImagePanel->SetImage("swarm/MissionPics/DifficultyPicInsane"); break;
default: m_pImagePanel->SetImage("swarm/MissionPics/UnknownMissionPic"); break;
}

View File

@ -40,17 +40,28 @@ ExperienceBar::ExperienceBar(vgui::Panel *parent, const char *name) :
m_pExperienceBar->SetShowMaxOnCounter( true );
m_pExperienceBar->SetColors( Color( 255, 255, 255, 0 ), Color( 93,148,192,255 ), Color( 255, 255, 255, 255 ), Color( 17,37,57,255 ), Color( 35, 77, 111, 255 ) );
//m_pExperienceBar->m_bShowCumulativeTotal = true;
m_pExperienceBar->AddMinMax( 0, g_iLevelExperience[ 0 ] );
for ( int i = 0; i < ASW_NUM_EXPERIENCE_LEVELS - 1; i++ )
{
m_pExperienceBar->AddMinMax( g_iLevelExperience[ i ], g_iLevelExperience[ i + 1 ] );
}
m_nLastPromotion = -1;
UpdateMinMaxes( 0 );
m_pExperienceBar->m_flBorder = 1.5f;
vgui::ivgui()->AddTickSignal( GetVPanel() );
}
void ExperienceBar::UpdateMinMaxes( int nPromotion )
{
if ( m_nLastPromotion == nPromotion )
return;
m_nLastPromotion = nPromotion;
m_pExperienceBar->ClearMinMax();
m_pExperienceBar->AddMinMax( 0, g_iLevelExperience[ 0 ] * g_flPromotionXPScale[ m_nLastPromotion ] );
for ( int i = 0; i < ASW_NUM_EXPERIENCE_LEVELS - 1; i++ )
{
m_pExperienceBar->AddMinMax( g_iLevelExperience[ i ] * g_flPromotionXPScale[ m_nLastPromotion ] , g_iLevelExperience[ i + 1 ] * g_flPromotionXPScale[ m_nLastPromotion ] );
}
}
void ExperienceBar::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
@ -97,9 +108,9 @@ void ExperienceBar::OnTick()
}
}
if ( ASWGameRules()->GetGameState() <= ASW_GS_BRIEFING )
{
if ( m_hPlayer.Get() )
{
if ( ASWGameRules()->GetGameState() <= ASW_GS_BRIEFING )
{
int nXP = m_hPlayer->GetExperience();
if ( nXP != m_nOldPlayerXP )
@ -114,11 +125,10 @@ void ExperienceBar::OnTick()
m_pPlayerNameLabel->SetText( m_hPlayer->GetPlayerName() );
}
}
else
{
float flBarMin = m_pExperienceBar->GetBarMin();
bool bCapped = ( (int) m_pExperienceBar->m_fCurrent ) == ASW_XP_CAP;
bool bCapped = ( (int) m_pExperienceBar->m_fCurrent ) >= ASW_XP_CAP * g_flPromotionXPScale[ m_hPlayer->GetPromotion() ];
if ( m_flOldBarMin == -1 )
{
@ -127,7 +137,7 @@ void ExperienceBar::OnTick()
if ( m_flOldBarMin != -1 && ( m_flOldBarMin != flBarMin || m_bOldCapped != bCapped ) ) // bar min has changed - player has levelled up!
{
m_iPlayerLevel = LevelFromXP( m_pExperienceBar->m_fCurrent );
m_iPlayerLevel = LevelFromXP( m_pExperienceBar->m_fCurrent, m_hPlayer->GetPromotion() );
UpdateLevelLabel();
m_pLevelUpLabel->SetVisible( true );
@ -141,6 +151,7 @@ void ExperienceBar::OnTick()
m_flOldBarMin = flBarMin;
m_bOldCapped = bCapped;
}
}
}
void ExperienceBar::InitFor( C_ASW_Player *pPlayer )
@ -157,11 +168,6 @@ void ExperienceBar::InitFor( C_ASW_Player *pPlayer )
m_pPlayerNameLabel->SetText( "Player" );
m_pPlayerLevelLabel->SetText( "Level 5" );
m_pExperienceBar->Init( 1200, 1500, 1500.0f / 4.0f, true, false );
m_pExperienceBar->AddMinMax( 0, g_iLevelExperience[ 0 ] );
for ( int i = 0; i < ASW_NUM_EXPERIENCE_LEVELS - 1; i++ )
{
m_pExperienceBar->AddMinMax( g_iLevelExperience[ i ], g_iLevelExperience[ i + 1 ] );
}
m_pExperienceBar->SetStartCountingTime( gpGlobals->curtime + 15.0f );
}
return;
@ -188,6 +194,7 @@ void ExperienceBar::InitFor( C_ASW_Player *pPlayer )
}
#endif
UpdateMinMaxes( pPlayer->GetPromotion() );
if ( ASWGameRules()->GetGameState() <= ASW_GS_BRIEFING )
{
m_iPlayerLevel = pPlayer->GetLevel();
@ -204,7 +211,7 @@ void ExperienceBar::InitFor( C_ASW_Player *pPlayer )
int iEarnedXP = pPlayer->GetEarnedXP( ASW_XP_TOTAL );
int nGoalXP = pPlayer->GetExperienceBeforeDebrief() + iEarnedXP;
nGoalXP = MIN( nGoalXP, ASW_XP_CAP );
nGoalXP = MIN( nGoalXP, ASW_XP_CAP * g_flPromotionXPScale[ pPlayer->GetPromotion() ] );
float flRate = (float) iEarnedXP / 3.0f; // take 4 seconds to increase XP.
if ( iEarnedXP < 150 ) // if XP is really low, count it up in 1 second
{

View File

@ -32,6 +32,7 @@ public:
void InitFor( C_ASW_Player *pPlayer );
void UpdateLevelLabel();
void UpdateMinMaxes( int nPromotion );
bool IsDoneAnimating();
@ -51,6 +52,7 @@ public:
int m_iPlayerLevel;
int m_nOldPlayerXP;
CSteamID m_lastSteamID;
int m_nLastPromotion;
};
class ExperienceBarSmall : public ExperienceBar

View File

@ -161,7 +161,7 @@ void CExperienceReport::PerformLayout()
if ( pPlayer )
{
int nPlayerLevel = pPlayer->GetLevel();
m_pWeaponUnlockPanel->SetVisible( nPlayerLevel < ASW_LEVEL_CAP );
m_pWeaponUnlockPanel->SetVisible( nPlayerLevel < ASW_NUM_EXPERIENCE_LEVELS );
if ( ASWGameRules() && ASWGameRules()->m_iSkillLevel == 2 && !ASWGameRules()->IsOfflineGame() &&
!( ASWGameRules()->IsCampaignGame() && ASWGameRules()->CampaignMissionsLeft() <= 1 ) )
@ -194,8 +194,12 @@ void CExperienceReport::OnThink()
// monitor local player's experience bar to see when it loops
float flBarMin = m_pExperienceBar[ 0 ]->m_pExperienceBar->GetBarMin();
bool bCapped = ( (int) m_pExperienceBar[ 0 ]->m_pExperienceBar->m_fCurrent ) == ASW_XP_CAP;
bool bCapped = false;
C_ASW_Player *pPlayer = C_ASW_Player::GetLocalASWPlayer();
if ( pPlayer )
{
bCapped = ( (int) m_pExperienceBar[ 0 ]->m_pExperienceBar->m_fCurrent ) >= ASW_XP_CAP * g_flPromotionXPScale[ pPlayer->GetPromotion() ];
if ( m_flOldBarMin == -1 )
{
m_bOldCapped = bCapped;
@ -205,15 +209,13 @@ void CExperienceReport::OnThink()
{
m_bPendingUnlockSequence = true;
IGameEvent *event = gameeventmanager->CreateEvent( "level_up" );
int nNewLevel = LevelFromXP( (int) m_pExperienceBar[ 0 ]->m_pExperienceBar->m_fCurrent );
int nNewLevel = LevelFromXP( (int) m_pExperienceBar[ 0 ]->m_pExperienceBar->m_fCurrent, pPlayer->GetPromotion() );
if ( event )
{
event->SetInt( "level", nNewLevel );
gameeventmanager->FireEventClientSide( event );
}
C_ASW_Player *pPlayer = C_ASW_Player::GetLocalASWPlayer();
if ( pPlayer )
{
const char *szWeaponClassUnlocked = pPlayer->GetWeaponUnlockedAtLevel( nNewLevel );
if ( szWeaponClassUnlocked )
{
@ -227,10 +229,11 @@ void CExperienceReport::OnThink()
pComplete->OnWeaponUnlocked( szWeaponClassUnlocked );
}
}
}
CLocalPlayerFilter filter;
C_BaseEntity::EmitSound( filter, -1 /*SOUND_FROM_LOCAL_PLAYER*/, "ASW_XP.LevelUp" );
}
}
m_flOldBarMin = flBarMin;
m_bOldCapped = bCapped;
@ -256,6 +259,7 @@ void CExperienceReport::OnThink()
case 2: m_pXPDifficultyScaleNumber->SetText( "" ); flTotalXP *= g_flXPDifficultyScale[1]; break;
case 3: m_pXPDifficultyScaleNumber->SetText( "+20%" ); flTotalXP *= g_flXPDifficultyScale[2]; break;
case 4: m_pXPDifficultyScaleNumber->SetText( "+40%" ); flTotalXP *= g_flXPDifficultyScale[3]; break;
case 5: m_pXPDifficultyScaleNumber->SetText( "+50%" ); flTotalXP *= g_flXPDifficultyScale[4]; break;
}
bool bShowDifficultyBonus = ( ASWGameRules()->GetSkillLevel() != 2 );
m_pXPDifficultyScaleNumber->SetVisible( bShowDifficultyBonus );

View File

@ -115,29 +115,25 @@ void MissionStatsPanel::SetMissionLabels(vgui::Label *pMissionLabel, vgui::Label
pszToken = "#asw_difficulty_easy";
else if (iDiff == 3)
pszToken = "#asw_difficulty_hard";
else if (iDiff >= 4)
else if (iDiff == 4)
pszToken = "#asw_difficulty_insane";
else if (iDiff >= 5)
pszToken = "#asw_difficulty_imba";
const wchar_t *pDiff = g_pVGuiLocalize->Find( pszToken );
// find campaign/single mission
if (bCampaign)
pszToken = "#asw_difficulty_campaign";
else
pszToken = "#asw_difficulty_mission";
const wchar_t *pCampaign = g_pVGuiLocalize->Find( pszToken );
bool bOnslaught = CAlienSwarm::IsOnslaught();
// find style
if (bUber)
pszToken = "#asw_difficulty_uber";
else if (bCarnage)
pszToken = "#asw_difficulty_carnage";
else if (bHardcore)
pszToken = "#asw_difficulty_hardcore";
const wchar_t *pStyle = L"";
if (bUber || bCarnage || bHardcore)
const wchar_t *pOnslaught = L"";
if ( bOnslaught )
{
pStyle = g_pVGuiLocalize->Find( pszToken );
pOnslaught = g_pVGuiLocalize->Find( "#nb_onslaught_title" );
}
bool bHardcoreFriendlyFire = CAlienSwarm::IsHardcoreFF();
const wchar_t *pHardcoreFF = L"";
if ( bHardcoreFriendlyFire )
{
pHardcoreFF = g_pVGuiLocalize->Find( "#asw_hardcore_ff" );
}
const wchar_t *pCheated = L"";
@ -149,7 +145,7 @@ void MissionStatsPanel::SetMissionLabels(vgui::Label *pMissionLabel, vgui::Label
wchar_t mission_difficulty[96];
g_pVGuiLocalize->ConstructString( mission_difficulty, sizeof(mission_difficulty),
g_pVGuiLocalize->Find("#asw_mission_difficulty"), 4,
pCampaign, pDiff, pStyle, pCheated);
pDiff, pOnslaught, pHardcoreFF, pCheated);
pDifficultyLabel->SetText(mission_difficulty);
}

View File

@ -87,7 +87,7 @@ void CNB_Commander_List_Entry::OnThink()
m_pCommanderName->SetText( pPlayer->GetPlayerName() );
int nXP = pPlayer->GetExperienceBeforeDebrief() + pPlayer->GetEarnedXP( ASW_XP_TOTAL );
int nLevel = LevelFromXP( nXP );
int nLevel = LevelFromXP( nXP, pPlayer->GetPromotion() );
wchar_t szLevelNum[16]=L"";
_snwprintf( szLevelNum, ARRAYSIZE( szLevelNum ), L"%i", nLevel + 1 ); // levels start at 0 in code, but show from 1 in the UI

View File

@ -77,10 +77,11 @@ CNB_Lobby_Row::CNB_Lobby_Row( vgui::Panel *parent, const char *name ) : BaseClas
m_pXPBar->SetShowMaxOnCounter( true );
m_pXPBar->SetColors( Color( 255, 255, 255, 0 ), Color( 93,148,192,255 ), Color( 255, 255, 255, 255 ), Color( 17,37,57,255 ), Color( 35, 77, 111, 255 ) );
//m_pXPBar->m_bShowCumulativeTotal = true;
m_pXPBar->AddMinMax( 0, g_iLevelExperience[ 0 ] );
m_nLastPromotion = 0;
m_pXPBar->AddMinMax( 0, g_iLevelExperience[ 0 ] * g_flPromotionXPScale[ m_nLastPromotion ] );
for ( int i = 0; i < ASW_NUM_EXPERIENCE_LEVELS - 1; i++ )
{
m_pXPBar->AddMinMax( g_iLevelExperience[ i ], g_iLevelExperience[ i + 1 ] );
m_pXPBar->AddMinMax( g_iLevelExperience[ i ] * g_flPromotionXPScale[ m_nLastPromotion ], g_iLevelExperience[ i + 1 ] * g_flPromotionXPScale[ m_nLastPromotion ] );
}
m_pXPBar->m_flBorder = 1.5f;

View File

@ -68,6 +68,7 @@ public:
char m_szLastWeaponImage[ ASW_NUM_INVENTORY_SLOTS ][ 255 ];
char m_szLastPortraitImage[ 255 ];
CSteamID m_lastSteamID;
int m_nLastPromotion;
int m_nLobbySlot;
};

View File

@ -170,6 +170,9 @@ void CNB_Lobby_Tooltip::OnTick()
case 1: m_pPromotionLabel->SetText( "#nb_first_promotion" ); m_pTitle->SetText( "#nb_promotion_medal_1"); break;
case 2: m_pPromotionLabel->SetText( "#nb_second_promotion" ); m_pTitle->SetText( "#nb_promotion_medal_2"); break;
case 3: m_pPromotionLabel->SetText( "#nb_third_promotion" ); m_pTitle->SetText( "#nb_promotion_medal_3"); break;
case 4: m_pPromotionLabel->SetText( "#nb_fourth_promotion" ); m_pTitle->SetText( "#nb_promotion_medal_4"); break;
case 5: m_pPromotionLabel->SetText( "#nb_fifth_promotion" ); m_pTitle->SetText( "#nb_promotion_medal_5"); break;
case 6: m_pPromotionLabel->SetText( "#nb_sixth_promotion" ); m_pTitle->SetText( "#nb_promotion_medal_6"); break;
}
m_pPromotionIcon->SetImage( VarArgs( "briefing/promotion_%d_LG", nPromotion ) );
}

View File

@ -158,7 +158,7 @@ void CNB_Main_Panel::OnThink()
m_pChatButton->SetVisible( gpGlobals->maxClients > 1 );
m_pVoteButton->SetVisible( gpGlobals->maxClients > 1 );
C_ASW_Player *pPlayer = C_ASW_Player::GetLocalASWPlayer();
m_pPromotionButton->SetVisible( pPlayer && pPlayer->GetExperience() >= ASW_XP_CAP && pPlayer->GetPromotion() < ASW_PROMOTION_CAP );
m_pPromotionButton->SetVisible( pPlayer && pPlayer->GetExperience() >= ( ASW_XP_CAP * g_flPromotionXPScale[ pPlayer->GetPromotion() ] ) && pPlayer->GetPromotion() < ASW_PROMOTION_CAP );

View File

@ -70,6 +70,8 @@ void CNB_Mission_Options::OnThink()
m_pSkillLevelLabel->SetText("#asw_difficulty_hard");
else if (m_iLastSkillLevel == 1)
m_pSkillLevelLabel->SetText("#asw_difficulty_easy");
else if (m_iLastSkillLevel == 5)
m_pSkillLevelLabel->SetText("#asw_difficulty_imba");
else
m_pSkillLevelLabel->SetText("#asw_difficulty_normal");
@ -80,6 +82,7 @@ void CNB_Mission_Options::OnThink()
case 2: m_pSkillDescriptionLabel->SetText("#asw_difficulty_chooser_normald"); break;
case 3: m_pSkillDescriptionLabel->SetText("#asw_difficulty_chooser_hardd"); break;
case 4: m_pSkillDescriptionLabel->SetText("#asw_difficulty_chooser_insaned"); break;
case 5: m_pSkillDescriptionLabel->SetText("#asw_difficulty_chooser_imbad"); break;
default: m_pSkillDescriptionLabel->SetText("???"); break;
}

View File

@ -19,6 +19,8 @@
#include "c_asw_game_resource.h"
#include "asw_input.h"
#include "nb_island.h"
#include "gameui/swarm/basemodpanel.h"
#include "gameui/swarm/VFooterPanel.h"
using namespace vgui;
@ -45,6 +47,8 @@ CNB_Mission_Panel::CNB_Mission_Panel( vgui::Panel *parent, const char *name ) :
// == MANAGED_MEMBER_CREATION_END ==
m_pBackButton = new CNB_Button( this, "BackButton", "", this, "BackButton" );
m_drpDifficulty = new BaseModUI::DropDownMenu( this, "DrpDifficulty" );
m_drpFriendlyFire = new BaseModUI::DropDownMenu( this, "DrpFriendlyFire" );
m_drpOnslaught = new BaseModUI::DropDownMenu( this, "DrpOnslaught" );
m_drpFixedSkillPoints = new BaseModUI::DropDownMenu( this, "DrpFixedSkillPoints" );
m_pHeaderFooter->SetTitle( "#nb_mission_details" );
@ -61,6 +65,8 @@ CNB_Mission_Panel::CNB_Mission_Panel( vgui::Panel *parent, const char *name ) :
m_iLastSkillLevel = -1;
m_iLastFixedSkillPoints = -1;
m_iLastHardcoreFF = -1;
m_iLastOnslaught = -1;
}
CNB_Mission_Panel::~CNB_Mission_Panel()
@ -165,6 +171,8 @@ void CNB_Mission_Panel::OnThink()
bool bLeader = ( pPlayer && (pPlayer->entindex() == iLeaderIndex ) );
m_drpDifficulty->SetEnabled( ASWGameRules()->GetGameState() == ASW_GS_BRIEFING && bLeader );
m_drpFriendlyFire->SetEnabled( ASWGameRules()->GetGameState() == ASW_GS_BRIEFING && bLeader );
m_drpOnslaught->SetEnabled( ASWGameRules()->GetGameState() == ASW_GS_BRIEFING && bLeader );
m_drpFixedSkillPoints->SetEnabled( false ); //ASWGameRules()->GetGameState() == ASW_GS_BRIEFING && bLeader );
if (m_iLastSkillLevel != ASWGameRules()->GetSkillLevel())
@ -173,27 +181,69 @@ void CNB_Mission_Panel::OnThink()
if (m_iLastSkillLevel == 4)
{
m_drpDifficulty->SetCurrentSelection("#L4D360UI_Difficulty_insane");
m_pDifficultyDescription->SetText( "#asw_difficulty_chooser_insaned" );
//m_pDifficultyDescription->SetText( "#asw_difficulty_chooser_insaned" );
}
else if (m_iLastSkillLevel == 3)
{
m_drpDifficulty->SetCurrentSelection("#L4D360UI_Difficulty_hard");
m_pDifficultyDescription->SetText( "#asw_difficulty_chooser_hardd" );
//m_pDifficultyDescription->SetText( "#asw_difficulty_chooser_hardd" );
}
else if (m_iLastSkillLevel == 1)
{
m_drpDifficulty->SetCurrentSelection("#L4D360UI_Difficulty_easy");
m_pDifficultyDescription->SetText( "#asw_difficulty_chooser_easyd" );
//m_pDifficultyDescription->SetText( "#asw_difficulty_chooser_easyd" );
}
else if (m_iLastSkillLevel == 5)
{
m_drpDifficulty->SetCurrentSelection("#L4D360UI_Difficulty_imba");
//m_pDifficultyDescription->SetText( "#asw_difficulty_chooser_imbad" );
}
else
{
m_drpDifficulty->SetCurrentSelection("#L4D360UI_Difficulty_normal");
m_pDifficultyDescription->SetText( "#asw_difficulty_chooser_normald" );
//m_pDifficultyDescription->SetText( "#asw_difficulty_chooser_normald" );
}
}
extern ConVar asw_sentry_friendly_fire_scale;
extern ConVar asw_marine_ff_absorption;
int nHardcoreFF = ( asw_sentry_friendly_fire_scale.GetFloat() != 0.0f || asw_marine_ff_absorption.GetInt() != 1 ) ? 1 : 0;
if ( m_iLastHardcoreFF != nHardcoreFF )
{
m_iLastHardcoreFF = nHardcoreFF;
if ( nHardcoreFF == 1 )
{
m_drpFriendlyFire->SetCurrentSelection( "#L4D360UI_HardcoreFF" );
}
else
{
m_drpFriendlyFire->SetCurrentSelection( "#L4D360UI_RegularFF" );
}
}
extern ConVar asw_horde_override;
extern ConVar asw_wanderer_override;
int nOnslaught = ( asw_horde_override.GetBool() || asw_wanderer_override.GetBool() ) ? 1 : 0;
if ( m_iLastOnslaught != nOnslaught )
{
m_iLastOnslaught = nOnslaught;
if ( nOnslaught == 1 )
{
m_drpOnslaught->SetCurrentSelection( "#L4D360UI_OnslaughtEnabled" );
}
else
{
m_drpOnslaught->SetCurrentSelection( "#L4D360UI_OnslaughtDisabled" );
}
}
BaseModUI::CBaseModFooterPanel *footer = BaseModUI::CBaseModPanel::GetSingleton().GetFooterPanel();
if ( footer )
{
m_pDifficultyDescription->SetText( footer->GetHelpText() );
}
// only show insane in multiplayer
m_drpDifficulty->SetFlyoutItemEnabled( "BtnImpossible", gpGlobals->maxClients > 1 );
m_drpDifficulty->SetFlyoutItemEnabled( "BtnImba", gpGlobals->maxClients > 1 );
if ( ASWGameRules()->IsCampaignGame() && ASWGameRules()->GetCampaignSave() && ASWGameRules()->GetGameState() != ASW_GS_INGAME )
{
@ -265,6 +315,31 @@ void CNB_Mission_Panel::OnCommand( const char *command )
engine->ClientCmd( "cl_skill 4" );
return;
}
else if ( !Q_stricmp( command, "#L4D360UI_Difficulty_imba" ) )
{
engine->ClientCmd( "cl_skill 5" );
return;
}
else if ( !Q_stricmp( command, "#L4D360UI_RegularFF" ) )
{
engine->ClientCmd( "cl_hardcore_ff 0" );
return;
}
else if ( !Q_stricmp( command, "#L4D360UI_HardcoreFF" ) )
{
engine->ClientCmd( "cl_hardcore_ff 1" );
return;
}
else if ( !Q_stricmp( command, "#L4D360UI_OnslaughtDisabled" ) )
{
engine->ClientCmd( "cl_onslaught 0" );
return;
}
else if ( !Q_stricmp( command, "#L4D360UI_OnslaughtEnabled" ) )
{
engine->ClientCmd( "cl_onslaught 1" );
return;
}
BaseClass::OnCommand( command );
}

View File

@ -45,6 +45,8 @@ public:
CNB_Button *m_pBackButton;
BaseModUI::DropDownMenu* m_drpDifficulty;
BaseModUI::DropDownMenu* m_drpFixedSkillPoints;
BaseModUI::DropDownMenu* m_drpFriendlyFire;
BaseModUI::DropDownMenu* m_drpOnslaught;
ObjectiveListBox* m_pObjectiveList;
ObjectiveDetailsPanel* m_pObjectiveDetails;
@ -59,6 +61,8 @@ public:
int m_iLastSkillLevel;
int m_iLastFixedSkillPoints;
int m_iLastHardcoreFF;
int m_iLastOnslaught;
};
class InGameMissionPanelFrame : public vgui::Frame

View File

@ -105,14 +105,31 @@ void CNB_Mission_Summary::OnThink()
return;
int nSkillLevel = ASWGameRules()->GetSkillLevel();
if (nSkillLevel == 4)
m_pDifficultyLabel->SetText("#asw_difficulty_insane");
else if (nSkillLevel == 3)
m_pDifficultyLabel->SetText("#asw_difficulty_hard");
else if (nSkillLevel == 1)
m_pDifficultyLabel->SetText("#asw_difficulty_easy");
const wchar_t *pDifficulty = NULL;
switch( nSkillLevel )
{
case 1: pDifficulty = g_pVGuiLocalize->Find( "#asw_difficulty_easy" ); break;
default:
case 2: pDifficulty = g_pVGuiLocalize->Find( "#asw_difficulty_normal" ); break;
case 3: pDifficulty = g_pVGuiLocalize->Find( "#asw_difficulty_hard" ); break;
case 4: pDifficulty = g_pVGuiLocalize->Find( "#asw_difficulty_insane" ); break;
case 5: pDifficulty = g_pVGuiLocalize->Find( "#asw_difficulty_imba" ); break;
}
if ( !pDifficulty )
{
pDifficulty = L"";
}
if ( CAlienSwarm::IsOnslaught() )
{
wchar_t wszText[ 128 ];
_snwprintf( wszText, sizeof( wszText ), L"%s %s", pDifficulty, g_pVGuiLocalize->FindSafe( "#nb_onslaught_title" ) );
m_pDifficultyLabel->SetText( wszText );
}
else
m_pDifficultyLabel->SetText("#asw_difficulty_normal");
{
m_pDifficultyLabel->SetText( pDifficulty );
}
CASWHudMinimap *pMap = GET_HUDELEMENT( CASWHudMinimap );
if ( pMap )

View File

@ -642,8 +642,8 @@ void CAI_BaseNPC::CleanupOnDeath( CBaseEntity *pCulprit, bool bFireDeathOutput )
RemoveActorFromScriptedScenes( this, false /*all scenes*/ );
}
else
DevMsg( "Unexpected double-death-cleanup\n" );
//else
//DevMsg( "Unexpected double-death-cleanup\n" );
}
void CAI_BaseNPC::SelectDeathPose( const CTakeDamageInfo &info )

View File

@ -1900,13 +1900,15 @@ void CServerGameDLL::GetMatchmakingTags( char *buf, size_t bufSize )
#ifdef INFESTED_DLL
extern ConVar asw_marine_ff_absorption;
extern ConVar asw_sentry_friendly_fire_scale;
extern ConVar asw_horde_override;
extern ConVar asw_wanderer_override;
extern ConVar asw_skill;
char * const bufBase = buf;
int len = 0;
// hardcore friendly fire
if ( asw_marine_ff_absorption.GetInt() != 1 || asw_sentry_friendly_fire_scale.GetFloat() != 0.0f )
if ( CAlienSwarm::IsHardcoreFF() )
{
Q_strncpy( buf, "HardcoreFF,", bufSize );
len = strlen( buf );
@ -1914,6 +1916,15 @@ void CServerGameDLL::GetMatchmakingTags( char *buf, size_t bufSize )
bufSize -= len;
}
// onslaught
if ( CAlienSwarm::IsOnslaught() )
{
Q_strncpy( buf, "Onslaught,", bufSize );
len = strlen( buf );
buf += len;
bufSize -= len;
}
// difficulty level
const char *szSkill = "Normal,";
switch( asw_skill.GetInt() )
@ -1921,6 +1932,7 @@ void CServerGameDLL::GetMatchmakingTags( char *buf, size_t bufSize )
case 1: szSkill = "Easy,"; break;
case 3: szSkill = "Hard,"; break;
case 4: szSkill = "Insane,"; break;
case 5: szSkill = "Imba,"; break;
}
Q_strncpy( buf, szSkill, bufSize );
len = strlen( buf );

View File

@ -29,6 +29,7 @@
#include "datacache/imdlcache.h"
#include "asw_tesla_trap.h"
#include "sendprop_priorities.h"
#include "asw_spawn_manager.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -151,6 +152,7 @@ IMPLEMENT_AUTO_LIST( IAlienAutoList );
CASW_Alien::CASW_Alien( void ) :
m_BehaviorParms( DefLessFunc( const CUtlSymbol ) )
{
m_bRegisteredAsAwake = false;
m_pszAlienModelName = NULL;
m_bRunAtChasingPathEnds = true;
m_bPerformingZigZag = false;
@ -493,6 +495,32 @@ void CASW_Alien::UpdateSleepState(bool bInPVS)
}
}
}
if ( GetSleepState() == AISS_AWAKE )
{
if ( !m_bRegisteredAsAwake )
{
ASWSpawnManager()->OnAlienWokeUp( this );
m_bRegisteredAsAwake = true;
}
}
else
{
if ( m_bRegisteredAsAwake )
{
ASWSpawnManager()->OnAlienSleeping( this );
m_bRegisteredAsAwake = false;
}
}
}
void CASW_Alien::UpdateOnRemove()
{
if ( m_bRegisteredAsAwake )
{
m_bRegisteredAsAwake = false;
ASWSpawnManager()->OnAlienSleeping( this );
}
BaseClass::UpdateOnRemove();
}
void CASW_Alien::SetDistSwarmSense( float flDistSense )

View File

@ -93,6 +93,8 @@ public:
// make the aliens wake up when a marine gets within a certain distance
void UpdateSleepState( bool bInPVS );
void UpdateEfficiency( bool bInPVS );
virtual void UpdateOnRemove();
bool m_bRegisteredAsAwake;
float m_fLastSleepCheckTime;
bool m_bVisibleWhenAsleep;

View File

@ -316,10 +316,13 @@ CBaseEntity* CASW_Base_Spawner::GetAlienOrderTarget()
bool CASW_Base_Spawner::IsValidOnThisSkillLevel()
{
if (m_iMinSkillLevel > 0 && ASWGameRules()->GetSkillLevel() < m_iMinSkillLevel)
// treat difficulty 5 and 4 as the same
int nSkillLevel = ASWGameRules()->GetSkillLevel();
nSkillLevel = clamp<int>( nSkillLevel, 1, 4 );
if (m_iMinSkillLevel > 0 && nSkillLevel < m_iMinSkillLevel)
return false;
if (m_iMaxSkillLevel > 0 && m_iMaxSkillLevel < 10
&& ASWGameRules()->GetSkillLevel() > m_iMaxSkillLevel)
&& nSkillLevel > m_iMaxSkillLevel)
return false;
return true;
}

View File

@ -2745,7 +2745,9 @@ float CASW_Buzzer::GetMaxEnginePower()
if (ASWGameRules())
{
return ASWGameRules()->GetSkillLevel() + 0.1f;
int nSkillLevel = ASWGameRules()->GetSkillLevel();
nSkillLevel = clamp<int>( nSkillLevel, 1, 4 );
return nSkillLevel + 0.1f;
}
return 2.0f;
}

View File

@ -22,12 +22,12 @@ ConVar asw_director_debug("asw_director_debug", "0", FCVAR_CHEAT, "Displays dire
extern ConVar asw_intensity_far_range;
extern ConVar asw_spawning_enabled;
ConVar asw_horde_override( "asw_horde_override", "0", FCVAR_NONE, "Forces hordes to spawn" );
ConVar asw_wanderer_override( "asw_wanderer_override", "0", FCVAR_NONE, "Forces wanderers to spawn" );
ConVar asw_horde_interval_min("asw_horde_interval_min", "40", FCVAR_CHEAT, "Min time between hordes" );
ConVar asw_horde_interval_max("asw_horde_interval_max", "60", FCVAR_CHEAT, "Min time between hordes" );
extern ConVar asw_horde_override;
extern ConVar asw_wanderer_override;
ConVar asw_horde_interval_min("asw_horde_interval_min", "45", FCVAR_CHEAT, "Min time between hordes" );
ConVar asw_horde_interval_max("asw_horde_interval_max", "65", FCVAR_CHEAT, "Min time between hordes" );
ConVar asw_horde_size_min("asw_horde_size_min", "9", FCVAR_CHEAT, "Min horde size" );
ConVar asw_horde_size_max("asw_horde_size_max", "12", FCVAR_CHEAT, "Max horde size" );
ConVar asw_horde_size_max("asw_horde_size_max", "14", FCVAR_CHEAT, "Max horde size" );
ConVar asw_director_relaxed_min_time("asw_director_relaxed_min_time", "25", FCVAR_CHEAT, "Min time that director stops spawning aliens");
ConVar asw_director_relaxed_max_time("asw_director_relaxed_max_time", "40", FCVAR_CHEAT, "Max time that director stops spawning aliens");
@ -102,6 +102,11 @@ void CASW_Director::LevelInitPreEntity()
void CASW_Director::LevelInitPostEntity()
{
Init();
if ( ASWSpawnManager() )
{
ASWSpawnManager()->LevelInitPostEntity();
}
}
void CASW_Director::FrameUpdatePreEntityThink()
@ -250,24 +255,22 @@ void CASW_Director::MarineTookDamage( CASW_Marine *pMarine, const CTakeDamageInf
void CASW_Director::UpdateHorde()
{
bool bHordesEnabled = m_bHordesEnabled || asw_horde_override.GetBool();
if ( !bHordesEnabled || !ASWSpawnManager() )
return;
if ( asw_director_debug.GetInt() > 0 )
{
if ( m_bHordeInProgress )
{
engine->Con_NPrintf( 11, "Horde in progress. Left to spawn = %d", ASWSpawnManager()->GetHordeToSpawn() );
}
else
{
engine->Con_NPrintf( 11, "Next Horde due: %f", m_HordeTimer.GetRemainingTime() );
}
engine->Con_NPrintf( 12, "Next Horde due: %f", m_HordeTimer.GetRemainingTime() );
engine->Con_NPrintf( 15, "Awake aliens: %d\n", ASWSpawnManager()->GetAwakeAliens() );
engine->Con_NPrintf( 16, "Awake drones: %d\n", ASWSpawnManager()->GetAwakeDrones() );
}
if ( !m_bHordeInProgress )
{
bool bHordesEnabled = m_bHordesEnabled || asw_horde_override.GetBool();
if ( !bHordesEnabled || !ASWSpawnManager() )
return;
if ( !m_HordeTimer.HasStarted() )
{
float flDuration = RandomFloat( asw_horde_interval_min.GetFloat(), asw_horde_interval_max.GetFloat() );
@ -275,35 +278,53 @@ void CASW_Director::UpdateHorde()
{
flDuration = RandomFloat( 5.0f, 10.0f );
}
if ( asw_director_debug.GetBool() )
{
Msg( "Will be spawning a horde in %f seconds\n", flDuration );
}
m_HordeTimer.Start( flDuration );
}
else if ( m_HordeTimer.IsElapsed() )
{
if ( ASWSpawnManager()->GetAwakeDrones() < 25 )
{
int iNumAliens = RandomInt( asw_horde_size_min.GetInt(), asw_horde_size_max.GetInt() );
if ( ASWSpawnManager()->AddHorde( iNumAliens ) )
{
if ( asw_director_debug.GetBool() )
{
Msg("Created horde of size %d\n", iNumAliens);
}
m_bHordeInProgress = true;
if ( ASWGameRules() )
{
ASWGameRules()->BroadcastSound( "Spawner.Horde" );
}
m_HordeTimer.Invalidate();
}
else
{
m_HordeTimer.Invalidate();
// if we failed to find a horde position, try again shortly.
m_HordeTimer.Start( RandomFloat( 10.0f, 16.0f ) );
}
}
else
{
// if there are currently too many awake aliens, then wait 10 seconds before trying again
m_HordeTimer.Start( 10.0f );
}
}
}
void CASW_Director::OnHordeFinishedSpawning()
{
if ( asw_director_debug.GetBool() )
{
Msg("Horde finishes spawning\n");
}
m_bHordeInProgress = false;
m_HordeTimer.Invalidate();
}
void CASW_Director::UpdateSpawningState()
@ -417,10 +438,13 @@ void CASW_Director::UpdateWanderers()
m_AlienSpawnTimer.Start( m_fTimeBetweenAliens );
if ( ASWSpawnManager() )
{
if ( ASWSpawnManager()->GetAwakeDrones() < 20 )
{
ASWSpawnManager()->AddAlien();
}
}
}
}
// if director is controlling alien spawns, then mapper set spawners ask permission before spawning
@ -497,3 +521,35 @@ void CASW_Director::UpdateMarineInsideEscapeRoom( CASW_Marine *pMarine )
m_bFiredEscapeRoom = true;
}
void CASW_Director::OnMissionStarted()
{
// if we have wanders turned on, spawn a couple of encounters
if ( asw_wanderer_override.GetBool() && ASWGameRules() )
{
ASWSpawnManager()->SpawnRandomShieldbug();
int nParasites = 1;
switch( ASWGameRules()->GetSkillLevel() )
{
case 1: nParasites = RandomInt( 4, 6 ); break;
default:
case 2: nParasites = RandomInt( 4, 6 ); break;
case 3: nParasites = RandomInt( 5, 7 ); break;
case 4: nParasites = RandomInt( 5, 9 ); break;
case 5: nParasites = RandomInt( 5, 10 ); break;
}
while ( nParasites > 0 )
{
int nParasitesInThisPack = RandomInt( 3, 6 );
if ( ASWSpawnManager()->SpawnRandomParasitePack( nParasitesInThisPack ) )
{
nParasites -= nParasitesInThisPack;
}
else
{
break;
}
}
}
}

View File

@ -68,6 +68,8 @@ public:
void OnMarineStartedHack( CASW_Marine *pMarine, CBaseEntity *pComputer );
void UpdateMarineInsideEscapeRoom( CASW_Marine *pMarine );
void OnMissionStarted();
// Spawning hordes of aliens
void OnHordeFinishedSpawning();

View File

@ -306,6 +306,7 @@ float CASW_Drone_Advanced::GetIdealSpeed() const
switch (ASWGameRules()->GetSkillLevel())
{
case 5: boost *= asw_alien_speed_scale_insane.GetFloat(); break;
case 4: boost *= asw_alien_speed_scale_insane.GetFloat(); break;
case 3: boost *= asw_alien_speed_scale_hard.GetFloat(); break;
case 2: boost *= asw_alien_speed_scale_normal.GetFloat(); break;

View File

@ -297,7 +297,7 @@ void CASW_Egg::AnimThink( void )
}
else
{
if (ASWGameRules() && ASWGameRules()->GetSkillLevel() == 4 )
if (ASWGameRules() && ASWGameRules()->GetSkillLevel() >= 4 )
{
m_fNextMarineCheckTime = gpGlobals->curtime + 1.5f;
}

View File

@ -32,6 +32,9 @@ void CServerGameClients::GetPlayerLimits( int& minplayers, int& maxplayers, int
void CServerGameDLL::LevelInit_ParseAllEntities( const char *pMapEntities )
{
// precache even if not in the level, for onslaught mode
UTIL_PrecacheOther( "asw_shieldbug" );
UTIL_PrecacheOther( "asw_parasite" );
}
bool g_bOfflineGame = false;
@ -122,6 +125,38 @@ void CServerGameDLL::ApplyGameSettings( KeyValues *pKV )
{
asw_skill.SetValue( 4 );
}
else if ( !Q_stricmp( szDifficulty, "imba" ) )
{
asw_skill.SetValue( 5 );
}
extern ConVar asw_sentry_friendly_fire_scale;
extern ConVar asw_marine_ff_absorption;
int nHardcoreFF = pKV->GetInt( "game/hardcoreFF", 0 );
if ( nHardcoreFF == 1 )
{
asw_sentry_friendly_fire_scale.SetValue( 1.0f );
asw_marine_ff_absorption.SetValue( 0 );
}
else
{
asw_sentry_friendly_fire_scale.SetValue( 0.0f );
asw_marine_ff_absorption.SetValue( 1 );
}
extern ConVar asw_horde_override;
extern ConVar asw_wanderer_override;
int nOnslaught = pKV->GetInt( "game/onslaught", 0 );
if ( nOnslaught == 1 )
{
asw_horde_override.SetValue( 1 );
asw_wanderer_override.SetValue( 1 );
}
else
{
asw_horde_override.SetValue( 0 );
asw_wanderer_override.SetValue( 0 );
}
char const *szMapCommand = pKV->GetString( "map/mapcommand", "map" );

View File

@ -177,7 +177,7 @@ void CASW_Hack_Computer::SelectHackOption(int i)
diff_factor = 1.55f;
else if (iSkill == 3)
diff_factor = 1.50f;
else if (iSkill == 4)
else if (iSkill >= 4)
diff_factor = 1.45f;
// estimate the time for a fast hack
// try, time taken for each column to rotate through twice

View File

@ -144,6 +144,7 @@ const char* CASW_Map_Scores::GetBestKillsKeyName(int iSkill)
case 1: return "BestKillsEasy"; break;
case 3: return "BestKillsHard"; break;
case 4: return "BestKillsInsane"; break;
case 5: return "BestKillsImba"; break;
default: break;
}
return "BestKillsNormal";
@ -156,6 +157,7 @@ const char* CASW_Map_Scores::GetBestTimeKeyName(int iSkill)
case 1: return "BestTimeEasy"; break;
case 3: return "BestTimeHard"; break;
case 4: return "BestTimeInsane"; break;
case 5: return "BestTimeImba"; break;
default: break;
}
return "BestTimeNormal";

View File

@ -345,13 +345,6 @@ BEGIN_DATADESC( CASW_Marine )
DEFINE_FIELD( m_bPowerupExpires, FIELD_BOOLEAN ),
END_DATADESC()
void UpdateMatchmakingTags();
static void FriendlyFireCallback( IConVar *pConVar, const char *pOldValue, float flOldValue )
{
UpdateMatchmakingTags();
}
extern ConVar weapon_showproficiency;
extern ConVar asw_leadership_radius;
extern ConVar asw_buzzer_poison_duration;
@ -381,7 +374,6 @@ ConVar asw_marine_ff("asw_marine_ff", "1", FCVAR_CHEAT, "Marine friendly fire se
ConVar asw_marine_ff_guard_time("asw_marine_ff_guard_time", "5.0", FCVAR_CHEAT, "Amount of time firing is disabled for when activating friendly fire guard");
ConVar asw_marine_ff_dmg_base("asw_marine_ff_dmg_base", "1.0", FCVAR_CHEAT, "Amount of friendly fire damage on mission difficulty 5");
ConVar asw_marine_ff_dmg_step("asw_marine_ff_dmg_step", "0.2", FCVAR_CHEAT, "Amount friendly fire damage is modified per mission difficuly level away from 5");
ConVar asw_marine_ff_absorption("asw_marine_ff_absorption", "1", FCVAR_NONE, "Friendly fire absorption style (0=none 1=ramp up 2=ramp down)", FriendlyFireCallback );
ConVar asw_marine_ff_absorption_decay_rate("asw_marine_ff_absorption_decay_rate", "0.33f", FCVAR_CHEAT, "Rate of FF absorption decay");
ConVar asw_marine_ff_absorption_build_rate("asw_marine_ff_absorption_build_rate", "0.25f", FCVAR_CHEAT, "Rate of FF absorption decay build up when being shot by friendlies");
ConVar asw_marine_burn_time_easy("asw_marine_burn_time_easy", "6", FCVAR_CHEAT, "Amount of time marine burns for when ignited on easy difficulty");
@ -395,7 +387,8 @@ ConVar asw_marine_special_idle_chatter_chance("asw_marine_special_idle_chatter_c
ConVar asw_force_ai_fire("asw_force_ai_fire", "0", FCVAR_CHEAT, "Forces all AI marines to fire constantly");
ConVar asw_realistic_death_chatter("asw_realistic_death_chatter", "0", FCVAR_NONE, "If true, only 1 nearby marine will shout about marine deaths");
ConVar asw_god( "asw_god", "0", FCVAR_CHEAT, "Set to 1 to make marines invulnerable" );
ConVar asw_sentry_friendly_fire_scale( "asw_sentry_friendly_fire_scale", "0", FCVAR_NONE, "Damage scale for sentry gun friendly fire", FriendlyFireCallback );
extern ConVar asw_sentry_friendly_fire_scale;
extern ConVar asw_marine_ff_absorption;
ConVar asw_movement_direction_tolerance( "asw_movement_direction_tolerance", "30.0", FCVAR_CHEAT );
ConVar asw_movement_direction_interval( "asw_movement_direction_interval", "0.5", FCVAR_CHEAT );
@ -4058,7 +4051,7 @@ void CASW_Marine::ASW_Ignite( float flFlameLifetime, float flSize, CBaseEntity *
flFlameLifetime *= asw_marine_burn_time_normal.GetFloat();
else if (iDiff == 3)
flFlameLifetime *= asw_marine_burn_time_hard.GetFloat();
else if (iDiff == 4)
else if (iDiff == 4 || iDiff == 5)
flFlameLifetime *= asw_marine_burn_time_insane.GetFloat();
if ( m_flFirstBurnTime == 0 )
@ -4127,7 +4120,8 @@ bool CASW_Marine::AllowedToIgnite( void )
if ( m_iJumpJetting.Get() != 0 )
return false;
if ( m_flFirstBurnTime > 0 && (gpGlobals->curtime - m_flFirstBurnTime) >= asw_marine_time_until_ignite.GetFloat() )
float flBurnTime = ( asw_marine_ff_absorption.GetInt() > 0 ) ? asw_marine_time_until_ignite.GetFloat() : 0.2f;
if ( m_flFirstBurnTime > 0 && (gpGlobals->curtime - m_flFirstBurnTime) >= flBurnTime )
return true;
// don't ignite, but play a flesh burn sound if we aren't on fire already

View File

@ -169,6 +169,7 @@ float CASW_Marine::GetCloseCombatSightRange()
case 2: return ASW_CLOSE_COMBAT_SIGHT_RANGE_NORMAL; break;
case 3: return ASW_CLOSE_COMBAT_SIGHT_RANGE_HARD; break;
case 4:
case 5:
default: return ASW_CLOSE_COMBAT_SIGHT_RANGE_INSANE; break;
}
}

View File

@ -1089,6 +1089,7 @@ void CASW_Parasite::UpdatePlaybackRate()
float boost = asw_parasite_speedboost.GetFloat();
switch (ASWGameRules()->GetSkillLevel())
{
case 5: boost *= asw_alien_speed_scale_insane.GetFloat(); break;
case 4: boost *= asw_alien_speed_scale_insane.GetFloat(); break;
case 3: boost *= asw_alien_speed_scale_hard.GetFloat(); break;
case 2: boost *= asw_alien_speed_scale_normal.GetFloat(); break;

View File

@ -299,7 +299,7 @@ void ASW_DrawAwakeAI()
int iVEfficient = 0;
int iSEfficient = 0;
int iNormal = 0;
int nprintIndex = 0;
int nprintIndex = 18;
engine->Con_NPrintf( nprintIndex, "AI (awake/asleep) (normal/efficient/very efficient/super efficient/dormant)");
nprintIndex++;
engine->Con_NPrintf( nprintIndex, "================================");
@ -789,6 +789,76 @@ bool CASW_Player::ClientCommand( const CCommand &args )
ASWGameRules()->RequestSkillDown(this);
return true;
}
else if ( FStrEq( pcmd, "cl_hardcore_ff") )
{
if ( args.ArgC() < 2 )
{
Warning("Player sent a bad cl_hardcore_ff command\n");
return false;
}
if ( ASWGameResource() && ASWGameResource()->GetLeader() == this )
{
bool bOldHardcoreMode = CAlienSwarm::IsHardcoreFF();
int nHardcore = atoi( args[1] );
nHardcore = clamp<int>( nHardcore, 0, 1 );
extern ConVar asw_sentry_friendly_fire_scale;
extern ConVar asw_marine_ff_absorption;
asw_sentry_friendly_fire_scale.SetValue( nHardcore );
asw_marine_ff_absorption.SetValue( 1 - nHardcore );
if ( CAlienSwarm::IsHardcoreFF() != bOldHardcoreMode )
{
CReliableBroadcastRecipientFilter filter;
filter.RemoveRecipient( this ); // notify everyone except the player changing the setting
if ( nHardcore > 0 )
{
UTIL_ClientPrintFilter( filter, ASW_HUD_PRINTTALKANDCONSOLE, "#asw_enabled_hardcoreff", GetPlayerName() );
}
else
{
UTIL_ClientPrintFilter( filter, ASW_HUD_PRINTTALKANDCONSOLE, "#asw_disabled_hardcoreff", GetPlayerName() );
}
}
}
return true;
}
else if ( FStrEq( pcmd, "cl_onslaught") )
{
if ( args.ArgC() < 2 )
{
Warning("Player sent a bad cl_onslaught command\n");
return false;
}
if ( ASWGameResource() && ASWGameResource()->GetLeader() == this )
{
bool bOldOnslaughtMode = CAlienSwarm::IsOnslaught();
int nOnslaught = atoi( args[1] );
nOnslaught = clamp<int>( nOnslaught, 0, 1 );
extern ConVar asw_horde_override;
extern ConVar asw_wanderer_override;
asw_horde_override.SetValue( nOnslaught );
asw_wanderer_override.SetValue( nOnslaught );
if ( CAlienSwarm::IsOnslaught() != bOldOnslaughtMode )
{
CReliableBroadcastRecipientFilter filter;
filter.RemoveRecipient( this ); // notify everyone except the player changing the setting
if ( nOnslaught > 0 )
{
UTIL_ClientPrintFilter( filter, ASW_HUD_PRINTTALKANDCONSOLE, "#asw_enabled_onslaught", GetPlayerName() );
}
else
{
UTIL_ClientPrintFilter( filter, ASW_HUD_PRINTTALKANDCONSOLE, "#asw_disabled_onslaught", GetPlayerName() );
}
}
}
return true;
}
else if ( FStrEq( pcmd, "cl_fixedskills") )
{
/*

View File

@ -1418,6 +1418,7 @@ void CASW_Queen::SetHealthByDifficultyLevel()
case 2: health = asw_queen_health_normal.GetInt(); break;
case 3: health = asw_queen_health_hard.GetInt(); break;
case 4: health = asw_queen_health_insane.GetInt(); break;
case 5: health = asw_queen_health_insane.GetInt(); break;
default: 5000;
}
}

View File

@ -15,6 +15,8 @@
#include "asw_objective_escape.h"
#include "triggers.h"
#include "datacache/imdlcache.h"
#include "ai_link.h"
#include "asw_alien.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -33,12 +35,10 @@ ConVar asw_batch_interval("asw_batch_interval", "5", FCVAR_CHEAT, "Time between
ConVar asw_candidate_interval("asw_candidate_interval", "1.0", FCVAR_CHEAT, "Interval between updating candidate spawning nodes");
ConVar asw_horde_class( "asw_horde_class", "asw_drone", FCVAR_CHEAT, "Alien class used when spawning hordes" );
// TODO: Notify the director when a horde is all killed?
// - currently you could try to spawn a 2nd horde while the first is still sitting out in the world
CASW_Spawn_Manager::CASW_Spawn_Manager()
{
m_nAwakeAliens = 0;
m_nAwakeDrones = 0;
}
CASW_Spawn_Manager::~CASW_Spawn_Manager()
@ -87,6 +87,8 @@ ASW_Alien_Class_Entry* CASW_Spawn_Manager::GetAlienClass( int i )
void CASW_Spawn_Manager::LevelInitPreEntity()
{
m_nAwakeAliens = 0;
m_nAwakeDrones = 0;
// init alien classes
for ( int i = 0; i < GetNumAlienClasses(); i++ )
{
@ -109,6 +111,24 @@ void CASW_Spawn_Manager::LevelInitPostEntity()
FindEscapeTriggers();
}
void CASW_Spawn_Manager::OnAlienWokeUp( CASW_Alien *pAlien )
{
m_nAwakeAliens++;
if ( pAlien && pAlien->Classify() == CLASS_ASW_DRONE )
{
m_nAwakeDrones++;
}
}
void CASW_Spawn_Manager::OnAlienSleeping( CASW_Alien *pAlien )
{
m_nAwakeAliens--;
if ( pAlien && pAlien->Classify() == CLASS_ASW_DRONE )
{
m_nAwakeDrones--;
}
}
// finds all trigger_multiples linked to asw_objective_escape entities
void CASW_Spawn_Manager::FindEscapeTriggers()
{
@ -180,7 +200,7 @@ void CASW_Spawn_Manager::Update()
if ( m_vecHordePosition != vec3_origin && ( !m_batchInterval.HasStarted() || m_batchInterval.IsElapsed() ) )
{
int iToSpawn = MIN( m_iHordeToSpawn, asw_max_alien_batch.GetInt() );
int iSpawned = SpawnAlienBatch( asw_horde_class.GetString(), iToSpawn, m_vecHordePosition, m_angHordeAngle, MARINE_NEAR_DISTANCE );
int iSpawned = SpawnAlienBatch( asw_horde_class.GetString(), iToSpawn, m_vecHordePosition, m_angHordeAngle, 0 );
m_iHordeToSpawn -= iSpawned;
if ( m_iHordeToSpawn <= 0 )
{
@ -189,6 +209,10 @@ void CASW_Spawn_Manager::Update()
}
else if ( iSpawned == 0 ) // if we failed to spawn any aliens, then try to find a new horde location
{
if ( asw_director_debug.GetBool() )
{
Msg( "Horde failed to spawn any aliens, trying new horde position.\n" );
}
if ( !FindHordePosition() ) // if we failed to find a new location, just abort this horde
{
m_iHordeToSpawn = 0;
@ -198,6 +222,17 @@ void CASW_Spawn_Manager::Update()
}
m_batchInterval.Start( asw_batch_interval.GetFloat() );
}
else if ( m_vecHordePosition == vec3_origin )
{
Msg( "Warning: Had horde to spawn but no position, clearing.\n" );
m_iHordeToSpawn = 0;
ASWDirector()->OnHordeFinishedSpawning();
}
}
if ( asw_director_debug.GetBool() )
{
engine->Con_NPrintf( 14, "SM: Batch interval: %f pos = %f %f %f\n", m_batchInterval.HasStarted() ? m_batchInterval.GetRemainingTime() : -1, VectorExpand( m_vecHordePosition ) );
}
if ( m_iAliensToSpawn > 0 )
@ -209,6 +244,10 @@ void CASW_Spawn_Manager::Update()
void CASW_Spawn_Manager::AddAlien()
{
// don't stock up more than 10 wanderers at once
if ( m_iAliensToSpawn > 10 )
return;
m_iAliensToSpawn++;
}
@ -236,7 +275,7 @@ bool CASW_Spawn_Manager::SpawnAlientAtRandomNode()
Vector vecMins, vecMaxs;
GetAlienBounds( szAlienClass, vecMins, vecMaxs );
int iMaxTries = 10;
int iMaxTries = 1;
for ( int i=0 ; i<iMaxTries ; i++ )
{
int iChosen = RandomInt( 0, candidateNodes.Count() - 1);
@ -252,7 +291,13 @@ bool CASW_Spawn_Manager::SpawnAlientAtRandomNode()
// check if there's a route from this node to the marine(s)
AI_Waypoint_t *pRoute = ASWPathUtils()->BuildRoute( pNode->GetPosition( CANDIDATE_ALIEN_HULL ), pMarine->GetAbsOrigin(), NULL, 100 );
if ( !pRoute )
{
if ( asw_director_debug.GetBool() )
{
NDebugOverlay::Cross3D( pNode->GetOrigin(), 10.0f, 255, 128, 0, true, 20.0f );
}
continue;
}
if ( bNorth && UTIL_ASW_DoorBlockingRoute( pRoute, true ) )
{
@ -265,9 +310,27 @@ bool CASW_Spawn_Manager::SpawnAlientAtRandomNode()
{
if ( SpawnAlienAt( szAlienClass, vecSpawnPos, vec3_angle ) )
{
if ( asw_director_debug.GetBool() )
{
NDebugOverlay::Cross3D( vecSpawnPos, 25.0f, 255, 255, 255, true, 20.0f );
float flDist;
CASW_Marine *pMarine = UTIL_ASW_NearestMarine( vecSpawnPos, flDist );
if ( pMarine )
{
NDebugOverlay::Line( pMarine->GetAbsOrigin(), vecSpawnPos, 64, 64, 64, true, 60.0f );
}
}
DeleteRoute( pRoute );
return true;
}
}
else
{
if ( asw_director_debug.GetBool() )
{
NDebugOverlay::Cross3D( vecSpawnPos, 25.0f, 255, 0, 0, true, 20.0f );
}
}
DeleteRoute( pRoute );
}
return false;
@ -288,7 +351,13 @@ bool CASW_Spawn_Manager::AddHorde( int iHordeSize )
{
if ( asw_director_debug.GetBool() )
{
NDebugOverlay::Cross3D( m_vecHordePosition, 50.0f, 255, 128, 0, true, 40.0f );
NDebugOverlay::Cross3D( m_vecHordePosition, 50.0f, 255, 128, 0, true, 60.0f );
float flDist;
CASW_Marine *pMarine = UTIL_ASW_NearestMarine( m_vecHordePosition, flDist );
if ( pMarine )
{
NDebugOverlay::Line( pMarine->GetAbsOrigin(), m_vecHordePosition, 255, 128, 0, true, 60.0f );
}
}
}
}
@ -378,11 +447,19 @@ void CASW_Spawn_Manager::UpdateCandidateNodes()
if ( vecPos.y >= vecSouthMarine.y )
{
if ( asw_director_debug.GetInt() == 3 )
{
NDebugOverlay::Box( vecPos, -Vector( 5, 5, 5 ), Vector( 5, 5, 5 ), 32, 32, 128, 10, 60.0f );
}
m_northCandidateNodes.AddToTail( i );
}
if ( vecPos.y <= vecNorthMarine.y )
{
m_southCandidateNodes.AddToTail( i );
if ( asw_director_debug.GetInt() == 3 )
{
NDebugOverlay::Box( vecPos, -Vector( 5, 5, 5 ), Vector( 5, 5, 5 ), 128, 32, 32, 10, 60.0f );
}
}
}
}
@ -410,9 +487,15 @@ bool CASW_Spawn_Manager::FindHordePosition()
CUtlVector<int> &candidateNodes = bNorth ? m_northCandidateNodes : m_southCandidateNodes;
if ( candidateNodes.Count() <= 0 )
{
if ( asw_director_debug.GetBool() )
{
Msg( " Failed to find horde pos as there are no candidate nodes\n" );
}
return false;
}
int iMaxTries = 10;
int iMaxTries = 3;
for ( int i=0 ; i<iMaxTries ; i++ )
{
int iChosen = RandomInt( 0, candidateNodes.Count() - 1);
@ -423,24 +506,56 @@ bool CASW_Spawn_Manager::FindHordePosition()
float flDistance = 0;
CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>(UTIL_ASW_NearestMarine( pNode->GetPosition( CANDIDATE_ALIEN_HULL ), flDistance ));
if ( !pMarine )
{
if ( asw_director_debug.GetBool() )
{
Msg( " Failed to find horde pos as there is no nearest marine\n" );
}
return false;
}
// check if there's a route from this node to the marine(s)
AI_Waypoint_t *pRoute = ASWPathUtils()->BuildRoute( pNode->GetPosition( CANDIDATE_ALIEN_HULL ), pMarine->GetAbsOrigin(), NULL, 100 );
if ( !pRoute )
{
if ( asw_director_debug.GetInt() >= 2 )
{
Msg( " Discarding horde node %d as there's no route.\n", iChosen );
}
continue;
}
if ( bNorth && UTIL_ASW_DoorBlockingRoute( pRoute, true ) )
{
if ( asw_director_debug.GetInt() >= 2 )
{
Msg( " Discarding horde node %d as there's a door in the way.\n", iChosen );
}
DeleteRoute( pRoute );
continue;
}
m_vecHordePosition = pNode->GetPosition( CANDIDATE_ALIEN_HULL ) + Vector( 0, 0, 32 );
// spawn facing the nearest marine
Vector vecDir = pMarine->GetAbsOrigin() - m_vecHordePosition;
vecDir.z = 0;
vecDir.NormalizeInPlace();
VectorAngles( vecDir, m_angHordeAngle );
if ( asw_director_debug.GetInt() >= 2 )
{
Msg( " Accepting horde node %d.\n", iChosen );
}
DeleteRoute( pRoute );
return true;
}
if ( asw_director_debug.GetBool() )
{
Msg( " Failed to find horde pos as we tried 3 times to build routes to possible locations, but failed\n" );
}
return false;
}
@ -485,8 +600,9 @@ bool CASW_Spawn_Manager::GetAlienBounds( string_t iszAlienClass, Vector &vecMins
}
// spawn a group of aliens at the target point
int CASW_Spawn_Manager::SpawnAlienBatch( const char* szAlienClass, int iNumAliens, const Vector &vecPosition, const QAngle &angle, float flMarinesBeyondDist )
int CASW_Spawn_Manager::SpawnAlienBatch( const char* szAlienClass, int iNumAliens, const Vector &vecPosition, const QAngle &angFacing, float flMarinesBeyondDist )
{
int iSpawned = 0;
bool bCheckGround = true;
Vector vecMins = NAI_Hull::Mins(HULL_MEDIUMBIG);
@ -499,7 +615,7 @@ int CASW_Spawn_Manager::SpawnAlienBatch( const char* szAlienClass, int iNumAlien
// spawn one in the middle
if ( ValidSpawnPoint( vecPosition, vecMins, vecMaxs, bCheckGround, flMarinesBeyondDist ) )
{
if ( SpawnAlienAt( szAlienClass, vecPosition, angle ) )
if ( SpawnAlienAt( szAlienClass, vecPosition, angFacing ) )
iSpawned++;
}
@ -507,6 +623,8 @@ int CASW_Spawn_Manager::SpawnAlienBatch( const char* szAlienClass, int iNumAlien
Vector vecNewPos = vecPosition;
for ( int i=1; i<=5 && iSpawned < iNumAliens; i++ )
{
QAngle angle = angFacing;
angle[YAW] += RandomFloat( -20, 20 );
// spawn aliens along top of box
for ( int x=-i; x<=i && iSpawned < iNumAliens; x++ )
{
@ -591,6 +709,14 @@ CBaseEntity* CASW_Spawn_Manager::SpawnAlienAt(const char* szAlienClass, const Ve
return NULL;
}
// have drones unburrow by default, so we don't worry so much about them spawning onscreen
if ( !Q_strcmp( szAlienClass, "asw_drone" ) )
{
pSpawnable->StartBurrowed();
pSpawnable->SetUnburrowIdleActivity( NULL_STRING );
pSpawnable->SetUnburrowActivity( NULL_STRING );
}
DispatchSpawn( pEntity );
pEntity->Activate();
@ -663,6 +789,308 @@ void CASW_Spawn_Manager::DeleteRoute( AI_Waypoint_t *pWaypointList )
}
}
bool CASW_Spawn_Manager::SpawnRandomShieldbug()
{
int iNumNodes = g_pBigAINet->NumNodes();
if ( iNumNodes < 6 )
return false;
int nHull = HULL_WIDE_SHORT;
CUtlVector<CASW_Open_Area*> aAreas;
for ( int i = 0; i < 6; i++ )
{
CAI_Node *pNode = NULL;
int nTries = 0;
while ( nTries < 5 && ( !pNode || pNode->GetType() != NODE_GROUND ) )
{
pNode = g_pBigAINet->GetNode( RandomInt( 0, iNumNodes ) );
nTries++;
}
if ( pNode )
{
CASW_Open_Area *pArea = FindNearbyOpenArea( pNode->GetOrigin(), HULL_MEDIUMBIG );
if ( pArea && pArea->m_nTotalLinks > 30 )
{
// test if there's room to spawn a shieldbug at that spot
if ( ValidSpawnPoint( pArea->m_pNode->GetPosition( nHull ), NAI_Hull::Mins( nHull ), NAI_Hull::Maxs( nHull ), true, false ) )
{
aAreas.AddToTail( pArea );
}
else
{
delete pArea;
}
}
}
// stop searching once we have 3 acceptable candidates
if ( aAreas.Count() >= 3 )
break;
}
// find area with the highest connectivity
CASW_Open_Area *pBestArea = NULL;
for ( int i = 0; i < aAreas.Count(); i++ )
{
CASW_Open_Area *pArea = aAreas[i];
if ( !pBestArea || pArea->m_nTotalLinks > pBestArea->m_nTotalLinks )
{
pBestArea = pArea;
}
}
if ( pBestArea )
{
CBaseEntity *pAlien = SpawnAlienAt( "asw_shieldbug", pBestArea->m_pNode->GetPosition( nHull ), RandomAngle( 0, 360 ) );
IASW_Spawnable_NPC *pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>( pAlien );
if ( pSpawnable )
{
pSpawnable->SetAlienOrders(AOT_SpreadThenHibernate, vec3_origin, NULL);
}
aAreas.PurgeAndDeleteElements();
return true;
}
aAreas.PurgeAndDeleteElements();
return false;
}
Vector TraceToGround( const Vector &vecPos )
{
trace_t tr;
UTIL_TraceLine( vecPos + Vector( 0, 0, 100 ), vecPos, MASK_NPCSOLID, NULL, ASW_COLLISION_GROUP_PARASITE, &tr );
return tr.endpos;
}
bool CASW_Spawn_Manager::SpawnRandomParasitePack( int nParasites )
{
int iNumNodes = g_pBigAINet->NumNodes();
if ( iNumNodes < 6 )
return false;
int nHull = HULL_TINY;
CUtlVector<CASW_Open_Area*> aAreas;
for ( int i = 0; i < 6; i++ )
{
CAI_Node *pNode = NULL;
int nTries = 0;
while ( nTries < 5 && ( !pNode || pNode->GetType() != NODE_GROUND ) )
{
pNode = g_pBigAINet->GetNode( RandomInt( 0, iNumNodes ) );
nTries++;
}
if ( pNode )
{
CASW_Open_Area *pArea = FindNearbyOpenArea( pNode->GetOrigin(), HULL_MEDIUMBIG );
if ( pArea && pArea->m_nTotalLinks > 30 )
{
// test if there's room to spawn a shieldbug at that spot
if ( ValidSpawnPoint( pArea->m_pNode->GetPosition( nHull ), NAI_Hull::Mins( nHull ), NAI_Hull::Maxs( nHull ), true, false ) )
{
aAreas.AddToTail( pArea );
}
else
{
delete pArea;
}
}
}
// stop searching once we have 3 acceptable candidates
if ( aAreas.Count() >= 3 )
break;
}
// find area with the highest connectivity
CASW_Open_Area *pBestArea = NULL;
for ( int i = 0; i < aAreas.Count(); i++ )
{
CASW_Open_Area *pArea = aAreas[i];
if ( !pBestArea || pArea->m_nTotalLinks > pBestArea->m_nTotalLinks )
{
pBestArea = pArea;
}
}
if ( pBestArea )
{
for ( int i = 0; i < nParasites; i++ )
{
CBaseEntity *pAlien = SpawnAlienAt( "asw_parasite", TraceToGround( pBestArea->m_pNode->GetPosition( nHull ) ), RandomAngle( 0, 360 ) );
IASW_Spawnable_NPC *pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>( pAlien );
if ( pSpawnable )
{
pSpawnable->SetAlienOrders(AOT_SpreadThenHibernate, vec3_origin, NULL);
}
if ( asw_director_debug.GetBool() && pAlien )
{
Msg( "Spawned parasite at %f %f %f\n", pAlien->GetAbsOrigin() );
NDebugOverlay::Cross3D( pAlien->GetAbsOrigin(), 8.0f, 255, 0, 0, true, 20.0f );
}
}
aAreas.PurgeAndDeleteElements();
return true;
}
aAreas.PurgeAndDeleteElements();
return false;
}
// heuristic to find reasonably open space - searches for areas with high node connectivity
CASW_Open_Area* CASW_Spawn_Manager::FindNearbyOpenArea( const Vector &vecSearchOrigin, int nSearchHull )
{
CBaseEntity *pStartEntity = gEntList.FindEntityByClassname( NULL, "info_player_start" );
int iNumNodes = g_pBigAINet->NumNodes();
CAI_Node *pHighestConnectivity = NULL;
int nHighestLinks = 0;
for ( int i=0 ; i<iNumNodes; i++ )
{
CAI_Node *pNode = g_pBigAINet->GetNode( i );
if ( !pNode || pNode->GetType() != NODE_GROUND )
continue;
Vector vecPos = pNode->GetOrigin();
float flDist = vecPos.DistTo( vecSearchOrigin );
if ( flDist > 400.0f )
continue;
// discard if node is too near start location
if ( pStartEntity && vecPos.DistTo( pStartEntity->GetAbsOrigin() ) < 1400.0f ) // NOTE: assumes all start points are clustered near one another
continue;
// discard if node is inside an escape area
bool bInsideEscapeArea = false;
for ( int d=0; d<m_EscapeTriggers.Count(); d++ )
{
if ( m_EscapeTriggers[d]->CollisionProp()->IsPointInBounds( vecPos ) )
{
bInsideEscapeArea = true;
break;
}
}
if ( bInsideEscapeArea )
continue;
// count links that drones could follow
int nLinks = pNode->NumLinks();
int nValidLinks = 0;
for ( int k = 0; k < nLinks; k++ )
{
CAI_Link *pLink = pNode->GetLinkByIndex( k );
if ( !pLink )
continue;
if ( !( pLink->m_iAcceptedMoveTypes[nSearchHull] & bits_CAP_MOVE_GROUND ) )
continue;
nValidLinks++;
}
if ( nValidLinks > nHighestLinks )
{
nHighestLinks = nValidLinks;
pHighestConnectivity = pNode;
}
if ( asw_director_debug.GetBool() )
{
NDebugOverlay::Text( vecPos, UTIL_VarArgs( "%d", nValidLinks ), false, 10.0f );
}
}
if ( !pHighestConnectivity )
return NULL;
// now, starting at the new node, find all nearby nodes with a minimum connectivity
CASW_Open_Area *pArea = new CASW_Open_Area();
pArea->m_vecOrigin = pHighestConnectivity->GetOrigin();
pArea->m_pNode = pHighestConnectivity;
int nMinLinks = nHighestLinks * 0.3f;
nMinLinks = MAX( nMinLinks, 4 );
pArea->m_aAreaNodes.AddToTail( pHighestConnectivity );
if ( asw_director_debug.GetBool() )
{
Msg( "minLinks = %d\n", nMinLinks );
}
pArea->m_nTotalLinks = 0;
for ( int i=0 ; i<iNumNodes; i++ )
{
CAI_Node *pNode = g_pBigAINet->GetNode( i );
if ( !pNode || pNode->GetType() != NODE_GROUND )
continue;
Vector vecPos = pNode->GetOrigin();
float flDist = vecPos.DistTo( pArea->m_vecOrigin );
if ( flDist > 400.0f )
continue;
// discard if node is inside an escape area
bool bInsideEscapeArea = false;
for ( int d=0; d<m_EscapeTriggers.Count(); d++ )
{
if ( m_EscapeTriggers[d]->CollisionProp()->IsPointInBounds( vecPos ) )
{
bInsideEscapeArea = true;
break;
}
}
if ( bInsideEscapeArea )
continue;
// count links that drones could follow
int nLinks = pNode->NumLinks();
int nValidLinks = 0;
for ( int k = 0; k < nLinks; k++ )
{
CAI_Link *pLink = pNode->GetLinkByIndex( k );
if ( !pLink )
continue;
if ( !( pLink->m_iAcceptedMoveTypes[nSearchHull] & bits_CAP_MOVE_GROUND ) )
continue;
nValidLinks++;
}
if ( nValidLinks >= nMinLinks )
{
pArea->m_aAreaNodes.AddToTail( pNode );
pArea->m_nTotalLinks += nValidLinks;
}
}
// highlight and measure bounds
Vector vecAreaMins = Vector( FLT_MAX, FLT_MAX, FLT_MAX );
Vector vecAreaMaxs = Vector( -FLT_MAX, -FLT_MAX, -FLT_MAX );
for ( int i = 0; i < pArea->m_aAreaNodes.Count(); i++ )
{
vecAreaMins = VectorMin( vecAreaMins, pArea->m_aAreaNodes[i]->GetOrigin() );
vecAreaMaxs = VectorMax( vecAreaMaxs, pArea->m_aAreaNodes[i]->GetOrigin() );
if ( asw_director_debug.GetBool() )
{
if ( i == 0 )
{
NDebugOverlay::Cross3D( pArea->m_aAreaNodes[i]->GetOrigin(), 20.0f, 255, 255, 64, true, 10.0f );
}
else
{
NDebugOverlay::Cross3D( pArea->m_aAreaNodes[i]->GetOrigin(), 10.0f, 255, 128, 0, true, 10.0f );
}
}
}
Vector vecArea = ( vecAreaMaxs - vecAreaMins );
float flArea = vecArea.x * vecArea.y;
if ( asw_director_debug.GetBool() )
{
Msg( "area mins = %f %f %f\n", VectorExpand( vecAreaMins ) );
Msg( "area maxs = %f %f %f\n", VectorExpand( vecAreaMaxs ) );
NDebugOverlay::Box( vec3_origin, vecAreaMins, vecAreaMaxs, 255, 128, 128, 10, 10.0f );
Msg( "Total links = %d Area = %f\n", pArea->m_nTotalLinks, flArea );
}
return pArea;
}
// creates a batch of aliens at the mouse cursor
void asw_alien_batch_f( const CCommand& args )
@ -716,3 +1144,14 @@ void asw_alien_horde_f( const CCommand& args )
}
}
static ConCommand asw_alien_horde("asw_alien_horde", asw_alien_horde_f, "Creates a horde of aliens somewhere nearby", FCVAR_GAMEDLL | FCVAR_CHEAT);
CON_COMMAND_F( asw_spawn_shieldbug, "Spawns a shieldbug somewhere randomly in the map", FCVAR_CHEAT )
{
ASWSpawnManager()->SpawnRandomShieldbug();
}
CON_COMMAND_F( asw_spawn_parasite_pack, "Spawns a group of parasites somewhere randomly in the map", FCVAR_CHEAT )
{
ASWSpawnManager()->SpawnRandomParasitePack( RandomInt( 3, 5 ) );
}

View File

@ -7,6 +7,8 @@
class CAI_Network;
class CTriggerMultiple;
struct AI_Waypoint_t;
class CAI_Node;
class CASW_Alien;
// The spawn manager can spawn aliens and groups of aliens
@ -20,6 +22,23 @@ public:
int m_nHullType;
};
class CASW_Open_Area
{
public:
CASW_Open_Area()
{
m_flArea = 0.0f;
m_nTotalLinks = 0;
m_vecOrigin = vec3_origin;
m_pNode = NULL;
}
float m_flArea;
int m_nTotalLinks;
Vector m_vecOrigin;
CAI_Node *m_pNode;
CUtlVector<CAI_Node*> m_aAreaNodes;
};
class CASW_Spawn_Manager
{
public:
@ -43,9 +62,18 @@ public:
int GetHordeToSpawn() { return m_iHordeToSpawn; }
void OnAlienWokeUp( CASW_Alien *pAlien );
void OnAlienSleeping( CASW_Alien *pAlien );
int GetAwakeAliens() { return m_nAwakeAliens; }
int GetAwakeDrones() { return m_nAwakeDrones; }
int GetNumAlienClasses();
ASW_Alien_Class_Entry* GetAlienClass( int i );
// spawns a shieldbug somewhere randomly in the map
bool SpawnRandomShieldbug();
bool SpawnRandomParasitePack( int nParasites );
private:
void UpdateCandidateNodes();
bool FindHordePosition();
@ -54,12 +82,18 @@ private:
void FindEscapeTriggers();
void DeleteRoute( AI_Waypoint_t *pWaypointList );
// finds an area with good node connectivity. Caller should take ownership of the CASW_Open_Area instance.
CASW_Open_Area* FindNearbyOpenArea( const Vector &vecSearchOrigin, int nSearchHull );
CountdownTimer m_batchInterval;
Vector m_vecHordePosition;
QAngle m_angHordeAngle;
int m_iHordeToSpawn;
int m_iAliensToSpawn;
int m_nAwakeAliens;
int m_nAwakeDrones;
// maintaining a list of possible nodes to spawn aliens from
CUtlVector<int> m_northCandidateNodes;
CUtlVector<int> m_southCandidateNodes;

View File

@ -153,6 +153,9 @@ void CASW_Spawner::AlienKilled( CBaseEntity *pVictim )
m_nCurrentLiveAliens--;
if (asw_debug_spawners.GetBool())
Msg("%d AlienKilled NumLive = %d\n", entindex(), m_nCurrentLiveAliens );
// If we're here, we're getting erroneous death messages from children we haven't created
AssertMsg( m_nCurrentLiveAliens >= 0, "asw_spawner receiving child death notice but thinks has no children\n" );
@ -293,6 +296,22 @@ bool CASW_Spawner::ApplyCarnageMode( float fScaler, float fInvScaler )
return false;
}
int CASW_Spawner::DrawDebugTextOverlays()
{
int text_offset = BaseClass::DrawDebugTextOverlays();
if (m_debugOverlays & OVERLAY_TEXT_BIT)
{
NDebugOverlay::EntityText( entindex(),text_offset,CFmtStr( "Num Live Aliens: %d", m_nCurrentLiveAliens ),0 );
text_offset++;
NDebugOverlay::EntityText( entindex(),text_offset,CFmtStr( "Max Live Aliens: %d", m_nMaxLiveAliens ),0 );
text_offset++;
NDebugOverlay::EntityText( entindex(),text_offset,CFmtStr( "Alien supply: %d", m_bInfiniteAliens ? -1 : m_nNumAliens ),0 );
text_offset++;
}
return text_offset;
}
void ASW_ApplyCarnage_f(float fScaler)
{
if ( fScaler <= 0 )

View File

@ -21,6 +21,7 @@ public:
virtual void Spawn();
virtual void Precache();
virtual void InitAlienClassName();
virtual int DrawDebugTextOverlays();
Class_T Classify() { return (Class_T) CLASS_ASW_SPAWNER; }

View File

@ -1208,6 +1208,9 @@ void SoundSystemPreloadSounds( void )
CON_COMMAND( sv_soundemitter_flush, "Flushes the sounds.txt system (server only)" )
{
if ( !UTIL_IsCommandIssuedByServerAdmin() )
return;
// save the current soundscape
// kill the system
g_SoundEmitterSystem.Flush();
@ -1222,12 +1225,18 @@ CON_COMMAND( sv_soundemitter_flush, "Flushes the sounds.txt system (server only)
CON_COMMAND( sv_soundemitter_filecheck, "Report missing wave files for sounds and game_sounds files." )
{
if ( !UTIL_IsCommandIssuedByServerAdmin() )
return;
int missing = soundemitterbase->CheckForMissingWavFiles( true );
DevMsg( "---------------------------\nTotal missing files %i\n", missing );
}
CON_COMMAND( sv_findsoundname, "Find sound names which reference the specified wave files." )
{
if ( !UTIL_IsCommandIssuedByServerAdmin() )
return;
if ( args.ArgC() != 2 )
return;

View File

@ -639,6 +639,11 @@ IResponseSystem *g_pResponseSystem = &defaultresponsesytem;
CON_COMMAND( rr_reloadresponsesystems, "Reload all response system scripts." )
{
#ifdef GAME_DLL
if ( !UTIL_IsCommandIssuedByServerAdmin() )
return;
#endif
defaultresponsesytem.ReloadAllResponseSystems();
}

View File

@ -762,7 +762,7 @@ class CAchievement_Unlock_All_Weapons : public CASW_Achievement
{
if ( !Q_stricmp( event->GetName(), "level_up" ) )
{
if ( event->GetInt( "level" ) >= ASW_LEVEL_CAP )
if ( event->GetInt( "level" ) >= ASW_NUM_EXPERIENCE_LEVELS )
{
IncrementCount();
}
@ -1077,5 +1077,73 @@ class CAchievement_Para_Hat : public CASW_Achievement
};
DECLARE_ACHIEVEMENT_ORDER( CAchievement_Para_Hat, ACHIEVEMENT_ASW_PARA_HAT, "ASW_PARA_HAT", 5, 149 );
class CAchievement_Imba_Campaign : public CASW_Achievement
{
void Init()
{
SetFlags( ACH_SAVE_GLOBAL | ACH_HAS_COMPONENTS );
SetStoreProgressInSteam( true );
SetGoal( NELEMS( g_szAchievementMapNames ) );
}
virtual void ListenForEvents( void )
{
ListenForGameEvent( "mission_success" );
}
void FireGameEvent_Internal( IGameEvent *event )
{
if ( !Q_stricmp( event->GetName(), "mission_success" ) && ASWGameRules() && ASWGameRules()->GetSkillLevel() >= 5 )
{
if ( LocalPlayerWasSpectating() )
return;
const char *szMapName = event->GetString( "strMapName" );
for ( int i = 0; i < NELEMS( g_szAchievementMapNames ); i++ )
{
if ( !Q_stricmp( szMapName, g_szAchievementMapNames[i] ) )
{
EnsureComponentBitSetAndEvaluate( i );
break;
}
}
}
}
};
DECLARE_ACHIEVEMENT_ORDER( CAchievement_Imba_Campaign, ACHIEVEMENT_ASW_IMBA_CAMPAIGN, "ASW_IMBA_CAMPAIGN", 5, 182 );
class CAchievement_Hardcore : public CASW_Achievement
{
void Init()
{
SetFlags( ACH_SAVE_GLOBAL );
SetGoal( 1 );
}
virtual void ListenForEvents( void )
{
ListenForGameEvent( "mission_success" );
}
void FireGameEvent_Internal( IGameEvent *event )
{
if ( !Q_stricmp( event->GetName(), "mission_success" ) && ASWGameRules() && ASWGameRules()->GetSkillLevel() >= 5
&& CAlienSwarm::IsHardcoreFF() && CAlienSwarm::IsOnslaught() )
{
if ( LocalPlayerWasSpectating() )
return;
const char *szMapName = event->GetString( "strMapName" );
for ( int i = 0; i < NELEMS( g_szAchievementMapNames ); i++ )
{
if ( !Q_stricmp( szMapName, g_szAchievementMapNames[i] ) )
{
IncrementCount();
break;
}
}
}
}
};
DECLARE_ACHIEVEMENT_ORDER( CAchievement_Hardcore, ACHIEVEMENT_ASW_HARDCORE, "ASW_HARDCORE", 5, 184 );
#endif

View File

@ -68,7 +68,9 @@ enum
ACHIEVEMENT_ASW_SPEEDRUN_TIMOR,
ACHIEVEMENT_ASW_CAMPAIGN_NO_DEATHS,
ACHIEVEMENT_ASW_MISSION_NO_DEATHS,
ACHIEVEMENT_ASW_PARA_HAT
ACHIEVEMENT_ASW_PARA_HAT,
ACHIEVEMENT_ASW_IMBA_CAMPAIGN,
ACHIEVEMENT_ASW_HARDCORE,
};
#define ACH_LISTEN_ALIEN_DEATH_EVENTS 0x1000

View File

@ -84,6 +84,7 @@
#include "EntityFlame.h"
#include "asw_buffgrenade_projectile.h"
#include "asw_achievements.h"
#include "asw_director.h"
#endif
#include "game_timescale_shared.h"
#include "asw_gamerules.h"
@ -135,6 +136,19 @@ extern ConVar old_radius_damage;
ConVar sv_vote_kick_ban_duration("sv_vote_kick_ban_duration", "5", 0, "How long should a kick vote ban someone from the server? (in minutes)");
ConVar sv_timeout_when_fully_connected( "sv_timeout_when_fully_connected", "30", FCVAR_NONE, "Once fully connected, player will be kicked if he doesn't send a network message within this interval." );
ConVar mm_swarm_state( "mm_swarm_state", "ingame", FCVAR_DEVELOPMENTONLY );
static void UpdateMatchmakingTagsCallback( IConVar *pConVar, const char *pOldValue, float flOldValue )
{
// update sv_tags to force an update of the matchmaking tags
static ConVarRef sv_tags( "sv_tags" );
if ( sv_tags.IsValid() )
{
char buffer[ 1024 ];
Q_snprintf( buffer, sizeof( buffer ), "%s", sv_tags.GetString() );
sv_tags.SetValue( buffer );
}
}
#else
extern ConVar asw_controls;
#endif
@ -153,6 +167,30 @@ ConVar asw_stim_time_scale("asw_stim_time_scale", "0.35", FCVAR_REPLICATED | FCV
ConVar asw_time_scale_delay("asw_time_scale_delay", "0.15", FCVAR_REPLICATED | FCVAR_CHEAT, "Delay before timescale changes to give a chance for the client to comply and predict.");
ConVar asw_ignore_need_two_player_requirement("asw_ignore_need_two_player_requirement", "0", FCVAR_REPLICATED, "If set to 1, ignores the mission setting that states two players are needed to start the mission.");
ConVar mp_gamemode( "mp_gamemode", "campaign", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Current game mode, acceptable values are campaign and single_mission.", false, 0.0f, false, 0.0f );
ConVar asw_sentry_friendly_fire_scale( "asw_sentry_friendly_fire_scale", "0", FCVAR_REPLICATED, "Damage scale for sentry gun friendly fire"
#ifdef GAME_DLL
,UpdateMatchmakingTagsCallback );
#else
);
#endif
ConVar asw_marine_ff_absorption("asw_marine_ff_absorption", "1", FCVAR_REPLICATED, "Friendly fire absorption style (0=none 1=ramp up 2=ramp down)"
#ifdef GAME_DLL
,UpdateMatchmakingTagsCallback );
#else
);
#endif
ConVar asw_horde_override( "asw_horde_override", "0", FCVAR_REPLICATED, "Forces hordes to spawn"
#ifdef GAME_DLL
,UpdateMatchmakingTagsCallback );
#else
);
#endif
ConVar asw_wanderer_override( "asw_wanderer_override", "0", FCVAR_REPLICATED, "Forces wanderers to spawn"
#ifdef GAME_DLL
,UpdateMatchmakingTagsCallback );
#else
);
#endif
// ASW Weapons
// Rifle
@ -251,7 +289,7 @@ ConVar asw_vote_kick_fraction("asw_vote_kick_fraction", "0.6", FCVAR_REPLICATED
ConVar asw_vote_leader_fraction("asw_vote_leader_fraction", "0.6", FCVAR_REPLICATED | FCVAR_ARCHIVE, "Fraction of players needed to activate a leader vote");
ConVar asw_vote_map_fraction("asw_vote_map_fraction", "0.6", FCVAR_REPLICATED | FCVAR_ARCHIVE, "Fraction of players needed to activate a map vote");
ConVar asw_marine_collision("asw_marine_collision", "0", FCVAR_REPLICATED, "Whether marines collide with each other or not, in a multiplayer game");
ConVar asw_skill( "asw_skill","2", FCVAR_REPLICATED | FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX, "Game skill level (1-4).", true, 1, true, 4 );
ConVar asw_skill( "asw_skill","2", FCVAR_REPLICATED | FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX, "Game skill level (1-5).", true, 1, true, 5 );
ConVar asw_money( "asw_money", "0", FCVAR_REPLICATED, "Can players collect money?" );
ConVar asw_client_build_maps("asw_client_build_maps", "0", FCVAR_REPLICATED, "Whether clients compile random maps rather than getting sent them");
@ -456,7 +494,7 @@ CAmmoDef *GetAmmoDef()
def.AddAmmoType("ASW_P", DMG_BULLET, TRACER_LINE_AND_WHIZ, "sk_plr_dmg_asw_p", "sk_npc_dmg_asw_p", "sk_max_asw_p", BULLET_IMPULSE(200, 1225), 0 );
// mining laser
def.AddAmmoType("ASW_ML", DMG_ENERGYBEAM, TRACER_LINE_AND_WHIZ, "sk_plr_dmg_asw_ml", "sk_npc_dmg_asw_ml", "sk_max_asw_ml", BULLET_IMPULSE(200, 1225), 0 );
// mining laser
// tesla gun - happy LJ?
def.AddAmmoType("ASW_TG", DMG_ENERGYBEAM, TRACER_LINE_AND_WHIZ, "sk_plr_dmg_asw_tg", "sk_npc_dmg_asw_tg", "sk_max_asw_tg", BULLET_IMPULSE(200, 1225), 0 );
// railgun
def.AddAmmoType("ASW_RG", DMG_SONIC, TRACER_LINE_AND_WHIZ, "sk_plr_dmg_asw_rg", "sk_npc_dmg_asw_rg", "sk_max_asw_rg", BULLET_IMPULSE(200, 1225), 0 );
@ -627,19 +665,6 @@ const char * GenerateNewSaveGameName()
return NULL;
}
void UpdateMatchmakingTags()
{
// update sv_tags to force an update of the matchmaking tags
static ConVarRef sv_tags( "sv_tags" );
if ( sv_tags.IsValid() )
{
char buffer[ 1024 ];
Q_snprintf( buffer, sizeof( buffer ), "%s", sv_tags.GetString() );
sv_tags.SetValue( buffer );
}
}
CAlienSwarm::CAlienSwarm()
{
Msg("CAlienSwarm created\n");
@ -1610,6 +1635,11 @@ void CAlienSwarm::StartMission()
m_Medals.OnStartMission();
if ( ASWDirector() )
{
ASWDirector()->OnMissionStarted();
}
Msg("==STARTMISSION==\n");
SetGameState(ASW_GS_LAUNCHING);
@ -3319,7 +3349,7 @@ void CAlienSwarm::MissionComplete( bool bSuccess )
if (!MapScores()->IsModeUnlocked(mapName, GetSkillLevel(), ASW_SM_CARNAGE))
{
// check for unlocking carnage (if we completed the mission on Insane)
bJustUnlockedCarnage = (GetSkillLevel() == 4);
bJustUnlockedCarnage = (GetSkillLevel() >= 4);
//Msg("Checked just carnage unlock = %d\n", bJustUnlockedCarnage);
}
if (!MapScores()->IsModeUnlocked(mapName, GetSkillLevel(), ASW_SM_UBER))
@ -5144,6 +5174,11 @@ void CAlienSwarm::OnSkillLevelChanged( int iNewLevel )
m_iMissionDifficulty = 10;
szDifficulty = "insane";
}
else if (iNewLevel == 5) // imba
{
m_iMissionDifficulty = 13;
szDifficulty = "imba";
}
else // normal
{
m_iMissionDifficulty = 5;
@ -5200,7 +5235,7 @@ void CAlienSwarm::OnSkillLevelChanged( int iNewLevel )
}
}
UpdateMatchmakingTags();
UpdateMatchmakingTagsCallback( NULL, "0", 0.0f );
m_iSkillLevel = iNewLevel;
}
@ -5226,12 +5261,28 @@ void CAlienSwarm::RequestSkill( CASW_Player *pPlayer, int nSkill )
if ( !( m_iGameState == ASW_GS_BRIEFING || m_iGameState == ASW_GS_DEBRIEF ) ) // don't allow skill change outside of briefing
return;
if ( nSkill >= 1 && nSkill <= 4 && ASWGameResource() && ASWGameResource()->GetLeader() == pPlayer )
if ( nSkill >= 1 && nSkill <= 5 && ASWGameResource() && ASWGameResource()->GetLeader() == pPlayer )
{
ConVar *var = (ConVar *)cvar->FindVar( "asw_skill" );
if (var)
{
int iOldSkill = var->GetInt();
var->SetValue( nSkill );
if ( iOldSkill != var->GetInt() )
{
CReliableBroadcastRecipientFilter filter;
filter.RemoveRecipient( pPlayer ); // notify everyone except the player changing the difficulty level
switch(var->GetInt())
{
case 1: UTIL_ClientPrintFilter( filter, ASW_HUD_PRINTTALKANDCONSOLE, "#asw_set_difficulty_easy", pPlayer->GetPlayerName() ); break;
case 2: UTIL_ClientPrintFilter( filter, ASW_HUD_PRINTTALKANDCONSOLE, "#asw_set_difficulty_normal", pPlayer->GetPlayerName() ); break;
case 3: UTIL_ClientPrintFilter( filter, ASW_HUD_PRINTTALKANDCONSOLE, "#asw_set_difficulty_hard", pPlayer->GetPlayerName() ); break;
case 4: UTIL_ClientPrintFilter( filter, ASW_HUD_PRINTTALKANDCONSOLE, "#asw_set_difficulty_insane", pPlayer->GetPlayerName() ); break;
case 5: UTIL_ClientPrintFilter( filter, ASW_HUD_PRINTTALKANDCONSOLE, "#asw_set_difficulty_imba", pPlayer->GetPlayerName() ); break;
}
}
}
}
}
@ -5241,7 +5292,7 @@ void CAlienSwarm::RequestSkillUp(CASW_Player *pPlayer)
if (m_iGameState != ASW_GS_BRIEFING) // don't allow skill change outside of briefing
return;
if (m_iSkillLevel < 4 && ASWGameResource() && ASWGameResource()->GetLeader() == pPlayer)
if (m_iSkillLevel < 5 && ASWGameResource() && ASWGameResource()->GetLeader() == pPlayer)
{
ConVar *var = (ConVar *)cvar->FindVar( "asw_skill" );
if (var)
@ -6598,6 +6649,8 @@ int CAlienSwarm::TotalInfestDamage()
return 270;
case 4:
return 280; // BARELY survivable with Bastille and heal beacon
case 5:
return 280;
}
// ASv1 Total infest damage = 90 + difficulty * 20;
@ -6749,3 +6802,13 @@ const QAngle& CAlienSwarm::GetTopDownMovementAxis()
static QAngle axis = ASW_MOVEMENT_AXIS;
return axis;
}
bool CAlienSwarm::IsHardcoreFF()
{
return ( asw_marine_ff_absorption.GetInt() != 1 || asw_sentry_friendly_fire_scale.GetFloat() != 0.0f );
}
bool CAlienSwarm::IsOnslaught()
{
return ( asw_horde_override.GetBool() || asw_wanderer_override.GetBool() );
}

View File

@ -234,9 +234,9 @@ public:
{
iLevel = 1;
}
else if ( iLevel > 4 )
else if ( iLevel > 5 )
{
iLevel = 4;
iLevel = 5;
}
m_iSkillLevel = iLevel;
@ -386,8 +386,8 @@ public:
virtual void RefreshSkillData ( bool forceUpdate );
// difficulty
virtual int GetSkillLevel() { return m_iSkillLevel; } // skill level (expanded HL2 style: 1 = easy, 2 = normal, 3 = hard, 4 = insane )
CNetworkVar(int, m_iSkillLevel); // 1 = easy, 2 = normal, 3 = hard, 4 = insane
virtual int GetSkillLevel() { return m_iSkillLevel; } // skill level (expanded HL2 style: 1 = easy, 2 = normal, 3 = hard, 4 = insane, 5 = imba )
CNetworkVar(int, m_iSkillLevel); // 1 = easy, 2 = normal, 3 = hard, 4 = insane, 5 = imba
int GetMissionDifficulty() { return m_iMissionDifficulty; } // overall difficulty of the mission from 2-10, based on skill level and campaign modifier
CNetworkVar(int, m_iMissionDifficulty);
CNetworkVar(bool, m_bCheated);
@ -475,6 +475,8 @@ public:
bool IsIntroMap() { return m_bIsIntro; }
bool IsOutroMap() { return m_bIsOutro; }
bool IsLobbyMap() { return m_bIsLobby; }
static bool IsHardcoreFF();
static bool IsOnslaught();
bool m_bIsTutorial;
bool m_bIsIntro;

View File

@ -296,6 +296,7 @@ float CASW_Marine::MaxSpeed()
// adjust the speed by difficulty level
switch (ASWGameRules()->GetSkillLevel())
{
case 5: speedscale *= asw_marine_speed_scale_insane.GetFloat(); break;
case 4: speedscale *= asw_marine_speed_scale_insane.GetFloat(); break;
case 3: speedscale *= asw_marine_speed_scale_hard.GetFloat(); break;
case 2: speedscale *= asw_marine_speed_scale_normal.GetFloat(); break;

View File

@ -100,15 +100,28 @@ int g_iXPAward[ ASW_NUM_XP_TYPES ]=
50, // ASW_XP_HACKING
};
// scalar applied to XP required to level, based on your current promotion
float g_flPromotionXPScale[ ASW_PROMOTION_CAP + 1 ]=
{
1.0f,
1.0f,
1.0f,
1.0f,
2.0f,
4.0f,
6.0f,
};
#define ASW_MISSION_XP_AWARD_ON_FAILURE 750 // XP award divided up between objectives
// NOTE: If you change this, update the labels in CExperienceReport::OnThink too
float g_flXPDifficultyScale[4]=
float g_flXPDifficultyScale[5]=
{
0.5f, // easy
1.0f, // normal
1.2f, // hard
1.4f, // insane
1.5f, // imba
};
// Weapon unlocks
@ -153,17 +166,18 @@ ASW_Weapon_Unlock g_WeaponUnlocks[]=
ASW_Weapon_Unlock( "asw_weapon_night_vision", 23 ),//
ASW_Weapon_Unlock( "asw_weapon_sentry_cannon", 24 ),
ASW_Weapon_Unlock( "asw_weapon_smart_bomb", 25 ),//
ASW_Weapon_Unlock( "asw_weapon_grenade_launcher", 26 ), // ASW_LEVEL_CAP
ASW_Weapon_Unlock( "asw_weapon_grenade_launcher", 26 ), // ASW_NUM_EXPERIENCE_LEVELS
};
// given an Experience total, this tells you the player's level
int LevelFromXP( int iExperience )
int LevelFromXP( int iExperience, int iPromotion )
{
iExperience = MIN( iExperience, ASW_XP_CAP );
iExperience = MIN( iExperience, ASW_XP_CAP * g_flPromotionXPScale[ iPromotion ] );
for ( int i = 0; i < NELEMS( g_iLevelExperience ); i++ )
{
if ( iExperience < g_iLevelExperience[ i ] )
int iRequiredXP = (int) ( g_flPromotionXPScale[ iPromotion ] * g_iLevelExperience[ i ] );
if ( iExperience < iRequiredXP )
{
return i;
}
@ -368,13 +382,13 @@ void CASW_Player::CalculateEarnedXP()
int CASW_Player::GetLevel()
{
return LevelFromXP( GetExperience() );
return LevelFromXP( GetExperience(), GetPromotion() );
}
int CASW_Player::GetLevelBeforeDebrief()
{
return LevelFromXP( GetExperienceBeforeDebrief() );
return LevelFromXP( GetExperienceBeforeDebrief(), GetPromotion() );
}
void CASW_Player::RequestExperience()
@ -460,7 +474,7 @@ void CASW_Player::AwardExperience()
Msg( "%s: AwardExperience: Pre XP is %d\n", IsServerDll() ? "S" : "C", m_iExperience );
m_iExperience += m_iEarnedXP[ ASW_XP_TOTAL ];
m_iExperience = MIN( m_iExperience, ASW_XP_CAP );
m_iExperience = MIN( m_iExperience, ASW_XP_CAP * g_flPromotionXPScale[ GetPromotion() ] );
#ifdef CLIENT_DLL
if ( IsLocalPlayer() )
@ -646,7 +660,7 @@ void CASW_Player::Steam_OnUserStatsReceived( UserStatsReceived_t *pUserStatsRece
if( GetLocalASWPlayer() == this )
g_ASW_Steamstats.FetchStats( steamID, this );
if ( IsLocalPlayer() && GetLevel() >= ASW_LEVEL_CAP )
if ( IsLocalPlayer() && GetLevel() >= ASW_NUM_EXPERIENCE_LEVELS )
{
CAchievementMgr *pAchievementMgr = dynamic_cast<CAchievementMgr *>( engine->GetAchievementMgr() );
if ( !pAchievementMgr )
@ -694,7 +708,7 @@ ConCommand asw_debug_xp( "asw_debug_xp", asw_debug_xp_f, "Lists XP details for l
void CASW_Player::AcceptPromotion()
{
if ( GetExperience() < ASW_XP_CAP )
if ( GetExperience() < ASW_XP_CAP * g_flPromotionXPScale[ GetPromotion() ] )
return;
if ( GetPromotion() >= ASW_PROMOTION_CAP )

View File

@ -26,11 +26,13 @@ enum
ASW_USE_HOLD_RELEASE_FULL,
};
#define ASW_PROMOTION_CAP 6
#define ASW_NUM_EXPERIENCE_LEVELS 26
extern int g_iLevelExperience[ ASW_NUM_EXPERIENCE_LEVELS ];
extern float g_flPromotionXPScale[ ASW_PROMOTION_CAP + 1 ];
int LevelFromXP( int iExperience );
int LevelFromXP( int iExperience, int iPromotion );
enum CASW_Earned_XP_t
{

View File

@ -583,8 +583,6 @@ enum
};
#define ASW_XP_CAP 42250
#define ASW_LEVEL_CAP 26
#define ASW_PROMOTION_CAP 3
extern ConVar asw_visrange_generic;
@ -602,4 +600,13 @@ public:
#endif
enum CASW_Flock_Leader_State
{
ASW_FL_CHASING = 0,
ASW_FL_CHARGING,
ASW_FL_FLEEING,
NUM_FLOCK_LEADER_STATES,
};
#endif // ASW_SHAREDDEFS_H

View File

@ -954,7 +954,7 @@ float UTIL_ASW_CalcFastDoorHackTime(int iNumRows, int iNumColumns, int iNumWires
ideal_time *= 1.05f; // 5% slower on easy mode
else if (iSkill == 3)
ideal_time *= 0.95f; // 5% faster on hard mode
else if (iSkill == 4)
else if (iSkill == 4 || iSkill == 5)
ideal_time *= 0.90f; // 10% faster on insane mode
return ideal_time;

View File

@ -885,6 +885,7 @@ bool CASW_Weapon::ASWReload( int iClipSize1, int iClipSize2, int iActivity )
case 2: flFastReloadWidth = random->RandomFloat( 0.10f, 0.1f ); break; // easy/normal
case 3: flFastReloadWidth = random->RandomFloat( 0.08f, 0.12f ); break; // hard
case 4: flFastReloadWidth = random->RandomFloat( 0.06f, 0.10f ); break; // insane
case 5: flFastReloadWidth = random->RandomFloat( 0.055f, 0.09f ); break; // imba
}
// scale by marine skills
flFastReloadWidth *= MarineSkills()->GetSkillBasedValueByMarine( pMarine, ASW_MARINE_SKILL_RELOADING, ASW_MARINE_SUBSKILL_RELOADING_FAST_WIDTH_SCALE );