Razor panel for the post-match screen in a soccer career game. Shows the result (win/draw/loss, score, penalties), a match statistics tab fed from MatchController.Match counters, a rewards tab with animated coin and cup token counters, and buttons to continue to the club or retry career round calculation. Includes English/Russian string lookup.
@using Sandbox
@using Sandbox.UI
@using Socer
@using System
@using System.Globalization
@inherits Panel
<root class="localized-text @OutcomeClass @(Ready?"ready":"entering")">
<div class="result-stage">
@if(Game.FinalCupVictoryMatch)
{
<div class="career-finale-victory"><img src="/ui-icons/ui-bold-nav-cup.svg" /><div><label>@T("YOU WIN SOCER","ВЫ ПОБЕДИЛИ В SOCER")</label><label>@T("Champions Cup winners","Обладатели Кубка чемпионов")</label><label>@T("Five leagues. One final trophy. Your club made it.","Пять лиг. Главный трофей. Ваш клуб прошёл весь путь.")</label></div></div>
}
<div class="result-heading"><label class="result-kicker">@T("SOCER / FULL TIME")</label><label class="result-outcome">@Outcome</label></div>
<div class="result-scoreline"><img class="result-crest" src="@Socer.ClubIdentity.Crest(Game.Match.HomeName)" /><label>@T(Game.Match.HomeName)</label><label class="result-score">@Game.Match.Goals[0] : @Game.Match.Goals[1]</label><label>@T(Game.Match.AwayName)</label><img class="result-crest" src="@Socer.ClubIdentity.Crest(Game.Match.AwayName)" /></div>
@if(Game.Match.ShootoutComplete){<label class="result-penalties">@($"{T("Penalties","Серия пенальти")} {Game.Match.ShootoutScores[0]} : {Game.Match.ShootoutScores[1]}")</label>}
<div class="result-tabs"><button class="@(!Rewards?"active":"")" onclick=@(()=>Rewards=false)>@T("Match")</button><button class="@(Rewards?"active":"")" disabled="@Game.AwaitingCareerRoundResults" onclick=@(()=>Rewards=true)>@T("Rewards")</button></div>
@if(!Rewards)
{
<div class="result-content match-statistics">
<div class="stats-head"><label>@T(Game.Match.HomeName)</label><label>@T("MATCH STATISTICS")</label><label>@T(Game.Match.AwayName)</label></div>
@foreach(var stat in MatchStats)
{
<div class="result-stat-row"><label class="result-value">@($"{stat.Home}{stat.Suffix}")</label><div class="stat-center"><label>@T(stat.Name)</label><div class="comparison-track"><div style="@StatWidth(stat.Home,stat.Away)"></div></div></div><label class="result-value">@($"{stat.Away}{stat.Suffix}")</label></div>
}
@if(!string.IsNullOrEmpty(Game.MatchMedicalSummary)){<label class="result-caption result-medical-summary">@T(Game.MatchMedicalSummary)</label>}
</div>
}
else
{
<div class="result-content rewards-content">
<div class="reward-tile"><label class="reward-symbol">◈</label><label class="result-caption">@T("CLUB BUDGET")</label><label class="reward-value">+@CoinsShown</label><label>@T(Receipt!=null?"Awarded, including competition bonuses":"Friendly match · no career rewards")</label></div>
@if(Receipt?.CupTokens>0){<div class="reward-tile cup-currency-reward"><div class="reward-cup-icon"></div><label class="result-caption">@T("CUP TOKENS","КУБКИ")</label><label class="reward-value">+@CupTokensShown</label><label>@T("For a cup win or first place in the league","За кубковую победу или первое место в лиге")</label></div>}
</div>
}
<div class="result-bottom">
@if(Game.AwaitingCareerRoundResults)
{
<label class="result-round-status" style="white-space: normal;">@(Game.CareerRoundCalculationFailed?T("Could not finish the round. Your score is kept in this session; retry the other matches to collect your rewards.","Не удалось рассчитать тур. Счёт вашего матча сохранён в этой сессии; повторите расчёт остальных встреч, чтобы получить награды."):T("Finishing the other matches…","Считаем остальные матчи тура…"))</label>
@if(Game.CareerRoundCalculationFailed){<div><button class="result-continue retry-round-results" disabled="@(!Game.CanRetryCareerRoundResults)" onclick=@(()=>Game.RetryCareerRoundResults())>@T("Retry calculation","Повторить расчёт")</button></div>}
}
else
{
<label>@ReceiptSummary</label><div><button class="result-continue" onclick=@(()=>{if(!Rewards)Rewards=true;else Game.ExitFinishedMatch();})>@T(Rewards?"To club →":"To rewards →")</button>@if(!Rewards){<button class="result-exit" onclick=@(()=>Game.ExitFinishedMatch())>@T("Go straight to club")</button>}</div>
}
</div>
</div>
</root>
@code {
public MatchController Game {get;set;}
public MatchController.MatchSettlement PreviewReceipt {get;set;}
public bool HandleHotkey(string id)
{
if(id!="app.confirm" || !Ready || Game.AwaitingCareerRoundResults || Game.CareerRoundCalculationFailed)return false;
if(!Rewards)Rewards=true;else Game.ExitFinishedMatch();return true;
}
bool rewards;
float rewardsAt;
bool Rewards { get=>rewards; set { if(value && !rewards)rewardsAt=Time.Now;rewards=value; } }
float opened=Time.Now;
bool Ready=>Time.Now-opened>.05f;
MatchController.MatchSettlement Receipt=>Game.IsRulesPreview?PreviewReceipt:Game.Settlement?.Match==Game.Match?Game.Settlement:null;
string OutcomeKey=>Receipt!=null?(Receipt.Won?"WIN":Receipt.Draw?"DRAW":"LOSS"):Game.Match.ShootoutComplete?(Game.Match.ShootoutWinner==0?"WIN":"LOSS"):Game.Match.Goals[0]>Game.Match.Goals[1]?"WIN":Game.Match.Goals[0]==Game.Match.Goals[1]?"DRAW":"LOSS";
string Outcome=>T(OutcomeKey);
string OutcomeClass=>OutcomeKey switch {"WIN"=>"outcome-win","DRAW"=>"outcome-draw",_=>"outcome-loss"};
string ReceiptSummary=>string.IsNullOrWhiteSpace(Receipt?.Summary)?T("Match complete","Матч завершён"):T(UiEnglish.Text(Receipt.Summary,"Match complete"));
// This child rerenders independently while the reward counters animate.
// Resolve language here so a parent localization pass never races the render.
static string T(string text,string russianFallback=null)
{
if(!GamePreferences.Russian)return text;
string translated=UiRussian.Translate(text);
return translated==text && russianFallback!=null?russianFallback:translated;
}
float RewardProgress=>1-MathF.Pow(1-Math.Clamp((Time.Now-rewardsAt)/.65f,0,1),3);
int CoinsShown=>(int)MathF.Round((Receipt?.Coins??0)*RewardProgress);
int CupTokensShown=>(int)MathF.Round((Receipt?.CupTokens??0)*RewardProgress);
(string Name,int Home,int Away,string Suffix)[] MatchStats
{
get
{
var m=Game.Match;float possession=m.Possession[0]+m.Possession[1];
int home=possession>0?(int)MathF.Round(m.Possession[0]*100/possession):50;
int Accuracy(int team)=>m.Passes[team]>0?(int)MathF.Round(m.Completed[team]*100f/m.Passes[team]):0;
return new[]{
("Possession",home,100-home,"%"),
("Shots",m.Shots[0],m.Shots[1],""),
("Shots on target",m.Goals[0]+m.Saves[1],m.Goals[1]+m.Saves[0],""),
("Shots off target",m.ShotsWide[0]+m.ShotsOver[0],m.ShotsWide[1]+m.ShotsOver[1],""),
("Passes",m.Passes[0],m.Passes[1],""),
("Pass accuracy",Accuracy(0),Accuracy(1),"%"),
("Through balls",m.ThroughBalls[0],m.ThroughBalls[1],""),
("Wall passes",m.WallPassesCompleted[0],m.WallPassesCompleted[1],""),
("Third-man combinations",m.ThirdManPassesCompleted[0],m.ThirdManPassesCompleted[1],""),
("Coordinated runs",m.CoordinatedRuns[0],m.CoordinatedRuns[1],""),
("Dribbles won",m.DribblesWonByTeam[0],m.DribblesWonByTeam[1],""),
("Possessions lost",m.PossessionLosses[0],m.PossessionLosses[1],""),
("Corners",m.Corners[0],m.Corners[1],""),
("Set-piece shots",m.FreeKickShots[0],m.FreeKickShots[1],""),
("Set-piece crosses",m.FreeKickCrosses[0]+m.CornerNear[0]+m.CornerFar[0],m.FreeKickCrosses[1]+m.CornerNear[1]+m.CornerFar[1],""),
("Short set pieces",m.FreeKickShort[0]+m.CornerShort[0],m.FreeKickShort[1]+m.CornerShort[1],""),
("Penalties awarded",m.PenaltiesAwarded[0],m.PenaltiesAwarded[1],""),
("Tackles",m.Tackles[0],m.Tackles[1],""),
("Saves",m.Saves[0],m.Saves[1],""),
("Fouls",m.Fouls[0],m.Fouls[1],""),
("Offsides",m.Offsides[0],m.Offsides[1],""),
("Yellow cards",m.YellowCards[0],m.YellowCards[1],""),
("Red cards",m.RedCards[0],m.RedCards[1],"")
};
}
}
static string StatWidth(int home,int away)=>FormattableString.Invariant($"width:{(home+away>0?home*100f/(home+away):50):0.#}%;");
protected override int BuildHash()=>HashCode.Combine(Ready,Rewards,Receipt,Game.Match.Goals[0],Game.Match.Goals[1],CoinsShown,CupTokensShown,GamePreferences.Revision)^HashCode.Combine(Game.AwaitingCareerRoundResults,Game.CareerRoundCalculationFailed,Game.CanRetryCareerRoundResults,Game.FinalCupVictoryMatch);
}