stations in the deck
This commit is contained in:
parent
ca74f692ec
commit
9e89092090
@ -20,6 +20,7 @@ class Suit(IntEnum):
|
||||
HEARTS = 2 # ♥
|
||||
SPADES = 3 # ♠
|
||||
GOLD = 4 # 🤑
|
||||
TRAIN = 5 # 🚂
|
||||
|
||||
|
||||
class Card(ABC):
|
||||
|
@ -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]
|
||||
|
0
backend/bang/expansions/train_robbery/cards.py
Normal file
0
backend/bang/expansions/train_robbery/cards.py
Normal file
0
backend/bang/expansions/train_robbery/characters.py
Normal file
0
backend/bang/expansions/train_robbery/characters.py
Normal file
173
backend/bang/expansions/train_robbery/stations.py
Normal file
173
backend/bang/expansions/train_robbery/stations.py
Normal 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(),
|
||||
]
|
101
backend/bang/expansions/train_robbery/trains.py
Normal file
101
backend/bang/expansions/train_robbery/trains.py
Normal 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,
|
||||
# l’abilità di Evan Babbit, e così via.
|
||||
# Sleeper Car: puoi anche usare
|
||||
# l’effetto 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 l’effetto dell’Emporio, 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
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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',
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user