From 7da9e47696a35ed0d83ae57c7f81ddafc5d3af2d Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Wed, 23 Dec 2020 18:22:23 +0100 Subject: [PATCH 1/6] 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 6de8c8e84d2d7e3fde1d444bc1873c2f9d73dbab Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Thu, 24 Dec 2020 10:23:27 +0100 Subject: [PATCH 2/6] fix rissa --- backend/bang/players.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/bang/players.py b/backend/bang/players.py index cb0297a..c939afc 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -541,15 +541,15 @@ 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 (len([p.name for p in self.game.players if p != self and (len(p.hand)+len(p.equipment)) > 0]) == 0 or self.target_p == [p.name for p in self.game.players if p != self and (len(p.hand)+len(p.equipment)) > 0][-1])): self.event_type = '' self.target_p = '' self.choose_action = '' self.pending_action = PendingAction.PLAY else: - self.target_p = self.game.players[self.game.players_map[self.target_p]+1].name + self.target_p = self.game.players[(self.game.players_map[self.target_p]+1)%len(self.game.players)].name while self.target_p == self.name or len(self.game.players[self.game.players_map[self.target_p]].hand) + len(self.game.players[self.game.players_map[self.target_p]].equipment) == 0: - self.target_p = self.game.players[self.game.players_map[self.target_p]+1].name + self.target_p = self.game.players[(self.game.players_map[self.target_p]+1)%len(self.game.players)].name self.notify_self() elif self.is_giving_life and self.game.check_event(ce.FratelliDiSangue): try: From 3394b10896965541baae6b448a41e82717f285fa Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Thu, 24 Dec 2020 11:01:59 +0100 Subject: [PATCH 3/6] 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 4/6] 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 @@