diff --git a/backend/bang/deck.py b/backend/bang/deck.py
index 52354c8..ef1a25a 100644
--- a/backend/bang/deck.py
+++ b/backend/bang/deck.py
@@ -6,6 +6,7 @@ import bang.expansions.wild_west_show.card_events as cew
import bang.expansions.wild_west_show.characters as chw
import bang.expansions.gold_rush.shop_cards as grc
import bang.expansions.train_robbery.stations as trs
+import bang.expansions.train_robbery.trains as trt
from globals import G
if TYPE_CHECKING:
@@ -36,6 +37,8 @@ class Deck:
self.event_cards: List[ce.CardEvent] = []
self.event_cards_wildwestshow: List[ce.CardEvent] = []
self.stations: List[trs.StationCard] = []
+ self.train_pile: List[trt.TrainCard] = []
+ self.current_train: List[trt.TrainCard] = []
endgame_cards: List[ce.CardEvent] = []
if "fistful_of_cards" in game.expansions:
self.event_cards.extend(ce.get_all_events(game.rng))
@@ -50,6 +53,10 @@ class Deck:
self.event_cards_wildwestshow.append(cew.get_endgame_card())
if "train_robbery" in game.expansions:
self.stations = game.rng.sample(trs.get_all_stations(), len(game.players))
+ self.train_pile = trt.get_all_cards(game.rng)
+ self.current_train = [trt.get_locomotives(game.rng)[0]] + self.train_pile[
+ :3
+ ]
if len(self.event_cards) > 0:
game.rng.shuffle(self.event_cards)
self.event_cards = self.event_cards[:12]
@@ -109,6 +116,15 @@ class Deck:
self.shop_cards[i].reset_card()
self.game.notify_gold_rush_shop()
+ def move_train_forward(self):
+ if len(self.stations) == 0:
+ return
+ if len(self.current_train) == len(self.stations) + 4:
+ return
+ if len(self.current_train) > 0:
+ self.current_train.append(None)
+ self.game.notify_stations()
+
def peek(self, n_cards: int) -> list:
return self.cards[:n_cards]
diff --git a/backend/bang/expansions/train_robbery/trains.py b/backend/bang/expansions/train_robbery/trains.py
index 53d93db..0193e0b 100644
--- a/backend/bang/expansions/train_robbery/trains.py
+++ b/backend/bang/expansions/train_robbery/trains.py
@@ -1,9 +1,10 @@
+import random
from bang.cards import Card
class TrainCard(Card):
def __init__(self, name: str, is_locomotive: bool = False):
- super().__init__(suit=5, number="", name=name)
+ super().__init__(suit=5, number=0, name=name)
self.expansion_icon = "๐"
self.is_equipment = True
self.is_locomotive = is_locomotive
@@ -92,10 +93,212 @@ class Leland(TrainCard):
return True
+class BaggageCar(TrainCard):
+ """Scartalo: ottieni l'effetto di un Mancato!, Panico!, Cat Balou o di un BANG! extra.
+ Discard this for a Missed!Panic!, Cat Balou, or an extra BANG!"""
+
+ def __init__(self):
+ super().__init__("Baggage Car")
+ self.icon = "๐๐"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class Caboose(TrainCard):
+ """Pro scartare un aura tua carta bordo bin incuso un vagone come se fosse un Mancato!"""
+
+ def __init__(self):
+ super().__init__("Caboose")
+ self.icon = "๐"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class CattleTruck(TrainCard):
+ """Scartalo: guarda le 3 carte in cima agli scarti e pescane I"""
+
+ def __init__(self):
+ super().__init__("Cattle Truck")
+ self.icon = "๐๐"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
class CircusWagon(TrainCard):
+ """Scartalo: ogni altro giocatore deve scartare una carta che ha in gioco."""
+
def __init__(self):
super().__init__("Circus Wagon", is_locomotive=True)
self.icon = "๐๐ช"
def play_card(self, player, against=None, _with=None) -> bool:
return True
+
+
+class CoalHopper(TrainCard):
+ """Scartalo: pesca una carta e scarta un vagone in gioco davanti a un giocatore a ma scelta."""
+
+ def __init__(self):
+ super().__init__("Coal Hopper")
+ self.icon = "๐๐ฅ"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class DiningCar(TrainCard):
+ """A inizio turno, "estrai!": se รจ Cnori, recuperi I punto vita."""
+
+ def __init__(self):
+ super().__init__("Dining Car")
+ self.icon = "๐๐ฝ"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class ExpressCar(TrainCard):
+ """Scarta tutte le carte in mano, poi gioca un altro turno"""
+
+ def __init__(self):
+ super().__init__("Express Car")
+ self.icon = "๐โก"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class GhostCar(TrainCard):
+ """Giocalo su chiunque tranne lo Sceritfo. Se vieni eliminato, invece resti in gioco, ma non puol guada nare ne perdere punk vita."""
+
+ def __init__(self):
+ super().__init__("Ghost Car")
+ self.icon = "๐๐ป"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class LoungeCar(TrainCard):
+ """Scartalo: pesca 2 vagoni dal mazzo, mettine I in gioco di fronte a te e 1 di fronte a un altro giocatore."""
+
+ def __init__(self):
+ super().__init__("Lounge Car")
+ self.icon = "๐๐"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class LumberFlatcar(TrainCard):
+ """Giocalo su un qualsiasi giocatore (compreso te). Finchรฉ questa carta รจ in gioco, quel giocatore vede gli altri giocatori a distanza aumentata di 1."""
+
+ def __init__(self):
+ super().__init__("Lumber Flatcar")
+ self.icon = "๐๐ชต"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class MailCar(TrainCard):
+ """Scartalo: pesca 3 carte e dai 1 di esse a un altro giocatore a tua scelta."""
+
+ def __init__(self):
+ super().__init__("Mail Car")
+ self.icon = "๐๐ฎ"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class ObservationCar(TrainCard):
+ """Tu vedi gli altri a distanza -1. Gli altri a vedono a distanza +1."""
+
+ def __init__(self):
+ super().__init__("Observation Car")
+ self.icon = "๐๐"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class PassengerCar(TrainCard):
+ """Scartalo: pesca una carta (in mano o in gioco) da un altro giocatore"""
+
+ def __init__(self):
+ super().__init__("Passenger Car")
+ self.icon = "๐๐ถ"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class PrisonerCar(TrainCard):
+ """Le carte Duello e Indiani! giocate dagli altri giocatori non hanno effetto su di te."""
+
+ def __init__(self):
+ super().__init__("Prisoner Car")
+ self.icon = "๐๐ฎ๐ปโโ๏ธ"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class PrivateCar(TrainCard):
+ """se non hai carte in mano. non puoi essere bersaelio di carte BANG"""
+
+ def __init__(self):
+ super().__init__("Private Car")
+ self.icon = "๐๐๐ป"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+class SleeperCar(TrainCard):
+ """Una volta per turno, puoi scartare un'altra tua carta a bordo blu incluso."""
+
+ def __init__(self):
+ super().__init__("Sleeper Car")
+ self.icon = "๐๐"
+
+ def play_card(self, player, against=None, _with=None) -> bool:
+ return True
+
+
+def get_all_cards(rng=random):
+ """Return a list of all train cards in the expansion"""
+ cars = [
+ BaggageCar(),
+ Caboose(),
+ CattleTruck(),
+ CircusWagon(),
+ CoalHopper(),
+ DiningCar(),
+ ExpressCar(),
+ GhostCar(),
+ LoungeCar(),
+ LumberFlatcar(),
+ MailCar(),
+ ObservationCar(),
+ PassengerCar(),
+ PrisonerCar(),
+ PrivateCar(),
+ SleeperCar(),
+ ]
+ rng.shuffle(cars)
+ return cars
+
+
+def get_locomotives(rng=random):
+ """Return a list of all locomotive cards in the expansion"""
+ locs = [
+ Ironhorse(),
+ Leland(),
+ ]
+ rng.shuffle(locs)
+ return locs
diff --git a/backend/bang/game.py b/backend/bang/game.py
index dcc4894..ae3fcaa 100644
--- a/backend/bang/game.py
+++ b/backend/bang/game.py
@@ -59,6 +59,8 @@ debug_commands = [
{"cmd": "/getcard", "help": "Get a brand new card - sample /getcard Birra"},
{"cmd": "/meinfo", "help": "Get player data"},
{"cmd": "/gameinfo", "help": "Get game data"},
+ {"cmd": "/deckinfo", "help": "Get deck data"},
+ {"cmd": "/trainfw", "help": "move train forward"},
{"cmd": "/playerinfo", "help": "Get player data - sample /playerinfo player"},
{"cmd": "/cardinfo", "help": "Get card data - sample /cardinfo handindex"},
{"cmd": "/mebot", "help": "Toggles bot mode"},
@@ -844,6 +846,7 @@ class Game:
)
):
self.deck.flip_event()
+ self.deck.move_train_forward()
if self.check_event(ce.RouletteRussa):
self.is_russian_roulette_on = True
if self.players[self.turn].get_banged(self.deck.event_cards[0]):
@@ -925,7 +928,13 @@ class Game:
G.sio.emit(
"stations",
room=room,
- data=json.dumps(self.deck.stations, default=lambda o: o.__dict__),
+ data=json.dumps(
+ {
+ "stations": self.deck.stations,
+ "current_train": self.deck.current_train,
+ },
+ default=lambda o: o.__dict__,
+ ),
)
def notify_scrap_pile(self, sid=None):
diff --git a/backend/server.py b/backend/server.py
index ba45db7..f7e7274 100644
--- a/backend/server.py
+++ b/backend/server.py
@@ -1089,6 +1089,21 @@ def chat_message(sid, msg, pl=None):
"type": "json",
},
)
+ elif "/deckinfo" in msg:
+ sio.emit(
+ "chat_message",
+ room=sid,
+ data={
+ "color": "",
+ "text": json.dumps(
+ ses.game.deck.__dict__,
+ default=lambda o: f"<{o.__class__.__name__}() not serializable>",
+ ),
+ "type": "json",
+ },
+ )
+ elif "/trainfw" in msg:
+ ses.game.deck.move_train_forward()
elif "/status" in msg and ses.is_admin():
sio.emit("mount_status", room=sid)
elif "/meinfo" in msg:
diff --git a/frontend/src/components/Card.vue b/frontend/src/components/Card.vue
index 2f17766..4b7b9b2 100644
--- a/frontend/src/components/Card.vue
+++ b/frontend/src/components/Card.vue
@@ -355,6 +355,9 @@ export default {
transform: scaleX(-1);
/* filter: grayscale(1); */
}
+.train-piece .suit, .train-piece .expansion {
+ display: none;
+}
.train-piece h4 {
position: absolute;
text-align: center;
diff --git a/frontend/src/components/Deck.vue b/frontend/src/components/Deck.vue
index 157b20f..0f9c771 100644
--- a/frontend/src/components/Deck.vue
+++ b/frontend/src/components/Deck.vue
@@ -11,18 +11,8 @@