Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c64749267 |
@@ -35,9 +35,6 @@
|
||||
<div id="seatsLayer"></div>
|
||||
</div>
|
||||
<p id="tableHint" class="tableHint"></p>
|
||||
<p class="tableHintActions">
|
||||
<button type="button" id="openRulingsBtn" class="linkBtn">Common rulings</button>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<aside id="holdemSidebar">
|
||||
@@ -182,7 +179,6 @@
|
||||
<span>Stack</span>
|
||||
<input type="number" class="stackInput" min="0" step="1" placeholder="table default" />
|
||||
</label>
|
||||
<div class="seatBuyIns" hidden></div>
|
||||
<div class="seatContribution">
|
||||
<div class="chipCounts"></div>
|
||||
<label class="fieldRow amountOverrideRow">
|
||||
@@ -239,73 +235,6 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div id="addChipsOverlay" hidden>
|
||||
<div id="addChipsSheet" role="dialog" aria-labelledby="addChipsTitle">
|
||||
<div class="seatSheetGrip" aria-hidden="true"></div>
|
||||
<div class="addChipsHeader">
|
||||
<h2 id="addChipsTitle"></h2>
|
||||
<span id="addChipsSubtitle"></span>
|
||||
</div>
|
||||
<div id="addChipsQuick"></div>
|
||||
<div class="addChipsEntry">
|
||||
<span class="addChipsCurrency">$</span>
|
||||
<input type="text" id="addChipsInput" inputmode="decimal" autocomplete="off" aria-label="Amount to add" />
|
||||
</div>
|
||||
<div class="addChipsActions">
|
||||
<button id="addChipsConfirmBtn" class="holdemBtn holdemBtnAccent" type="button">Add to stack</button>
|
||||
<button id="addChipsCancelBtn" class="holdemBtn holdemBtnGhost" type="button">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="rulingsOverlay" hidden>
|
||||
<div id="rulingsSheet" role="dialog" aria-labelledby="rulingsTitle">
|
||||
<div class="seatSheetGrip" aria-hidden="true"></div>
|
||||
<div class="rulingsHeader">
|
||||
<h2 id="rulingsTitle">Common rulings</h2>
|
||||
<button id="closeRulingsBtn" class="holdemBtn holdemBtnSmall holdemBtnGhost" type="button">Done</button>
|
||||
</div>
|
||||
|
||||
<p class="rulingsIntro">
|
||||
The conventions most rooms follow, for the calls that come up mid-hand.
|
||||
Your house rules always win — and settle a dispute before the next hand,
|
||||
not during it.
|
||||
</p>
|
||||
|
||||
<section class="ruling">
|
||||
<h3>Redeal it — misdeal</h3>
|
||||
<ul>
|
||||
<li>The first card goes to the wrong seat.</li>
|
||||
<li>A seat entitled to a hand gets dealt out, or a seat that isn't entitled gets dealt in.</li>
|
||||
<li>Two or more boxed cards turn up on the initial deal.</li>
|
||||
<li>Either of the first two cards is exposed by dealer error.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="ruling">
|
||||
<h3>A board card turned too early</h3>
|
||||
<p>
|
||||
If the fourth board card gets turned before the betting round is finished,
|
||||
that card is out of play for the round. Finish the betting, then burn and
|
||||
turn what would have been the fifth card in the fourth card's place.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="ruling">
|
||||
<h3>Acting out of turn</h3>
|
||||
<p>
|
||||
A one-off is usually just backed up if no one has acted behind them.
|
||||
Doing it repeatedly is what earns a penalty.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<p class="rulingsSource">
|
||||
Follows the Tournament Directors Association rules, which most rooms and
|
||||
home games take their lead from.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="seatMenuOverlay" hidden>
|
||||
<div id="seatMenuSheet" role="dialog" aria-labelledby="seatMenuTitle">
|
||||
<div class="seatSheetGrip" aria-hidden="true"></div>
|
||||
@@ -368,7 +297,6 @@
|
||||
<script src="~/js/casino/holdem/render.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/cardPicker.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/seatMenu.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/addChips.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/betting.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/actionBar.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/shortcuts.js?v=@ViewData["cssVersion"]"></script>
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
<p class="splitSubtitle">Chop a pot without setting up a table.</p>
|
||||
</header>
|
||||
|
||||
<div id="modeToggle" class="chipRow" role="group" aria-label="How the money went in">
|
||||
<button type="button" id="modeEvenBtn" class="choiceChip selected">Everyone matched</button>
|
||||
<button type="button" id="modeUnevenBtn" class="choiceChip">Someone's all-in</button>
|
||||
</div>
|
||||
|
||||
<div id="splitResult" aria-live="polite">
|
||||
<div id="splitResultLabel">Each player gets</div>
|
||||
<div id="splitResultAmount">$0.00</div>
|
||||
@@ -18,7 +23,18 @@
|
||||
<div id="splitDustNote" hidden></div>
|
||||
</div>
|
||||
|
||||
<section class="splitField">
|
||||
<div id="unevenResult" hidden aria-live="polite">
|
||||
<div id="unevenPots"></div>
|
||||
<p id="unevenEmpty" class="unevenEmpty">Enter what each player put in.</p>
|
||||
</div>
|
||||
|
||||
<section class="splitField unevenOnly" hidden>
|
||||
<span class="splitLabel">What each player put in</span>
|
||||
<div id="unevenRows"></div>
|
||||
<button type="button" id="addPlayerBtn" class="splitBtn splitBtnGhost">+ Add player</button>
|
||||
</section>
|
||||
|
||||
<section class="splitField evenOnly">
|
||||
<label for="potInput" class="splitLabel">Pot</label>
|
||||
<div class="potInputWrap">
|
||||
<span class="potCurrency">$</span>
|
||||
@@ -28,12 +44,12 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="splitField">
|
||||
<section class="splitField evenOnly">
|
||||
<span class="splitLabel" id="waysLabel">Split between</span>
|
||||
<div id="waysChoices" class="chipRow" role="group" aria-labelledby="waysLabel"></div>
|
||||
</section>
|
||||
|
||||
<section class="splitField">
|
||||
<section class="splitField evenOnly">
|
||||
<span class="splitLabel" id="chipLabel">Smallest chip in play</span>
|
||||
<div id="chipChoices" class="chipRow" role="group" aria-labelledby="chipLabel"></div>
|
||||
</section>
|
||||
@@ -43,12 +59,30 @@
|
||||
<a href="/casino/texasholdem" class="splitBtn splitBtnGhost">Full dealer table →</a>
|
||||
</div>
|
||||
|
||||
<p class="splitFootnote">
|
||||
Uneven pots — someone all-in for less — need the side-pot walkthrough on the
|
||||
<a href="/casino/texasholdem">full table</a>.
|
||||
<p class="splitFootnote evenOnly">
|
||||
If somebody was all-in for less than the others, switch to
|
||||
<strong>Someone's all-in</strong> above.
|
||||
</p>
|
||||
|
||||
<p class="splitFootnote unevenOnly" hidden>
|
||||
Pots are listed with who can win each. Award them by hand strength, best hand
|
||||
first. Nothing here is saved — the <a href="/casino/texasholdem">full table</a>
|
||||
keeps a log.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<template id="unevenRowTemplate">
|
||||
<div class="unevenRow">
|
||||
<span class="unevenRowLabel"></span>
|
||||
<div class="unevenAmountWrap">
|
||||
<span class="unevenCurrency">$</span>
|
||||
<input type="text" class="unevenAmount" inputmode="decimal" autocomplete="off" placeholder="0" />
|
||||
</div>
|
||||
<button type="button" class="unevenFoldBtn" aria-pressed="false">Folded</button>
|
||||
<button type="button" class="unevenRemoveBtn" aria-label="Remove player">✕</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@section Styles {
|
||||
<link href="/css/casino/quicksplit.css?v=@ViewData["cssVersion"]" rel="stylesheet" type="text/css" />
|
||||
}
|
||||
@@ -56,5 +90,6 @@
|
||||
@section Scripts {
|
||||
<script src="~/js/casino/holdem/money.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/splitCalculator.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/potCalculator.js?v=@ViewData["cssVersion"]"></script>
|
||||
<script src="~/js/casino/holdem/quickSplit.js?v=@ViewData["cssVersion"]"></script>
|
||||
}
|
||||
|
||||
@@ -585,260 +585,6 @@ body {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* ---------- Add chips ---------- */
|
||||
|
||||
.seatBuyIns {
|
||||
margin-top: -0.3rem;
|
||||
color: #9a9a9a;
|
||||
font-size: 0.75rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
#addChipsOverlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.72);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
z-index: 98;
|
||||
}
|
||||
|
||||
#addChipsOverlay[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#addChipsSheet {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
background: linear-gradient(180deg, #242424, #1a1a1a);
|
||||
border: 1px solid #3a3a3a;
|
||||
border-bottom: none;
|
||||
border-radius: 16px 16px 0 0;
|
||||
padding: 0.35rem 1rem calc(1.2rem + env(safe-area-inset-bottom, 0px));
|
||||
box-shadow: 0 -14px 40px rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
.addChipsHeader {
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
.addChipsHeader h2 {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
#addChipsSubtitle {
|
||||
color: #9a9a9a;
|
||||
font-size: 0.78rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
#addChipsQuick {
|
||||
display: flex;
|
||||
gap: 0.45rem;
|
||||
margin-bottom: 0.7rem;
|
||||
}
|
||||
|
||||
.addChipsQuickBtn {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.1rem;
|
||||
min-height: 52px;
|
||||
border-radius: 11px;
|
||||
border: 1px solid #3a3a3a;
|
||||
background: linear-gradient(180deg, #2e2e2e, #232323);
|
||||
color: #ddd;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.addChipsQuickBtn.selected {
|
||||
border-color: #d8b46a;
|
||||
background: linear-gradient(180deg, #3a2f18, #241d0f);
|
||||
color: #f0d9a8;
|
||||
}
|
||||
|
||||
.addChipsQuickLabel {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.addChipsQuickAmount {
|
||||
font-size: 0.7rem;
|
||||
color: #a8a8a8;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.addChipsQuickBtn.selected .addChipsQuickAmount {
|
||||
color: #d8b46a;
|
||||
}
|
||||
|
||||
.addChipsEntry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
background: #141414;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 11px;
|
||||
padding: 0.2rem 0.8rem;
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
|
||||
.addChipsEntry:focus-within {
|
||||
border-color: #d8b46a;
|
||||
}
|
||||
|
||||
.addChipsCurrency {
|
||||
color: #777;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
#addChipsInput {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: #f2f2f2;
|
||||
font-family: inherit;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
font-variant-numeric: tabular-nums;
|
||||
padding: 0.4rem 0;
|
||||
}
|
||||
|
||||
.addChipsActions {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.addChipsActions .holdemBtn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
/* ---------- Rulings reference ---------- */
|
||||
|
||||
.tableHintActions {
|
||||
margin: 0.35rem 0 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.linkBtn {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
color: #a9782f;
|
||||
font-family: inherit;
|
||||
font-size: 0.78rem;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.linkBtn:hover {
|
||||
color: #d8b46a;
|
||||
}
|
||||
|
||||
#rulingsOverlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.72);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
z-index: 97;
|
||||
}
|
||||
|
||||
#rulingsOverlay[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#rulingsSheet {
|
||||
width: 100%;
|
||||
max-width: 460px;
|
||||
max-height: 86vh;
|
||||
overflow-y: auto;
|
||||
background: linear-gradient(180deg, #242424, #1a1a1a);
|
||||
border: 1px solid #3a3a3a;
|
||||
border-bottom: none;
|
||||
border-radius: 16px 16px 0 0;
|
||||
padding: 0.35rem 1.1rem calc(1.2rem + env(safe-area-inset-bottom, 0px));
|
||||
box-shadow: 0 -14px 40px rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
.rulingsHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.rulingsHeader h2 {
|
||||
flex: 1;
|
||||
margin: 0;
|
||||
font-size: 1.05rem;
|
||||
font-weight: 500;
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
.rulingsIntro {
|
||||
margin: 0 0 1rem;
|
||||
color: #9a9a9a;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.ruling {
|
||||
margin-bottom: 1rem;
|
||||
padding-left: 0.7rem;
|
||||
border-left: 2px solid rgba(216, 180, 106, 0.4);
|
||||
}
|
||||
|
||||
.ruling h3 {
|
||||
margin: 0 0 0.35rem;
|
||||
color: #d8b46a;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
.ruling p,
|
||||
.ruling li {
|
||||
color: #c4c4c4;
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.ruling p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ruling ul {
|
||||
margin: 0;
|
||||
padding-left: 1.1rem;
|
||||
}
|
||||
|
||||
.ruling li + li {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.rulingsSource {
|
||||
margin: 0;
|
||||
padding-top: 0.6rem;
|
||||
border-top: 1px solid #2c2c2c;
|
||||
color: #7a7a7a;
|
||||
font-size: 0.72rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
/* ---------- Seat long-press menu ---------- */
|
||||
|
||||
/* Held down, before the menu opens — the only feedback that a press is being
|
||||
@@ -1962,75 +1708,20 @@ body.hasActionBar #toastHost {
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
/* This is the screen where the money gets decided, so it holds the same 44px+
|
||||
targets as the rest of the tool rather than the smallest ones in it. Picking the
|
||||
wrong winner is the one mistake here that costs somebody real money. */
|
||||
.potWizardChoice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.7rem;
|
||||
min-height: 56px;
|
||||
gap: 0.5rem;
|
||||
background: #141414;
|
||||
border: 1px solid #333;
|
||||
border-radius: 10px;
|
||||
padding: 0.6rem 0.8rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 0.7rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
transition: border-color 0.12s ease, background 0.12s ease;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.potWizardChoice:hover {
|
||||
border-color: #555;
|
||||
background: #191919;
|
||||
}
|
||||
|
||||
.potWizardChoice input {
|
||||
flex: none;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
accent-color: #1e8449;
|
||||
}
|
||||
|
||||
/* Selected has to be obvious at a glance — a dealer confirms this with players
|
||||
watching, and a checkbox alone is easy to misread across a table. */
|
||||
.potWizardChoice.chosen {
|
||||
border-color: #1e8449;
|
||||
background: linear-gradient(180deg, #16301f, #12241a);
|
||||
}
|
||||
|
||||
.potWizardChoice.chosen .potWizardChoiceName {
|
||||
color: #d6ffe0;
|
||||
}
|
||||
|
||||
.potWizardChoiceText {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.1rem;
|
||||
}
|
||||
|
||||
.potWizardChoiceName {
|
||||
color: #f0f0f0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.potWizardChoiceUpTo {
|
||||
color: #9a9a9a;
|
||||
font-size: 0.76rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.potWizardChoiceCards {
|
||||
flex: none;
|
||||
font-family: var(--font-mono, monospace);
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.potWizardChoiceCards .cardRed {
|
||||
color: #ff6b6b;
|
||||
}
|
||||
|
||||
.potWizardSummary ul {
|
||||
@@ -2051,37 +1742,6 @@ body.hasActionBar #toastHost {
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
/* Every button in this modal is one a dealer presses with players waiting. */
|
||||
#potWizardBody .holdemBtn {
|
||||
min-height: 48px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* The confirm is the whole point of the step, so it gets the whole width rather
|
||||
than being sized to the length of its own label. */
|
||||
.potWizardRound > .holdemBtn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.potWizardActions .holdemBtn {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.potWizardSummary li {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
/* Stacked, with the action that ends the hand furthest from a stray thumb. */
|
||||
.potWizardActions {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
.potWizardChoice {
|
||||
min-height: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
#holdemLayout {
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
@@ -45,6 +45,171 @@ body {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
/* ---------- Mode toggle ---------- */
|
||||
|
||||
#modeToggle {
|
||||
margin-bottom: 1.1rem;
|
||||
}
|
||||
|
||||
/* ---------- Uneven amounts ---------- */
|
||||
|
||||
#unevenRows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.45rem;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.unevenRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.unevenRowLabel {
|
||||
flex: none;
|
||||
width: 2rem;
|
||||
color: #8f8f8f;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.unevenAmountWrap {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
background: #141414;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 10px;
|
||||
padding: 0 0.6rem;
|
||||
}
|
||||
|
||||
.unevenAmountWrap:focus-within {
|
||||
border-color: #d8b46a;
|
||||
}
|
||||
|
||||
.unevenCurrency {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.unevenAmount {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
color: #f2f2f2;
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
padding: 0.6rem 0;
|
||||
}
|
||||
|
||||
.unevenFoldBtn {
|
||||
flex: none;
|
||||
min-height: 44px;
|
||||
padding: 0 0.6rem;
|
||||
border-radius: 9px;
|
||||
border: 1px solid #3a3a3a;
|
||||
background: #232323;
|
||||
color: #8f8f8f;
|
||||
font-family: inherit;
|
||||
font-size: 0.72rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.unevenFoldBtn.selected {
|
||||
background: linear-gradient(180deg, #3d1f1f, #2c1515);
|
||||
border-color: #5b2626;
|
||||
color: #ffd6d6;
|
||||
}
|
||||
|
||||
.unevenRemoveBtn {
|
||||
flex: none;
|
||||
width: 30px;
|
||||
height: 44px;
|
||||
border: none;
|
||||
background: none;
|
||||
color: #6a6a6a;
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.unevenRemoveBtn:disabled {
|
||||
opacity: 0.3;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
#unevenResult {
|
||||
background: linear-gradient(160deg, #1f2a21, #161c17);
|
||||
border: 1px solid #2c3a2f;
|
||||
border-radius: 14px;
|
||||
padding: 0.9rem 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
#unevenResult[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.unevenPot {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.6rem;
|
||||
padding: 0.3rem 0;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.unevenPot + .unevenPot {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.unevenPotLabel {
|
||||
flex: none;
|
||||
color: #d8b46a;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.unevenPotAmount {
|
||||
flex: none;
|
||||
color: #f2f2f2;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.unevenPotWho {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
text-align: right;
|
||||
color: #9a9a9a;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.unevenPotReturn .unevenPotLabel,
|
||||
.unevenPotReturn .unevenPotAmount {
|
||||
color: #9a9a9a;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.unevenPotTotal {
|
||||
margin-top: 0.15rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.14) !important;
|
||||
}
|
||||
|
||||
.unevenPotTotal .unevenPotLabel {
|
||||
color: #8f9d92;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.unevenEmpty {
|
||||
margin: 0;
|
||||
color: #8f9d92;
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
/* ---------- The answer ---------- */
|
||||
|
||||
#splitResult {
|
||||
@@ -104,6 +269,12 @@ body {
|
||||
margin-bottom: 1.35rem;
|
||||
}
|
||||
|
||||
/* A `display` declaration outranks the browser's own [hidden] rule, so anything
|
||||
given one has to opt back out explicitly or toggling `hidden` does nothing. */
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.splitLabel {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
// "Add chips" — a rebuy, a top-up, or the first buy-in of the night.
|
||||
//
|
||||
// Quick amounts come off the table's starting stack, because a rebuy is almost
|
||||
// always one buy-in, sometimes half or two. The keypad is there for the times it
|
||||
// isn't. Recorded as cash in as well as chips, so at the end of the night the
|
||||
// dealer can say what each player actually handed over.
|
||||
const AddChips = {
|
||||
state: null,
|
||||
onConfirm: null,
|
||||
seatIndex: null,
|
||||
draft: "",
|
||||
|
||||
open(state, seatIndex, onConfirm) {
|
||||
this.state = state;
|
||||
this.seatIndex = seatIndex;
|
||||
this.onConfirm = onConfirm;
|
||||
this.draft = String(this.baseAmount());
|
||||
this.render();
|
||||
document.getElementById("addChipsOverlay").hidden = false;
|
||||
},
|
||||
|
||||
close() {
|
||||
document.getElementById("addChipsOverlay").hidden = true;
|
||||
},
|
||||
|
||||
// The table's starting stack if there is one, otherwise something sane to nudge
|
||||
// rather than an empty box.
|
||||
baseAmount() {
|
||||
const configured = Number(this.state.defaultStack);
|
||||
if (!Number.isNaN(configured) && configured > 0) return configured;
|
||||
const bb = Number(this.state.bigBlind) || 0;
|
||||
return bb > 0 ? bb * 100 : 100;
|
||||
},
|
||||
|
||||
quickAmounts() {
|
||||
const base = this.baseAmount();
|
||||
return [
|
||||
{ label: "½ buy-in", value: Math.round(base / 2 * 100) / 100 },
|
||||
{ label: "Buy-in", value: base },
|
||||
{ label: "2 buy-ins", value: base * 2 },
|
||||
];
|
||||
},
|
||||
|
||||
render() {
|
||||
const player = this.state.seats[this.seatIndex];
|
||||
document.getElementById("addChipsTitle").textContent =
|
||||
`Add chips — ${HoldemState.displayName(player, this.seatIndex)}`;
|
||||
|
||||
const stack = Betting.stackOf(this.state, player);
|
||||
const boughtIn = Number(player.buyIns) || 0;
|
||||
document.getElementById("addChipsSubtitle").textContent = boughtIn > 0
|
||||
? `${Money.format(stack)} in front · ${Money.format(boughtIn)} in so far`
|
||||
: `${Money.format(stack)} in front`;
|
||||
|
||||
const quick = document.getElementById("addChipsQuick");
|
||||
quick.innerHTML = "";
|
||||
this.quickAmounts().forEach(option => {
|
||||
const btn = document.createElement("button");
|
||||
btn.type = "button";
|
||||
btn.className = "addChipsQuickBtn";
|
||||
btn.classList.toggle("selected", Number(this.draft) === option.value);
|
||||
|
||||
const label = document.createElement("span");
|
||||
label.className = "addChipsQuickLabel";
|
||||
label.textContent = option.label;
|
||||
const amount = document.createElement("span");
|
||||
amount.className = "addChipsQuickAmount";
|
||||
amount.textContent = Money.format(option.value);
|
||||
|
||||
btn.appendChild(label);
|
||||
btn.appendChild(amount);
|
||||
btn.addEventListener("click", () => {
|
||||
this.draft = String(option.value);
|
||||
this.render();
|
||||
});
|
||||
quick.appendChild(btn);
|
||||
});
|
||||
|
||||
const input = document.getElementById("addChipsInput");
|
||||
input.value = this.draft;
|
||||
},
|
||||
|
||||
confirm() {
|
||||
const amount = Math.max(0, Number(document.getElementById("addChipsInput").value) || 0);
|
||||
this.close();
|
||||
if (amount > 0) this.onConfirm(this.seatIndex, Math.round(amount * 100) / 100);
|
||||
},
|
||||
};
|
||||
|
||||
if (typeof module !== "undefined" && module.exports) {
|
||||
module.exports = AddChips;
|
||||
}
|
||||
@@ -35,19 +35,9 @@ const HandHistoryExport = {
|
||||
if (standings.length > 0) {
|
||||
rows.push([]);
|
||||
rows.push(["Session Standings"]);
|
||||
// Bought in and chips now are what a cash-out is settled from; paid in and
|
||||
// won describe the hands. Both belong in the file the dealer hands over.
|
||||
rows.push(["Player", "Paid In", "Won", "Net", "Bought In", "Chips Now", "Up/Down"]);
|
||||
rows.push(["Player", "Paid In", "Won", "Net"]);
|
||||
standings.forEach(row => {
|
||||
rows.push([
|
||||
row.name,
|
||||
Money.format(row.in),
|
||||
Money.format(row.won),
|
||||
Money.formatSigned(row.net),
|
||||
Money.format(row.boughtIn || 0),
|
||||
Money.format(row.chipsNow || 0),
|
||||
Money.formatSigned(row.cashPosition || 0),
|
||||
]);
|
||||
rows.push([row.name, Money.format(row.in), Money.format(row.won), Money.formatSigned(row.net)]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -57,15 +57,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
},
|
||||
makeDealer: index => seatAction(index, `Button on ${nameOf(index)}.`, () => { state.dealerSeatIndex = index; }),
|
||||
editSeat: index => Render.toggleSeatEditor(index),
|
||||
|
||||
addChips: index => AddChips.open(state, index, (seatIndex, amount) => {
|
||||
seatAction(seatIndex, `${nameOf(seatIndex)} added ${Money.format(amount)}.`, player => {
|
||||
// Chips in front and cash in are different questions — the stack moves
|
||||
// every hand, what they've handed over only moves when they buy.
|
||||
player.stack = Math.round((Betting.stackOf(state, player) + amount) * 100) / 100;
|
||||
player.buyIns = Math.round(((Number(player.buyIns) || 0) + amount) * 100) / 100;
|
||||
});
|
||||
}),
|
||||
};
|
||||
|
||||
Render.mount(state, hooks);
|
||||
@@ -269,26 +260,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
document.getElementById("closeSeatEditorBtn").addEventListener("click", () => Render.closeSeatEditor());
|
||||
|
||||
document.getElementById("addChipsConfirmBtn").addEventListener("click", () => AddChips.confirm());
|
||||
document.getElementById("addChipsCancelBtn").addEventListener("click", () => AddChips.close());
|
||||
document.getElementById("addChipsOverlay").addEventListener("click", e => {
|
||||
if (e.target.id === "addChipsOverlay") AddChips.close();
|
||||
});
|
||||
document.getElementById("addChipsInput").addEventListener("keydown", e => {
|
||||
if (e.key === "Enter") AddChips.confirm();
|
||||
});
|
||||
|
||||
const rulingsOverlay = document.getElementById("rulingsOverlay");
|
||||
const closeRulings = () => { rulingsOverlay.hidden = true; };
|
||||
document.getElementById("openRulingsBtn").addEventListener("click", () => { rulingsOverlay.hidden = false; });
|
||||
document.getElementById("closeRulingsBtn").addEventListener("click", closeRulings);
|
||||
rulingsOverlay.addEventListener("click", e => {
|
||||
if (e.target === rulingsOverlay) closeRulings();
|
||||
});
|
||||
document.addEventListener("keydown", e => {
|
||||
if (e.key === "Escape" && !rulingsOverlay.hidden) closeRulings();
|
||||
});
|
||||
|
||||
document.getElementById("seatMenuCancelBtn").addEventListener("click", () => SeatMenu.close());
|
||||
document.getElementById("seatMenuOverlay").addEventListener("click", e => {
|
||||
if (e.target.id === "seatMenuOverlay") SeatMenu.close();
|
||||
|
||||
@@ -18,14 +18,6 @@ const PotWizard = {
|
||||
this.playerLabelById = new Map(
|
||||
players.map(p => [p.id, this.labelFor(p, state.seats.indexOf(p))])
|
||||
);
|
||||
// The label carries name and cards together for the log and the payout lines;
|
||||
// the choice rows want them separately so each can be styled and read on its own.
|
||||
this.nameById = new Map(
|
||||
players.map(p => [p.id, HoldemState.displayName(p, state.seats.indexOf(p))])
|
||||
);
|
||||
this.cardsById = new Map(
|
||||
players.map(p => [p.id, (p.cards || []).filter(Boolean)])
|
||||
);
|
||||
const contributions = players.map(p => ({
|
||||
id: p.id,
|
||||
contribution: HoldemState.computeContribution(p, state.chipLegend, state.basePotAmount),
|
||||
@@ -113,46 +105,13 @@ const PotWizard = {
|
||||
contenders.forEach(c => {
|
||||
const label = document.createElement("label");
|
||||
label.className = "potWizardChoice";
|
||||
|
||||
const checkbox = document.createElement("input");
|
||||
checkbox.type = "checkbox";
|
||||
checkbox.value = c.id;
|
||||
// The row is the target, not the box — so the row has to look chosen too.
|
||||
checkbox.addEventListener("change", () => {
|
||||
label.classList.toggle("chosen", checkbox.checked);
|
||||
});
|
||||
label.appendChild(checkbox);
|
||||
|
||||
const text = document.createElement("span");
|
||||
text.className = "potWizardChoiceText";
|
||||
|
||||
const name = document.createElement("span");
|
||||
name.className = "potWizardChoiceName";
|
||||
name.textContent = this.nameById.get(c.id);
|
||||
text.appendChild(name);
|
||||
|
||||
const upTo = document.createElement("span");
|
||||
upTo.className = "potWizardChoiceUpTo";
|
||||
upTo.textContent = `up to ${Money.format(c.remaining)}`;
|
||||
text.appendChild(upTo);
|
||||
text.textContent = `${this.playerLabelById.get(c.id)} — up to ${Money.format(c.remaining)}`;
|
||||
label.appendChild(checkbox);
|
||||
label.appendChild(text);
|
||||
|
||||
// Cards sit apart from the name rather than inside it, so a dealer reading
|
||||
// a row across the table sees the hand, not a sentence.
|
||||
const cards = this.cardsById.get(c.id) || [];
|
||||
if (cards.length > 0) {
|
||||
const cardsEl = document.createElement("span");
|
||||
cardsEl.className = "potWizardChoiceCards";
|
||||
cards.forEach((card, i) => {
|
||||
if (i > 0) cardsEl.appendChild(document.createTextNode(" "));
|
||||
const span = document.createElement("span");
|
||||
if (/[HD]$/i.test(card)) span.className = "cardRed";
|
||||
span.textContent = Render.formatCard(card);
|
||||
cardsEl.appendChild(span);
|
||||
});
|
||||
label.appendChild(cardsEl);
|
||||
}
|
||||
|
||||
choices.appendChild(label);
|
||||
});
|
||||
round.appendChild(choices);
|
||||
|
||||
@@ -15,12 +15,28 @@ const QuickSplit = {
|
||||
ways: 2,
|
||||
chip: 1,
|
||||
|
||||
// "even" is the common case — one pot, everyone matched. "uneven" is the one this
|
||||
// screen used to send people back to the full table for: somebody all-in for less,
|
||||
// so the money splits into a main pot and side pots.
|
||||
mode: "even",
|
||||
entries: [],
|
||||
|
||||
mount() {
|
||||
this.potInput = document.getElementById("potInput");
|
||||
this.clearPotBtn = document.getElementById("clearPotBtn");
|
||||
this.entries = [{ amount: "", folded: false }, { amount: "", folded: false }, { amount: "", folded: false }];
|
||||
|
||||
this.renderWayChoices();
|
||||
this.renderChipChoices();
|
||||
this.renderUnevenRows();
|
||||
|
||||
document.getElementById("modeEvenBtn").addEventListener("click", () => this.setMode("even"));
|
||||
document.getElementById("modeUnevenBtn").addEventListener("click", () => this.setMode("uneven"));
|
||||
document.getElementById("addPlayerBtn").addEventListener("click", () => {
|
||||
this.entries.push({ amount: "", folded: false });
|
||||
this.renderUnevenRows();
|
||||
this.update();
|
||||
});
|
||||
|
||||
this.potInput.addEventListener("input", () => {
|
||||
this.sanitizePotInput();
|
||||
@@ -127,7 +143,112 @@ const QuickSplit = {
|
||||
});
|
||||
},
|
||||
|
||||
setMode(mode) {
|
||||
this.mode = mode;
|
||||
document.getElementById("modeEvenBtn").classList.toggle("selected", mode === "even");
|
||||
document.getElementById("modeUnevenBtn").classList.toggle("selected", mode === "uneven");
|
||||
|
||||
document.querySelectorAll(".evenOnly").forEach(el => { el.hidden = mode !== "even"; });
|
||||
document.querySelectorAll(".unevenOnly").forEach(el => { el.hidden = mode !== "uneven"; });
|
||||
document.getElementById("splitResult").hidden = mode !== "even";
|
||||
document.getElementById("unevenResult").hidden = mode !== "uneven";
|
||||
|
||||
this.update();
|
||||
},
|
||||
|
||||
renderUnevenRows() {
|
||||
const host = document.getElementById("unevenRows");
|
||||
const template = document.getElementById("unevenRowTemplate");
|
||||
host.innerHTML = "";
|
||||
|
||||
this.entries.forEach((entry, index) => {
|
||||
const row = template.content.firstElementChild.cloneNode(true);
|
||||
row.querySelector(".unevenRowLabel").textContent = `P${index + 1}`;
|
||||
|
||||
const amount = row.querySelector(".unevenAmount");
|
||||
amount.value = entry.amount;
|
||||
amount.setAttribute("aria-label", `Player ${index + 1} amount`);
|
||||
amount.addEventListener("input", () => {
|
||||
entry.amount = amount.value.replace(/[^0-9.]/g, "").replace(/(\..*)\./g, "$1");
|
||||
if (entry.amount !== amount.value) amount.value = entry.amount;
|
||||
this.update();
|
||||
});
|
||||
|
||||
// Folded money stays in the pot as dead money, but its owner can't win any
|
||||
// of it — which is exactly the distinction that makes side pots tricky.
|
||||
const fold = row.querySelector(".unevenFoldBtn");
|
||||
fold.classList.toggle("selected", entry.folded);
|
||||
fold.setAttribute("aria-pressed", String(entry.folded));
|
||||
fold.addEventListener("click", () => {
|
||||
entry.folded = !entry.folded;
|
||||
this.renderUnevenRows();
|
||||
this.update();
|
||||
});
|
||||
|
||||
const remove = row.querySelector(".unevenRemoveBtn");
|
||||
remove.disabled = this.entries.length <= 2;
|
||||
remove.addEventListener("click", () => {
|
||||
this.entries.splice(index, 1);
|
||||
this.renderUnevenRows();
|
||||
this.update();
|
||||
});
|
||||
|
||||
host.appendChild(row);
|
||||
});
|
||||
},
|
||||
|
||||
updateUneven() {
|
||||
const players = this.entries
|
||||
.map((entry, index) => ({ id: `P${index + 1}`, contribution: Number(entry.amount) || 0, folded: entry.folded }))
|
||||
.filter(p => p.contribution > 0);
|
||||
|
||||
const pots = PotCalculator.layers(players);
|
||||
const returns = PotCalculator.uncalledReturns(players);
|
||||
|
||||
const host = document.getElementById("unevenPots");
|
||||
const empty = document.getElementById("unevenEmpty");
|
||||
host.innerHTML = "";
|
||||
|
||||
if (pots.length === 0 && returns.length === 0) {
|
||||
empty.hidden = false;
|
||||
empty.textContent = players.length === 0
|
||||
? "Enter what each player put in."
|
||||
: "Nobody left who can win — un-fold whoever should take it.";
|
||||
return;
|
||||
}
|
||||
empty.hidden = true;
|
||||
|
||||
const addRow = (label, amount, who, className) => {
|
||||
const row = document.createElement("div");
|
||||
row.className = `unevenPot ${className || ""}`;
|
||||
const name = document.createElement("span");
|
||||
name.className = "unevenPotLabel";
|
||||
name.textContent = label;
|
||||
const value = document.createElement("span");
|
||||
value.className = "unevenPotAmount";
|
||||
value.textContent = Money.format(amount);
|
||||
const eligible = document.createElement("span");
|
||||
eligible.className = "unevenPotWho";
|
||||
eligible.textContent = who;
|
||||
row.appendChild(name);
|
||||
row.appendChild(value);
|
||||
row.appendChild(eligible);
|
||||
host.appendChild(row);
|
||||
};
|
||||
|
||||
pots.forEach(pot => addRow(pot.label, pot.amount, pot.eligible.join(", ")));
|
||||
returns.forEach(ret => addRow("Uncalled", ret.amount, `back to ${ret.id}`, "unevenPotReturn"));
|
||||
|
||||
const total = players.reduce((sum, p) => sum + p.contribution, 0);
|
||||
addRow("On the table", Math.round(total * 100) / 100, "", "unevenPotTotal");
|
||||
},
|
||||
|
||||
update() {
|
||||
if (this.mode === "uneven") {
|
||||
this.updateUneven();
|
||||
return;
|
||||
}
|
||||
|
||||
const potValue = Number(this.potInput.value);
|
||||
const pot = Number.isNaN(potValue) ? 0 : potValue;
|
||||
this.clearPotBtn.hidden = this.potInput.value === "";
|
||||
|
||||
@@ -491,13 +491,6 @@ const Render = {
|
||||
});
|
||||
});
|
||||
|
||||
// What they've handed over tonight, shown next to what's in front of them so a
|
||||
// cash-out is one subtraction rather than a memory test.
|
||||
const boughtIn = Number(player.buyIns) || 0;
|
||||
const boughtInEl = form.querySelector(".seatBuyIns");
|
||||
boughtInEl.textContent = boughtIn > 0 ? `Bought in ${Money.format(boughtIn)}` : "";
|
||||
boughtInEl.hidden = boughtIn <= 0;
|
||||
|
||||
const stackInput = form.querySelector(".stackInput");
|
||||
stackInput.value = player.stack ?? "";
|
||||
stackInput.addEventListener("input", () => {
|
||||
|
||||
@@ -32,10 +32,6 @@ const SeatMenu = {
|
||||
actions.push({ label: "Un-fold", run: () => this.hooks.unfold(index) });
|
||||
}
|
||||
|
||||
// The most common interruption in a cash game, and until now it meant opening
|
||||
// the editor and retyping a stack from memory.
|
||||
actions.push({ label: "Add chips…", run: () => this.hooks.addChips(index) });
|
||||
|
||||
actions.push({
|
||||
label: dealtIn ? "Sit out" : "Deal in",
|
||||
run: () => this.hooks.toggleDealtIn(index),
|
||||
|
||||
@@ -35,7 +35,7 @@ const Shortcuts = {
|
||||
// An overlay owns the keyboard while it's up: the confirm dialog already binds
|
||||
// Enter and Escape, and the card picker and seat menu are modal.
|
||||
overlayOpen() {
|
||||
return ["confirmOverlay", "potWizardOverlay", "cardPickerOverlay", "seatMenuOverlay", "rulingsOverlay", "addChipsOverlay"]
|
||||
return ["confirmOverlay", "potWizardOverlay", "cardPickerOverlay", "seatMenuOverlay"]
|
||||
.some(id => {
|
||||
const el = document.getElementById(id);
|
||||
return el && !el.hidden;
|
||||
|
||||
@@ -31,8 +31,6 @@ const HoldemState = {
|
||||
stack: null,
|
||||
committed: 0,
|
||||
hasActed: false,
|
||||
// Cash handed over tonight, which only moves when they buy chips.
|
||||
buyIns: 0,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -81,7 +79,6 @@ const HoldemState = {
|
||||
if (player.stack === undefined) player.stack = null;
|
||||
if (player.committed === undefined) player.committed = 0;
|
||||
if (player.hasActed === undefined) player.hasActed = false;
|
||||
if (player.buyIns === undefined) player.buyIns = 0;
|
||||
});
|
||||
|
||||
return parsed;
|
||||
@@ -239,32 +236,13 @@ const HoldemState = {
|
||||
});
|
||||
});
|
||||
|
||||
// Cash bought in and chips currently in front don't come from the hand log at
|
||||
// all, so they're read off the seat rather than summed — a rebuy isn't a hand.
|
||||
const seatById = new Map(state.seats.map(p => [p.id, p]));
|
||||
|
||||
return Array.from(totals.values())
|
||||
.map(t => {
|
||||
const seat = seatById.get(t.id);
|
||||
const boughtIn = seat ? Math.round((Number(seat.buyIns) || 0) * 100) / 100 : 0;
|
||||
const chipsNow = seat ? Math.round((Number(seat.stack) || 0) * 100) / 100 : 0;
|
||||
// Chips already pushed into the hand in progress are still this
|
||||
// player's money until it's won. Leaving them out makes the cash
|
||||
// position disagree with the hand log for as long as a hand is open —
|
||||
// and blinds are posted the instant the previous one settles, so that
|
||||
// window is almost always.
|
||||
const inFrontOfThem = seat ? (Number(seat.amountOverride) || 0) + (Number(seat.committed) || 0) : 0;
|
||||
|
||||
return {
|
||||
...t,
|
||||
in: Math.round(t.in * 100) / 100,
|
||||
won: Math.round(t.won * 100) / 100,
|
||||
net: Math.round((t.won - t.in) * 100) / 100,
|
||||
boughtIn,
|
||||
chipsNow,
|
||||
cashPosition: Math.round((chipsNow + inFrontOfThem - boughtIn) * 100) / 100,
|
||||
};
|
||||
})
|
||||
.map(t => ({
|
||||
...t,
|
||||
in: Math.round(t.in * 100) / 100,
|
||||
won: Math.round(t.won * 100) / 100,
|
||||
net: Math.round((t.won - t.in) * 100) / 100,
|
||||
}))
|
||||
.sort((a, b) => b.net - a.net);
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user