Closed armanossiloko closed 2 months 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.
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 */ }
It's been a while since this post, but I just wanted to let you know that in case you need the functionality you posted in the post on your servers, it appears to be broken on Linux. In Versus, when Team 1 is playing, if you set the score of the infected team (Team 2 that has not played as survivors yet) which currently is (e.g) 400 pts to 800pts, it will change the score of the infected team to 800 temporarily, but it will screw up the score of the survivors (aka Team 1). Then, at the end of the round, when the scores are computed by the game, the score of the survivor team will be ok, but the infected score will revert back to its original value prior to you setting it to anything (in this case 400).
Is that happening in Left4DHooks 1.153? Or are you referring to the alternative method posted in this comments section? If the latter, try Left4DHooks 1.153.
Is that happening in Left4DHooks 1.153? Or are you referring to the alternative method posted in this comments section? If the latter, try Left4DHooks 1.153.
Left4DHooks does not update the scoreboard at all, so I was using the alternative that @spumer posted, which appears to be buggy. Not sure if I never tested some of the use cases or if Valve broke it in the meantime since the last time spumer posted here.
This fix was partially included in 1.153 and after numerous tests it all seems to work including updating the scoreboard. Please test 1.153 and see if that works, this fix is outdated now.
This fix was partially included in 1.153 and after numerous tests it all seems to work including updating the scoreboard. Please test 1.153 and see if that works, this fix is outdated now.
I take it you are referring to using L4D2_SetVersusCampaignScores
, correct? aka L4D2_SetVersusCampaignScores
should be updating the scoreboard now?
Fixes were applied to all Versus score commands.
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?