stations in the deck

This commit is contained in:
Alberto Xamin 2023-04-16 18:55:00 +01:00 committed by Alberto Xamin
parent ca74f692ec
commit 9e89092090
11 changed files with 323 additions and 16 deletions

View File

@ -20,6 +20,7 @@ class Suit(IntEnum):
HEARTS = 2 # ♥
SPADES = 3 # ♠
GOLD = 4 # 🤑
TRAIN = 5 # 🚂
class Card(ABC):

View File

@ -1,11 +1,11 @@
from typing import List, Set, Dict, Tuple, Optional, TYPE_CHECKING
import random
import bang.cards as cs
import bang.expansions.fistful_of_cards.card_events as ce
import bang.expansions.high_noon.card_events as ceh
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
from globals import G
if TYPE_CHECKING:
@ -35,6 +35,7 @@ class Deck:
self.game = game
self.event_cards: List[ce.CardEvent] = []
self.event_cards_wildwestshow: List[ce.CardEvent] = []
self.stations: List[trs.StationCard] = []
endgame_cards: List[ce.CardEvent] = []
if "fistful_of_cards" in game.expansions:
self.event_cards.extend(ce.get_all_events(game.rng))
@ -47,6 +48,8 @@ class Deck:
game.rng.shuffle(self.event_cards_wildwestshow)
self.event_cards_wildwestshow.insert(0, None)
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))
if len(self.event_cards) > 0:
game.rng.shuffle(self.event_cards)
self.event_cards = self.event_cards[:12]

View File

@ -0,0 +1,173 @@
import bang.cards as cs
class StationCard:
def __init__(self, name: str):
self.name = name
self.expansion = "train_robbery"
self.price: list[dict] = []
def card_check(self, card: cs.Card):
"""Check if the card can be used to rob the train"""
class BoomTown(StationCard):
"""Discard a Bang! to rob the train"""
def __init__(self):
super().__init__("Boom Town")
self.price = [cs.Bang(0, 0).__dict__]
def card_check(self, card: cs.Card):
return isinstance(card, cs.Bang)
class Caticor(StationCard):
"""Discard a Cat Balou or Panico to rob the train"""
def __init__(self):
super().__init__("Caticor")
self.price = [cs.CatBalou(0, 0).__dict__, cs.Panico(0, 0).__dict__]
def card_check(self, card: cs.Card):
return isinstance(card, cs.CatBalou) or isinstance(card, cs.Panico)
class CreepyCreek(StationCard):
"""Discard a card of spades to rob the train"""
def __init__(self):
super().__init__("Creepy Creek")
self.price = [{"icon": "♠️"}]
def card_check(self, card: cs.Card):
return card.suit == cs.Suit.SPADES
class CrownsHole(StationCard):
"""Discard a beer to rob the train"""
def __init__(self):
super().__init__("Crown's Hole")
self.price = [cs.Birra(0, 0).__dict__]
def card_check(self, card: cs.Card):
return isinstance(card, cs.Birra)
class Deadwood(StationCard):
"""Discard an equipment card to rob the train"""
def __init__(self):
super().__init__("Deadwood")
self.price = [{"is_equipment": True}]
def card_check(self, card: cs.Card):
return card.is_equipment
class Dodgeville(StationCard):
"""Discard a Missed! to rob the train"""
def __init__(self):
super().__init__("Dodgeville")
self.price = [cs.Mancato(0, 0).__dict__]
def card_check(self, card: cs.Card):
return isinstance(card, cs.Mancato)
class FortWorth(StationCard):
"""Discard a card with number 10, J, Q, K, A to rob the train"""
def __init__(self):
super().__init__("Fort Worth")
self.price = [{"icon": "10\nJ\nQ\nK\nA"}]
def card_check(self, card: cs.Card):
return card.number in {1, 10, 11, 12, 13}
class Frisco(StationCard):
"""Discard a card of clubs to rob the train"""
def __init__(self):
super().__init__("Frisco")
self.price = [{"icon": "♣️"}]
def card_check(self, card: cs.Card):
return card.suit == cs.Suit.CLUBS
class MinersOath(StationCard):
"""Discard a card of diamonds to rob the train"""
def __init__(self):
super().__init__("Miner's Oath")
self.price = [{"icon": "♦️"}]
def card_check(self, card: cs.Card):
return card.suit == cs.Suit.DIAMONDS
class SanTafe(StationCard):
"""Discard a card of hearts to rob the train"""
def __init__(self):
super().__init__("San Tafe")
self.price = [{"icon": "♥️"}]
def card_check(self, card: cs.Card):
return card.suit == cs.Suit.HEARTS
class Tombrock(StationCard):
"""Lose 1 life point to rob the train"""
def __init__(self):
super().__init__("Tombrock")
self.price = [{"icon": "💔"}]
def card_check(self, card: cs.Card):
return True
class Yooma(StationCard):
"""Discard a card with number between 2 and 9 to rob the train"""
def __init__(self):
super().__init__("Yooma")
self.price = [{"icon": "2-9"}]
def card_check(self, card: cs.Card):
return 2 <= card.number <= 9
class VirginiaTown(StationCard):
"""Discard two cards to rob the train"""
def __init__(self):
super().__init__("Virginia Town")
self.price = [{}, {}]
def card_check(self, card: cs.Card):
return True
def get_all_stations():
"""Return a list of all the station cards"""
return [
BoomTown(),
Caticor(),
CreepyCreek(),
CrownsHole(),
Deadwood(),
Dodgeville(),
FortWorth(),
Frisco(),
MinersOath(),
SanTafe(),
Tombrock(),
Yooma(),
VirginiaTown(),
]

View File

@ -0,0 +1,101 @@
from bang.cards import Card
class TrainCard(Card):
def __init__(self, name: str, is_locomotive: bool = False):
super().__init__(suit=5, number="", name=name)
self.expansion_icon = "🚂"
self.is_equipment = True
self.is_locomotive = is_locomotive
self.expansion = "train_robbery"
# Circus Wagon: gli altri giocatori
# scartano una carta, in senso orario, a
# partire dal giocatore alla tua sinistra.
# Express Car: non puoi svolgere
# un altro turno extra dopo quello
# ottenuto da questo effetto, anche se
# riesci a giocare di nuovo Express Car.
# Ghost Car: giocabile su un
# qualsiasi giocatore, anche se già
# eliminato, te compreso. Non può
# essere giocato sullo Sceriffo.
# Se quel giocatore è/viene eliminato,
# invece ritorna/resta in gioco, senza
# punti vita. Non può guadagnare né
# perdere punti vita, e viene considerato
# un personaggio in gioco per tutti gli
# effetti (condizioni di vittoria, distanza
# tra giocatori, abilità dei personaggi,
# ecc.). Non avendo punti vita, deve
# scartare la sua intera mano alla fine
# del turno, ma può tenere qualsiasi
# carta in gioco di fronte a sé, incluso
# Ghost Car. Tuttavia, è eliminato
# dal gioco non appena Ghost Car
# viene scartato: nessuna ricompensa
# viene assegnata in questo caso se il
# giocatore è un Fuorilegge, e le abilità
# dei personaggi (ad es. Vulture Sam)
# non si attivano
# Lounge Car: i vagoni che peschi
# non contano per il normale limite di
# acquisizione di 1 vagone per turno. Se
# sei lo Sceriffo e peschi Ghost Car, devi
# darlo a un altro giocatore.
# Lumber Flatcar: gioca su un
# qualsiasi giocatore (compreso te).
# Finché questa carta è in gioco, quel
# giocatore vede gli altri giocatori a
# distanza aumentata di 1.
# Private Car: questo effetto non
# ti protegge da Gatling, Knife Revolver,
# labilità di Evan Babbit, e così via.
# Sleeper Car: puoi anche usare
# leffetto una volta per turno con
# Indiani!, Duello, ecc.
class Ironhorse(TrainCard):
"""LOCOMOTIVA:
Ogni giocatore, incluso colui che ha attivato l'effetto, è bersaglio di un BANG!
Nessun giocatore è responsabile dell'eventuale perdita di punti vita.
Se tutti i giocatori vengono eliminati allo stesso tempo, i Fuorilegge vincono.
"""
def __init__(self):
super().__init__("Ironhorse", is_locomotive=True)
self.icon = "🚂"
def play_card(self, player, against=None, _with=None) -> bool:
player.game.attack(player, player.name, card_name=self.name)
player.game.attack_others(player, card_name=self.name)
return True
class Leland(TrainCard):
"""
LOCOMOTIVA: svolgi leffetto dellEmporio, cominciando dal giocatore di turno e procedendo in senso orario.
"""
def __init__(self):
super().__init__("Leland", is_locomotive=True)
self.icon = "🚂"
def play_card(self, player, against=None, _with=None) -> bool:
player.game.emporio(player)
return True
class CircusWagon(TrainCard):
def __init__(self):
super().__init__("Circus Wagon", is_locomotive=True)
self.icon = "🚋🎪"
def play_card(self, player, against=None, _with=None) -> bool:
return True

View File

@ -93,6 +93,7 @@ class Game:
"gold_rush",
"the_valley_of_shadows",
"wild_west_show",
"train_robbery",
]
self.shutting_down = False
self.is_competitive = False
@ -354,6 +355,7 @@ class Game:
roles_str += f"|{role}|{str(current_roles.count(role))}"
G.sio.emit("chat_message", room=self.name, data=f"_allroles{roles_str}")
self.play_turn()
self.notify_stations()
def choose_characters(self):
n = self.characters_to_distribute
@ -917,6 +919,15 @@ class Game:
data=json.dumps(self.deck.shop_cards, default=lambda o: o.__dict__),
)
def notify_stations(self, sid=None):
if "train_robbery" in self.expansions:
room = self.name if sid is None else sid
G.sio.emit(
"stations",
room=room,
data=json.dumps(self.deck.stations, default=lambda o: o.__dict__),
)
def notify_scrap_pile(self, sid=None):
print(f"{self.name}: scrap")
room = self.name if sid is None else sid

View File

@ -346,6 +346,7 @@ def get_me(sid, data):
room.notify_scrap_pile(sid)
room.notify_all()
room.notify_gold_rush_shop()
room.notify_stations()
room.notify_event_card()
room.notify_event_card_wildwestshow(sid)
else:

View File

@ -11,15 +11,13 @@
<card :card="goldRushCardBack" :donotlocalize="true" class="gold-rush back last-event" @click.native="goldRushShopOpen = !goldRushShopOpen"/>
</div>
</div>
<div class="deck" :style="`position:relative;border: 2px dashed #6a6a6a42;border-radius:8pt;align-items: flex-end;`" >
<station-card v-for="i in 8" :key="i" :card="{
name: 'station' + i,
}" :price="lastScrap" :trainPiece="
i == 6 ? {
<div v-if="current_stations.length > 0" class="deck" :style="`position:relative;border: 2px dashed #6a6a6a42;border-radius:8pt;align-items: flex-end;`" >
<station-card v-for="station, i in current_stations" :key="station.name" :card="station" :price="station.price" :trainPiece="
i == 2 ? {
name: 'Iron House',
icon: '🚂',
back: true,
} : i > 6 ? {
} : i > 2 ? {
name: 'Passenger Car',
icon: '🚃',
back: true,
@ -107,6 +105,7 @@ export default {
goldRushDesc: null,
can_gold_rush_discard: false,
gold_rush_discount: 0,
current_stations: [],
}),
sockets: {
self(self){
@ -140,6 +139,9 @@ export default {
console.log('GOLD RUSH:'+ cards)
this.goldRushCards = JSON.parse(cards)
},
stations(stations) {
this.current_stations = JSON.parse(stations)
},
},
computed: {
endTurnCard() {

View File

@ -4,7 +4,9 @@
<h4>{{ cardName }}</h4>
<div :class="{ emoji: true, bottomed: card.avatar }">{{ emoji }}</div>
<div class="alt_text">{{ card.alt_text }}</div>
<card :card="price" />
<div class="price">
<card v-for="c, i in price" :key="i" :card="c"/>
</div>
</div>
<card v-if="trainPiece" class="train-piece" :card="trainPiece" />
</div>
@ -17,7 +19,7 @@ export default {
name: "StationCard",
props: {
card: Object,
price: Object,
price: Array,
trainPiece: Object,
donotlocalize: Boolean,
},
@ -89,8 +91,8 @@ export default {
position: absolute;
text-align: center;
width: 100%;
top: -10pt;
font-size: 12pt;
top: -15pt;
font-size: 10pt;
}
.alt_text {
right: 3pt;
@ -100,11 +102,17 @@ export default {
bottom: 20pt;
left: 3pt;
}
.stationcard .card {
position: absolute;
transform: scale(0.3) rotate(14deg);
left: -12pt;
top: -22pt;
.stationcard .price {
justify-content: center;
/* left: -12pt; */
margin-top: -20pt;
/* left: 0; */
display: flex;
width: 60pt;
transform: scale(0.3);
}
.price .card {
transform: rotate(14deg);
}
.train-piece {
margin: 6pt;

View File

@ -36,5 +36,12 @@ export const expansionsMap = {
back: true,
expansion: 'wild-west-show',
status: 'alpha',
},
'train_robbery': {
name: 'The Great Train Robbery',
icon: '🚂',
back: true,
expansion: 'train-roobbery',
status: 'alpha',
}
}