Stop telling a brand-new table its players are broke, and give it a way out
Following on from seating the table: a dealer who names six people and hasn't yet
said what a buy-in is gets told
Nobody at the table has chips left. Add a buy-in to deal.
with no buttons on the bar at all. Both halves are wrong for that table. "Left" says
the chips were had and lost, which sends the dealer looking for a rebuy — and a
blocked prompt with nothing to press is a dead end, when the fix is one field in the
sidebar the message never pointed at.
A table where nobody has ever bought in is now told what is actually true, and given
the way out:
Nobody has bought in yet. Set what everyone starts with, or give each seat
their chips. [ Set starting stack ]
The button opens Table Setup, scrolls the starting stack into view and selects it, so
the next thing typed is the answer. A seat with no stack of its own falls back to the
table default, which is why one number is enough to seat everybody's chips at once.
A table that genuinely busted out is a different situation and still says so, with no
starting-stack button — there the fix is a rebuy, not a default.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
This commit is contained in:
@@ -593,10 +593,19 @@ const ActionBar = {
|
|||||||
// thing: "only one player is dealt in" is wrong when four are sitting there
|
// thing: "only one player is dealt in" is wrong when four are sitting there
|
||||||
// and three of them are just out of chips.
|
// and three of them are just out of chips.
|
||||||
const withChips = seated - broke.length;
|
const withChips = seated - broke.length;
|
||||||
|
// "Nobody has chips left" is the wrong story for a table that never had
|
||||||
|
// any. A dealer who has just named six people and not yet said what a
|
||||||
|
// buy-in is gets told their players are busted, which sends them looking
|
||||||
|
// for a rebuy button instead of the one field that fixes it.
|
||||||
|
const nobodyHasEverBoughtIn = this.state.seats.every(p =>
|
||||||
|
!(Number(p.buyIns) > 0) && !(Number(p.stack) > 0));
|
||||||
|
|
||||||
if (broke.length > 0 && withChips < 2) {
|
if (broke.length > 0 && withChips < 2) {
|
||||||
line.textContent = withChips === 1
|
line.textContent = withChips === 1
|
||||||
? `Only ${listNames(Betting.liveSeats(this.state).map(s => s.index).filter(i => !broke.includes(i)))} has chips — ${listNames(broke)} ${broke.length === 1 ? "needs" : "need"} to buy in.`
|
? `Only ${listNames(Betting.liveSeats(this.state).map(s => s.index).filter(i => !broke.includes(i)))} has chips — ${listNames(broke)} ${broke.length === 1 ? "needs" : "need"} to buy in.`
|
||||||
: "Nobody at the table has chips left. Add a buy-in to deal.";
|
: nobodyHasEverBoughtIn
|
||||||
|
? "Nobody has bought in yet. Set what everyone starts with, or give each seat their chips."
|
||||||
|
: "Nobody at the table has chips left. Add a buy-in to deal.";
|
||||||
} else {
|
} else {
|
||||||
line.textContent = seated === 0
|
line.textContent = seated === 0
|
||||||
? "Nobody is dealt in yet. Tap a seat to add a player."
|
? "Nobody is dealt in yet. Tap a seat to add a player."
|
||||||
@@ -605,6 +614,26 @@ const ActionBar = {
|
|||||||
line.classList.add("dealPromptBlocked");
|
line.classList.add("dealPromptBlocked");
|
||||||
wrap.appendChild(line);
|
wrap.appendChild(line);
|
||||||
|
|
||||||
|
// A blocked prompt with nothing to press is a dead end, and this was the
|
||||||
|
// one a first-time dealer hits: six players named, a sentence saying they
|
||||||
|
// have no chips, and no button anywhere on the bar. The starting stack is a
|
||||||
|
// single field in the sidebar and the message never pointed at it.
|
||||||
|
if (nobodyHasEverBoughtIn && seated > 0) {
|
||||||
|
const row = document.createElement("div");
|
||||||
|
row.className = "actionButtons";
|
||||||
|
row.appendChild(this.button("Set starting stack", "actionDeal", () => {
|
||||||
|
const field = document.getElementById("defaultStackInput");
|
||||||
|
if (!field) return;
|
||||||
|
const panel = field.closest("details");
|
||||||
|
if (panel) panel.open = true;
|
||||||
|
field.scrollIntoView({ block: "center", behavior: "smooth" });
|
||||||
|
field.focus();
|
||||||
|
field.select();
|
||||||
|
}));
|
||||||
|
wrap.appendChild(row);
|
||||||
|
return wrap;
|
||||||
|
}
|
||||||
|
|
||||||
// Named seats that aren't in the hand. Naming a chair now seats whoever is
|
// Named seats that aren't in the hand. Naming a chair now seats whoever is
|
||||||
// in it, so reaching this takes something else — a table where everyone was
|
// in it, so reaching this takes something else — a table where everyone was
|
||||||
// sat out, or a save from before that was true — but the way out of it
|
// sat out, or a save from before that was true — but the way out of it
|
||||||
|
|||||||
@@ -132,3 +132,50 @@ describe("the way back from a table where everybody is sat out", () => {
|
|||||||
assert.equal(state.seats.filter(p => p.inHand).length, 1, "empty chairs stay empty");
|
assert.equal(state.seats.filter(p => p.inHand).length, 1, "empty chairs stay empty");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("a table where nobody has bought in", () => {
|
||||||
|
// Different from a table that has busted out, and the difference is the whole
|
||||||
|
// point: one needs a starting stack named, the other needs a rebuy. Telling a
|
||||||
|
// dealer their brand-new players have "no chips left" sends them hunting for the
|
||||||
|
// wrong thing.
|
||||||
|
const neverBoughtIn = state => state.seats.every(p =>
|
||||||
|
!(Number(p.buyIns) > 0) && !(Number(p.stack) > 0));
|
||||||
|
|
||||||
|
test("six freshly named players have never bought in", () => {
|
||||||
|
const state = emptyTable();
|
||||||
|
["Ann", "Ben", "Cal", "Dee", "Eve", "Fay"].forEach((name, i) => {
|
||||||
|
state.seats[i].name = name;
|
||||||
|
state.seats[i].inHand = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(neverBoughtIn(state), true);
|
||||||
|
assert.equal(Betting.blindPreview(state), null, "and there is no hand to deal");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("a table that has busted out is not the same thing", () => {
|
||||||
|
const state = makeTable({ seatCount: 6, seated: [0, 1], stack: 200 });
|
||||||
|
state.seats.forEach(p => { p.buyIns = 200; p.stack = 0; });
|
||||||
|
|
||||||
|
assert.equal(neverBoughtIn(state), false, "they had chips — they lost them");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("one player still holding chips is not a never-bought-in table either", () => {
|
||||||
|
const state = emptyTable();
|
||||||
|
["Ann", "Ben"].forEach((name, i) => { state.seats[i].name = name; state.seats[i].inHand = true; });
|
||||||
|
state.seats[0].stack = 50;
|
||||||
|
|
||||||
|
assert.equal(neverBoughtIn(state), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("naming a starting stack is enough to deal", () => {
|
||||||
|
// The one field the message now points at. A seat with no stack of its own
|
||||||
|
// falls back to the table default, so setting it seats everybody's chips at
|
||||||
|
// once — which is why it's the right thing to send the dealer to.
|
||||||
|
const state = emptyTable();
|
||||||
|
["Ann", "Ben", "Cal"].forEach((name, i) => { state.seats[i].name = name; state.seats[i].inHand = true; });
|
||||||
|
assert.equal(Betting.blindPreview(state), null);
|
||||||
|
|
||||||
|
state.defaultStack = 200;
|
||||||
|
assert.ok(Betting.blindPreview(state), "one number and the table can play");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user