From 363ae304f0b5ee754c37e50a7d0b3a34f43215a6 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 25 Nov 2020 11:18:04 +0100 Subject: [PATCH] less spaghetti is always better --- backend/cards.py | 159 ++++++++++++++++++++++++++-- backend/deck.py | 18 ++-- backend/players.py | 258 +++++++++++++++++++-------------------------- 3 files changed, 264 insertions(+), 171 deletions(-) diff --git a/backend/cards.py b/backend/cards.py index 08b18aa..580ce46 100644 --- a/backend/cards.py +++ b/backend/cards.py @@ -2,12 +2,14 @@ from typing import List, Set, Dict, Tuple, Optional from abc import ABC, abstractmethod from enum import IntEnum + class Suit(IntEnum): - DIAMONDS = 0 # ♦ - CLUBS = 1 # ♣ - HEARTS = 2 # ♥ + DIAMONDS = 0 # ♦ + CLUBS = 1 # ♣ + HEARTS = 2 # ♥ SPADES = 3 # ♠ + class Card(ABC): sym = { 'A': 1, @@ -15,7 +17,8 @@ class Card(ABC): 'Q': 12, 'K': 13 } - def __init__(self, suit: Suit, name: str, number, is_equipment:bool=False, is_weapon:bool=False, vis_mod:int=0, sight_mod:int=0, range:int=99, desc:str=''): + + def __init__(self, suit: Suit, name: str, number, is_equipment: bool = False, is_weapon: bool = False, vis_mod: int = 0, sight_mod: int = 0, range: int = 99, desc: str = ''): super().__init__() self.name = name self.suit = suit @@ -29,39 +32,50 @@ class Card(ABC): self.sight_mod = sight_mod self.range = range if self.range != 0 and self.range != 99: - self.alt_text = f'{self.range} 🔍' + self.alt_text = f'{self.range} 🔍' self.desc = desc self.need_target = False def __str__(self): - char = ['♦️','♣️','♥️','♠️'][int(self.suit)] + char = ['♦️', '♣️', '♥️', '♠️'][int(self.suit)] return f'{self.name} {char}{self.number}' return super().__str__() + def play_card(self, player, against): + contro = f'contro {against}' if against else '' + player.sio.emit('chat_message', room=player.game.name, + data=f'{player.name} ha giocato {self.name}{contro}.') + return True + + class Barile(Card): def __init__(self, suit, number): super().__init__(suit, 'Barile', number, is_equipment=True) self.icon = '🛢' self.desc = "Quando sei bersagliato da un Bang puoi estrarre la prima carta dalla cima del mazzo, se la carta estratta è del seme Cuori allora vale come un Mancato" + class Dinamite(Card): def __init__(self, suit, number): super().__init__(suit, 'Dinamite', number, is_equipment=True) self.icon = '🧨' self.desc = "Giocando la Dinamite, posizionala davanti a te, resterà innocua per un intero giro. All'inizio del prossimo turno prima di pescare e prima di una eventuale estrazione (es. Prigione), estrai una carta dalla cima del mazzo. Se esce una carta tra il 2 il 9 di picche (compresi) allora la dinamite esplode: perdi 3 vite e scarta la carta, altrimenti passa la dinamite al giocatore successivo, il quale estrarà a sua volta dopo che tu avrai passato il tuo turno" + class Mirino(Card): def __init__(self, suit, number): super().__init__(suit, 'Mirino', number, is_equipment=True, sight_mod=1) self.icon = '🔎' self.desc = "Tu vedi gli altri giocatori a distanza -1" + class Mustang(Card): def __init__(self, suit, number): super().__init__(suit, 'Mustang', number, is_equipment=True, vis_mod=1) self.icon = '🐎' self.desc = "Gli altri giocatori ti vedono a distanza +1" + class Prigione(Card): def __init__(self, suit, number): super().__init__(suit, 'Prigione', number, is_equipment=True) @@ -69,36 +83,47 @@ class Prigione(Card): self.desc = "Equipaggia questa carta a un altro giocatore, tranne lo Sceriffo. Il giocatore scelto all'inizio del suo turno, prima di pescare dovrà estrarre: se esce Cuori scarta questa carta e gioca normalmente il turno, altrimenti scarta questa carta e salta il turno" self.need_target = True + class Remington(Card): def __init__(self, suit, number): - super().__init__(suit, 'Remington', number, is_equipment=True, is_weapon=True, range=3) + super().__init__(suit, 'Remington', number, + is_equipment=True, is_weapon=True, range=3) self.icon = '🔫' self.desc = "Puoi sparare a un giocatore che sia distante 3 o meno" + class RevCarabine(Card): def __init__(self, suit, number): - super().__init__(suit, 'Rev. Carabine', number, is_equipment=True, is_weapon=True, range=4) + super().__init__(suit, 'Rev. Carabine', number, + is_equipment=True, is_weapon=True, range=4) self.icon = '🔫' self.desc = "Puoi sparare a un giocatore che sia distante 4 o meno" + class Schofield(Card): def __init__(self, suit, number): - super().__init__(suit, 'Schofield', number, is_equipment=True, is_weapon=True, range=2) + super().__init__(suit, 'Schofield', number, + is_equipment=True, is_weapon=True, range=2) self.icon = '🔫' self.desc = "Puoi sparare a un giocatore che sia distante 2 o meno" + class Volcanic(Card): def __init__(self, suit, number): - super().__init__(suit, 'Volcanic', number, is_equipment=True, is_weapon=True, range=1) + super().__init__(suit, 'Volcanic', number, + is_equipment=True, is_weapon=True, range=1) self.icon = '🔫' self.desc = "Puoi sparare a un giocatore che sia distante 1 o meno, tuttavia puoi giocare quanti bang vuoi" + class Winchester(Card): def __init__(self, suit, number): - super().__init__(suit, 'Winchester', number, is_equipment=True, is_weapon=True, range=5) + super().__init__(suit, 'Winchester', number, + is_equipment=True, is_weapon=True, range=5) self.icon = '🔫' self.desc = "Puoi sparare a un giocatore che sia distante 5 o meno" + class Bang(Card): def __init__(self, suit, number): super().__init__(suit, 'Bang!', number) @@ -106,12 +131,37 @@ class Bang(Card): self.desc = "Spara a un giocatore a distanta raggiungibile. Se non hai armi la distanza di default è 1" self.need_target = True + def play_card(self, player, against): + if player.has_played_bang and not any([isinstance(c, Volcanic) for c in player.equipment]) and against != None: + return False + elif against != None: + import characters as chars + super().play_card(player, against=against) + player.has_played_bang = not isinstance( + player.character, chars.WillyTheKid) + player.game.attack(player, against) + return True + return False + + class Birra(Card): def __init__(self, suit, number): super().__init__(suit, 'Birra', number) self.icon = '🍺' self.desc = "Gioca questa carta per recuperare un punto vita. Non puoi andare oltre al limite massimo del tuo personaggio. Se stai per perdere l'ultimo punto vita puoi giocare questa carta anche nel turno dell'avversario. La birra non ha più effetto se ci sono solo due giocatori" + def play_card(self, player, against): + if len(player.game.players) != 2 and player.lives != player.max_lives: + super().play_card(player, against=against) + player.lives = min(player.lives+1, player.max_lives) + return True + elif len(player.game.players) == 2: + player.sio.emit('chat_message', room=player.game.name, + data=f'{player.name} ha rovesciato una {self.name}.') + return True + return False + + class CatBalou(Card): def __init__(self, suit, number): super().__init__(suit, 'Cat Balou', number) @@ -119,12 +169,33 @@ class CatBalou(Card): self.desc = "Fai scartare una carta a un qualsiasi giocatore, scegli a caso dalla mano, oppure fra quelle che ha in gioco" self.need_target = True + def play_card(self, player, against): + if against != None: + super().play_card(player, against=against) + from players import PendingAction + player.pending_action = PendingAction.CHOOSE + player.choose_action = 'discard' + player.target_p = against + print('choose now') + return True + return False + + class Diligenza(Card): def __init__(self, suit, number): super().__init__(suit, 'Diligenza', number) self.icon = '🚡' self.desc = "Pesca 2 carte dalla cima del mazzo" + def play_card(self, player, against): + super().play_card(player, against=against) + player.sio.emit('chat_message', room=player.game.name, + data=f'{player.name} ha giocato {self.name} e ha pescato 2 carte.') + for i in range(2): + player.hand.append(player.game.deck.draw()) + return True + + class Duello(Card): def __init__(self, suit, number): super().__init__(suit, 'Duello', number) @@ -132,30 +203,67 @@ class Duello(Card): self.icon = '⚔️' self.desc = "Gioca questa carta contro un qualsiasi giocatore. A turno, cominciando dal tuo avversario, potete scartare una carta Bang!, il primo giocatore che non lo fa perde 1 vita" + def play_card(self, player, against): + if against != None: + super().play_card(player, against=against) + player.game.duel(player, against) + return True + return False + + class Emporio(Card): def __init__(self, suit, number): super().__init__(suit, 'Emporio', number) self.icon = '🏪' self.desc = "Scopri dal mazzo tante carte quanto il numero di giocatori, a turno, partendo da te, scegliete una carta e aggiungetela alla vostra mano" + def play_card(self, player, against): + super().play_card(player, against=against) + player.game.emporio() + return True + + class Gatling(Card): def __init__(self, suit, number): super().__init__(suit, 'Gatling', number) self.icon = '🛰' self.desc = "Spara a tutti gli altri giocatori" + def play_card(self, player, against): + super().play_card(player, against=against) + player.game.attack_others(player) + return True + + class Indiani(Card): def __init__(self, suit, number): super().__init__(suit, 'Indiani!', number) self.icon = '🏹' self.desc = "Tutti gli altri giocatori devono scartare un Bang! o perdere una vita" + def play_card(self, player, against): + super().play_card(player, against=against) + player.game.indian_others(player) + return True + + class Mancato(Card): def __init__(self, suit, number): super().__init__(suit, 'Mancato!', number) self.icon = '😅' self.desc = "Usa questa carta per annullare un bang" + def play_card(self, player, against): + import characters as chars + if (not player.has_played_bang and against != None and isinstance(player.character, chars.CalamityJanet)): + player.sio.emit('chat_message', room=player.game.name, + data=f'{player.name} ha giocato {self.name} come un BANG! contro {against}.') + player.has_played_bang = True + player.game.attack(player, against) + return True + return False + + class Panico(Card): def __init__(self, suit, number): super().__init__(suit, 'Panico!', number, range=1) @@ -163,18 +271,47 @@ class Panico(Card): self.need_target = True self.desc = "Pesca una carta da un giocatore a distanza 1, scegli a caso dalla mano, oppure fra quelle che ha in gioco" + def play_card(self, player, against): + if against != None: + super().play_card(player, against=against) + from players import PendingAction + player.pending_action = PendingAction.CHOOSE + player.choose_action = 'steal' + player.target_p = against + print('choose now') + return True + return False + + class Saloon(Card): def __init__(self, suit, number): super().__init__(suit, 'Saloon', number) self.desc = "Tutti i giocatori recuperano un punto vita compreso chi gioca la carta" self.icon = '🍻' + def play_card(self, player, against): + player.sio.emit('chat_message', room=player.game.name, + data=f'{player.name} ha giocato {self.name} e ha curato 1 punto vita a tutti.') + for p in player.game.players: + p.lives = min(p.lives+1, p.max_lives) + p.notify_self() + return True + + class WellsFargo(Card): def __init__(self, suit, number): super().__init__(suit, 'WellsFargo', number) self.desc = "Pesca 3 carte dalla cima del mazzo" self.icon = '💸' + def play_card(self, player, against): + player.sio.emit('chat_message', room=player.game.name, + data=f'{player.name} ha giocato {self.name} e ha pescato 3 carte.') + for i in range(3): + player.hand.append(player.game.deck.draw()) + return True + + def get_starting_deck() -> List[Card]: return [ Barile(Suit.SPADES, 'Q'), diff --git a/backend/deck.py b/backend/deck.py index 736966b..202fbe0 100644 --- a/backend/deck.py +++ b/backend/deck.py @@ -1,35 +1,35 @@ from typing import List, Set, Dict, Tuple, Optional import random -from cards import Card, get_starting_deck +import cards as cs class Deck: def __init__(self, game): super().__init__() - self.cards: List[Card] = get_starting_deck() + self.cards: List[cs.Card] = cs.get_starting_deck() self.game = game random.shuffle(self.cards) - self.scrap_pile: List[Card] = [] + self.scrap_pile: List[cs.Card] = [] print(f'Deck initialized with {len(self.cards)} cards') def peek(self, n_cards: int) -> list: return self.cards[:n_cards] - def peek_scrap_pile(self) -> Card: + 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) -> Card: + def pick_and_scrap(self) -> cs.Card: card = self.cards.pop(0) self.scrap_pile.append(card) self.game.notify_scrap_pile() return card - def put_on_top(self, card: Card): + def put_on_top(self, card: cs.Card): self.cards.insert(0, card) - def draw(self) -> Card: + def draw(self) -> cs.Card: card = self.cards.pop(0) if len(self.cards) == 0: self.cards = self.scrap_pile[:-1].copy() @@ -37,7 +37,7 @@ class Deck: self.scrap_pile = self.scrap_pile[-1:] return card - def draw_from_scrap_pile(self) -> Card: + 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() @@ -45,6 +45,6 @@ class Deck: else: return self.draw() - def scrap(self, card: Card): + def scrap(self, card: cs.Card): self.scrap_pile.append(card) self.game.notify_scrap_pile() diff --git a/backend/players.py b/backend/players.py index 2a8f6e4..ce2f631 100644 --- a/backend/players.py +++ b/backend/players.py @@ -3,11 +3,10 @@ from enum import IntEnum import json from random import randrange import socketio -import cards -import roles -import cards -import characters +import roles as r +import cards as cs +import characters as chars class PendingAction(IntEnum): PICK = 0 @@ -17,19 +16,22 @@ class PendingAction(IntEnum): WAIT = 4 CHOOSE = 5 + class Player: + import game as g + def __init__(self, name, sid, sio): super().__init__() self.name = name self.sid = sid self.sio = sio - self.hand: cards.Card = [] - self.equipment: cards.Card = [] - self.role: roles.Role = None - self.character: characters.Character = None + self.hand: cs.Card = [] + self.equipment: cs.Card = [] + self.role: r.Role = None + self.character: chars.Character = None self.lives = 0 self.max_lives = 0 - self.game = None + self.game: g = None self.is_my_turn = False self.is_waiting_for_action = True self.has_played_bang = False @@ -41,7 +43,7 @@ class Player: self.event_type: str = None self.expected_response = None self.attacker = None - self.target_p: str = None + self.target_p: str = None self.is_drawing = False self.mancato_needed = 0 @@ -52,17 +54,20 @@ class Player: def disconnect(self): return self.game.handle_disconnect(self) - def set_role(self, role: roles.Role): + def set_role(self, role: r.Role): self.role = role print(f'I {self.name} am a {role.name}, my goal is "{role.goal}"') - self.sio.emit('role', room=self.sid, data=json.dumps(role, default=lambda o: o.__dict__)) + self.sio.emit('role', room=self.sid, data=json.dumps( + role, default=lambda o: o.__dict__)) def set_character(self, character: str): print(self.available_characters, character) - self.character = next(x for x in self.available_characters if x.name==character) + self.character = next( + x for x in self.available_characters if x.name == character) self.available_characters = [] print(f'I {self.name} chose character {self.character.name}') - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha scelto il personaggio.') + self.sio.emit('chat_message', room=self.game.name, + data=f'{self.name} ha scelto il personaggio.') self.game.notify_character_selection() def prepare(self): @@ -75,7 +80,8 @@ class Player: def set_available_character(self, available): self.available_characters = available print(f'I {self.name} have to choose between {available}') - self.sio.emit('characters', room=self.sid, data=json.dumps(available, default=lambda o: o.__dict__)) + self.sio.emit('characters', room=self.sid, data=json.dumps( + available, default=lambda o: o.__dict__)) def notify_card(self, player, card): mess = { @@ -86,9 +92,10 @@ class Player: self.sio.emit('notify_card', room=self.sid, data=mess) def notify_self(self): - if isinstance(self.character, characters.CalamityJanet): - self.expected_response = [cards.Mancato(0,0).name, cards.Bang(0,0).name] - elif isinstance(self.character, characters.SuzyLafayette) and len(self.hand) == 0: + if isinstance(self.character, chars.CalamityJanet): + self.expected_response = [ + cs.Mancato(0, 0).name, cs.Bang(0, 0).name] + elif isinstance(self.character, chars.SuzyLafayette) and len(self.hand) == 0: self.hand.append(self.game.deck.draw()) ser = self.__dict__.copy() ser.pop('game') @@ -102,14 +109,18 @@ class Player: ser['attacker'] = self.attacker.name ser['sight'] = self.get_sight() ser['lives'] = max(ser['lives'], 0) - self.sio.emit('self', room=self.sid, data=json.dumps(ser, default=lambda o: o.__dict__)) - self.sio.emit('self_vis', room=self.sid, data=json.dumps(self.game.get_visible_players(self), default=lambda o: o.__dict__)) + self.sio.emit('self', room=self.sid, data=json.dumps( + ser, default=lambda o: o.__dict__)) + self.sio.emit('self_vis', room=self.sid, data=json.dumps( + self.game.get_visible_players(self), default=lambda o: o.__dict__)) if self.lives <= 0 and self.max_lives > 0: print('dying, attacker', self.attacker) - if isinstance(self.character, characters.SidKetchum) and len(self.hand) > 1: + if isinstance(self.character, chars.SidKetchum) and len(self.hand) > 1: self.lives += 1 - self.game.deck.scrap(self.hand.pop(randrange(0, len(self.hand)))) - self.game.deck.scrap(self.hand.pop(randrange(0, len(self.hand)))) + self.game.deck.scrap(self.hand.pop( + randrange(0, len(self.hand)))) + self.game.deck.scrap(self.hand.pop( + randrange(0, len(self.hand)))) self.game.player_death(self) self.game.notify_all() @@ -117,13 +128,14 @@ class Player: if self.lives == 0: return self.end_turn(forced=True) self.scrapped_cards = 0 - self.sio.emit('chat_message', room=self.game.name, data=f'È il turno di {self.name}.') + self.sio.emit('chat_message', room=self.game.name, + data=f'È il turno di {self.name}.') print(f'I {self.name} was notified that it is my turn') self.was_shot = False self.is_my_turn = True self.is_waiting_for_action = True self.has_played_bang = False - if any([isinstance(c, cards.Dinamite) or isinstance(c, cards.Prigione) for c in self.equipment]): + if any([isinstance(c, cs.Dinamite) or isinstance(c, cs.Prigione) for c in self.equipment]): self.pending_action = PendingAction.PICK else: self.pending_action = PendingAction.DRAW @@ -132,28 +144,29 @@ class Player: def draw(self, pile): if self.pending_action != PendingAction.DRAW: return - if isinstance(self.character, characters.KitCarlson): + if isinstance(self.character, chars.KitCarlson): self.is_drawing = True self.available_cards = [self.game.deck.draw() for i in range(3)] self.pending_action = PendingAction.CHOOSE self.notify_self() else: self.pending_action = PendingAction.PLAY - if pile == 'scrap' and isinstance(self.character, characters.PedroRamirez): + if pile == 'scrap' and isinstance(self.character, chars.PedroRamirez): self.hand.append(self.game.deck.draw_from_scrap_pile()) self.hand.append(self.game.deck.draw()) - elif type(pile) == str and pile != self.name and pile in self.game.players_map and isinstance(self.character, characters.JesseJones) and len(self.game.get_player_named(pile).hand) > 0: - self.hand.append(self.game.get_player_named(pile).hand.pop(randrange(0, len(self.game.get_player_named(pile).hand)))) + elif type(pile) == str and pile != self.name and pile in self.game.players_map and isinstance(self.character, chars.JesseJones) and len(self.game.get_player_named(pile).hand) > 0: + self.hand.append(self.game.get_player_named(pile).hand.pop( + randrange(0, len(self.game.get_player_named(pile).hand)))) self.hand.append(self.game.deck.draw()) else: for i in range(2): - card: cards.Card = self.game.deck.draw() + card: cs.Card = self.game.deck.draw() self.hand.append(card) - if i == 1 and isinstance(self.character, characters.BlackJack): + if i == 1 and isinstance(self.character, chars.BlackJack): for p in self.game.players: if p != self: p.notify_card(self, card) - if card.suit == cards.Suit.HEARTS or card.suit == cards.Suit.DIAMONDS: + if card.suit == cs.Suit.HEARTS or card.suit == cs.Suit.DIAMONDS: self.hand.append(self.game.deck.draw()) self.notify_self() @@ -163,33 +176,36 @@ class Player: pickable_cards = 1 + self.character.pick_mod if self.is_my_turn: for i in range(len(self.equipment)): - if isinstance(self.equipment[i], cards.Dinamite): + if isinstance(self.equipment[i], cs.Dinamite): while pickable_cards > 0: pickable_cards -= 1 - picked: cards.Card = self.game.deck.pick_and_scrap() + picked: cs.Card = self.game.deck.pick_and_scrap() print(f'Did pick {picked}') - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha estratto {picked}.') - if picked.suit == cards.Suit.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0: + self.sio.emit('chat_message', room=self.game.name, + data=f'{self.name} ha estratto {picked}.') + if picked.suit == cs.Suit.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0: self.lives -= 3 self.game.deck.scrap(self.equipment.pop(i)) - if isinstance(self.character, characters.BartCassidy): + if isinstance(self.character, chars.BartCassidy): self.hand.append(self.game.deck.draw()) - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha fatto esplodere la dinamite.') + self.sio.emit('chat_message', room=self.game.name, + data=f'{self.name} ha fatto esplodere la dinamite.') print(f'{self.name} Boom, -3 hp') else: self.game.next_player().equipment.append(self.equipment.pop(i)) self.game.next_player().notify_self() - if any([isinstance(c, cards.Dinamite) or isinstance(c, cards.Prigione) for c in self.equipment]): + if any([isinstance(c, cs.Dinamite) or isinstance(c, cs.Prigione) for c in self.equipment]): self.notify_self() return for i in range(len(self.equipment)): - if isinstance(self.equipment[i], cards.Prigione): + if isinstance(self.equipment[i], cs.Prigione): while pickable_cards > 0: pickable_cards -= 1 - picked: cards.Card = self.game.deck.pick_and_scrap() + picked: cs.Card = self.game.deck.pick_and_scrap() print(f'Did pick {picked}') - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha estratto {picked}.') - if picked.suit != cards.Suit.HEARTS and pickable_cards == 0: + self.sio.emit('chat_message', room=self.game.name, + data=f'{self.name} ha estratto {picked}.') + if picked.suit != cs.Suit.HEARTS and pickable_cards == 0: self.game.deck.scrap(self.equipment.pop(i)) self.end_turn(forced=True) return @@ -207,29 +223,30 @@ class Player: playable_cards = [] for i in range(len(self.hand)): card = self.hand[i] - if isinstance(card, cards.Bang) and self.has_played_bang and not any([isinstance(c, cards.Volcanic) for c in self.equipment]): + if isinstance(card, cs.Bang) and self.has_played_bang and not any([isinstance(c, cs.Volcanic) for c in self.equipment]): continue - elif isinstance(card, cards.Birra) and self.lives >= self.max_lives: + elif isinstance(card, cs.Birra) and self.lives >= self.max_lives: continue else: - playable_cards.append(i) + playable_cs.append(i) return playable_cards def get_public_description(self): - s = f"{self.name} {'Sheriff ⭐️' if isinstance(self.role, roles.Sheriff) else ''} ({self.lives}/{self.max_lives} ⁍) {len(self.hand)} Cards in hand, " + s = f"{self.name} {'Sheriff ⭐️' if isinstance(self.role, r.Sheriff) else ''} ({self.lives}/{self.max_lives} ⁍) {len(self.hand)} Cards in hand, " s += f"equipment {[str(c) for c in self.equipment]}" return s - def play_card(self, hand_index: int, againts=None): + def play_card(self, hand_index: int, against=None): if not (0 <= hand_index < len(self.hand)): print('illegal') return - card: cards.Card = self.hand.pop(hand_index) - print(self.name, 'is playing ', card, ' against:', againts) - if isinstance(card, cards.Prigione) and not isinstance(self.game.get_player_named(againts).role, roles.Sheriff): - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name} contro {againts}.') - self.game.get_player_named(againts).equipment.append(card) - self.game.get_player_named(againts).notify_self() + card: cs.Card = self.hand.pop(hand_index) + print(self.name, 'is playing ', card, ' against:', against) + if isinstance(card, cs.Prigione) and not isinstance(self.game.get_player_named(against).role, r.Sheriff): + self.sio.emit('chat_message', room=self.game.name, + data=f'{self.name} ha giocato {card.name} contro {against}.') + self.game.get_player_named(against).equipment.append(card) + self.game.get_player_named(against).notify_self() elif card.is_equipment: if card.is_weapon: has_weapon = False @@ -241,7 +258,7 @@ class Player: break if not has_weapon: self.equipment.append(card) - elif card.name in [c.name for c in self.equipment if not isinstance(c, cards.Dinamite)]: + elif card.name in [c.name for c in self.equipment if not isinstance(c, cs.Dinamite)]: for i in range(len(self.equipment)): if type(self.equipment[i]) == type(card): self.game.deck.scrap(self.equipment[i]) @@ -250,74 +267,7 @@ class Player: else: self.equipment.append(card) else: - did_play_card = False - if isinstance(card, cards.Bang) and self.has_played_bang and not any([isinstance(c, cards.Volcanic) for c in self.equipment]) and againts != None: - self.hand.insert(hand_index, card) - return - elif isinstance(card, cards.Bang) and againts != None: - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name} contro {againts}.') - self.has_played_bang = not isinstance(self.character, characters.WillyTheKid) - self.game.attack(self, againts) - did_play_card = True - elif isinstance(card, cards.Birra): - if len(self.game.players) != 2 and self.lives != self.max_lives: - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato una {card.name}.') - self.lives = min(self.lives+1, self.max_lives) - did_play_card = True - elif len(self.game.players) == 2: - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha rovesciato una {card.name}.') - did_play_card = True - elif isinstance(card, cards.CatBalou) and againts != None: - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name} contro {againts}.') - self.pending_action = PendingAction.CHOOSE - self.choose_action = 'discard' - self.target_p = againts - did_play_card = True - print('choose now') - elif isinstance(card, cards.Diligenza): - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name} e ha pescato 2 carte.') - for i in range(2): - self.hand.append(self.game.deck.draw()) - did_play_card = True - elif isinstance(card, cards.Duello): - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name} contro {againts}.') - self.game.duel(self, againts) - did_play_card = True - elif isinstance(card, cards.Emporio): - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name}.') - self.game.emporio() - did_play_card = True - elif isinstance(card, cards.Gatling): - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name}.') - self.game.attack_others(self) - did_play_card = True - elif isinstance(card, cards.Indiani): - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name}.') - self.game.indian_others(self) - did_play_card = True - elif isinstance(card, cards.Mancato) and (not self.has_played_bang and againts != None and isinstance(self.character, characters.CalamityJanet)): - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name} come un BANG! contro {againts}.') - self.has_played_bang = True - self.game.attack(self, againts) - did_play_card = True - elif isinstance(card, cards.Panico) and againts != None: - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name} contro {againts}.') - self.pending_action = PendingAction.CHOOSE - self.choose_action = 'steal' - self.target_p = againts - print('choose now') - did_play_card = True - elif isinstance(card, cards.Saloon): - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name} e ha curato 1 punto vita a tutti.') - for p in self.game.players: - p.lives = min(p.lives+1, p.max_lives) - p.notify_self() - did_play_card = True - elif isinstance(card, cards.WellsFargo): - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha giocato {card.name} e ha pescato 3 carte.') - for i in range(3): - self.hand.append(self.game.deck.draw()) - did_play_card = True + did_play_card = card.play_card(self, against) if did_play_card: self.game.deck.scrap(card) else: @@ -327,7 +277,7 @@ class Player: def choose(self, card_index): if self.pending_action != PendingAction.CHOOSE: return - if self.target_p and self.target_p != '': # panico, cat balou + if self.target_p and self.target_p != '': # panico, cat balou target = self.game.get_player_named(self.target_p) card = None if card_index >= len(target.hand): @@ -343,70 +293,72 @@ class Player: self.choose_action = '' self.pending_action = PendingAction.PLAY self.notify_self() - elif self.is_drawing and isinstance(self.character, characters.KitCarlson): # specifico per personaggio - self.hand.append(self.available_cards.pop(card_index)) + # specifico per personaggio + elif self.is_drawing and isinstance(self.character, chars.KitCarlson): + self.hand.append(self.available_cs.pop(card_index)) if len(self.available_cards) == 1: - self.game.deck.put_on_top(self.available_cards.pop()) + self.game.deck.put_on_top(self.available_cs.pop()) self.is_drawing = False self.pending_action = PendingAction.PLAY self.notify_self() - else: # emporio + else: # emporio self.game.respond_emporio(self, card_index) def barrel_pick(self): pickable_cards = 1 + self.character.pick_mod - if len([c for c in self.equipment if isinstance(c, cards.Barile)]) > 0 and isinstance(self.character, characters.Jourdonnais): + if len([c for c in self.equipment if isinstance(c, cs.Barile)]) > 0 and isinstance(self.character, chars.Jourdonnais): pickable_cards = 2 while pickable_cards > 0: pickable_cards -= 1 - picked: cards.Card = self.game.deck.pick_and_scrap() + picked: cs.Card = self.game.deck.pick_and_scrap() print(f'Did pick {picked}') - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha estratto {picked}.') - if picked.suit == cards.Suit.HEARTS: + self.sio.emit('chat_message', room=self.game.name, + data=f'{self.name} ha estratto {picked}.') + if picked.suit == cs.Suit.HEARTS: self.mancato_needed -= 1 self.notify_self() if self.mancato_needed <= 0: self.game.responders_did_respond_resume_turn() return - if len([c for c in self.hand if isinstance(c, cards.Mancato) or (isinstance(self.character, characters.CalamityJanet) and isinstance(c, cards.Bang))]) == 0: + if len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang))]) == 0: self.take_damage_response() self.game.responders_did_respond_resume_turn() else: self.pending_action = PendingAction.RESPOND - self.expected_response = [cards.Mancato(0,0).name] + self.expected_response = [cs.Mancato(0, 0).name] self.on_failed_response_cb = self.take_damage_response self.notify_self() def get_banged(self, attacker, double=False): self.attacker = attacker self.mancato_needed = 1 if not double else 2 - if len([c for c in self.hand if isinstance(c, cards.Mancato) or (isinstance(self.character, characters.CalamityJanet) and isinstance(c, cards.Bang))]) == 0 and len([c for c in self.equipment if isinstance(c, cards.Barile)]) == 0 and not isinstance(self.character, characters.Jourdonnais): + if len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang))]) == 0 and len([c for c in self.equipment if isinstance(c, cs.Barile)]) == 0 and not isinstance(self.character, chars.Jourdonnais): print('Cant defend') self.take_damage_response() return False else: - if len([c for c in self.equipment if isinstance(c, cards.Barile)]) > 0 or isinstance(self.character, characters.Jourdonnais): + if len([c for c in self.equipment if isinstance(c, cs.Barile)]) > 0 or isinstance(self.character, chars.Jourdonnais): print('has barrel') self.pending_action = PendingAction.PICK self.on_pick_cb = self.barrel_pick else: print('has mancato') self.pending_action = PendingAction.RESPOND - self.expected_response = [cards.Mancato(0,0).name] + self.expected_response = [cs.Mancato(0, 0).name] self.on_failed_response_cb = self.take_damage_response self.notify_self() return True def get_indians(self, attacker): self.attacker = attacker - if len([c for c in self.hand if isinstance(c, cards.Bang) or (isinstance(self.character, characters.CalamityJanet) and isinstance(c, cards.Mancato))]) == 0: + if len([c for c in self.hand if isinstance(c, cs.Bang) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0: print('Cant defend') self.take_damage_response() return False else: print('has bang') self.pending_action = PendingAction.RESPOND - self.expected_response = [cards.Bang(0,0).name] + self.expected_response = [cs.Bang(0, 0).name] self.event_type = 'indians' self.on_failed_response_cb = self.take_damage_response self.notify_self() @@ -414,14 +366,14 @@ class Player: def get_dueled(self, attacker): self.attacker = attacker - if len([c for c in self.hand if isinstance(c, cards.Bang) or (isinstance(self.character, characters.CalamityJanet) and isinstance(c, cards.Mancato))]) == 0: + if len([c for c in self.hand if isinstance(c, cs.Bang) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0: print('Cant defend') self.take_damage_response() self.game.responders_did_respond_resume_turn() return False else: self.pending_action = PendingAction.RESPOND - self.expected_response = [cards.Bang(0,0).name] + self.expected_response = [cs.Bang(0, 0).name] self.event_type = 'duel' self.on_failed_response_cb = self.take_damage_response self.notify_self() @@ -430,17 +382,19 @@ class Player: def take_damage_response(self): self.lives -= 1 if self.lives > 0: - if isinstance(self.character, characters.BartCassidy): + if isinstance(self.character, chars.BartCassidy): self.hand.append(self.game.deck.draw()) - elif isinstance(self.character, characters.ElGringo) and self.attacker and len(self.attacker.hand) > 0: - self.hand.append(self.attacker.hand.pop(randrange(0, len(self.attacker.hand)))) + elif isinstance(self.character, chars.ElGringo) and self.attacker and len(self.attacker.hand) > 0: + self.hand.append(self.attacker.hand.pop( + randrange(0, len(self.attacker.hand)))) self.attacker.notify_self() - while self.lives <= 0 and len(self.game.players) > 2 and len([c for c in self.hand if isinstance(c, cards.Birra)]) > 0: + while self.lives <= 0 and len(self.game.players) > 2 and len([c for c in self.hand if isinstance(c, cs.Birra)]) > 0: for i in range(len(self.hand)): - if isinstance(self.hand[i], cards.Birra): + if isinstance(self.hand[i], cs.Birra): self.lives += 1 self.game.deck.scrap(self.hand.pop(i)) - self.sio.emit('chat_message', room=self.game.name, data=f'{self.name} ha usato una birra per recuperare una vita.') + self.sio.emit('chat_message', room=self.game.name, + data=f'{self.name} ha usato una birra per recuperare una vita.') break self.mancato_needed = 0 self.notify_self() @@ -487,18 +441,20 @@ class Player: return self.character.visibility_mod + covers def scrap(self, card_index): - if self.is_my_turn or isinstance(self.character, characters.SidKetchum): + if self.is_my_turn or isinstance(self.character, chars.SidKetchum): self.scrapped_cards += 1 - if isinstance(self.character, characters.SidKetchum) and self.scrapped_cards == 2: + if isinstance(self.character, chars.SidKetchum) and self.scrapped_cards == 2: self.scrapped_cards = 0 self.lives = min(self.lives+1, self.max_lives) self.game.deck.scrap(self.hand.pop(card_index)) self.notify_self() def end_turn(self, forced=False): - if not self.is_my_turn: return + if not self.is_my_turn: + return if len(self.hand) > self.max_lives and not forced: - print(f"I {self.name} have to many cards in my hand and I can't end the turn") + print( + f"I {self.name} have to many cards in my hand and I can't end the turn") else: self.is_my_turn = False self.pending_action = PendingAction.WAIT