193 lines
7.3 KiB
Python
193 lines
7.3 KiB
Python
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
|
|
from globals import G
|
|
|
|
if TYPE_CHECKING:
|
|
from bang.game import Game
|
|
|
|
|
|
class Deck:
|
|
"""Class that handles all deck dealing information"""
|
|
|
|
def __init__(self, game: "Game"):
|
|
super().__init__()
|
|
self.cards: List[cs.Card] = cs.get_starting_deck(game.expansions)
|
|
self.mancato_cards: List[str] = []
|
|
self.mancato_cards_not_green_or_blue: List[str] = []
|
|
self.green_cards: Set[str] = set()
|
|
for c in self.cards:
|
|
if isinstance(c, cs.Mancato) and c.name not in self.mancato_cards:
|
|
self.mancato_cards.append(c.name)
|
|
if not (c.usable_next_turn or c.is_equipment):
|
|
self.mancato_cards_not_green_or_blue.append(c.name)
|
|
elif c.usable_next_turn:
|
|
self.green_cards.add(c.name)
|
|
self.all_cards_str: List[str] = []
|
|
for c in self.cards:
|
|
if c.name not in self.all_cards_str:
|
|
self.all_cards_str.append(c.name)
|
|
self.game = game
|
|
self.event_cards: List[ce.CardEvent] = []
|
|
self.event_cards_wildwestshow: List[ce.CardEvent] = []
|
|
endgame_cards: List[ce.CardEvent] = []
|
|
if "fistful_of_cards" in game.expansions:
|
|
self.event_cards.extend(ce.get_all_events(game.rng))
|
|
endgame_cards.append(ce.get_endgame_card())
|
|
if "high_noon" in game.expansions:
|
|
self.event_cards.extend(ceh.get_all_events(game.rng))
|
|
endgame_cards.append(ceh.get_endgame_card())
|
|
if "wild_west_show" in game.expansions:
|
|
self.event_cards_wildwestshow.extend(cew.get_all_events(game.rng))
|
|
game.rng.shuffle(self.event_cards_wildwestshow)
|
|
self.event_cards_wildwestshow.insert(0, None)
|
|
self.event_cards_wildwestshow.append(cew.get_endgame_card())
|
|
if len(self.event_cards) > 0:
|
|
game.rng.shuffle(self.event_cards)
|
|
self.event_cards = self.event_cards[:12]
|
|
self.event_cards.insert(0, None)
|
|
self.event_cards.insert(
|
|
0, None
|
|
) # 2 perchè iniziale, e primo flip dallo sceriffo
|
|
self.event_cards.append(game.rng.choice(endgame_cards))
|
|
game.rng.shuffle(self.cards)
|
|
self.shop_deck: List[grc.ShopCard] = []
|
|
self.shop_cards: List[grc.ShopCard] = []
|
|
if "gold_rush" in game.expansions:
|
|
self.shop_cards = [None, None, None]
|
|
self.shop_deck = grc.get_cards()
|
|
game.rng.shuffle(self.shop_deck)
|
|
self.fill_gold_rush_shop()
|
|
self.scrap_pile: List[cs.Card] = []
|
|
print(f"Deck initialized with {len(self.cards)} cards")
|
|
|
|
def flip_event(self):
|
|
"""Flip event for regular Sheriff turn (High Noon, Fistful of Cards)"""
|
|
if len(self.event_cards) > 0 and not (
|
|
isinstance(self.event_cards[0], ce.PerUnPugnoDiCarte)
|
|
or isinstance(self.event_cards[0], ceh.MezzogiornoDiFuoco)
|
|
):
|
|
self.event_cards.append(self.event_cards.pop(0))
|
|
if len(self.event_cards) > 0 and self.event_cards[0] is not None:
|
|
self.event_cards[0].on_flipped(self.game)
|
|
self.game.notify_event_card()
|
|
self.game.notify_all()
|
|
|
|
def flip_wildwestshow(self):
|
|
"""Flip event for Wild West Show only"""
|
|
if len(self.event_cards_wildwestshow) > 0 and not isinstance(
|
|
self.event_cards_wildwestshow[0], cew.WildWestShow
|
|
):
|
|
self.event_cards_wildwestshow.append(self.event_cards_wildwestshow.pop(0))
|
|
if (
|
|
len(self.event_cards_wildwestshow) > 0
|
|
and self.event_cards_wildwestshow[0] is not None
|
|
):
|
|
self.event_cards_wildwestshow[0].on_flipped(self.game)
|
|
self.game.notify_event_card_wildwestshow()
|
|
self.game.notify_all()
|
|
|
|
def fill_gold_rush_shop(self):
|
|
"""
|
|
As gold_rush shop cards are stored in a fixed 3 space array,
|
|
this function replaces the None values with new cards.
|
|
"""
|
|
if not any((c is None for c in self.shop_cards)):
|
|
return
|
|
for i in range(3):
|
|
if self.shop_cards[i] is None:
|
|
print(f"replacing gr-card {i}")
|
|
self.shop_cards[i] = self.shop_deck.pop(0)
|
|
self.shop_cards[i].reset_card()
|
|
self.game.notify_gold_rush_shop()
|
|
|
|
def peek(self, n_cards: int) -> list:
|
|
return self.cards[:n_cards]
|
|
|
|
def peek_scrap_pile(self) -> cs.Card:
|
|
if len(self.scrap_pile) > 0:
|
|
return self.scrap_pile[-1]
|
|
else:
|
|
return None
|
|
|
|
def pick_and_scrap(self) -> cs.Card:
|
|
card = self.cards.pop(0)
|
|
jpain = None
|
|
for p in self.game.players:
|
|
if p.character.check(self.game, chw.JohnPain) and len(p.hand) < 6:
|
|
jpain = p
|
|
break
|
|
if jpain:
|
|
jpain.hand.append(card)
|
|
jpain.notify_self()
|
|
else:
|
|
self.scrap_pile.append(card)
|
|
if len(self.cards) == 0:
|
|
self.reshuffle()
|
|
self.game.notify_scrap_pile()
|
|
return card
|
|
|
|
def put_on_top(self, card: cs.Card):
|
|
self.cards.insert(0, card)
|
|
|
|
def draw(self, ignore_event=False, player=None) -> cs.Card:
|
|
if (
|
|
self.game.check_event(ce.MinieraAbbandonata)
|
|
and len(self.scrap_pile) > 0
|
|
and not ignore_event
|
|
):
|
|
return self.draw_from_scrap_pile()
|
|
card = self.cards.pop(0)
|
|
if len(self.cards) == 0:
|
|
self.reshuffle()
|
|
if player is not None and self.game.replay_speed > 0:
|
|
G.sio.emit(
|
|
"card_drawn",
|
|
room=self.game.name,
|
|
data={"player": player.name, "pile": "deck"},
|
|
)
|
|
player.hand.append(card)
|
|
return card
|
|
|
|
def reshuffle(self):
|
|
self.cards = self.scrap_pile[:-1].copy()
|
|
self.game.rng.shuffle(self.cards)
|
|
self.scrap_pile = self.scrap_pile[-1:]
|
|
|
|
def draw_from_scrap_pile(self) -> cs.Card:
|
|
if len(self.scrap_pile) > 0:
|
|
card = self.scrap_pile.pop(-1)
|
|
self.game.notify_scrap_pile()
|
|
card.reset_card()
|
|
return card
|
|
else:
|
|
return self.draw()
|
|
|
|
def scrap(self, card: cs.Card, ignore_event=False, player=None):
|
|
if card.number == 42:
|
|
return
|
|
card.reset_card()
|
|
if self.game.check_event(ce.MinieraAbbandonata) and not ignore_event:
|
|
self.put_on_top(card)
|
|
else:
|
|
self.scrap_pile.append(card)
|
|
if player is not None and self.game.replay_speed > 0:
|
|
G.sio.emit(
|
|
"card_scrapped",
|
|
room=self.game.name,
|
|
data={
|
|
"player": player.name,
|
|
"card": card.__dict__,
|
|
"pile": "scrap",
|
|
},
|
|
)
|
|
G.sio.sleep(0.6)
|
|
self.game.notify_scrap_pile()
|
|
else:
|
|
self.game.notify_scrap_pile()
|