Closed armanossiloko closed 2 days ago
We are use this approach to set scores for L4D2
SetScores( iSurvScore, iInfScore )
{
new bool:bAreTeamsFlipped = bool:GameRules_GetProp( "m_bAreTeamsFlipped" );
new iSurvTeamIndex = bAreTeamsFlipped ? 1 : 0;
new iInfTeamIndex = bAreTeamsFlipped ? 0 : 1;
/*new scores[2];
scores[0] = iSurvScore;
scores[1] = iInfScore;*/
//L4D2_SetVersusCampaignScores( scores ); // visible scores
L4D2_SetVersusCampaignScores123( iSurvScore, iInfScore ); // visible scores
L4D2Direct_SetVSCampaignScore( iSurvTeamIndex, iSurvScore ); // real scores
L4D2Direct_SetVSCampaignScore( iInfTeamIndex, iInfScore );
CPrintToChatAll( "Set Scores > (Survivors) {olive}%d{default} : {olive}%d{default} (Infected)", iSurvScore, iInfScore );
}
bool:L4D2_SetVersusCampaignScores123( surv_score, inf_score )
{
static Handle:hSetVersusCampaignScores = INVALID_HANDLE;
if( hSetVersusCampaignScores == INVALID_HANDLE )
{
new Handle:hGameData = LoadGameConfigFile( FILE_DOWNTOWN_GAMEDATA );
if( hGameData == INVALID_HANDLE )
{
LogError( "Unable to find 'gamedata/%s.txt'", FILE_DOWNTOWN_GAMEDATA );
return false;
}
StartPrepSDKCall( SDKCall_GameRules );
PrepSDKCall_SetFromConf( hGameData, SDKConf_Signature, "SetCampaignScores" );
PrepSDKCall_AddParameter( SDKType_PlainOldData, SDKPass_Plain );
PrepSDKCall_AddParameter( SDKType_PlainOldData, SDKPass_Plain );
hSetVersusCampaignScores = EndPrepSDKCall();
CloseHandle( hGameData );
if( hSetVersusCampaignScores == INVALID_HANDLE )
{
LogError( "Signature SetCampaignScores is broken. Check 'gamedata/%s.txt'", FILE_DOWNTOWN_GAMEDATA );
return false;
}
}
SDKCall( hSetVersusCampaignScores, surv_score, inf_score );
return true;
}
Gamedata:
/*
* CTerrorGameRules::SetCampaignScores(int,int)
* Search for unique string "singlechapter"
* -> has two xref from same function, CTerrorGameRules::IsSingleChapterMode()
* -> has two xref, one is CRestartGameIssue::ExecuteCommand() (exclude the other, CServerGameDLL::ServerHibernationUpdate(), which has string "FCVAR_NEVER_AS_STRING")
* -> CRestartGameIssue::ExecuteCommand() calls CDirectorVersusMode::VoteRestartVersusLevel() (fourth call..?)
* -> first call is CTerrorGameRules::SetCampaignScores()
* make sure to double check uniqueness when done
*/
"SetCampaignScores"
{
"library" "server"
"linux" "@_ZN16CTerrorGameRules17SetCampaignScoresEii"
"windows" "\x55\x8B\xEC\x56\x57\x8B\x7D\x08\x8B\xF1\x39\xBE\x2A\x2A\x2A\x2A\x74\x2A\xE8\x2A\x2A\x2A\x2A\x89\xBE\x2A\x2A\x2A\x2A\x8B"
/* 55 8B EC 56 57 8B 7D 08 8B F1 39 BE ? ? ? ? 74 ? E8 ? ? ? ? 89 BE ? ? ? ? 8B */
}
We are use this approach to set scores for L4D2
SetScores( iSurvScore, iInfScore ) { new bool:bAreTeamsFlipped = bool:GameRules_GetProp( "m_bAreTeamsFlipped" ); new iSurvTeamIndex = bAreTeamsFlipped ? 1 : 0; new iInfTeamIndex = bAreTeamsFlipped ? 0 : 1; /*new scores[2]; scores[0] = iSurvScore; scores[1] = iInfScore;*/ //L4D2_SetVersusCampaignScores( scores ); // visible scores L4D2_SetVersusCampaignScores123( iSurvScore, iInfScore ); // visible scores L4D2Direct_SetVSCampaignScore( iSurvTeamIndex, iSurvScore ); // real scores L4D2Direct_SetVSCampaignScore( iInfTeamIndex, iInfScore ); CPrintToChatAll( "Set Scores > (Survivors) {olive}%d{default} : {olive}%d{default} (Infected)", iSurvScore, iInfScore ); } bool:L4D2_SetVersusCampaignScores123( surv_score, inf_score ) { static Handle:hSetVersusCampaignScores = INVALID_HANDLE; if( hSetVersusCampaignScores == INVALID_HANDLE ) { new Handle:hGameData = LoadGameConfigFile( FILE_DOWNTOWN_GAMEDATA ); if( hGameData == INVALID_HANDLE ) { LogError( "Unable to find 'gamedata/%s.txt'", FILE_DOWNTOWN_GAMEDATA ); return false; } StartPrepSDKCall( SDKCall_GameRules ); PrepSDKCall_SetFromConf( hGameData, SDKConf_Signature, "SetCampaignScores" ); PrepSDKCall_AddParameter( SDKType_PlainOldData, SDKPass_Plain ); PrepSDKCall_AddParameter( SDKType_PlainOldData, SDKPass_Plain ); hSetVersusCampaignScores = EndPrepSDKCall(); CloseHandle( hGameData ); if( hSetVersusCampaignScores == INVALID_HANDLE ) { LogError( "Signature SetCampaignScores is broken. Check 'gamedata/%s.txt'", FILE_DOWNTOWN_GAMEDATA ); return false; } } SDKCall( hSetVersusCampaignScores, surv_score, inf_score ); return true; }
Gamedata:
/* * CTerrorGameRules::SetCampaignScores(int,int) * Search for unique string "singlechapter" * -> has two xref from same function, CTerrorGameRules::IsSingleChapterMode() * -> has two xref, one is CRestartGameIssue::ExecuteCommand() (exclude the other, CServerGameDLL::ServerHibernationUpdate(), which has string "FCVAR_NEVER_AS_STRING") * -> CRestartGameIssue::ExecuteCommand() calls CDirectorVersusMode::VoteRestartVersusLevel() (fourth call..?) * -> first call is CTerrorGameRules::SetCampaignScores() * make sure to double check uniqueness when done */ "SetCampaignScores" { "library" "server" "linux" "@_ZN16CTerrorGameRules17SetCampaignScoresEii" "windows" "\x55\x8B\xEC\x56\x57\x8B\x7D\x08\x8B\xF1\x39\xBE\x2A\x2A\x2A\x2A\x74\x2A\xE8\x2A\x2A\x2A\x2A\x89\xBE\x2A\x2A\x2A\x2A\x8B" /* 55 8B EC 56 57 8B 7D 08 8B F1 39 BE ? ? ? ? 74 ? E8 ? ? ? ? 89 BE ? ? ? ? 8B */ }
Does that automatically show the updated scores in the scoreboard for everyone?
Does that automatically show the updated scores in the scoreboard for everyone?
Yes
Does that automatically show the updated scores in the scoreboard for everyone?
Yes
So, gave that a shot and it indeed updates the scoreboard properly. The scores work fine. However, if I switch to the Spectators team, the scoreboard still shows the "old" scores. xD It's not too big of a deal as spectators usually don't monitor the scores, but I figured it'd be worth mentioning.
Does that automatically show the updated scores in the scoreboard for everyone?
Yes
So, gave that a shot and it indeed updates the scoreboard properly. The scores work fine. However, if I switch to the Spectators team, the scoreboard still shows the "old" scores. xD It's not too big of a deal as spectators usually don't monitor the scores, but I figured it'd be worth mentioning.
Yea, we have workaround for that
public Action:Event_LeftStartArea( Handle:event, const String:name[], bool:dontBroadcast )
{
// It could be wrong even on first found
// if player enter surv team after map change
// So we need to switch spec team on each round start
CreateTimer( 1.0, Timer_FixSpecScoreBug );
}
// Spec Score Bug. Wrong Score by TAB, need switch team to fix score.
public Action:Timer_FixSpecScoreBug( Handle:timer )
{
for( new i = 1; i <= MaxClients; i++ )
{
if( IsClientInGame( i ) && GetClientTeam( i ) == L4D_TEAM_SPECTATE )
{
// team switch will trigger NextFrame_HideSpecBars
ChangeClientTeam( i, L4D_TEAM_INFECTED );
ChangeClientTeam( i, L4D_TEAM_SPECTATE );
}
}
}
Does that automatically show the updated scores in the scoreboard for everyone?
Yes
So, gave that a shot and it indeed updates the scoreboard properly. The scores work fine. However, if I switch to the Spectators team, the scoreboard still shows the "old" scores. xD It's not too big of a deal as spectators usually don't monitor the scores, but I figured it'd be worth mentioning.
Yea, we have workaround for that
public Action:Event_LeftStartArea( Handle:event, const String:name[], bool:dontBroadcast ) { // It could be wrong even on first found // if player enter surv team after map change // So we need to switch spec team on each round start CreateTimer( 1.0, Timer_FixSpecScoreBug ); } // Spec Score Bug. Wrong Score by TAB, need switch team to fix score. public Action:Timer_FixSpecScoreBug( Handle:timer ) { for( new i = 1; i <= MaxClients; i++ ) { if( IsClientInGame( i ) && GetClientTeam( i ) == L4D_TEAM_SPECTATE ) { // team switch will trigger NextFrame_HideSpecBars ChangeClientTeam( i, L4D_TEAM_INFECTED ); ChangeClientTeam( i, L4D_TEAM_SPECTATE ); } } }
Would this work if the Infected team is full?
As i know it can't be full for ChangeClientTeam
As i know it can't be full for
ChangeClientTeam
Okay, fair enough. Thanks.
I think this overall is a decent workaround (though a bit hacky at times xD) for the time being until we perhaps get a proper L4D2 version of the RecomputeTeamScores if @SilvDev finds some spare time for it sometime in the future. Thanks, @spumer.
Thanks, added into 1.152. Please test and open this topic again if there are any issues.
Potentially not the right place to ask this, but calling
L4D2_SetVersusCampaignScores
updates the scores properly, however that change is not propagated to the scoreboard. Looking into the hooks, there is anative void L4DDirect_RecomputeTeamScores();
which is labeled for L4D1 use only.Is there something similar (or planned to be added) in existence for L4D2 as well?