Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 56 additions & 17 deletions src/main/java/net/tfminecraft/games/game/BlackjackGame.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ private static Table stillLive(UUID tableId) {
/** TableManager only offers the shoe for claiming while the table is idle. */
@Override
public boolean tryClaimDealer(Table table, Player player) {
if (table.floatOwner() != null) {
// Only a dealer who is offline still has a float waiting here: anyone online gets theirs
// back when their round ends or they log in. A new dealer would be paying with it.
player.sendMessage(Messages.get("dealer.float_held"));
return true;
}
if (auto(table)) {
if (!inStandRange(table, player)) {
return true;
Expand Down Expand Up @@ -135,6 +141,7 @@ public boolean tryClaimDealer(Table table, Player player) {
}
if (have.equals(player.getUniqueId())) {
table.setDealerId(null);
TableManager.get().returnDealerFloat(table, player);
TableManager.get().persistHouseChange(table);
player.sendMessage(Messages.get("dealer.unset"));
return true;
Expand Down Expand Up @@ -361,22 +368,63 @@ public void onChipIn(Table table, Player player) {

@Override
public void onLeave(Table table, Player player) {
UUID id = player.getUniqueId();
if (table.live()) {
forfeitBox(table, player);
// A dealer can leave as a seat too, when they had their own chips on the felt.
continueWithout(table, id, id.equals(table.dealerId()));
return;
}
TableManager manager = TableManager.get();
int felt = 0;
boolean peel = auto(table) && !table.live() && table.betOpen();
boolean peel = auto(table) && table.betOpen();
if (peel) {
felt = manager.ownedDenars(table, player.getUniqueId());
felt = manager.ownedDenars(table, id);
}
Game.super.onLeave(table, player);
if (peel && felt > 0) {
peelAutoTray(table, felt);
}
onChipIn(table, player);
if (table.live()) {
// A dealer can leave as a seat too, when they had their own chips on the felt.
UUID id = player.getUniqueId();
continueWithout(table, id, id.equals(table.dealerId()));
}

/**
* A box that walks away or logs off once the round has started loses its bet, doubles and
* splits included, exactly as a bust would. Handing it back would let a player see a losing
* hand and leave with the stake.
*/
private void forfeitBox(Table table, Player player) {
UUID owner = player.getUniqueId();
List<PayoutFlight> flights = new ArrayList<>();
collectLoss(table, owner, 0, dealerAtShoe(table), flights, "box forfeited");
WagerEngine.get().forget(table, owner);
// Its hands are lost with the bet, so the settle does not count them again. A live table
// always holds its round, which onSessionStart put there before any card was dealt.
rounds.get(table.getId()).removeIf(hand -> owner.equals(hand.owner));
table.actives().remove(owner);
TableManager.get().flushPiles(table, flights, null);
player.sendMessage(Messages.get("bet.forfeit"));
}

/**
* A losing bet leaves its box: into the house tray on a backed table, and into a private
* dealer's pockets on their own. With that dealer gone from the shoe it goes into the tray they
* stocked, which is handed back to them after the round, rather than onto the floor for anyone
* to pick up. Pass {@code denars} below 1 for the whole box. Returns what left the table.
*/
private static int collectLoss(Table table, UUID owner, int denars, Player dealer,
List<PayoutFlight> flights, String reason) {
if (houseFunded(table) || dealer == null) {
WagerEngine.get().toTray(table, owner, denars, flights, reason);
return 0;
}
return WagerEngine.get().refund(table, owner, dealer, denars, flights, reason + " to dealer").moved();
}

/** The human dealer, while they hold the shoe and are online. */
private static Player dealerAtShoe(Table table) {
UUID dealerId = table.dealerId();
return dealerId != null ? Bukkit.getPlayer(dealerId) : null;
}

@Override
Expand Down Expand Up @@ -1136,8 +1184,7 @@ private void settle(Table table) {
TableManager manager = TableManager.get();
int dealerTotal = bestTotal(table.tablePile(DEALER));
boolean dealerBust = dealerTotal > 21;
UUID dealerId = table.dealerId();
Player dealer = dealerId != null ? Bukkit.getPlayer(dealerId) : null;
Player dealer = dealerAtShoe(table);
Map<UUID, Integer> collect = new HashMap<>();
Map<UUID, Integer> pay = new HashMap<>();
Map<UUID, ItemStack> templates = new HashMap<>();
Expand Down Expand Up @@ -1170,16 +1217,8 @@ private void settle(Table table) {
// Nothing comes into the table during a settle. A dealer or a bank covering a win pays the
// winner directly, so that money is never table money for even an instant.
int wentOut = 0;
// Losing bets leave the box: a private dealer takes them, the house tray keeps them.
for (Map.Entry<UUID, Integer> entry : collect.entrySet()) {
UUID owner = entry.getKey();
if (dealerBacked) {
wentOut += WagerEngine.get()
.refund(table, owner, dealer, entry.getValue(), flights, "loss to dealer")
.moved();
} else {
WagerEngine.get().toTray(table, owner, entry.getValue(), flights, "loss");
}
wentOut += collectLoss(table, entry.getKey(), entry.getValue(), dealer, flights, "loss");
}
// A winning box still holds the coins it staked, so they show what to pay it in.
for (Map.Entry<UUID, Integer> entry : pay.entrySet()) {
Expand Down
11 changes: 9 additions & 2 deletions src/main/java/net/tfminecraft/games/game/DrawGame.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ public void onLeave(Table table, Player player) {
List<UUID> before = new ArrayList<>(table.actives());
boolean live = table.live();
Street street = streets.get(table.getId());
boolean folded = street != null && street.folded.contains(leaver);
if (street != null) {
street.folded.remove(leaver);
street.acted.remove(leaver);
Expand All @@ -286,8 +287,14 @@ public void onLeave(Table table, Player player) {
TableManager.get().refreshLabel(table);
int streetId = table.street();
List<PayoutFlight> flights = new ArrayList<>();
// A leaver gets this street's bet back; earlier streets stay in the pot.
WagerEngine.get().refundStreet(table, leaver, streetId, flights, "player left");
// Earlier streets stay in the pot whatever happens. Before the hand, nothing on the felt has
// been bet against anyone, so it all goes back. Once it is dealt, only the part of this
// street's bet nobody has called goes back, and a folded hand has given up even that.
if (!live) {
WagerEngine.get().refundStreet(table, leaver, streetId, flights, "player left");
} else if (!folded) {
WagerEngine.get().refundUncalled(table, leaver, streetId, flights, "player left");
}
UUID rest = null;
if (table.actives().size() == 1) {
rest = table.actives().iterator().next();
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/net/tfminecraft/games/game/FreePlayGame.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ public boolean allowReturnSelected(Table table, Player player) {
return table != null && !table.live();
}

/**
* The felt is paid out whole, other players' stakes included, so only the table's host may
* do it: whoever put the table down, or whoever holds its shoe.
*/
@Override
public boolean allowManualPotFlush(Table table, Player player) {
return table != null && !table.live();
return table != null && !table.live() && table.hostedBy(player.getUniqueId());
}

@Override
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/net/tfminecraft/games/game/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public interface Game {

/**
* Open table: refund every pile this player owns, then drop them from actives.
* Poker overrides to refund only the current street and pay the last remaining player.
* Poker and draw override to refund only the part of the current street nobody has called
* and pay the last remaining player; blackjack forfeits a box that leaves a round in play.
*/
default void onLeave(Table table, Player player) {
TableManager manager = TableManager.get();
Expand Down
11 changes: 9 additions & 2 deletions src/main/java/net/tfminecraft/games/game/PokerGame.java
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ public void onLeave(Table table, Player player) {
List<UUID> before = new ArrayList<>(table.actives());
boolean live = table.live();
Street street = streets.get(table.getId());
boolean folded = street != null && street.folded.contains(leaver);
if (street != null) {
street.folded.remove(leaver);
street.acted.remove(leaver);
Expand All @@ -250,8 +251,14 @@ public void onLeave(Table table, Player player) {
TableManager.get().refreshLabel(table);
int streetId = table.street();
List<PayoutFlight> flights = new ArrayList<>();
// A leaver gets this street's bet back; earlier streets stay in the pot.
WagerEngine.get().refundStreet(table, leaver, streetId, flights, "player left");
// Earlier streets stay in the pot whatever happens. Before the hand, nothing on the felt has
// been bet against anyone, so it all goes back. Once it is dealt, only the part of this
// street's bet nobody has called goes back, and a folded hand has given up even that.
if (!live) {
WagerEngine.get().refundStreet(table, leaver, streetId, flights, "player left");
} else if (!folded) {
WagerEngine.get().refundUncalled(table, leaver, streetId, flights, "player left");
}
UUID rest = null;
if (table.actives().size() == 1) {
rest = table.actives().iterator().next();
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/net/tfminecraft/games/guild/GuildTables.java
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ public static boolean mayDeal(Table table, Player player) {
return table.ownerPlayer() != null && table.ownerPlayer().equals(player.getUniqueId());
}

/** True for the leader of the guild that owns this table, who is the one who may place and remove it. */
public static boolean leadsOwner(Table table, Player player) {
String guildId = table.ownerGuildId();
return guildId != null && !guildId.isBlank() && isLeader(guildId, player);
}

private static boolean isMember(String guildId, Player player) {
try {
Guild guild = guild(guildId);
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/net/tfminecraft/games/table/Table.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public final class Table {
private ShufflePolicy shufflePolicy = ShufflePolicy.SHOE;
private int smallBlind;
private int bigBlind;
private UUID floatOwner;
private boolean deckConsumed = true;

public Table(UUID id, String gameId, Location origin, float yaw, Deck deck) {
this.id = id;
Expand Down Expand Up @@ -437,6 +439,33 @@ public void setBigBlind(int bigBlind) {
this.bigBlind = Math.max(0, bigBlind);
}

/**
* The player whose own money sits in the tray of a table no house backs, once they are no
* longer at the shoe to take it back. Null while the tray is the current dealer's, or the
* house's.
*/
public UUID floatOwner() {
return floatOwner;
}

public void setFloatOwner(UUID floatOwner) {
this.floatOwner = floatOwner;
}

/** The player who put this table down, or whoever is holding its shoe. */
public boolean hostedBy(UUID playerId) {
return playerId.equals(ownerPlayer) || playerId.equals(dealerId);
}

/** Whether putting this table down used up a deck, so picking it up should give one back. */
public boolean deckConsumed() {
return deckConsumed;
}

public void setDeckConsumed(boolean deckConsumed) {
this.deckConsumed = deckConsumed;
}

public void clearBetWindow() {
betOpen = false;
autoCountdown = 0;
Expand Down
Loading
Loading