From a7fe148ff93479444954865b88b13bf67cdb59fe Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 14:06:07 +0100 Subject: [PATCH 01/21] benedizione, maledizione --- backend/bang/cards.py | 9 ++++ backend/bang/deck.py | 4 ++ .../bang/expansions/high_noon/card_events.py | 41 +++++++++++++++++++ backend/bang/game.py | 2 +- backend/bang/players.py | 15 +++---- 5 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 backend/bang/expansions/high_noon/card_events.py diff --git a/backend/bang/cards.py b/backend/bang/cards.py index 20816d4..ad56b8b 100644 --- a/backend/bang/cards.py +++ b/backend/bang/cards.py @@ -75,6 +75,15 @@ class Card(ABC): def is_duplicate_card(self, player): return self.name in [c.name for c in player.equipment] + def check_suit(self, game, accepted): + import bang.expansions.high_noon.card_events as ceh + if game.check_event(ceh.Benedizione): + return Suit.HEARTS in accepted + elif game.check_event(ceh.Maledizione): + return Suit.SPADES in accepted + return self.suit in accepted + + class Barile(Card): def __init__(self, suit, number): diff --git a/backend/bang/deck.py b/backend/bang/deck.py index 136127d..0205e45 100644 --- a/backend/bang/deck.py +++ b/backend/bang/deck.py @@ -2,6 +2,7 @@ from typing import List, Set, Dict, Tuple, Optional 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 class Deck: def __init__(self, game): @@ -22,6 +23,9 @@ class Deck: self.event_cards: List[ce.CardEvent] = [] if 'fistful_of_cards' in game.expansions: self.event_cards.extend(ce.get_all_events()) + if 'high_noon' in game.expansions: + self.event_cards.extend(ceh.get_all_events()) + if len(self.event_cards) > 0: self.event_cards.insert(0, None) self.event_cards.insert(0, None) # 2 perchè iniziale, e primo flip dallo sceriffo random.shuffle(self.cards) diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py new file mode 100644 index 0000000..034c250 --- /dev/null +++ b/backend/bang/expansions/high_noon/card_events.py @@ -0,0 +1,41 @@ +import random +from bang.expansions.fistful_of_cards.card_events import CardEvent + +class Benedizione(CardEvent): + def __init__(self): + super().__init__("Benedizione", "🙏") + self.desc = "Tutte le carte sono considerate di cuori ♥️" + self.desc_eng = "" + +class Maledizione(CardEvent): + def __init__(self): + super().__init__("Maledizione", "🤬") + self.desc = "Tutte le carte sono considerate di picche ♠" + self.desc_eng = "" + +class MezzogiornoDiFuoco(CardEvent): + def __init__(self): + super().__init__("Mezzogiorno di Fuoco", "🔥") + self.desc = "Ogni giocatore perde 1 punto vita all'inizio del turno" + self.desc_eng = "Every player loses 1 HP when their turn starts" + +def get_all_events(): + cards = [ + Benedizione(), + Maledizione(), + # CittaFantasma(), + # CorsaAllOro(), + # IDalton(), + # IlDottore(), + # IlReverendo(), + # IlTreno(), + # Sbornia(), + # Seromone(), + # Sete(), + # Sparatoria(), + ] + random.shuffle(cards) + cards.append(MezzogiornoDiFuoco()) + for c in cards: + c.expansion = 'high-noon' + return cards \ No newline at end of file diff --git a/backend/bang/game.py b/backend/bang/game.py index b4a210b..f57798a 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -24,7 +24,7 @@ class Game: self.initial_players = 0 self.password = '' self.expansions = [] - self.available_expansions = ['dodge_city', 'fistful_of_cards'] + self.available_expansions = ['dodge_city', 'fistful_of_cards', 'high_noon'] self.shutting_down = False self.is_competitive = False self.disconnect_bot = True diff --git a/backend/bang/players.py b/backend/bang/players.py index cb0297a..ba36176 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -9,6 +9,7 @@ import bang.expansions.dodge_city.cards as csd import bang.characters as chars import bang.expansions.dodge_city.characters as chd import bang.expansions.fistful_of_cards.card_events as ce +import bang.expansions.high_noon.card_events as ceh import eventlet class PendingAction(IntEnum): @@ -403,7 +404,7 @@ class Player: for p in self.game.players: if p != self: p.notify_card(self, card, 'blackjack_special' if isinstance(self.character, chars.BlackJack) else 'foc.leggedelwest') - if card.suit == cs.Suit.HEARTS or card.suit == cs.Suit.DIAMONDS and isinstance(self.character, chars.BlackJack): + if card.check_suit(self.game, [cs.Suit.HEARTS, cs.Suit.DIAMONDS]) and isinstance(self.character, chars.BlackJack): self.hand.append(self.game.deck.draw()) if isinstance(self.character, chd.PixiePete): self.hand.append(self.game.deck.draw()) @@ -422,7 +423,7 @@ class Player: print(f'Did pick {picked}') self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked}') - if picked.suit == cs.Suit.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0: + if picked.check_suit(self.game, [cs.Suit.SPADES]) and 2 <= picked.number <= 9 and pickable_cards == 0: self.lives -= 3 self.game.deck.scrap(self.equipment.pop(i), True) self.sio.emit('chat_message', room=self.game.name, data=f'_explode|{self.name}') @@ -448,7 +449,7 @@ class Player: print(f'Did pick {picked}') self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked}') - if picked.suit != cs.Suit.HEARTS and pickable_cards == 0: + if not picked.check_suit(self.game, [cs.Suit.HEARTS]) and pickable_cards == 0: self.game.deck.scrap(self.equipment.pop(i), True) self.end_turn(forced=True) return @@ -497,7 +498,7 @@ class Player: print(self.name, 'is playing ', card, ' against:', against, ' with:', _with) did_play_card = False event_blocks_card = (self.game.check_event(ce.IlGiudice) and (card.is_equipment or (card.usable_next_turn and not card.can_be_used_now))) or (self.game.check_event(ce.Lazo) and card.usable_next_turn and card.can_be_used_now) - if not(against != None and isinstance(self.game.get_player_named(against).character, chd.ApacheKid) and card.suit == cs.Suit.DIAMONDS) and not event_blocks_card: + if not(against != None and isinstance(self.game.get_player_named(against).character, chd.ApacheKid) and card.check_suit(self.game, [cs.Suit.DIAMONDS])) and not event_blocks_card: if against == self.name and not isinstance(card, csd.Tequila): did_play_card = False else: @@ -647,7 +648,7 @@ class Player: print(f'Did pick {picked}') self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked}') - if picked.suit == cs.Suit.HEARTS: + if picked.check_suit(self.game, [cs.Suit.HEARTS]): self.mancato_needed -= 1 self.notify_self() if self.mancato_needed <= 0: @@ -677,7 +678,7 @@ class Player: print(f'Did pick {picked}') self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked}') - if picked.suit == cs.Suit.HEARTS: + if picked.check_suit(self.game, [cs.Suit.HEARTS]): self.mancato_needed -= 1 self.notify_self() if self.mancato_needed <= 0: @@ -921,7 +922,7 @@ class Player: if not forced and self.game.check_event(ce.Vendetta) and self.can_play_vendetta: picked: cs.Card = self.game.deck.pick_and_scrap() self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked}') - if picked.suit == cs.Suit.HEARTS: + if picked.check_suit(self.game, [cs.Suit.HEARTS]): self.play_turn(can_play_vendetta=False) return self.is_my_turn = False From 0ac0a66c06aa752ab7c3b75a5d6820f5008b9e4e Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 14:25:23 +0100 Subject: [PATCH 02/21] sbornia --- backend/bang/cards.py | 6 +- backend/bang/characters.py | 20 +--- .../bang/expansions/high_noon/card_events.py | 10 +- backend/bang/game.py | 6 +- backend/bang/players.py | 92 +++++++++---------- 5 files changed, 65 insertions(+), 69 deletions(-) diff --git a/backend/bang/cards.py b/backend/bang/cards.py index ad56b8b..979441d 100644 --- a/backend/bang/cards.py +++ b/backend/bang/cards.py @@ -196,7 +196,7 @@ class Bang(Card): super().play_card(player, against=against) player.has_played_bang = not isinstance( player.character, chars.WillyTheKid) - player.game.attack(player, against, double=isinstance(player.character, chars.SlabTheKiller)) + player.game.attack(player, against, double=player.character.check(player.game, chars.SlabTheKiller)) return True return False @@ -213,7 +213,7 @@ class Birra(Card): super().play_card(player, against=against) player.lives = min(player.lives+1, player.max_lives) import bang.expansions.dodge_city.characters as chd - if isinstance(player.character, chd.TequilaJoe): + if player.character.check(player.game, chd.TequilaJoe): player.lives = min(player.lives+1, player.max_lives) return True elif len(player.game.players) == 2: @@ -323,7 +323,7 @@ class Mancato(Card): def play_card(self, player, against, _with=None): import bang.characters as chars - if (not player.has_played_bang and against != None and isinstance(player.character, chars.CalamityJanet)): + if (not player.has_played_bang and against != None and player.character.check(player.game, chars.CalamityJanet)): player.sio.emit('chat_message', room=player.game.name, data=f'_special_calamity|{player.name}|{self.name}|{against}') player.has_played_bang = True diff --git a/backend/bang/characters.py b/backend/bang/characters.py index ea6c0ce..a72df42 100644 --- a/backend/bang/characters.py +++ b/backend/bang/characters.py @@ -13,21 +13,11 @@ class Character(ABC): self.icon = '🤷‍♂️' self.number = ''.join(['❤️']*self.max_lives) - # @abstractmethod - # def on_hurt(self, dmg: int): - # pass - - # @abstractmethod - # def on_pick(self, card): # tipo dinamite e prigione - # pass - - # @abstractmethod - # def on_empty_hand(self): - # pass - - # @abstractmethod - # def on_empty_hand(self): - # pass + def check(self, game, character): + import bang.expansions.high_noon.card_events as ceh + if game.check_event(ceh.Sbornia): + return False + return isinstance(self, character) class BartCassidy(Character): def __init__(self): diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index 034c250..fb9bde3 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -13,6 +13,12 @@ class Maledizione(CardEvent): self.desc = "Tutte le carte sono considerate di picche ♠" self.desc_eng = "" +class Sbornia(CardEvent): + def __init__(self): + super().__init__("Sbornia", "🥴") + self.desc = "I personaggi perdono la loro abilità speciale" + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -29,13 +35,13 @@ def get_all_events(): # IlDottore(), # IlReverendo(), # IlTreno(), - # Sbornia(), + Sbornia(), # Seromone(), # Sete(), # Sparatoria(), ] random.shuffle(cards) - cards.append(MezzogiornoDiFuoco()) + # cards.append(MezzogiornoDiFuoco()) for c in cards: c.expansion = 'high-noon' return cards \ No newline at end of file diff --git a/backend/bang/game.py b/backend/bang/game.py index f57798a..21179c6 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -376,7 +376,7 @@ class Game: eventlet.sleep(5.0) return self.reset() - vulture = [p for p in self.players if isinstance(p.character, characters.VultureSam)] + vulture = [p for p in self.players if p.character.check(self, characters.VultureSam)] if len(vulture) == 0: for i in range(len(player.hand)): self.deck.scrap(player.hand.pop(), True) @@ -402,10 +402,10 @@ class Game: self.deck.scrap(player.attacker.hand.pop(), True) player.attacker.notify_self() - greg = [p for p in self.players if isinstance(p.character, chd.GregDigger)] + greg = [p for p in self.players if p.character.check(self, chd.GregDigger)] if len(greg) > 0: greg[0].lives = min(greg[0].lives+2, greg[0].max_lives) - herb = [p for p in self.players if isinstance(p.character, chd.HerbHunter)] + herb = [p for p in self.players if p.character.check(self, chd.HerbHunter)] if len(herb) > 0: herb[0].hand.append(self.deck.draw(True)) herb[0].hand.append(self.deck.draw(True)) diff --git a/backend/bang/players.py b/backend/bang/players.py index ba36176..b9c0d65 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -174,11 +174,11 @@ class Player: self.is_playing_ranch = True self.choose_text = 'choose_ranch' self.pending_action = PendingAction.CHOOSE - elif isinstance(self.character, chars.SuzyLafayette) and len(self.hand) == 0 and ( not self.is_my_turn or self.pending_action == PendingAction.PLAY): + elif self.character and self.character.check(self.game, chars.SuzyLafayette) and len(self.hand) == 0 and ( not self.is_my_turn or self.pending_action == PendingAction.PLAY): self.hand.append(self.game.deck.draw(True)) if self.lives <= 0 and self.max_lives > 0: print('dying, attacker', self.attacker) - if isinstance(self.character, chars.SidKetchum) and len(self.hand) > 1: + if self.character.check(self.game, chars.SidKetchum) and len(self.hand) > 1: self.lives += 1 #TODO Sid dovrebbe poter decidere cosa scartare self.game.deck.scrap(self.hand.pop( @@ -272,7 +272,7 @@ class Player: if self.play_card(len(self.hand)+self.equipment.index(c), against=target['name']): return break - maxcards = self.lives if not isinstance(self.character, chd.SeanMallory) else 10 + maxcards = self.lives if not self.character.check(self.game, chd.SeanMallory) else 10 if len(self.hand) > maxcards: self.scrap(0) else: @@ -366,13 +366,13 @@ class Player: self.lives += 1 self.pending_action = PendingAction.PLAY self.notify_self() - elif isinstance(self.character, chars.KitCarlson): + elif self.character.check(self.game, chars.KitCarlson): self.is_drawing = True self.available_cards = [self.game.deck.draw() for i in range(3)] self.choose_text = 'choose_card_to_get' self.pending_action = PendingAction.CHOOSE self.notify_self() - elif isinstance(self.character, chd.PatBrennan) and type(pile) == str and pile != self.name and pile in self.game.players_map and len(self.game.get_player_named(pile).equipment) > 0: + elif self.character.check(self.game, chd.PatBrennan) and type(pile) == str and pile != self.name and pile in self.game.players_map and len(self.game.get_player_named(pile).equipment) > 0: self.is_drawing = True self.available_cards = self.game.get_player_named(pile).equipment self.choose_text = 'choose_card_to_get' @@ -380,19 +380,19 @@ class Player: self.notify_self() else: self.pending_action = PendingAction.PLAY - if pile == 'scrap' and isinstance(self.character, chars.PedroRamirez): + if pile == 'scrap' and self.character.check(self.game, chars.PedroRamirez): self.hand.append(self.game.deck.draw_from_scrap_pile()) self.hand.append(self.game.deck.draw()) self.sio.emit('chat_message', room=self.game.name, data=f'_draw_from_scrap|{self.name}') - 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: + elif type(pile) == str and pile != self.name and pile in self.game.players_map and self.character.check(self.game, 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.game.get_player_named(pile).notify_self() self.sio.emit('chat_message', room=self.game.name, data=f'_draw_from_player|{self.name}|{pile}') self.hand.append(self.game.deck.draw()) - elif isinstance(self.character, chd.BillNoface): + elif self.character.check(self.game, chd.BillNoface): self.hand.append(self.game.deck.draw()) for i in range(self.max_lives-self.lives): self.hand.append(self.game.deck.draw()) @@ -400,13 +400,13 @@ class Player: for i in range(2): card: cs.Card = self.game.deck.draw() self.hand.append(card) - if i == 1 and isinstance(self.character, chars.BlackJack) or self.game.check_event(ce.LeggeDelWest): + if i == 1 and self.character.check(self.game, chars.BlackJack) or self.game.check_event(ce.LeggeDelWest): for p in self.game.players: if p != self: - p.notify_card(self, card, 'blackjack_special' if isinstance(self.character, chars.BlackJack) else 'foc.leggedelwest') - if card.check_suit(self.game, [cs.Suit.HEARTS, cs.Suit.DIAMONDS]) and isinstance(self.character, chars.BlackJack): + p.notify_card(self, card, 'blackjack_special' if self.character.check(self.game, chars.BlackJack) else 'foc.leggedelwest') + if card.check_suit(self.game, [cs.Suit.HEARTS, cs.Suit.DIAMONDS]) and self.character.check(self.game, chars.BlackJack): self.hand.append(self.game.deck.draw()) - if isinstance(self.character, chd.PixiePete): + if self.character.check(self.game, chd.PixiePete): self.hand.append(self.game.deck.draw()) self.notify_self() @@ -428,7 +428,7 @@ class Player: self.game.deck.scrap(self.equipment.pop(i), True) self.sio.emit('chat_message', room=self.game.name, data=f'_explode|{self.name}') self.heal_if_needed() - if isinstance(self.character, chars.BartCassidy) and self.lives > 0: + if self.character.check(self.game, chars.BartCassidy) and self.lives > 0: for i in range(3): self.hand.append(self.game.deck.draw(True)) self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}') @@ -620,14 +620,14 @@ class Player: self.pending_action = PendingAction.PLAY self.notify_self() # specifico per personaggio - elif self.is_drawing and isinstance(self.character, chars.KitCarlson): + elif self.is_drawing and self.character.check(self.game, chars.KitCarlson): self.hand.append(self.available_cards.pop(card_index)) if len(self.available_cards) == 1: self.game.deck.put_on_top(self.available_cards.pop()) self.is_drawing = False self.pending_action = PendingAction.PLAY self.notify_self() - elif self.is_drawing and isinstance(self.character, chd.PatBrennan): + elif self.is_drawing and self.character.check(self.game, chd.PatBrennan): card = self.available_cards.pop(card_index) if card.usable_next_turn: card.can_be_used_now = False @@ -640,7 +640,7 @@ class Player: def barrel_pick(self): pickable_cards = 1 + self.character.pick_mod - if len([c for c in self.equipment if isinstance(c, cs.Barile)]) > 0 and isinstance(self.character, chars.Jourdonnais): + if len([c for c in self.equipment if isinstance(c, cs.Barile)]) > 0 and self.character.check(self.game, chars.Jourdonnais): pickable_cards = 2 while pickable_cards > 0: pickable_cards -= 1 @@ -654,23 +654,23 @@ class Player: if self.mancato_needed <= 0: self.game.responders_did_respond_resume_turn(did_lose=False) return - if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang)) or isinstance(self.character, chd.ElenaFuente)]) == 0\ + if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Mancato) or (self.character.check(self.game, chars.CalamityJanet) and isinstance(c, cs.Bang)) or self.character.check(self.game, chd.ElenaFuente)]) == 0\ and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 0: self.take_damage_response() self.game.responders_did_respond_resume_turn(did_lose=True) else: self.pending_action = PendingAction.RESPOND self.expected_response = self.game.deck.mancato_cards.copy() - if isinstance(self.character, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: + if self.character.check(self.game, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: self.expected_response.append(cs.Bang(0, 0).name) - elif isinstance(self.character, chd.ElenaFuente): + elif self.character.check(self.game, chd.ElenaFuente): self.expected_response = self.game.deck.all_cards_str self.on_failed_response_cb = self.take_damage_response self.notify_self() def barrel_pick_no_dmg(self): pickable_cards = 1 + self.character.pick_mod - if len([c for c in self.equipment if isinstance(c, cs.Barile)]) > 0 and isinstance(self.character, chars.Jourdonnais): + if len([c for c in self.equipment if isinstance(c, cs.Barile)]) > 0 and self.character.check(self.game, chars.Jourdonnais): pickable_cards = 2 while pickable_cards > 0: pickable_cards -= 1 @@ -684,16 +684,16 @@ class Player: if self.mancato_needed <= 0: self.game.responders_did_respond_resume_turn(did_lose=False) return - if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang)) or isinstance(self.character, chd.ElenaFuente)]) == 0\ + if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Mancato) or (self.character.check(self.game, chars.CalamityJanet) and isinstance(c, cs.Bang)) or self.character.check(self.game, chd.ElenaFuente)]) == 0\ and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 0: self.take_no_damage_response() self.game.responders_did_respond_resume_turn(did_lose=True) else: self.pending_action = PendingAction.RESPOND self.expected_response = self.game.deck.mancato_cards.copy() - if isinstance(self.character, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: + if self.character.check(self.game, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: self.expected_response.append(cs.Bang(0, 0).name) - elif isinstance(self.character, chd.ElenaFuente): + elif self.character.check(self.game, chd.ElenaFuente): self.expected_response = self.game.deck.all_cards_str self.on_failed_response_cb = self.take_no_damage_response self.notify_self() @@ -708,8 +708,8 @@ class Player: for i in range(len(self.equipment)): if self.equipment[i].can_be_used_now: print('usable', self.equipment[i]) - if not self.game.is_competitive and len([c for c in self.equipment if isinstance(c, cs.Barile)]) == 0 and not isinstance(self.character, chars.Jourdonnais)\ - and len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang)) or isinstance(self.character, chd.ElenaFuente)]) == 0\ + if not self.game.is_competitive and len([c for c in self.equipment if isinstance(c, cs.Barile)]) == 0 and not self.character.check(self.game, chars.Jourdonnais)\ + and len([c for c in self.hand if isinstance(c, cs.Mancato) or (self.character.check(self.game, chars.CalamityJanet) and isinstance(c, cs.Bang)) or self.character.check(self.game, chd.ElenaFuente)]) == 0\ and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 0: print('Cant defend') if not no_dmg: @@ -718,7 +718,7 @@ class Player: self.take_no_damage_response() return False else: - if (not self.game.check_event(ce.Lazo) and len([c for c in self.equipment if isinstance(c, cs.Barile)]) > 0) or isinstance(self.character, chars.Jourdonnais): + if (not self.game.check_event(ce.Lazo) and len([c for c in self.equipment if isinstance(c, cs.Barile)]) > 0) or self.character.check(self.game, chars.Jourdonnais): print('has barrel') self.pending_action = PendingAction.PICK if not no_dmg: @@ -731,9 +731,9 @@ class Player: self.expected_response = self.game.deck.mancato_cards.copy() if self.attacker and self.attacker in self.game.players and isinstance(self.attacker.character, chd.BelleStar) or self.game.check_event(ce.Lazo): self.expected_response = self.game.deck.mancato_cards_not_green - elif isinstance(self.character, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: + elif self.character.check(self.game, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: self.expected_response.append(cs.Bang(0, 0).name) - elif isinstance(self.character, chd.ElenaFuente): + elif self.character.check(self.game, chd.ElenaFuente): self.expected_response = self.game.deck.all_cards_str if not no_dmg: self.on_failed_response_cb = self.take_damage_response @@ -743,8 +743,8 @@ class Player: def get_indians(self, attacker): self.attacker = attacker - if isinstance(self.character, chd.ApacheKid): return False - if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Bang) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0: + if self.character.check(self.game, chd.ApacheKid): return False + if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Bang) or (self.character.check(self.game, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0: print('Cant defend') self.take_damage_response() return False @@ -752,7 +752,7 @@ class Player: print('has bang') self.pending_action = PendingAction.RESPOND self.expected_response = [cs.Bang(0, 0).name] - if isinstance(self.character, chars.CalamityJanet) and cs.Mancato(0, 0).name not in self.expected_response: + if self.character.check(self.game, chars.CalamityJanet) and cs.Mancato(0, 0).name not in self.expected_response: self.expected_response.append(cs.Mancato(0, 0).name) self.event_type = 'indians' self.on_failed_response_cb = self.take_damage_response @@ -760,7 +760,7 @@ class Player: def get_dueled(self, attacker): self.attacker = attacker - if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Bang) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0: + if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Bang) or (self.character.check(self.game, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0: print('Cant defend') self.take_damage_response() self.game.responders_did_respond_resume_turn(did_lose=True) @@ -768,7 +768,7 @@ class Player: else: self.pending_action = PendingAction.RESPOND self.expected_response = [cs.Bang(0, 0).name] - if isinstance(self.character, chars.CalamityJanet) and cs.Mancato(0, 0).name not in self.expected_response: + if self.character.check(self.game, chars.CalamityJanet) and cs.Mancato(0, 0).name not in self.expected_response: self.expected_response.append(cs.Mancato(0, 0).name) self.event_type = 'duel' self.on_failed_response_cb = self.take_damage_response @@ -778,9 +778,9 @@ class Player: 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], cs.Birra): - if isinstance(self.character, chd.MollyStark) and not self.is_my_turn: + if self.character.check(self.game, chd.MollyStark) and not self.is_my_turn: self.hand.append(self.game.deck.draw(True)) - self.lives += 1 if not isinstance(self.character, chd.TequilaJoe) else 2 + self.lives += 1 if not self.character.check(self.game, chd.TequilaJoe) else 2 self.game.deck.scrap(self.hand.pop(i), True) self.sio.emit('chat_message', room=self.game.name, data=f'_beer_save|{self.name}') @@ -789,11 +789,11 @@ class Player: def take_damage_response(self): self.lives -= 1 if self.lives > 0: - if isinstance(self.character, chars.BartCassidy): + if self.character.check(self.game, chars.BartCassidy): self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}') self.hand.append(self.game.deck.draw(True)) - elif isinstance(self.character, chars.ElGringo) and self.attacker and self.attacker in self.game.players and len(self.attacker.hand) > 0: + elif self.character.check(self.game, chars.ElGringo) and self.attacker and self.attacker in self.game.players and len(self.attacker.hand) > 0: self.hand.append(self.attacker.hand.pop( randrange(0, len(self.attacker.hand)))) self.sio.emit('chat_message', room=self.game.name, @@ -823,7 +823,7 @@ class Player: ((hand_index < len(self.hand) and self.hand[hand_index].name in self.expected_response)) or (hand_index-len(self.hand) < len(self.equipment) and self.equipment[hand_index-len(self.hand)].name in self.expected_response)): card = self.hand.pop(hand_index) if hand_index < len(self.hand) else self.equipment.pop(hand_index-len(self.hand)) - if isinstance(self.character, chd.MollyStark) and hand_index < len(self.hand)+1 and not self.is_my_turn and self.event_type != 'duel': + if self.character.check(self.game, chd.MollyStark) and hand_index < len(self.hand)+1 and not self.is_my_turn and self.event_type != 'duel': self.hand.append(self.game.deck.draw(True)) card.use_card(self) self.game.deck.scrap(card, True) @@ -832,7 +832,7 @@ class Player: if self.mancato_needed <= 0: if self.event_type == 'duel': self.game.duel(self, self.attacker.name) - if isinstance(self.character, chd.MollyStark) and hand_index < len(self.hand)+1 and not self.is_my_turn: + if self.character.check(self.game, chd.MollyStark) and hand_index < len(self.hand)+1 and not self.is_my_turn: self.molly_discarded_cards += 1 else: self.game.responders_did_respond_resume_turn(did_lose=False) @@ -842,7 +842,7 @@ class Player: self.pending_action = PendingAction.RESPOND self.notify_self() else: - if isinstance(self.character, chd.MollyStark) and not self.is_my_turn: + if self.character.check(self.game, chd.MollyStark) and not self.is_my_turn: for i in range(self.molly_discarded_cards): self.hand.append(self.game.deck.draw(True)) self.molly_discarded_cards = 0 @@ -882,13 +882,13 @@ class Player: return self.character.visibility_mod + covers def scrap(self, card_index): - if self.is_my_turn or isinstance(self.character, chars.SidKetchum): + if self.is_my_turn or self.character.check(self.game, chars.SidKetchum): self.scrapped_cards += 1 card = self.hand.pop(card_index) - if isinstance(self.character, chars.SidKetchum) and self.scrapped_cards == 2: + if self.character.check(self.game, chars.SidKetchum) and self.scrapped_cards == 2: self.scrapped_cards = 0 self.lives = min(self.lives+1, self.max_lives) - elif isinstance(self.character, chd.JoseDelgrado) and card.is_equipment and self.special_use_count < 2: + elif self.character.check(self.game, chd.JoseDelgrado) and card.is_equipment and self.special_use_count < 2: self.hand.append(self.game.deck.draw(True)) self.hand.append(self.game.deck.draw(True)) self.special_use_count += 1 @@ -896,7 +896,7 @@ class Player: self.notify_self() def holyday_special(self, data): - if isinstance(self.character, chd.DocHolyday) and self.special_use_count < 1: + if self.character.check(self.game, chd.DocHolyday) and self.special_use_count < 1: self.special_use_count += 1 cards = sorted(data['cards'], reverse=True) for c in cards: @@ -905,7 +905,7 @@ class Player: self.game.attack(self, data['against']) def chuck_lose_hp_draw(self): - if isinstance(self.character, chd.ChuckWengam) and self.lives > 1 and self.is_my_turn: + if self.character.check(self.game, chd.ChuckWengam) and self.lives > 1 and self.is_my_turn: self.lives -= 1 self.hand.append(self.game.deck.draw(True)) self.hand.append(self.game.deck.draw(True)) @@ -914,7 +914,7 @@ class Player: def end_turn(self, forced=False): if not self.is_my_turn: return - maxcards = self.lives if not isinstance(self.character, chd.SeanMallory) else 10 + maxcards = self.lives if not self.character.check(self.game, chd.SeanMallory) else 10 if len(self.hand) > maxcards and not forced: print( f"I {self.name} have to many cards in my hand and I can't end the turn") From 95b6f016d28708194be7256a7a2cd43e722f51ac Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 14:41:13 +0100 Subject: [PATCH 03/21] add sete --- backend/bang/expansions/high_noon/card_events.py | 8 +++++++- backend/bang/players.py | 13 +++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index fb9bde3..6ecd001 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -19,6 +19,12 @@ class Sbornia(CardEvent): self.desc = "I personaggi perdono la loro abilità speciale" self.desc_eng = "" +class Sete(CardEvent): + def __init__(self): + super().__init__("Sete", "🥵") + self.desc = "I giocatori pescano solo 1 carta" + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -37,7 +43,7 @@ def get_all_events(): # IlTreno(), Sbornia(), # Seromone(), - # Sete(), + Sete(), # Sparatoria(), ] random.shuffle(cards) diff --git a/backend/bang/players.py b/backend/bang/players.py index b9c0d65..04c03c5 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -382,7 +382,8 @@ class Player: self.pending_action = PendingAction.PLAY if pile == 'scrap' and self.character.check(self.game, chars.PedroRamirez): self.hand.append(self.game.deck.draw_from_scrap_pile()) - self.hand.append(self.game.deck.draw()) + if not self.game.check_event(ceh.Sete): + self.hand.append(self.game.deck.draw()) self.sio.emit('chat_message', room=self.game.name, data=f'_draw_from_scrap|{self.name}') elif type(pile) == str and pile != self.name and pile in self.game.players_map and self.character.check(self.game, chars.JesseJones) and len(self.game.get_player_named(pile).hand) > 0: @@ -391,11 +392,13 @@ class Player: self.game.get_player_named(pile).notify_self() self.sio.emit('chat_message', room=self.game.name, data=f'_draw_from_player|{self.name}|{pile}') - self.hand.append(self.game.deck.draw()) + if not self.game.check_event(ceh.Sete): + self.hand.append(self.game.deck.draw()) elif self.character.check(self.game, chd.BillNoface): self.hand.append(self.game.deck.draw()) - for i in range(self.max_lives-self.lives): - self.hand.append(self.game.deck.draw()) + if not self.game.check_event(ceh.Sete): + for i in range(self.max_lives-self.lives): + self.hand.append(self.game.deck.draw()) else: for i in range(2): card: cs.Card = self.game.deck.draw() @@ -406,6 +409,8 @@ class Player: p.notify_card(self, card, 'blackjack_special' if self.character.check(self.game, chars.BlackJack) else 'foc.leggedelwest') if card.check_suit(self.game, [cs.Suit.HEARTS, cs.Suit.DIAMONDS]) and self.character.check(self.game, chars.BlackJack): self.hand.append(self.game.deck.draw()) + if self.game.check_event(ceh.Sete): + return self.notify_self() if self.character.check(self.game, chd.PixiePete): self.hand.append(self.game.deck.draw()) self.notify_self() From c0a2481b00d62c09564c95e2835669d8f7248475 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 14:50:12 +0100 Subject: [PATCH 04/21] Il treno --- backend/bang/expansions/high_noon/card_events.py | 8 +++++++- backend/bang/players.py | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index 6ecd001..acf0e7f 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -25,6 +25,12 @@ class Sete(CardEvent): self.desc = "I giocatori pescano solo 1 carta" self.desc_eng = "" +class IlTreno(CardEvent): + def __init__(self): + super().__init__("Il Treno", "🚂") + self.desc = "I giocatori pescano 1 carta extra" + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -40,7 +46,7 @@ def get_all_events(): # IDalton(), # IlDottore(), # IlReverendo(), - # IlTreno(), + IlTreno(), Sbornia(), # Seromone(), Sete(), diff --git a/backend/bang/players.py b/backend/bang/players.py index 04c03c5..0d2d8f5 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -413,6 +413,8 @@ class Player: return self.notify_self() if self.character.check(self.game, chd.PixiePete): self.hand.append(self.game.deck.draw()) + if self.game.check_event(ceh.IlTreno): + self.hand.append(self.game.deck.draw()) self.notify_self() def pick(self): @@ -627,7 +629,10 @@ class Player: # specifico per personaggio elif self.is_drawing and self.character.check(self.game, chars.KitCarlson): self.hand.append(self.available_cards.pop(card_index)) - if len(self.available_cards) == 1: + pickable_stop = 1 + if self.game.check_event(ceh.Sete): pickable_stop = 2 + if self.game.check_event(ceh.IlTreno): pickable_stop = 0 + if len(self.available_cards) == pickable_stop: self.game.deck.put_on_top(self.available_cards.pop()) self.is_drawing = False self.pending_action = PendingAction.PLAY From 8f18bee200655aa60c3dc1581be7c00f50344935 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 14:57:33 +0100 Subject: [PATCH 05/21] il reverendo --- backend/bang/cards.py | 3 +++ backend/bang/expansions/high_noon/card_events.py | 8 +++++++- backend/bang/players.py | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/bang/cards.py b/backend/bang/cards.py index 979441d..3662673 100644 --- a/backend/bang/cards.py +++ b/backend/bang/cards.py @@ -209,6 +209,9 @@ class Birra(Card): self.desc_eng = "Play this card to regain a life point. You cannot heal more than your character's maximum limit. If you are about to lose your last life point, you can also play this card on your opponent's turn. Beer no longer takes effect if there are only two players" def play_card(self, player, against, _with=None): + import bang.expansions.high_noon.card_events as ceh + if player.game.check_event(ceh.IlReverendo): + return False if len(player.game.players) != 2: super().play_card(player, against=against) player.lives = min(player.lives+1, player.max_lives) diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index acf0e7f..51548ee 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -31,6 +31,12 @@ class IlTreno(CardEvent): self.desc = "I giocatori pescano 1 carta extra" self.desc_eng = "" +class IlReverendo(CardEvent): + def __init__(self): + super().__init__("Il Reverendo", "⛪️") + self.desc = "Non si possono giocare birre" + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -45,7 +51,7 @@ def get_all_events(): # CorsaAllOro(), # IDalton(), # IlDottore(), - # IlReverendo(), + IlReverendo(), IlTreno(), Sbornia(), # Seromone(), diff --git a/backend/bang/players.py b/backend/bang/players.py index 0d2d8f5..f6fed02 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -229,7 +229,7 @@ class Player: self.draw('') elif self.pending_action == PendingAction.PLAY: equippables = [c for c in self.hand if (c.is_equipment or c.usable_next_turn) and not isinstance(c, cs.Prigione) and not any([type(c) == type(x) for x in self.equipment])] - misc = [c for c in self.hand if (isinstance(c, cs.WellsFargo) and not c.usable_next_turn) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives)] + misc = [c for c in self.hand if (isinstance(c, cs.WellsFargo) and not c.usable_next_turn) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives and not self.game.check_event(ceh.IlReverendo))] need_target = [c for c in self.hand if c.need_target and c.can_be_used_now and not (c.need_with and len(self.hand) < 2) and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo))) and not ( isinstance(c, cs.Prigione) and self.game.check_event(ce.IlGiudice))] green_cards = [c for c in self.equipment if not self.game.check_event(ce.Lazo) and not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now] if len(equippables) > 0 and not self.game.check_event(ce.IlGiudice): From 60b5c7699e7c2ae865b39d99f24d2e1de2ecaa13 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 15:14:21 +0100 Subject: [PATCH 06/21] il dottore --- backend/bang/expansions/high_noon/card_events.py | 8 +++++++- backend/bang/game.py | 13 ++++++++++++- frontend/src/i18n/en.json | 3 ++- frontend/src/i18n/it.json | 3 ++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index 51548ee..ec57619 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -37,6 +37,12 @@ class IlReverendo(CardEvent): self.desc = "Non si possono giocare birre" self.desc_eng = "" +class IlDottore(CardEvent): + def __init__(self): + super().__init__("Il Dottore", "👨‍⚕️") + self.desc = "Il giocatore con meno vite recupera 1 vita" + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -50,7 +56,7 @@ def get_all_events(): # CittaFantasma(), # CorsaAllOro(), # IDalton(), - # IlDottore(), + IlDottore(), IlReverendo(), IlTreno(), Sbornia(), diff --git a/backend/bang/game.py b/backend/bang/game.py index 21179c6..a3d5d14 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -2,12 +2,14 @@ from typing import List, Set, Dict, Tuple, Optional import random import socketio +import eventlet + import bang.players as pl import bang.characters as characters from bang.deck import Deck import bang.roles as roles import bang.expansions.fistful_of_cards.card_events as ce -import eventlet +import bang.expansions.high_noon.card_events as ceh class Game: def __init__(self, name, sio:socketio): @@ -277,6 +279,15 @@ class Game: else: self.responders_did_respond_resume_turn(did_lose=True) return + elif self.check_event(ceh.IlDottore): + most_hurt = [p.lives for p in self.players if p.lives > 0 and p.max_lives > p.lives] + if len(most_hurt) > 0: + hurt_players = [p for p in self.players if p.lives == min(most_hurt)] + for p in hurt_players: + p.lives += 1 + self.sio.emit('chat_message', room=self.name, data=f'_doctor_heal|{p.name}') + p.notify_self() + if self.check_event(ce.PerUnPugnoDiCarte) and len(self.players[self.turn].hand) > 0: self.player_bangs = len(self.players[self.turn].hand) if self.players[self.turn].get_banged(self.deck.event_cards[0]): diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index b2e6efd..b848505 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -90,7 +90,8 @@ "guess": "{0} guesses {1}.", "guess_right": "{0} was right.", "guess_wrong": "{0} was wrong.", - "fratelli_sangue": "{0} gave one of his lives to {1}." + "fratelli_sangue": "{0} gave one of his lives to {1}.", + "doctor_heal": "{0} was healed by the doctor." }, "foc": { "leggedelwest": "He must play this card on this turn if possible." diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index 304a123..c186787 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -90,7 +90,8 @@ "guess": "{0} pensa sia {1}.", "guess_right": "{0} ha indovinato.", "guess_wrong": "{0} ha sbagliato.", - "fratelli_sangue": "{0} ha donato una delle sue vite a {1}." + "fratelli_sangue": "{0} ha donato una delle sue vite a {1}.", + "doctor_heal": "{0} è stato curato dal dottore." }, "foc": { "leggedelwest": "Ed è obbligato a usarla nel suo turno, se possibile" From 76641f08d581cc6fb874425725661fcd75033164 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 15:28:51 +0100 Subject: [PATCH 07/21] sermone --- backend/bang/cards.py | 6 ++++++ backend/bang/expansions/high_noon/card_events.py | 9 ++++++++- backend/bang/players.py | 6 ++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/backend/bang/cards.py b/backend/bang/cards.py index 3662673..10d0a69 100644 --- a/backend/bang/cards.py +++ b/backend/bang/cards.py @@ -189,6 +189,9 @@ class Bang(Card): def play_card(self, player, against, _with=None): import bang.expansions.fistful_of_cards.card_events as ce + import bang.expansions.high_noon.card_events as ceh + if player.game.check_event(ceh.Sermone): + return False if player.has_played_bang and (not any([isinstance(c, Volcanic) for c in player.equipment]) or player.game.check_event(ce.Lazo)) and against != None: return False elif against != None: @@ -327,6 +330,9 @@ class Mancato(Card): def play_card(self, player, against, _with=None): import bang.characters as chars if (not player.has_played_bang and against != None and player.character.check(player.game, chars.CalamityJanet)): + import bang.expansions.high_noon.card_events as ceh + if player.game.check_event(ceh.Sermone): + return False player.sio.emit('chat_message', room=player.game.name, data=f'_special_calamity|{player.name}|{self.name}|{against}') player.has_played_bang = True diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index ec57619..6a58765 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -43,6 +43,13 @@ class IlDottore(CardEvent): self.desc = "Il giocatore con meno vite recupera 1 vita" self.desc_eng = "" + +class Sermone(CardEvent): + def __init__(self): + super().__init__("Sermone", "✝️") + self.desc = "I giocatori non possono giocare Bang!" + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -60,7 +67,7 @@ def get_all_events(): IlReverendo(), IlTreno(), Sbornia(), - # Seromone(), + Sermone(), Sete(), # Sparatoria(), ] diff --git a/backend/bang/players.py b/backend/bang/players.py index f6fed02..2b141ca 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -230,7 +230,9 @@ class Player: elif self.pending_action == PendingAction.PLAY: equippables = [c for c in self.hand if (c.is_equipment or c.usable_next_turn) and not isinstance(c, cs.Prigione) and not any([type(c) == type(x) for x in self.equipment])] misc = [c for c in self.hand if (isinstance(c, cs.WellsFargo) and not c.usable_next_turn) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives and not self.game.check_event(ceh.IlReverendo))] - need_target = [c for c in self.hand if c.need_target and c.can_be_used_now and not (c.need_with and len(self.hand) < 2) and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo))) and not ( isinstance(c, cs.Prigione) and self.game.check_event(ce.IlGiudice))] + need_target = [c for c in self.hand if c.need_target and c.can_be_used_now and not (c.need_with and len(self.hand) < 2) and not ( + (self.game.check_event(ceh.Sermone) or self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and type(c) == type(cs.Bang) + ) and not self.game.check_event(ce.Lazo))) and not ( isinstance(c, cs.Prigione) and self.game.check_event(ce.IlGiudice))] green_cards = [c for c in self.equipment if not self.game.check_event(ce.Lazo) and not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now] if len(equippables) > 0 and not self.game.check_event(ce.IlGiudice): for c in equippables: @@ -770,7 +772,7 @@ class Player: def get_dueled(self, attacker): self.attacker = attacker - if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Bang) or (self.character.check(self.game, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0: + if self.game.check_event(ceh.Sermone) or (not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Bang) or (self.character.check(self.game, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0): print('Cant defend') self.take_damage_response() self.game.responders_did_respond_resume_turn(did_lose=True) From 39377bbb3158c505b5626eebc1ddddf416d4f642 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 15:41:10 +0100 Subject: [PATCH 08/21] sparatoria --- backend/bang/cards.py | 6 +++++- backend/bang/expansions/high_noon/card_events.py | 8 +++++++- backend/bang/players.py | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/backend/bang/cards.py b/backend/bang/cards.py index 10d0a69..f4f9055 100644 --- a/backend/bang/cards.py +++ b/backend/bang/cards.py @@ -197,8 +197,11 @@ class Bang(Card): elif against != None: import bang.characters as chars super().play_card(player, against=against) + player.bang_used += 1 player.has_played_bang = not isinstance( player.character, chars.WillyTheKid) + if player.game.check_event(ceh.Sparatoria) and player.has_played_bang: + player.has_played_bang = player.bang_used > 1 player.game.attack(player, against, double=player.character.check(player.game, chars.SlabTheKiller)) return True return False @@ -335,7 +338,8 @@ class Mancato(Card): return False player.sio.emit('chat_message', room=player.game.name, data=f'_special_calamity|{player.name}|{self.name}|{against}') - player.has_played_bang = True + player.bang_used += 1 + player.has_played_bang = True if not player.game.check_event(ceh.Sparatoria) else player.bang_used > 1 player.game.attack(player, against) return True return False diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index 6a58765..47897d4 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -50,6 +50,12 @@ class Sermone(CardEvent): self.desc = "I giocatori non possono giocare Bang!" self.desc_eng = "" +class Sparatoria(CardEvent): + def __init__(self): + super().__init__("Sparatoria", "‼️") + self.desc = "Il limite di bang è 2 invece che 1!" + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -69,7 +75,7 @@ def get_all_events(): Sbornia(), Sermone(), Sete(), - # Sparatoria(), + Sparatoria(), ] random.shuffle(cards) # cards.append(MezzogiornoDiFuoco()) diff --git a/backend/bang/players.py b/backend/bang/players.py index 2b141ca..b519b0b 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -59,6 +59,7 @@ class Player: self.mancato_needed = 0 self.molly_discarded_cards = 0 self.is_bot = bot + self.bang_used = 0 self.special_use_count = 0 def reset(self): @@ -319,6 +320,7 @@ class Player: self.is_waiting_for_action = True self.has_played_bang = False self.special_use_count = 0 + self.bang_used = 0 if self.game.check_event(ce.FratelliDiSangue) and self.lives > 1 and not self.is_giving_life and len([p for p in self.game.players if p != self and p.lives < p.max_lives]): self.available_cards = [{ 'name': p.name, From d6a84bbb8832875a126d271dbcb87c41a7ffe6a3 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 15:50:22 +0100 Subject: [PATCH 09/21] mezzogiorno di fuoco --- backend/bang/deck.py | 2 +- backend/bang/expansions/high_noon/card_events.py | 2 +- backend/bang/players.py | 7 +++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/backend/bang/deck.py b/backend/bang/deck.py index 0205e45..991d43c 100644 --- a/backend/bang/deck.py +++ b/backend/bang/deck.py @@ -33,7 +33,7 @@ class Deck: print(f'Deck initialized with {len(self.cards)} cards') def flip_event(self): - if len(self.event_cards) > 0 and not isinstance(self.event_cards[0], ce.PerUnPugnoDiCarte): + 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)) self.game.notify_event_card() diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index 47897d4..762c468 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -78,7 +78,7 @@ def get_all_events(): Sparatoria(), ] random.shuffle(cards) - # cards.append(MezzogiornoDiFuoco()) + cards.append(MezzogiornoDiFuoco()) for c in cards: c.expansion = 'high-noon' return cards \ No newline at end of file diff --git a/backend/bang/players.py b/backend/bang/players.py index b519b0b..3642c1a 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -321,6 +321,13 @@ class Player: self.has_played_bang = False self.special_use_count = 0 self.bang_used = 0 + if self.game.check_event(ceh.MezzogiornoDiFuoco): + self.lives -= 1 + if self.character.check(self.game, chars.BartCassidy) and self.lives > 0: + self.hand.append(self.game.deck.draw(True)) + self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}') + if self.lives <= 0: + return self.notify_self() if self.game.check_event(ce.FratelliDiSangue) and self.lives > 1 and not self.is_giving_life and len([p for p in self.game.players if p != self and p.lives < p.max_lives]): self.available_cards = [{ 'name': p.name, From 2b5e2dd128e4974f26af88d11ec5ce514787b615 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 16:14:38 +0100 Subject: [PATCH 10/21] corsa all'oro --- backend/bang/expansions/high_noon/card_events.py | 8 +++++++- backend/bang/game.py | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index 762c468..42dcf2c 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -56,6 +56,12 @@ class Sparatoria(CardEvent): self.desc = "Il limite di bang è 2 invece che 1!" self.desc_eng = "" +class CorsaAllOro(CardEvent): + def __init__(self): + super().__init__("Corsa All'Oro", "‼️") + self.desc = "Si gioca in senso antiorario!" + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -67,7 +73,7 @@ def get_all_events(): Benedizione(), Maledizione(), # CittaFantasma(), - # CorsaAllOro(), + CorsaAllOro(), # IDalton(), IlDottore(), IlReverendo(), diff --git a/backend/bang/game.py b/backend/bang/game.py index a3d5d14..0ce42b1 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -259,6 +259,8 @@ class Game: self.players[self.turn].notify_self() def next_player(self): + if self.check_event(ceh.CorsaAllOro): + return self.players[(self.turn - 1) % len(self.players)] return self.players[(self.turn + 1) % len(self.players)] def play_turn(self): @@ -300,7 +302,10 @@ class Game: def next_turn(self): if self.shutting_down: return if len(self.players) > 0: - self.turn = (self.turn + 1) % len(self.players) + if self.check_event(ceh.CorsaAllOro): + self.turn = (self.turn - 1) % len(self.players) + else: + self.turn = (self.turn + 1) % len(self.players) self.play_turn() def notify_event_card(self): From 57b9520eeddb0304fd299af44ea119901359fa2b Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 16:37:18 +0100 Subject: [PATCH 11/21] i dalton --- .../bang/expansions/high_noon/card_events.py | 11 ++++++++--- backend/bang/game.py | 12 ++++++++++++ backend/bang/players.py | 17 +++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index 42dcf2c..c181bc6 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -43,7 +43,6 @@ class IlDottore(CardEvent): self.desc = "Il giocatore con meno vite recupera 1 vita" self.desc_eng = "" - class Sermone(CardEvent): def __init__(self): super().__init__("Sermone", "✝️") @@ -58,10 +57,16 @@ class Sparatoria(CardEvent): class CorsaAllOro(CardEvent): def __init__(self): - super().__init__("Corsa All'Oro", "‼️") + super().__init__("Corsa All'Oro", "🌟") self.desc = "Si gioca in senso antiorario!" self.desc_eng = "" +class IDalton(CardEvent): + def __init__(self): + super().__init__("I Dalton", "🙇‍♂️") + self.desc = "Chi ha carte blu in gioco ne scarta 1 a sua scelta" + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -74,7 +79,7 @@ def get_all_events(): Maledizione(), # CittaFantasma(), CorsaAllOro(), - # IDalton(), + IDalton(), IlDottore(), IlReverendo(), IlTreno(), diff --git a/backend/bang/game.py b/backend/bang/game.py index 0ce42b1..1576eae 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -32,6 +32,7 @@ class Game: self.disconnect_bot = True self.player_bangs = 0 self.is_russian_roulette_on = False + self.dalton_on = False self.bot_speed = 1.5 def notify_room(self, sid=None): @@ -289,6 +290,17 @@ class Game: p.lives += 1 self.sio.emit('chat_message', room=self.name, data=f'_doctor_heal|{p.name}') p.notify_self() + elif self.check_event(ceh.IDalton): + self.waiting_for = 0 + self.readyCount = 0 + self.dalton_on = True + for p in self.players: + if p.get_dalton(): + self.waiting_for += 1 + p.notify_self() + if self.waiting_for != 0: + return + self.dalton_on = False if self.check_event(ce.PerUnPugnoDiCarte) and len(self.players[self.turn].hand) > 0: self.player_bangs = len(self.players[self.turn].hand) diff --git a/backend/bang/players.py b/backend/bang/players.py index 3642c1a..f7b0f73 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -623,6 +623,13 @@ class Player: else: self.discarded_cards.append(self.available_cards.pop(card_index)) self.notify_self() + elif self.game.dalton_on and self.game.check_event(ceh.IDalton): + card = next(c for c in self.equipment if c == self.available_cards[card_index]) + self.equipment.remove(card) + self.game.deck.scrap(card, True) + self.pending_action = PendingAction.WAIT + self.notify_self() + self.game.responders_did_respond_resume_turn() elif self.is_drawing and self.game.check_event(ce.Peyote): self.is_drawing = False card = self.game.deck.draw() @@ -762,6 +769,16 @@ class Player: self.on_failed_response_cb = self.take_no_damage_response return True + def get_dalton(self): + equipments = [c for c in self.equipment if not c.usable_next_turn] + if len(equipments) == 0: + return False + else: + self.sio.emit('chat_message', room=self.game.name, data=f"_dalton|{self.name}") + self.pending_action = PendingAction.CHOOSE + self.available_cards = equipments + return True + def get_indians(self, attacker): self.attacker = attacker if self.character.check(self.game, chd.ApacheKid): return False From 7da9e47696a35ed0d83ae57c7f81ddafc5d3af2d Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 18:22:23 +0100 Subject: [PATCH 12/21] wip-rewrite dead logic --- .../bang/expansions/high_noon/card_events.py | 8 +- backend/bang/game.py | 105 ++++++++++-------- backend/bang/players.py | 22 ++-- 3 files changed, 78 insertions(+), 57 deletions(-) diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index c181bc6..3b9359d 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -67,6 +67,12 @@ class IDalton(CardEvent): self.desc = "Chi ha carte blu in gioco ne scarta 1 a sua scelta" self.desc_eng = "" +class CittaFantasma(CardEvent): + def __init__(self): + super().__init__("Città Fantasma", "👻") + self.desc = "Tutti i giocatori morti tornano in vita al proprio turno, non possono morire e pescano 3 carte invece che 2. Quando terminano il turno tornano morti." + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -77,7 +83,7 @@ def get_all_events(): cards = [ Benedizione(), Maledizione(), - # CittaFantasma(), + CittaFantasma(), CorsaAllOro(), IDalton(), IlDottore(), diff --git a/backend/bang/game.py b/backend/bang/game.py index 1576eae..61a147b 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -151,7 +151,7 @@ class Game: attacker.notify_self() self.waiting_for = 0 self.readyCount = 0 - for p in self.players: + for p in self.get_alive_players(): if p != attacker: if p.get_banged(attacker=attacker): self.waiting_for += 1 @@ -165,7 +165,7 @@ class Game: attacker.notify_self() self.waiting_for = 0 self.readyCount = 0 - for p in self.players: + for p in self.get_alive_players(): if p != attacker: if p.get_indians(attacker=attacker): self.waiting_for += 1 @@ -199,24 +199,26 @@ class Game: self.get_player_named(target_username).notify_self() def emporio(self): - self.available_cards = [self.deck.draw(True) for i in range(len([p for p in self.players if p.lives > 0]))] - self.players[self.turn].pending_action = pl.PendingAction.CHOOSE - self.players[self.turn].choose_text = 'choose_card_to_get' - self.players[self.turn].available_cards = self.available_cards - self.players[self.turn].notify_self() + pls = self.get_alive_players() + self.available_cards = [self.deck.draw(True) for i in range(len(pls))] + pls[self.turn].pending_action = pl.PendingAction.CHOOSE + pls[self.turn].choose_text = 'choose_card_to_get' + pls[self.turn].available_cards = self.available_cards + pls[self.turn].notify_self() def respond_emporio(self, player, i): player.hand.append(self.available_cards.pop(i)) player.available_cards = [] player.pending_action = pl.PendingAction.WAIT player.notify_self() - nextPlayer = self.players[(self.turn + (len(self.players)-len(self.available_cards))) % len(self.players)] + pls = self.get_alive_players() + nextPlayer = pls[(pls.index(self.players[self.turn])+(len(pls)-len(self.available_cards))) % len(pls)] if nextPlayer == self.players[self.turn]: self.players[self.turn].pending_action = pl.PendingAction.PLAY self.players[self.turn].notify_self() else: nextPlayer.pending_action = pl.PendingAction.CHOOSE - self.players[self.turn].choose_text = 'choose_card_to_get' + nextPlayer.choose_text = 'choose_card_to_get' nextPlayer.available_cards = self.available_cards nextPlayer.notify_self() @@ -260,11 +262,14 @@ class Game: self.players[self.turn].notify_self() def next_player(self): + pls = self.get_alive_players() if self.check_event(ceh.CorsaAllOro): - return self.players[(self.turn - 1) % len(self.players)] - return self.players[(self.turn + 1) % len(self.players)] + return pls[(pls.index(self.players[self.turn]) - 1) % len(pls)] + return pls[(pls.index(self.players[self.turn]) + 1) % len(pls)] def play_turn(self): + if self.players[self.turn].lives <= 0: + return self.next_turn() self.player_bangs = 0 if isinstance(self.players[self.turn].role, roles.Sheriff): self.deck.flip_event() @@ -313,11 +318,12 @@ class Game: def next_turn(self): if self.shutting_down: return - if len(self.players) > 0: + pls = self.get_alive_players() + if len(pls) > 0: if self.check_event(ceh.CorsaAllOro): - self.turn = (self.turn - 1) % len(self.players) + self.turn = (pls.index(self.players[self.turn]) - 1) % len(pls) else: - self.turn = (self.turn + 1) % len(self.players) + self.turn = (pls.index(self.players[self.turn]) + 1) % len(pls) self.play_turn() def notify_event_card(self): @@ -336,15 +342,16 @@ class Game: def handle_disconnect(self, player: pl.Player): print(f'player {player.name} left the game {self.name}') - if player in self.players: - if self.disconnect_bot and self.started: - player.is_bot = True - eventlet.sleep(15) # he may reconnect - player.notify_self() - else: - self.player_death(player=player, disconnected=True) + # if player in self.players: + if self.disconnect_bot and self.started: + player.is_bot = True + eventlet.sleep(15) # he may reconnect + player.notify_self() else: - self.dead_players.remove(player) + self.player_death(player=player, disconnected=True) + # else: + # player.lives = 0 + # self.players.remove(player) if len([p for p in self.players if not p.is_bot])+len([p for p in self.dead_players if not p.is_bot]) == 0: print(f'no players left in game {self.name}') self.shutting_down = True @@ -372,13 +379,16 @@ class Game: if (self.waiting_for > 0): self.responders_did_respond_resume_turn() - if not player in self.players: return - index = self.players.index(player) - died_in_his_turn = self.started and index == self.turn - if self.started and index <= self.turn: - self.turn -= 1 + if player.is_dead: return + # if not player in self.players: return + # index = self.players.index(player) + # died_in_his_turn = self.started and index == self.turn + # if self.started and index <= self.turn: + # self.turn -= 1 + player.lives = 0 - corpse = self.players.pop(index) + # corpse = self.players.pop(index) + corpse = player if not disconnected: self.dead_players.append(corpse) self.notify_room() @@ -388,23 +398,23 @@ class Game: for p in self.players: if not p.is_bot: p.notify_self() - self.players_map = {c.name: i for i, c in enumerate(self.players)} + # self.players_map = {c.name: i for i, c in enumerate(self.players)} if self.started: print('Check win status') attacker_role = None if player.attacker and player.attacker in self.players: attacker_role = player.attacker.role - winners = [p for p in self.players if p.role != None and p.role.on_player_death(self.players, initial_players=self.initial_players, dead_role=player.role, attacker_role=attacker_role)] + winners = [p for p in self.players if p.role != None and p.role.on_player_death(self.get_alive_players(), initial_players=self.initial_players, dead_role=player.role, attacker_role=attacker_role)] if len(winners) > 0: print('WE HAVE A WINNER') - for p in self.players: + for p in self.get_alive_players(): p.win_status = p in winners self.sio.emit('chat_message', room=self.name, data=f'_won|{p.name}') p.notify_self() eventlet.sleep(5.0) return self.reset() - vulture = [p for p in self.players if p.character.check(self, characters.VultureSam)] + vulture = [p for p in self.get_alive_players() if p.character.check(self, characters.VultureSam)] if len(vulture) == 0: for i in range(len(player.hand)): self.deck.scrap(player.hand.pop(), True) @@ -425,21 +435,21 @@ class Game: vulture[0].notify_self() #se Vulture Sam è uno sceriffo e ha appena ucciso il suo Vice, deve scartare le carte che ha pescato con la sua abilità - if player.attacker and player.attacker in self.players and isinstance(player.attacker.role, roles.Sheriff) and isinstance(player.role, roles.Vice): + if player.attacker and player.attacker in self.get_alive_players() and isinstance(player.attacker.role, roles.Sheriff) and isinstance(player.role, roles.Vice): for i in range(len(player.attacker.hand)): self.deck.scrap(player.attacker.hand.pop(), True) player.attacker.notify_self() - greg = [p for p in self.players if p.character.check(self, chd.GregDigger)] + greg = [p for p in self.get_alive_players() if p.character.check(self, chd.GregDigger)] if len(greg) > 0: greg[0].lives = min(greg[0].lives+2, greg[0].max_lives) - herb = [p for p in self.players if p.character.check(self, chd.HerbHunter)] + herb = [p for p in self.get_alive_players() if p.character.check(self, chd.HerbHunter)] if len(herb) > 0: herb[0].hand.append(self.deck.draw(True)) herb[0].hand.append(self.deck.draw(True)) herb[0].notify_self() - if died_in_his_turn: + if corpse.is_my_turn: self.next_turn() def reset(self): @@ -461,17 +471,22 @@ class Game: return isinstance(self.deck.event_cards[0], ev) def get_visible_players(self, player: pl.Player): - i = self.players.index(player) + pls = self.get_alive_players() + if len(pls) == 0: return [] + i = pls.index(player) sight = player.get_sight() mindist = 99 if not self.check_event(ce.Agguato) else 1 return [{ - 'name': self.players[j].name, - 'dist': min([abs(i - j), (i+ abs(j-len(self.players))), (j+ abs(i-len(self.players))), mindist]) + self.players[j].get_visibility() - (player.get_sight(countWeapon=False)-1), - 'lives': self.players[j].lives, - 'max_lives': self.players[j].max_lives, - 'is_sheriff': isinstance(self.players[j].role, roles.Sheriff), - 'cards': len(self.players[j].hand)+len(self.players[j].equipment) - } for j in range(len(self.players)) if i != j] + 'name': pls[j].name, + 'dist': min([abs(i - j), (i+ abs(j-len(pls))), (j+ abs(i-len(pls))), mindist]) + pls[j].get_visibility() - (player.get_sight(countWeapon=False)-1), + 'lives': pls[j].lives, + 'max_lives': pls[j].max_lives, + 'is_sheriff': isinstance(pls[j].role, roles.Sheriff), + 'cards': len(pls[j].hand)+len(pls[j].equipment) + } for j in range(len(pls)) if i != j] + + def get_alive_players(self): + return [p for p in self.players if p.lives > 0] def notify_all(self): if self.started: @@ -487,5 +502,5 @@ class Game: 'character': p.character.__dict__ if p.character else None, 'real_character': p.real_character.__dict__ if p.real_character else None, 'icon': p.role.icon if self.initial_players == 3 and p.role else '🤠' - } for p in self.players] + } for p in self.get_alive_players()] self.sio.emit('players_update', room=self.name, data=data) diff --git a/backend/bang/players.py b/backend/bang/players.py index f7b0f73..a60b17c 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -328,12 +328,12 @@ class Player: self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}') if self.lives <= 0: return self.notify_self() - if self.game.check_event(ce.FratelliDiSangue) and self.lives > 1 and not self.is_giving_life and len([p for p in self.game.players if p != self and p.lives < p.max_lives]): + if self.game.check_event(ce.FratelliDiSangue) and self.lives > 1 and not self.is_giving_life and len([p for p in self.game.get_alive_players() if p != self and p.lives < p.max_lives]): self.available_cards = [{ 'name': p.name, 'icon': '⭐️' if isinstance(p.role, r.Sheriff) else '🤠', 'alt_text': ''.join(['❤️']*p.lives)+''.join(['💀']*(p.max_lives-p.lives)) - } for p in self.game.players if p != self and p.lives < p.max_lives] + } for p in self.game.get_alive_players() if p != self and p.lives < p.max_lives] self.available_cards.append({'icon': '❌'}) self.choose_text = 'choose_fratelli_di_sangue' self.pending_action = PendingAction.CHOOSE @@ -344,7 +344,7 @@ class Player: else: self.is_giving_life = False if isinstance(self.real_character, chd.VeraCuster): - self.set_available_character([p.character for p in self.game.players if p != self]) + self.set_available_character([p.character for p in self.game.get_alive_players() if p != self]) else: self.pending_action = PendingAction.DRAW self.notify_self() @@ -365,7 +365,7 @@ class Player: self.available_cards = [{ 'name': p.name, 'icon': '⭐️' if isinstance(p.role, r.Sheriff) else '🤠' - } for p in self.game.players if len(p.equipment) > 0 and p != self] + } for p in self.game.get_alive_players() if len(p.equipment) > 0 and p != self] self.available_cards.append({'icon': '❌'}) self.choose_text = 'choose_rimbalzo_player' self.pending_action = PendingAction.CHOOSE @@ -415,7 +415,7 @@ class Player: card: cs.Card = self.game.deck.draw() self.hand.append(card) if i == 1 and self.character.check(self.game, chars.BlackJack) or self.game.check_event(ce.LeggeDelWest): - for p in self.game.players: + for p in self.game.get_alive_players(): if p != self: p.notify_card(self, card, 'blackjack_special' if self.character.check(self.game, chars.BlackJack) else 'foc.leggedelwest') if card.check_suit(self.game, [cs.Suit.HEARTS, cs.Suit.DIAMONDS]) and self.character.check(self.game, chars.BlackJack): @@ -479,7 +479,7 @@ class Player: self.notify_self() return if isinstance(self.real_character, chd.VeraCuster): - self.set_available_character([p.character for p in self.game.players if p != self]) + self.set_available_character([p.character for p in self.game.get_alive_players() if p != self]) else: self.pending_action = PendingAction.DRAW self.notify_self() @@ -560,7 +560,7 @@ class Player: self.hand.append(card) else: self.game.deck.scrap(card, True) - if self.event_type != 'rissa' or (self.event_type == 'rissa' and self.target_p == [p.name for p in self.game.players if p != self and (len(p.hand)+len(p.equipment)) > 0][-1]): + if self.event_type != 'rissa' or (self.event_type == 'rissa' and self.target_p == [p.name for p in self.game.get_alive_players() if p != self and (len(p.hand)+len(p.equipment)) > 0][-1]): self.event_type = '' self.target_p = '' self.choose_action = '' @@ -757,7 +757,7 @@ class Player: print('has mancato') self.pending_action = PendingAction.RESPOND self.expected_response = self.game.deck.mancato_cards.copy() - if self.attacker and self.attacker in self.game.players and isinstance(self.attacker.character, chd.BelleStar) or self.game.check_event(ce.Lazo): + if self.attacker and self.attacker in self.game.get_alive_players() and isinstance(self.attacker.character, chd.BelleStar) or self.game.check_event(ce.Lazo): self.expected_response = self.game.deck.mancato_cards_not_green elif self.character.check(self.game, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: self.expected_response.append(cs.Bang(0, 0).name) @@ -813,7 +813,7 @@ class Player: return True def heal_if_needed(self): - while self.lives <= 0 and len(self.game.players) > 2 and len([c for c in self.hand if isinstance(c, cs.Birra)]) > 0: + while self.lives <= 0 and len(self.game.get_alive_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], cs.Birra): if self.character.check(self.game, chd.MollyStark) and not self.is_my_turn: @@ -831,7 +831,7 @@ class Player: self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}') self.hand.append(self.game.deck.draw(True)) - elif self.character.check(self.game, chars.ElGringo) and self.attacker and self.attacker in self.game.players and len(self.attacker.hand) > 0: + elif self.character.check(self.game, chars.ElGringo) and self.attacker and self.attacker in self.game.get_alive_players() and len(self.attacker.hand) > 0: self.hand.append(self.attacker.hand.pop( randrange(0, len(self.attacker.hand)))) self.sio.emit('chat_message', room=self.game.name, @@ -885,7 +885,7 @@ class Player: self.hand.append(self.game.deck.draw(True)) self.molly_discarded_cards = 0 self.notify_self() - elif self.attacker and self.attacker in self.game.players and isinstance(self.attacker.character, chd.MollyStark) and self.is_my_turn: + elif self.attacker and self.attacker in self.game.get_alive_players() and isinstance(self.attacker.character, chd.MollyStark) and self.is_my_turn: for i in range(self.attacker.molly_discarded_cards): self.attacker.hand.append(self.attacker.game.deck.draw(True)) self.attacker.molly_discarded_cards = 0 From 0e2edb7a24fef471cfda67aeabeb48da2c937891 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 18:38:26 +0100 Subject: [PATCH 13/21] fix logiche --- backend/bang/cards.py | 7 +++---- backend/bang/game.py | 4 +--- backend/bang/players.py | 1 + 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/backend/bang/cards.py b/backend/bang/cards.py index f4f9055..4afab56 100644 --- a/backend/bang/cards.py +++ b/backend/bang/cards.py @@ -198,10 +198,9 @@ class Bang(Card): import bang.characters as chars super().play_card(player, against=against) player.bang_used += 1 - player.has_played_bang = not isinstance( - player.character, chars.WillyTheKid) - if player.game.check_event(ceh.Sparatoria) and player.has_played_bang: - player.has_played_bang = player.bang_used > 1 + player.has_played_bang = player.bang_used > 1 + if player.character.check(player.game, chars.WillyTheKid): + player.has_played_bang = False player.game.attack(player, against, double=player.character.check(player.game, chars.SlabTheKiller)) return True return False diff --git a/backend/bang/game.py b/backend/bang/game.py index 1576eae..89f8359 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -259,9 +259,7 @@ class Game: self.players[self.turn].pending_action = pl.PendingAction.PLAY self.players[self.turn].notify_self() - def next_player(self): - if self.check_event(ceh.CorsaAllOro): - return self.players[(self.turn - 1) % len(self.players)] + def next_player(self): #viene usato solo per passare la dinamite return self.players[(self.turn + 1) % len(self.players)] def play_turn(self): diff --git a/backend/bang/players.py b/backend/bang/players.py index f7b0f73..177ef0d 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -326,6 +326,7 @@ class Player: if self.character.check(self.game, chars.BartCassidy) and self.lives > 0: self.hand.append(self.game.deck.draw(True)) self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}') + self.heal_if_needed() if self.lives <= 0: return self.notify_self() if self.game.check_event(ce.FratelliDiSangue) and self.lives > 1 and not self.is_giving_life and len([p for p in self.game.players if p != self and p.lives < p.max_lives]): From 3a9854211687adf3042255e47a138866e6498d5e Mon Sep 17 00:00:00 2001 From: Giulio Date: Wed, 23 Dec 2020 19:04:48 +0100 Subject: [PATCH 14/21] edit descriptions --- .../bang/expansions/high_noon/card_events.py | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index c181bc6..aee86a4 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -16,49 +16,49 @@ class Maledizione(CardEvent): class Sbornia(CardEvent): def __init__(self): super().__init__("Sbornia", "🥴") - self.desc = "I personaggi perdono la loro abilità speciale" + self.desc = "I personaggi perdono le loro abilità speciali" self.desc_eng = "" class Sete(CardEvent): def __init__(self): super().__init__("Sete", "🥵") - self.desc = "I giocatori pescano solo 1 carta" + self.desc = "I giocatori pescano 1 carta in meno nella loro fase 1" self.desc_eng = "" class IlTreno(CardEvent): def __init__(self): super().__init__("Il Treno", "🚂") - self.desc = "I giocatori pescano 1 carta extra" + self.desc = "I giocatori pescano 1 carta extra nella loro fase 1" self.desc_eng = "" class IlReverendo(CardEvent): def __init__(self): super().__init__("Il Reverendo", "⛪️") - self.desc = "Non si possono giocare birre" + self.desc = "Non si possono giocare le carte Birra" self.desc_eng = "" class IlDottore(CardEvent): def __init__(self): super().__init__("Il Dottore", "👨‍⚕️") - self.desc = "Il giocatore con meno vite recupera 1 vita" + self.desc = "Il/i giocatore/i con meno vite ne recupera/no una" self.desc_eng = "" class Sermone(CardEvent): def __init__(self): super().__init__("Sermone", "✝️") - self.desc = "I giocatori non possono giocare Bang!" + self.desc = "I giocatori non possono giocare Bang! durante il loro turno" self.desc_eng = "" class Sparatoria(CardEvent): def __init__(self): - super().__init__("Sparatoria", "‼️") - self.desc = "Il limite di bang è 2 invece che 1!" + super().__init__("Sparatoria", "🔫🔫") + self.desc = "Il limite di Bang! per turno è 2 invece che 1" self.desc_eng = "" class CorsaAllOro(CardEvent): def __init__(self): super().__init__("Corsa All'Oro", "🌟") - self.desc = "Si gioca in senso antiorario!" + self.desc = "Si gioca per un intero giro in senso antiorario, tuttavia gli effetti delle carte rimangono invariati" self.desc_eng = "" class IDalton(CardEvent): @@ -67,6 +67,18 @@ class IDalton(CardEvent): self.desc = "Chi ha carte blu in gioco ne scarta 1 a sua scelta" self.desc_eng = "" +class Manette(CardEvent): + def __init__(self): + super().__init__("Manette", "🔗") + self.desc = "Dopo aver pescato in fase 1, il giocatore di turno dichiara un seme: potrà usare solamente carte di quel seme nel suo turno" + self.desc_eng = "" + +class NuovaIdentita(CardEvent): + def __init__(self): + super().__init__("Nuova Identità", "🕶") + self.desc = "All'inizio del proprio turno, ogni giocatore potrà decidere se sostituire il suo personaggio attuale con quello era stato proposto ad inizio partita, se lo fa riparte con 2 punti vita" + self.desc_eng = "" + class MezzogiornoDiFuoco(CardEvent): def __init__(self): super().__init__("Mezzogiorno di Fuoco", "🔥") @@ -87,6 +99,8 @@ def get_all_events(): Sermone(), Sete(), Sparatoria(), + # Manette(), + # NuovaIdentita(), ] random.shuffle(cards) cards.append(MezzogiornoDiFuoco()) From 3394b10896965541baae6b448a41e82717f285fa Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Thu, 24 Dec 2020 11:01:59 +0100 Subject: [PATCH 15/21] update dead man --- backend/bang/game.py | 42 +++++++++++++++++++++++++++-------------- backend/bang/players.py | 6 +++++- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/backend/bang/game.py b/backend/bang/game.py index f2881ed..1baaf69 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -34,6 +34,8 @@ class Game: self.is_russian_roulette_on = False self.dalton_on = False self.bot_speed = 1.5 + self.incremental_turn = 0 + self.did_resuscitate_deadman = False def notify_room(self, sid=None): if len([p for p in self.players if p.character == None]) != 0 or sid: @@ -266,18 +268,23 @@ class Game: return pls[(pls.index(self.players[self.turn]) + 1) % len(pls)] def play_turn(self): - if self.players[self.turn].lives <= 0: - return self.next_turn() + self.incremental_turn += 1 + if self.players[self.turn].lives <= 0 or self.players[self.turn].is_dead: + if self.check_event(ce.DeadMan) and not self.did_resuscitate_deadman and len(self.get_dead_players()) > 0: + self.did_resuscitate_deadman = True + pl = sorted(self.get_dead_players(), key=lambda x:x.death_turn)[0] + pl.is_dead = False + pl.lives = 2 + pl.hand.append(self.deck.draw()) + pl.hand.append(self.deck.draw()) + pl.notify_self() + else: + return self.next_turn() self.player_bangs = 0 if isinstance(self.players[self.turn].role, roles.Sheriff): self.deck.flip_event() - if self.check_event(ce.DeadMan) and len(self.dead_players) > 0: - self.players.append(self.dead_players.pop(0)) - self.players[-1].lives = 2 - self.players[-1].hand.append(self.deck.draw()) - self.players[-1].hand.append(self.deck.draw()) - self.players_map = {c.name: i for i, c in enumerate(self.players)} - self.players[-1].notify_self() + if self.check_event(ce.DeadMan): + self.did_resuscitate_deadman = False elif self.check_event(ce.RouletteRussa): self.is_russian_roulette_on = True if self.players[self.turn].get_banged(self.deck.event_cards[0]): @@ -317,11 +324,12 @@ class Game: def next_turn(self): if self.shutting_down: return pls = self.get_alive_players() + print(self.turn) if len(pls) > 0: if self.check_event(ceh.CorsaAllOro): - self.turn = (pls.index(self.players[self.turn]) - 1) % len(pls) + self.turn = (self.turn - 1) % len(self.players) else: - self.turn = (pls.index(self.players[self.turn]) + 1) % len(pls) + self.turn = (self.turn + 1) % len(self.players) self.play_turn() def notify_event_card(self): @@ -384,11 +392,13 @@ class Game: # if self.started and index <= self.turn: # self.turn -= 1 player.lives = 0 + player.is_dead = True + player.death_turn = self.incremental_turn # corpse = self.players.pop(index) corpse = player - if not disconnected: - self.dead_players.append(corpse) + # if not disconnected: + # self.dead_players.append(corpse) self.notify_room() self.sio.emit('chat_message', room=self.name, data=f'_died|{player.name}') if self.started: @@ -458,6 +468,7 @@ class Game: print(self.players) self.started = False self.waiting_for = 0 + self.incremental_turn = 0 for p in self.players: p.reset() p.notify_self() @@ -484,7 +495,10 @@ class Game: } for j in range(len(pls)) if i != j] def get_alive_players(self): - return [p for p in self.players if p.lives > 0] + return [p for p in self.players if not p.is_dead] + + def get_dead_players(self): + return [p for p in self.players if p.is_dead] def notify_all(self): if self.started: diff --git a/backend/bang/players.py b/backend/bang/players.py index 7de0314..c7003b1 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -61,6 +61,8 @@ class Player: self.is_bot = bot self.bang_used = 0 self.special_use_count = 0 + self.is_dead = False + self.death_turn = 0 def reset(self): self.hand: cs.Card = [] @@ -93,6 +95,8 @@ class Player: pass self.mancato_needed = 0 self.molly_discarded_cards = 0 + self.is_dead = False + self.death_turn = 0 def join_game(self, game): self.game = game @@ -306,7 +310,7 @@ class Player: self.choose(randrange(0, len(target.hand)+len(target.equipment))) def play_turn(self, can_play_vendetta = True): - if self.lives == 0: + if self.lives == 0 or self.is_dead: return self.end_turn(forced=True) self.scrapped_cards = 0 self.can_play_ranch = True From 579501e01cd6ec3389ec1ae73c00c4f17746d1b5 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Thu, 24 Dec 2020 12:01:31 +0100 Subject: [PATCH 16/21] ghosts --- backend/bang/game.py | 28 ++++++++++++++++++++-------- backend/bang/players.py | 10 +++++++--- frontend/src/components/Deck.vue | 2 +- frontend/src/components/Lobby.vue | 5 ++++- frontend/src/components/Player.vue | 10 ++++++---- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/backend/bang/game.py b/backend/bang/game.py index 1baaf69..e8c70fa 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -270,14 +270,18 @@ class Game: def play_turn(self): self.incremental_turn += 1 if self.players[self.turn].lives <= 0 or self.players[self.turn].is_dead: - if self.check_event(ce.DeadMan) and not self.did_resuscitate_deadman and len(self.get_dead_players()) > 0: + pl = sorted(self.get_dead_players(), key=lambda x:x.death_turn)[0] + if self.check_event(ce.DeadMan) and not self.did_resuscitate_deadman and pl != self.players[self.turn]: self.did_resuscitate_deadman = True - pl = sorted(self.get_dead_players(), key=lambda x:x.death_turn)[0] pl.is_dead = False + pl.is_ghost = False pl.lives = 2 pl.hand.append(self.deck.draw()) pl.hand.append(self.deck.draw()) pl.notify_self() + elif self.check_event(ceh.CittaFantasma): + pl.is_ghost = True + pl.notify_self() else: return self.next_turn() self.player_bangs = 0 @@ -323,8 +327,14 @@ class Game: def next_turn(self): if self.shutting_down: return + if self.players[self.turn].is_dead and self.players[self.turn].is_ghost and self.check_event(ceh.CittaFantasma): + self.players[self.turn].is_ghost = False + for i in range(len(self.players[self.turn].attacker.hand)): + self.deck.scrap(self.players[self.turn].attacker.hand.pop(), True) + for i in range(len(self.players[self.turn].attacker.equipment)): + self.deck.scrap(self.players[self.turn].attacker.equipment.pop(), True) + self.players[self.turn].notify_self() pls = self.get_alive_players() - print(self.turn) if len(pls) > 0: if self.check_event(ceh.CorsaAllOro): self.turn = (self.turn - 1) % len(self.players) @@ -368,7 +378,7 @@ class Game: else: return False def player_death(self, player: pl.Player, disconnected=False): - if not player in self.players: return + if not player in self.players or player.is_ghost: return import bang.expansions.dodge_city.characters as chd print(player.attacker) if player.attacker and player.attacker in self.players and isinstance(player.attacker.role, roles.Sheriff) and isinstance(player.role, roles.Vice): @@ -481,7 +491,7 @@ class Game: def get_visible_players(self, player: pl.Player): pls = self.get_alive_players() - if len(pls) == 0: return [] + if len(pls) == 0 or player not in pls: return [] i = pls.index(player) sight = player.get_sight() mindist = 99 if not self.check_event(ce.Agguato) else 1 @@ -491,11 +501,12 @@ class Game: 'lives': pls[j].lives, 'max_lives': pls[j].max_lives, 'is_sheriff': isinstance(pls[j].role, roles.Sheriff), - 'cards': len(pls[j].hand)+len(pls[j].equipment) + 'cards': len(pls[j].hand)+len(pls[j].equipment), + 'is_ghost': pls[j].is_ghost, } for j in range(len(pls)) if i != j] def get_alive_players(self): - return [p for p in self.players if not p.is_dead] + return [p for p in self.players if not p.is_dead or p.is_ghost] def get_dead_players(self): return [p for p in self.players if p.is_dead] @@ -513,6 +524,7 @@ class Game: 'pending_action': p.pending_action, 'character': p.character.__dict__ if p.character else None, 'real_character': p.real_character.__dict__ if p.real_character else None, - 'icon': p.role.icon if self.initial_players == 3 and p.role else '🤠' + 'icon': p.role.icon if self.initial_players == 3 and p.role else '🤠', + 'is_ghost': p.is_ghost, } for p in self.get_alive_players()] self.sio.emit('players_update', room=self.name, data=data) diff --git a/backend/bang/players.py b/backend/bang/players.py index c7003b1..c41d6ea 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -63,6 +63,7 @@ class Player: self.special_use_count = 0 self.is_dead = False self.death_turn = 0 + self.is_ghost = False def reset(self): self.hand: cs.Card = [] @@ -96,6 +97,7 @@ class Player: self.mancato_needed = 0 self.molly_discarded_cards = 0 self.is_dead = False + self.is_ghost = False self.death_turn = 0 def join_game(self, game): @@ -181,7 +183,7 @@ class Player: self.pending_action = PendingAction.CHOOSE elif self.character and self.character.check(self.game, chars.SuzyLafayette) and len(self.hand) == 0 and ( not self.is_my_turn or self.pending_action == PendingAction.PLAY): self.hand.append(self.game.deck.draw(True)) - if self.lives <= 0 and self.max_lives > 0: + if self.lives <= 0 and self.max_lives > 0 and not self.is_ghost: print('dying, attacker', self.attacker) if self.character.check(self.game, chars.SidKetchum) and len(self.hand) > 1: self.lives += 1 @@ -203,7 +205,7 @@ class Player: ser['sight'] = self.get_sight() ser['lives'] = max(ser['lives'], 0) - if self.lives <= 0 and self.max_lives > 0: + if self.lives <= 0 and self.max_lives > 0 and not self.is_ghost: self.pending_action = PendingAction.WAIT ser['hand'] = [] ser['equipment'] = [] @@ -310,7 +312,7 @@ class Player: self.choose(randrange(0, len(target.hand)+len(target.equipment))) def play_turn(self, can_play_vendetta = True): - if self.lives == 0 or self.is_dead: + if (self.lives == 0 or self.is_dead) and not self.is_ghost: return self.end_turn(forced=True) self.scrapped_cards = 0 self.can_play_ranch = True @@ -333,6 +335,8 @@ class Player: self.heal_if_needed() if self.lives <= 0: return self.notify_self() + + #non è un elif perchè vera custer deve fare questo poi cambiare personaggio if self.game.check_event(ce.FratelliDiSangue) and self.lives > 1 and not self.is_giving_life and len([p for p in self.game.get_alive_players() if p != self and p.lives < p.max_lives]): self.available_cards = [{ 'name': p.name, diff --git a/frontend/src/components/Deck.vue b/frontend/src/components/Deck.vue index 2b0ed6a..27ea016 100644 --- a/frontend/src/components/Deck.vue +++ b/frontend/src/components/Deck.vue @@ -52,7 +52,7 @@ export default { sockets: { self(self){ self = JSON.parse(self) - this.isPlaying = self.lives > 0 + this.isPlaying = self.lives > 0 || self.is_ghost this.pending_action = self.pending_action }, scrap(card) { diff --git a/frontend/src/components/Lobby.vue b/frontend/src/components/Lobby.vue index 7f01be0..c964eab 100644 --- a/frontend/src/components/Lobby.vue +++ b/frontend/src/components/Lobby.vue @@ -16,10 +16,13 @@
- + ❤️ 💀 +
+ 👻 +
diff --git a/frontend/src/components/Player.vue b/frontend/src/components/Player.vue index 78fc6f3..384f6f4 100644 --- a/frontend/src/components/Player.vue +++ b/frontend/src/components/Player.vue @@ -1,6 +1,6 @@