Merge branch 'citta-fantasma' into high_noon

This commit is contained in:
Alberto 2020-12-24 13:30:05 +01:00
commit 96b71ed35e
No known key found for this signature in database
GPG Key ID: 4F026F48309500A2
7 changed files with 158 additions and 86 deletions

View File

@ -81,7 +81,7 @@ def get_me(sid, room):
sio.emit('role', room=sid, data=json.dumps(bot.role, default=lambda o: o.__dict__)) sio.emit('role', room=sid, data=json.dumps(bot.role, default=lambda o: o.__dict__))
bot.notify_self() bot.notify_self()
else: #spectate else: #spectate
de_games[0].dead_players.append(sio.get_session(sid)) de_games[0].spectators.append(sio.get_session(sid))
sio.get_session(sid).game = de_games[0] sio.get_session(sid).game = de_games[0]
sio.enter_room(sid, de_games[0].name) sio.enter_room(sid, de_games[0].name)
de_games[0].notify_room(sid) de_games[0].notify_room(sid)

View File

@ -79,6 +79,12 @@ class NuovaIdentita(CardEvent):
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 = "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 = "" 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): class MezzogiornoDiFuoco(CardEvent):
def __init__(self): def __init__(self):
super().__init__("Mezzogiorno di Fuoco", "🔥") super().__init__("Mezzogiorno di Fuoco", "🔥")
@ -89,7 +95,7 @@ def get_all_events():
cards = [ cards = [
Benedizione(), Benedizione(),
Maledizione(), Maledizione(),
# CittaFantasma(), CittaFantasma(),
CorsaAllOro(), CorsaAllOro(),
IDalton(), IDalton(),
IlDottore(), IlDottore(),

View File

@ -17,7 +17,7 @@ class Game:
self.sio = sio self.sio = sio
self.name = name self.name = name
self.players: List[pl.Player] = [] self.players: List[pl.Player] = []
self.dead_players: List[pl.Player] = [] self.spectators: List[pl.Player] = []
self.deck: Deck = None self.deck: Deck = None
self.started = False self.started = False
self.turn = 0 self.turn = 0
@ -34,6 +34,8 @@ class Game:
self.is_russian_roulette_on = False self.is_russian_roulette_on = False
self.dalton_on = False self.dalton_on = False
self.bot_speed = 1.5 self.bot_speed = 1.5
self.incremental_turn = 0
self.did_resuscitate_deadman = False
def notify_room(self, sid=None): def notify_room(self, sid=None):
if len([p for p in self.players if p.character == None]) != 0 or sid: if len([p for p in self.players if p.character == None]) != 0 or sid:
@ -151,7 +153,7 @@ class Game:
attacker.notify_self() attacker.notify_self()
self.waiting_for = 0 self.waiting_for = 0
self.readyCount = 0 self.readyCount = 0
for p in self.players: for p in self.get_alive_players():
if p != attacker: if p != attacker:
if p.get_banged(attacker=attacker): if p.get_banged(attacker=attacker):
self.waiting_for += 1 self.waiting_for += 1
@ -165,7 +167,7 @@ class Game:
attacker.notify_self() attacker.notify_self()
self.waiting_for = 0 self.waiting_for = 0
self.readyCount = 0 self.readyCount = 0
for p in self.players: for p in self.get_alive_players():
if p != attacker: if p != attacker:
if p.get_indians(attacker=attacker): if p.get_indians(attacker=attacker):
self.waiting_for += 1 self.waiting_for += 1
@ -199,24 +201,26 @@ class Game:
self.get_player_named(target_username).notify_self() self.get_player_named(target_username).notify_self()
def emporio(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]))] pls = self.get_alive_players()
self.players[self.turn].pending_action = pl.PendingAction.CHOOSE self.available_cards = [self.deck.draw(True) for i in range(len(pls))]
self.players[self.turn].choose_text = 'choose_card_to_get' pls[self.turn].pending_action = pl.PendingAction.CHOOSE
self.players[self.turn].available_cards = self.available_cards pls[self.turn].choose_text = 'choose_card_to_get'
self.players[self.turn].notify_self() pls[self.turn].available_cards = self.available_cards
pls[self.turn].notify_self()
def respond_emporio(self, player, i): def respond_emporio(self, player, i):
player.hand.append(self.available_cards.pop(i)) player.hand.append(self.available_cards.pop(i))
player.available_cards = [] player.available_cards = []
player.pending_action = pl.PendingAction.WAIT player.pending_action = pl.PendingAction.WAIT
player.notify_self() 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]: if nextPlayer == self.players[self.turn]:
self.players[self.turn].pending_action = pl.PendingAction.PLAY self.players[self.turn].pending_action = pl.PendingAction.PLAY
self.players[self.turn].notify_self() self.players[self.turn].notify_self()
else: else:
nextPlayer.pending_action = pl.PendingAction.CHOOSE 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.available_cards = self.available_cards
nextPlayer.notify_self() nextPlayer.notify_self()
@ -259,20 +263,36 @@ class Game:
self.players[self.turn].pending_action = pl.PendingAction.PLAY self.players[self.turn].pending_action = pl.PendingAction.PLAY
self.players[self.turn].notify_self() self.players[self.turn].notify_self()
def next_player(self): #viene usato solo per passare la dinamite def next_player(self):
return self.players[(self.turn + 1) % len(self.players)] pls = self.get_alive_players()
return pls[(pls.index(self.players[self.turn]) + 1) % len(pls)]
def play_turn(self): def play_turn(self):
self.incremental_turn += 1
if self.players[self.turn].lives <= 0 or self.players[self.turn].is_dead:
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]:
print(f'{self.players[self.turn]} is dead, revive')
self.did_resuscitate_deadman = True
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):
print(f'{self.players[self.turn]} is dead, event ghost')
self.players[self.turn].is_ghost = True
else:
print(f'{self.players[self.turn]} is dead, next turn')
return self.next_turn()
self.player_bangs = 0 self.player_bangs = 0
if isinstance(self.players[self.turn].role, roles.Sheriff): if isinstance(self.players[self.turn].role, roles.Sheriff):
self.deck.flip_event() self.deck.flip_event()
if self.check_event(ce.DeadMan) and len(self.dead_players) > 0: if len(self.deck.event_cards) > 0:
self.players.append(self.dead_players.pop(0)) print(f'flip new event {self.deck.event_cards[0].name}')
self.players[-1].lives = 2 if self.check_event(ce.DeadMan):
self.players[-1].hand.append(self.deck.draw()) self.did_resuscitate_deadman = False
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()
elif self.check_event(ce.RouletteRussa): elif self.check_event(ce.RouletteRussa):
self.is_russian_roulette_on = True self.is_russian_roulette_on = True
if self.players[self.turn].get_banged(self.deck.event_cards[0]): if self.players[self.turn].get_banged(self.deck.event_cards[0]):
@ -307,11 +327,14 @@ class Game:
else: else:
self.responders_did_respond_resume_turn() self.responders_did_respond_resume_turn()
else: else:
print(f'notifying {self.players[self.turn].name} about his turn')
self.players[self.turn].play_turn() self.players[self.turn].play_turn()
def next_turn(self): def next_turn(self):
if self.shutting_down: return if self.shutting_down: return
if len(self.players) > 0: print(f'{self.players[self.turn].name} invoked next turn')
pls = self.get_alive_players()
if len(pls) > 0:
if self.check_event(ceh.CorsaAllOro): if self.check_event(ceh.CorsaAllOro):
self.turn = (self.turn - 1) % len(self.players) self.turn = (self.turn - 1) % len(self.players)
else: else:
@ -334,26 +357,29 @@ class Game:
def handle_disconnect(self, player: pl.Player): def handle_disconnect(self, player: pl.Player):
print(f'player {player.name} left the game {self.name}') print(f'player {player.name} left the game {self.name}')
if player in self.players: if player in self.spectators:
if self.disconnect_bot and self.started: self.spectators.remove(player)
player.is_bot = True return
eventlet.sleep(15) # he may reconnect if self.disconnect_bot and self.started:
player.notify_self() player.is_bot = True
else: eventlet.sleep(15) # he may reconnect
self.player_death(player=player, disconnected=True) player.notify_self()
else: else:
self.dead_players.remove(player) self.player_death(player=player, disconnected=True)
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: # else:
# player.lives = 0
# self.players.remove(player)
if len([p for p in self.players if not p.is_bot]) == 0:
print(f'no players left in game {self.name}') print(f'no players left in game {self.name}')
self.shutting_down = True self.shutting_down = True
self.players = [] self.players = []
self.dead_players = [] self.spectators = []
self.deck = None self.deck = None
return True return True
else: return False else: return False
def player_death(self, player: pl.Player, disconnected=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 import bang.expansions.dodge_city.characters as chd
print(player.attacker) 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): if player.attacker and player.attacker in self.players and isinstance(player.attacker.role, roles.Sheriff) and isinstance(player.role, roles.Vice):
@ -370,15 +396,23 @@ class Game:
if (self.waiting_for > 0): if (self.waiting_for > 0):
self.responders_did_respond_resume_turn() self.responders_did_respond_resume_turn()
if not player in self.players: return if player.is_dead: return
index = self.players.index(player) if not self.started:
died_in_his_turn = self.started and index == self.turn self.players.remove(player)
if self.started and index <= self.turn: elif disconnected:
self.turn -= 1 index = self.players.index(player)
if self.started and index <= self.turn:
self.turn -= 1
self.players.remove(player)
self.players_map = {c.name: i for i, c in enumerate(self.players)}
player.lives = 0
player.is_dead = True
player.death_turn = self.incremental_turn
corpse = self.players.pop(index) # corpse = self.players.pop(index)
if not disconnected: corpse = player
self.dead_players.append(corpse) # if not disconnected:
# self.dead_players.append(corpse)
self.notify_room() self.notify_room()
self.sio.emit('chat_message', room=self.name, data=f'_died|{player.name}') self.sio.emit('chat_message', room=self.name, data=f'_died|{player.name}')
if self.started: if self.started:
@ -386,23 +420,23 @@ class Game:
for p in self.players: for p in self.players:
if not p.is_bot: if not p.is_bot:
p.notify_self() 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: if self.started:
print('Check win status') print('Check win status')
attacker_role = None attacker_role = None
if player.attacker and player.attacker in self.players: if player.attacker and player.attacker in self.players:
attacker_role = player.attacker.role 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: if len(winners) > 0:
print('WE HAVE A WINNER') print('WE HAVE A WINNER')
for p in self.players: for p in self.get_alive_players():
p.win_status = p in winners p.win_status = p in winners
self.sio.emit('chat_message', room=self.name, data=f'_won|{p.name}') self.sio.emit('chat_message', room=self.name, data=f'_won|{p.name}')
p.notify_self() p.notify_self()
eventlet.sleep(5.0) eventlet.sleep(5.0)
return self.reset() 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: if len(vulture) == 0:
for i in range(len(player.hand)): for i in range(len(player.hand)):
self.deck.scrap(player.hand.pop(), True) self.deck.scrap(player.hand.pop(), True)
@ -423,31 +457,32 @@ class Game:
vulture[0].notify_self() 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à #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)): for i in range(len(player.attacker.hand)):
self.deck.scrap(player.attacker.hand.pop(), True) self.deck.scrap(player.attacker.hand.pop(), True)
player.attacker.notify_self() 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: if len(greg) > 0:
greg[0].lives = min(greg[0].lives+2, greg[0].max_lives) 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: if len(herb) > 0:
herb[0].hand.append(self.deck.draw(True)) herb[0].hand.append(self.deck.draw(True))
herb[0].hand.append(self.deck.draw(True)) herb[0].hand.append(self.deck.draw(True))
herb[0].notify_self() herb[0].notify_self()
if died_in_his_turn: if corpse.is_my_turn:
self.next_turn() self.next_turn()
def reset(self): def reset(self):
print('resetting lobby') print('resetting lobby')
self.players.extend(self.dead_players) self.players.extend(self.spectators)
self.dead_players = [] self.spectators = []
self.players = [p for p in self.players if not p.is_bot] self.players = [p for p in self.players if not p.is_bot]
print(self.players) print(self.players)
self.started = False self.started = False
self.waiting_for = 0 self.waiting_for = 0
self.incremental_turn = 0
for p in self.players: for p in self.players:
p.reset() p.reset()
p.notify_self() p.notify_self()
@ -459,17 +494,26 @@ class Game:
return isinstance(self.deck.event_cards[0], ev) return isinstance(self.deck.event_cards[0], ev)
def get_visible_players(self, player: pl.Player): def get_visible_players(self, player: pl.Player):
i = self.players.index(player) pls = self.get_alive_players()
if len(pls) == 0 or player not in pls: return []
i = pls.index(player)
sight = player.get_sight() sight = player.get_sight()
mindist = 99 if not self.check_event(ce.Agguato) else 1 mindist = 99 if not self.check_event(ce.Agguato) else 1
return [{ return [{
'name': self.players[j].name, 'name': pls[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), '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': self.players[j].lives, 'lives': pls[j].lives,
'max_lives': self.players[j].max_lives, 'max_lives': pls[j].max_lives,
'is_sheriff': isinstance(self.players[j].role, roles.Sheriff), 'is_sheriff': isinstance(pls[j].role, roles.Sheriff),
'cards': len(self.players[j].hand)+len(self.players[j].equipment) 'cards': len(pls[j].hand)+len(pls[j].equipment),
} for j in range(len(self.players)) if i != j] '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 or p.is_ghost]
def get_dead_players(self):
return [p for p in self.players if p.is_dead]
def notify_all(self): def notify_all(self):
if self.started: if self.started:
@ -484,6 +528,7 @@ class Game:
'pending_action': p.pending_action, 'pending_action': p.pending_action,
'character': p.character.__dict__ if p.character else None, 'character': p.character.__dict__ if p.character else None,
'real_character': p.real_character.__dict__ if p.real_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 '🤠',
} for p in self.players] 'is_ghost': p.is_ghost,
} for p in self.get_alive_players()]
self.sio.emit('players_update', room=self.name, data=data) self.sio.emit('players_update', room=self.name, data=data)

View File

@ -61,6 +61,9 @@ class Player:
self.is_bot = bot self.is_bot = bot
self.bang_used = 0 self.bang_used = 0
self.special_use_count = 0 self.special_use_count = 0
self.is_dead = False
self.death_turn = 0
self.is_ghost = False
def reset(self): def reset(self):
self.hand: cs.Card = [] self.hand: cs.Card = []
@ -93,6 +96,9 @@ class Player:
pass pass
self.mancato_needed = 0 self.mancato_needed = 0
self.molly_discarded_cards = 0 self.molly_discarded_cards = 0
self.is_dead = False
self.is_ghost = False
self.death_turn = 0
def join_game(self, game): def join_game(self, game):
self.game = game self.game = game
@ -158,6 +164,7 @@ class Player:
self.sio.emit('notify_card', room=self.sid, data=mess) self.sio.emit('notify_card', room=self.sid, data=mess)
def notify_self(self): def notify_self(self):
if self.is_ghost: self.lives = 0
if self.pending_action == PendingAction.DRAW and self.game.check_event(ce.Peyote): if self.pending_action == PendingAction.DRAW and self.game.check_event(ce.Peyote):
self.available_cards = [{ self.available_cards = [{
'icon': '🔴' 'icon': '🔴'
@ -175,9 +182,9 @@ class Player:
self.is_playing_ranch = True self.is_playing_ranch = True
self.choose_text = 'choose_ranch' self.choose_text = 'choose_ranch'
self.pending_action = PendingAction.CHOOSE 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): elif self.character and self.character.check(self.game, chars.SuzyLafayette) and self.lives > 0 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)) 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_dead:
print('dying, attacker', self.attacker) print('dying, attacker', self.attacker)
if self.character.check(self.game, chars.SidKetchum) and len(self.hand) > 1: if self.character.check(self.game, chars.SidKetchum) and len(self.hand) > 1:
self.lives += 1 self.lives += 1
@ -199,7 +206,7 @@ class Player:
ser['sight'] = self.get_sight() ser['sight'] = self.get_sight()
ser['lives'] = max(ser['lives'], 0) 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_dead:
self.pending_action = PendingAction.WAIT self.pending_action = PendingAction.WAIT
ser['hand'] = [] ser['hand'] = []
ser['equipment'] = [] ser['equipment'] = []
@ -306,7 +313,7 @@ class Player:
self.choose(randrange(0, len(target.hand)+len(target.equipment))) self.choose(randrange(0, len(target.hand)+len(target.equipment)))
def play_turn(self, can_play_vendetta = True): def play_turn(self, can_play_vendetta = True):
if self.lives == 0: if (self.lives == 0 or self.is_dead) and not self.is_ghost:
return self.end_turn(forced=True) return self.end_turn(forced=True)
self.scrapped_cards = 0 self.scrapped_cards = 0
self.can_play_ranch = True self.can_play_ranch = True
@ -329,12 +336,14 @@ class Player:
self.heal_if_needed() self.heal_if_needed()
if self.lives <= 0: if self.lives <= 0:
return self.notify_self() 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]):
#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 = [{ self.available_cards = [{
'name': p.name, 'name': p.name,
'icon': '⭐️' if isinstance(p.role, r.Sheriff) else '🤠', 'icon': '⭐️' if isinstance(p.role, r.Sheriff) else '🤠',
'alt_text': ''.join(['❤️']*p.lives)+''.join(['💀']*(p.max_lives-p.lives)) '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.available_cards.append({'icon': ''})
self.choose_text = 'choose_fratelli_di_sangue' self.choose_text = 'choose_fratelli_di_sangue'
self.pending_action = PendingAction.CHOOSE self.pending_action = PendingAction.CHOOSE
@ -345,7 +354,7 @@ class Player:
else: else:
self.is_giving_life = False self.is_giving_life = False
if isinstance(self.real_character, chd.VeraCuster): 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: else:
self.pending_action = PendingAction.DRAW self.pending_action = PendingAction.DRAW
self.notify_self() self.notify_self()
@ -366,7 +375,7 @@ class Player:
self.available_cards = [{ self.available_cards = [{
'name': p.name, 'name': p.name,
'icon': '⭐️' if isinstance(p.role, r.Sheriff) else '🤠' '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.available_cards.append({'icon': ''})
self.choose_text = 'choose_rimbalzo_player' self.choose_text = 'choose_rimbalzo_player'
self.pending_action = PendingAction.CHOOSE self.pending_action = PendingAction.CHOOSE
@ -416,7 +425,7 @@ class Player:
card: cs.Card = self.game.deck.draw() card: cs.Card = self.game.deck.draw()
self.hand.append(card) self.hand.append(card)
if i == 1 and self.character.check(self.game, 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: for p in self.game.get_alive_players():
if p != self: if p != self:
p.notify_card(self, card, 'blackjack_special' if self.character.check(self.game, chars.BlackJack) else 'foc.leggedelwest') 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): if card.check_suit(self.game, [cs.Suit.HEARTS, cs.Suit.DIAMONDS]) and self.character.check(self.game, chars.BlackJack):
@ -480,7 +489,7 @@ class Player:
self.notify_self() self.notify_self()
return return
if isinstance(self.real_character, chd.VeraCuster): 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: else:
self.pending_action = PendingAction.DRAW self.pending_action = PendingAction.DRAW
self.notify_self() self.notify_self()
@ -561,15 +570,15 @@ class Player:
self.hand.append(card) self.hand.append(card)
else: else:
self.game.deck.scrap(card, True) 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.get_alive_players() if p != self and (len(p.hand)+len(p.equipment)) > 0]) == 0 or 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.event_type = ''
self.target_p = '' self.target_p = ''
self.choose_action = '' self.choose_action = ''
self.pending_action = PendingAction.PLAY self.pending_action = PendingAction.PLAY
else: 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: 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() self.notify_self()
elif self.is_giving_life and self.game.check_event(ce.FratelliDiSangue): elif self.is_giving_life and self.game.check_event(ce.FratelliDiSangue):
try: try:
@ -758,7 +767,7 @@ class Player:
print('has mancato') print('has mancato')
self.pending_action = PendingAction.RESPOND self.pending_action = PendingAction.RESPOND
self.expected_response = self.game.deck.mancato_cards.copy() 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 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: 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) self.expected_response.append(cs.Bang(0, 0).name)
@ -814,7 +823,7 @@ class Player:
return True return True
def heal_if_needed(self): 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)): for i in range(len(self.hand)):
if isinstance(self.hand[i], cs.Birra): if isinstance(self.hand[i], cs.Birra):
if self.character.check(self.game, chd.MollyStark) and not self.is_my_turn: if self.character.check(self.game, chd.MollyStark) and not self.is_my_turn:
@ -832,7 +841,7 @@ class Player:
self.sio.emit('chat_message', room=self.game.name, self.sio.emit('chat_message', room=self.game.name,
data=f'_special_bart_cassidy|{self.name}') data=f'_special_bart_cassidy|{self.name}')
self.hand.append(self.game.deck.draw(True)) 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( self.hand.append(self.attacker.hand.pop(
randrange(0, len(self.attacker.hand)))) randrange(0, len(self.attacker.hand))))
self.sio.emit('chat_message', room=self.game.name, self.sio.emit('chat_message', room=self.game.name,
@ -886,7 +895,7 @@ class Player:
self.hand.append(self.game.deck.draw(True)) self.hand.append(self.game.deck.draw(True))
self.molly_discarded_cards = 0 self.molly_discarded_cards = 0
self.notify_self() 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): for i in range(self.attacker.molly_discarded_cards):
self.attacker.hand.append(self.attacker.game.deck.draw(True)) self.attacker.hand.append(self.attacker.game.deck.draw(True))
self.attacker.molly_discarded_cards = 0 self.attacker.molly_discarded_cards = 0
@ -951,6 +960,7 @@ class Player:
self.notify_self() self.notify_self()
def end_turn(self, forced=False): def end_turn(self, forced=False):
print(f"{self.name} wants to end his turn")
if not self.is_my_turn: if not self.is_my_turn:
return return
maxcards = self.lives if not self.character.check(self.game, chd.SeanMallory) else 10 maxcards = self.lives if not self.character.check(self.game, chd.SeanMallory) else 10
@ -968,6 +978,12 @@ class Player:
for i in range(len(self.equipment)): for i in range(len(self.equipment)):
if self.equipment[i].usable_next_turn and not self.equipment[i].can_be_used_now: if self.equipment[i].usable_next_turn and not self.equipment[i].can_be_used_now:
self.equipment[i].can_be_used_now = True self.equipment[i].can_be_used_now = True
if self.is_dead and self.is_ghost and self.game.check_event(ceh.CittaFantasma):
self.is_ghost = False
for i in range(len(self.hand)):
self.deck.scrap(self.hand.pop(), True)
for i in range(len(self.equipment)):
self.deck.scrap(self.equipment.pop(), True)
self.pending_action = PendingAction.WAIT self.pending_action = PendingAction.WAIT
self.notify_self() self.notify_self()
self.game.next_turn() self.game.next_turn()

View File

@ -52,7 +52,7 @@ export default {
sockets: { sockets: {
self(self){ self(self){
self = JSON.parse(self) self = JSON.parse(self)
this.isPlaying = self.lives > 0 this.isPlaying = self.lives > 0 || self.is_ghost
this.pending_action = self.pending_action this.pending_action = self.pending_action
}, },
scrap(card) { scrap(card) {

View File

@ -16,10 +16,13 @@
<Card v-if="startGameCard" :card="startGameCard" @click.native="startGame"/> <Card v-if="startGameCard" :card="startGameCard" @click.native="startGame"/>
<!-- <div style="position: relative;width:260pt;height:400pt;"> --> <!-- <div style="position: relative;width:260pt;height:400pt;"> -->
<div v-for="p in playersTable" v-bind:key="p.card.name" style="position:relative;"> <div v-for="p in playersTable" v-bind:key="p.card.name" style="position:relative;">
<transition-group v-if="p.max_lives" name="list" tag="div" class="tiny-health"> <transition-group v-if="p.max_lives && !p.is_ghost" name="list" tag="div" class="tiny-health">
<span v-for="(n, i) in p.lives" v-bind:key="n" :alt="i"></span> <span v-for="(n, i) in p.lives" v-bind:key="n" :alt="i"></span>
<span v-for="(n, i) in (p.max_lives-p.lives)" v-bind:key="n" :alt="i">💀</span> <span v-for="(n, i) in (p.max_lives-p.lives)" v-bind:key="n" :alt="i">💀</span>
</transition-group> </transition-group>
<div v-else-if="p.is_ghost" class="tiny-health">
<span :alt="i">👻</span>
</div>
<Card :card="p.card" :class="{is_my_turn:p.is_my_turn}"/> <Card :card="p.card" :class="{is_my_turn:p.is_my_turn}"/>
<Card v-if="p.character" :card="p.character" class="character tiny-character" @click.native="selectedInfo = [p.character]"/> <Card v-if="p.character" :card="p.character" class="character tiny-character" @click.native="selectedInfo = [p.character]"/>
<Card v-if="p.character && p.character.name !== p.real_character.name" style="transform:scale(0.5) translate(-90px, -50px);" :card="p.character" class="character tiny-character" @click.native="selectedInfo = [p.character]"/> <Card v-if="p.character && p.character.name !== p.real_character.name" style="transform:scale(0.5) translate(-90px, -50px);" :card="p.character" class="character tiny-character" @click.native="selectedInfo = [p.character]"/>
@ -40,8 +43,8 @@
</div> </div>
<h3>{{$t('mods')}}</h3> <h3>{{$t('mods')}}</h3>
<PrettyCheck @click.native="toggleCompetitive" :disabled="!isRoomOwner" v-model="is_competitive" class="p-switch p-fill" style="margin-top:5px; margin-bottom:3px;">{{$t('mod_comp')}}</PrettyCheck> <PrettyCheck @click.native="toggleCompetitive" :disabled="!isRoomOwner" v-model="is_competitive" class="p-switch p-fill" style="margin-top:5px; margin-bottom:3px;">{{$t('mod_comp')}}</PrettyCheck>
<br> <!-- <br> -->
<PrettyCheck @click.native="toggleReplaceWithBot" :disabled="!isRoomOwner" v-model="disconnect_bot" class="p-switch p-fill" style="margin-top:5px; margin-bottom:3px;">{{$t('disconnect_bot')}}</PrettyCheck> <!-- <PrettyCheck @click.native="toggleReplaceWithBot" :disabled="!isRoomOwner" v-model="disconnect_bot" class="p-switch p-fill" style="margin-top:5px; margin-bottom:3px;">{{$t('disconnect_bot')}}</PrettyCheck> -->
</div> </div>
<div v-if="started"> <div v-if="started">
<deck :endTurnAction="()=>{wantsToEndTurn = true}"/> <deck :endTurnAction="()=>{wantsToEndTurn = true}"/>

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<p v-if="instruction && lives > 0" class="center-stuff">{{instruction}}</p> <p v-if="instruction && (lives > 0 || is_ghost)" class="center-stuff">{{instruction}}</p>
<!-- <button v-if="canEndTurn" @click="end_turn">Termina Turno</button> --> <!-- <button v-if="canEndTurn" @click="end_turn">Termina Turno</button> -->
<div class="equipment-slot"> <div class="equipment-slot">
<Card v-if="my_role" :card="my_role" class="back" <Card v-if="my_role" :card="my_role" class="back"
@ -11,7 +11,7 @@
<span v-for="(n, i) in lives" v-bind:key="n" :alt="i"></span> <span v-for="(n, i) in lives" v-bind:key="n" :alt="i"></span>
<span v-for="(n, i) in (max_lives-lives)" v-bind:key="n" :alt="i">💀</span> <span v-for="(n, i) in (max_lives-lives)" v-bind:key="n" :alt="i">💀</span>
</transition-group> </transition-group>
<transition-group v-if="lives > 0" name="list" tag="div" style="margin: 0 0 0 10pt; display:flex;"> <transition-group v-if="lives > 0 || is_ghost" name="list" tag="div" style="margin: 0 0 0 10pt; display:flex;">
<Card v-for="card in equipment" v-bind:key="card.name+card.number" :card="card" <Card v-for="card in equipment" v-bind:key="card.name+card.number" :card="card"
@pointerenter.native="desc=($i18n.locale=='it'?card.desc:card.desc_eng)" @pointerleave.native="desc=''" @pointerenter.native="desc=($i18n.locale=='it'?card.desc:card.desc_eng)" @pointerleave.native="desc=''"
@click.native="play_card(card, true)" /> @click.native="play_card(card, true)" />
@ -24,7 +24,7 @@
<button v-if="is_my_turn && character.name === 'Chuck Wengam' && lives > 1" @click="chuckSpecial">{{$t('special_ability')}}</button> <button v-if="is_my_turn && character.name === 'Chuck Wengam' && lives > 1" @click="chuckSpecial">{{$t('special_ability')}}</button>
<button v-if="is_my_turn && character.name === 'José Delgrado' && special_use_count < 2 && hand.filter(x => x.is_equipment).length > 0" @click="joseScrap=true">{{$t('special_ability')}}</button> <button v-if="is_my_turn && character.name === 'José Delgrado' && special_use_count < 2 && hand.filter(x => x.is_equipment).length > 0" @click="joseScrap=true">{{$t('special_ability')}}</button>
<button v-if="is_my_turn && character.name === 'Doc Holyday' && special_use_count < 1 && hand.length > 1" @click="holydayScrap=true">{{$t('special_ability')}}</button> <button v-if="is_my_turn && character.name === 'Doc Holyday' && special_use_count < 1 && hand.length > 1" @click="holydayScrap=true">{{$t('special_ability')}}</button>
<div v-if="lives > 0" style="position:relative"> <div v-if="lives > 0 || is_ghost" style="position:relative">
<span id="hand_text">{{$t('hand')}}</span> <span id="hand_text">{{$t('hand')}}</span>
<transition-group name="list" tag="div" class="hand"> <transition-group name="list" tag="div" class="hand">
<Card v-for="card in hand" v-bind:key="card.name+card.number" :card="card" <Card v-for="card in hand" v-bind:key="card.name+card.number" :card="card"
@ -39,7 +39,7 @@
<Chooser v-if="card_against" :text="$t('card_against')" :cards="visiblePlayers" :select="selectAgainst" :cancel="cancelCardAgainst"/> <Chooser v-if="card_against" :text="$t('card_against')" :cards="visiblePlayers" :select="selectAgainst" :cancel="cancelCardAgainst"/>
<Chooser v-if="pending_action == 3" :text="respondText" :cards="respondCards" :select="respond"/> <Chooser v-if="pending_action == 3" :text="respondText" :cards="respondCards" :select="respond"/>
<Chooser v-if="shouldChooseCard" :text="$t(choose_text)" :cards="available_cards" :select="choose"/> <Chooser v-if="shouldChooseCard" :text="$t(choose_text)" :cards="available_cards" :select="choose"/>
<Chooser v-if="lives <= 0 && max_lives > 0" :text="$t('you_died')" :cancelText="$t('spectate')" :cancel="()=>{max_lives = 0}"/> <Chooser v-if="lives <= 0 && max_lives > 0 && !is_ghost" :text="$t('you_died')" :cancelText="$t('spectate')" :cancel="()=>{max_lives = 0}"/>
<Chooser v-if="win_status !== undefined" :text="win_status?$t('you_win'):$t('you_lose')" /> <Chooser v-if="win_status !== undefined" :text="win_status?$t('you_win'):$t('you_lose')" />
<Chooser v-if="show_role" :text="$t('you_are')" :cards="[my_role]" :hintText="($i18n.locale=='it'?my_role.goal:my_role.goal_eng)" :select="() => {show_role=false}" :cancel="() => {show_role=false}" :cancelText="$t('ok')" /> <Chooser v-if="show_role" :text="$t('you_are')" :cards="[my_role]" :hintText="($i18n.locale=='it'?my_role.goal:my_role.goal_eng)" :select="() => {show_role=false}" :cancel="() => {show_role=false}" :cancelText="$t('ok')" />
<Chooser v-if="notifycard" :key="notifycard.card" :text="`${notifycard.player} ${$t('did_pick_as')}:`" :cards="[notifycard.card]" :hintText="$t(notifycard.message)" class="turn-notify-4s"/> <Chooser v-if="notifycard" :key="notifycard.card" :text="`${notifycard.player} ${$t('did_pick_as')}:`" :cards="[notifycard.card]" :hintText="$t(notifycard.message)" class="turn-notify-4s"/>
@ -106,6 +106,7 @@ export default {
holydayScrap: false, holydayScrap: false,
special_use_count: 0, special_use_count: 0,
mancato_needed: 0, mancato_needed: 0,
is_ghost: false,
name: '', name: '',
}), }),
sockets: { sockets: {
@ -141,6 +142,7 @@ export default {
this.sight = self.sight this.sight = self.sight
this.attacker = self.attacker this.attacker = self.attacker
this.mancato_needed = self.mancato_needed this.mancato_needed = self.mancato_needed
this.is_ghost = self.is_ghost
if (this.pending_action == 5 && self.target_p) { if (this.pending_action == 5 && self.target_p) {
this.chooseCardFromPlayer(self.target_p) this.chooseCardFromPlayer(self.target_p)
} else if (this.pending_action == 5) { } else if (this.pending_action == 5) {