Forfeit = 2x coin loss + 0 XP (no kot); end-of-game roster + add friend
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 21s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m0s
CI/CD / Deploy - local stack (db + server + web) (push) Failing after 0s

Forfeit penalty reworked (client + server gamification, in sync):
- Surrendering team loses DOUBLE the entry coins; winner takes the stake.
- Forfeiter earns NO XP. No kot is applied or mentioned anymore.
- MatchSummary/Dto carry a `forfeit` flag; GameRoom.FinalizeForfeit →
  ApplyRewardsAsync(team) with Forfeit=true (dropped the kot path).
- Forfeit confirm dialogs now alert the real penalty (double coins, no XP).

End-of-game roster: SeatPlayerDto/ServerSeatPlayer + game-store SeatPlayer gain
userId/isBot. New <MatchPlayersList> lists everyone at the table on the final
screen (PostMatchRewardsModal + AI MatchOverlay) with a tactile "Add" button to
send a friend request to real (non-bot, non-self) players ("Sent" after).

Verified: tsc + sim + dotnet + next build clean; stack rebuilt :1500/:1505.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-05 10:40:14 +03:30
parent 6bbdbac23b
commit b739b503eb
13 changed files with 127 additions and 19 deletions
+2 -1
View File
@@ -126,6 +126,7 @@ for (let i = 0; i < M; i++) {
shutout: won && i % 8 === 0,
hakemRounds: i % 3,
roundsWon: won ? 7 : i % 7,
forfeit: false,
};
const before = profile;
const { profile: after, reward } = applyMatchResult(before, summary, 1000);
@@ -152,7 +153,7 @@ for (let i = 0; i < M; i++) {
{
const r = applyMatchResult(baseProfile(), {
ranked: false, stake: 0, won: true, kotFor: false, kotAgainst: false,
tricksWon: 7, rounds: 7, trump: null, shutout: false, hakemRounds: 0, roundsWon: 7,
tricksWon: 7, rounds: 7, trump: null, shutout: false, hakemRounds: 0, roundsWon: 7, forfeit: false,
}, 1000);
assert(r.reward.ratingDelta === 0, "casual match must not change rating");
}