Merge pull request #16 from albertoxamin/dev

add fistful of cards
This commit is contained in:
Alberto Xamin 2020-12-23 13:11:50 +01:00 committed by GitHub
commit f3631232d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 719 additions and 278 deletions

2
.gitignore vendored
View File

@ -139,3 +139,5 @@ cython_debug/
frontend/package-lock.json frontend/package-lock.json
bang-workspace.code-workspace bang-workspace.code-workspace
.vscode/

View File

@ -8,6 +8,9 @@ import socketio
from bang.game import Game from bang.game import Game
from bang.players import Player from bang.players import Player
import sys
sys.setrecursionlimit(10**6) # this should prevents bots from stopping
sio = socketio.Server(cors_allowed_origins="*") sio = socketio.Server(cors_allowed_origins="*")
static_files={ static_files={
'/': {'content_type': 'text/html', 'filename': 'index.html'}, '/': {'content_type': 'text/html', 'filename': 'index.html'},
@ -205,6 +208,8 @@ def chat_message(sid, msg):
ses.game.reset() ses.game.reset()
elif '/startgame' in msg and not ses.game.started: elif '/startgame' in msg and not ses.game.started:
ses.game.start_game() ses.game.start_game()
elif '/setbotspeed' in msg:
ses.game.bot_speed = float(msg.split()[1])
elif '/addex' in msg and not ses.game.started: elif '/addex' in msg and not ses.game.started:
cmd = msg.split() cmd = msg.split()
if len(cmd) == 2: if len(cmd) == 2:
@ -214,10 +219,39 @@ def chat_message(sid, msg):
ses.game.notify_room() ses.game.notify_room()
else: else:
sio.emit('chat_message', room=sid, data={'color': f'','text':f'{msg} bad format'}) sio.emit('chat_message', room=sid, data={'color': f'','text':f'{msg} bad format'})
elif '/setcharacter' in msg:
sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'🚨 {ses.name} is in debug mode and changed character'})
import bang.characters as characters
cmd = msg.split()
if len(cmd) >= 2:
chs = characters.all_characters(ses.game.expansions)
ses.character = [c for c in chs if c.name == ' '.join(cmd[1:])][0]
ses.real_character = ses.character
ses.notify_self()
elif '/removecard' in msg:
sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'🚨 {ses.name} is in debug mode and removed a card'})
cmd = msg.split()
if len(cmd) == 2:
if len(ses.hand) > int(cmd[1]):
ses.hand.pop(int(cmd[1]))
else:
ses.hand.pop(int(cmd[1])-len(ses.hand))
ses.notify_self()
elif '/getcard' in msg:
sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'🚨 {ses.name} is in debug mode and got a card'})
import bang.cards as cs
cmd = msg.split()
if len(cmd) >= 2:
cards = cs.get_starting_deck(ses.game.expansions)
ses.hand.append([c for c in cards if c.name == ' '.join(cmd[1:])][0])
ses.notify_self()
elif '/gameinfo' in msg: elif '/gameinfo' in msg:
sio.emit('chat_message', room=sid, data={'color': f'','text':f'info: {ses.game.__dict__}'}) sio.emit('chat_message', room=sid, data={'color': f'','text':f'info: {ses.game.__dict__}'})
elif '/meinfo' in msg: elif '/meinfo' in msg:
sio.emit('chat_message', room=sid, data={'color': f'','text':f'info: {ses.__dict__}'}) sio.emit('chat_message', room=sid, data={'color': f'','text':f'info: {ses.__dict__}'})
elif '/mebot' in msg:
ses.is_bot = not ses.is_bot
ses.notify_self()
else: else:
sio.emit('chat_message', room=sid, data={'color': f'','text':f'{msg} COMMAND NOT FOUND'}) sio.emit('chat_message', room=sid, data={'color': f'','text':f'{msg} COMMAND NOT FOUND'})
else: else:

View File

@ -58,12 +58,7 @@ class Card(ABC):
if not has_weapon: if not has_weapon:
player.equipment.append(self) player.equipment.append(self)
elif self.name in [c.name for c in player.equipment if not isinstance(c, Dinamite)]: elif self.name in [c.name for c in player.equipment if not isinstance(c, Dinamite)]:
for i in range(len(player.equipment)): return False
print('tipo',type(self))
if type(player.equipment[i]) == type(self):
player.game.deck.scrap(player.equipment[i])
player.equipment[i] = self
break
else: else:
player.equipment.append(self) player.equipment.append(self)
if against: if against:
@ -77,6 +72,9 @@ class Card(ABC):
def use_card(self, player): def use_card(self, player):
pass pass
def is_duplicate_card(self, player):
return self.name in [c.name for c in player.equipment]
class Barile(Card): class Barile(Card):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -124,6 +122,7 @@ class Prigione(Card):
data=f'_play_card_against|{player.name}|{self.name}|{against}') data=f'_play_card_against|{player.name}|{self.name}|{against}')
player.game.get_player_named(against).equipment.append(self) player.game.get_player_named(against).equipment.append(self)
player.game.get_player_named(against).notify_self() player.game.get_player_named(against).notify_self()
return True
return False return False
class Remington(Card): class Remington(Card):

View File

@ -22,15 +22,16 @@ class Deck:
self.event_cards: List[ce.CardEvent] = [] self.event_cards: List[ce.CardEvent] = []
if 'fistful_of_cards' in game.expansions: if 'fistful_of_cards' in game.expansions:
self.event_cards.extend(ce.get_all_events()) self.event_cards.extend(ce.get_all_events())
random.shuffle(self.event_cards) self.event_cards.insert(0, None)
self.event_cards.insert(0, None) # 2 perchè iniziale, e primo flip dallo sceriffo
random.shuffle(self.cards) random.shuffle(self.cards)
self.scrap_pile: List[cs.Card] = [] self.scrap_pile: List[cs.Card] = []
print(f'Deck initialized with {len(self.cards)} cards') print(f'Deck initialized with {len(self.cards)} cards')
def flip_event(self): def flip_event(self):
if len(self.event_cards) > 0: if len(self.event_cards) > 0 and not isinstance(self.event_cards[0], ce.PerUnPugnoDiCarte):
self.event_cards.append(self.event_cards.pop(0)) self.event_cards.append(self.event_cards.pop(0))
self.game.notify_event_card() self.game.notify_event_card()
def peek(self, n_cards: int) -> list: def peek(self, n_cards: int) -> list:
return self.cards[:n_cards] return self.cards[:n_cards]
@ -52,7 +53,9 @@ class Deck:
def put_on_top(self, card: cs.Card): def put_on_top(self, card: cs.Card):
self.cards.insert(0, card) self.cards.insert(0, card)
def draw(self) -> cs.Card: def draw(self, ignore_event = False) -> cs.Card:
if self.game.check_event(ce.MinieraAbbandonata) and len(self.scrap_pile) > 0 and not ignore_event:
return self.draw_from_scrap_pile()
card = self.cards.pop(0) card = self.cards.pop(0)
if len(self.cards) == 0: if len(self.cards) == 0:
self.reshuffle() self.reshuffle()
@ -71,8 +74,11 @@ class Deck:
else: else:
return self.draw() return self.draw()
def scrap(self, card: cs.Card): def scrap(self, card: cs.Card, ignore_event = False):
if card.usable_next_turn: if card.usable_next_turn:
card.can_be_used_now = False card.can_be_used_now = False
self.scrap_pile.append(card) if self.game.check_event(ce.MinieraAbbandonata) and not ignore_event:
self.game.notify_scrap_pile() self.put_on_top(card)
else:
self.scrap_pile.append(card)
self.game.notify_scrap_pile()

View File

@ -152,8 +152,11 @@ class Bibbia(Schivata):
pass pass
return False return False
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
class Cappello(Mancato): class Cappello(Mancato):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -168,8 +171,11 @@ class Cappello(Mancato):
pass pass
return False return False
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
class PlaccaDiFerro(Cappello): class PlaccaDiFerro(Cappello):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -195,8 +201,11 @@ class Pugnale(Pugno):
if self.can_be_used_now: if self.can_be_used_now:
return super().play_card(player, against=against) return super().play_card(player, against=against)
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
class Derringer(Pugnale): class Derringer(Pugnale):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -212,8 +221,11 @@ class Derringer(Pugnale):
player.hand.append(player.game.deck.draw()) player.hand.append(player.game.deck.draw())
return super().play_card(player, against=against) return super().play_card(player, against=against)
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
def use_card(self, player): def use_card(self, player):
player.hand.append(player.game.deck.draw()) player.hand.append(player.game.deck.draw())
@ -235,8 +247,11 @@ class Borraccia(Card):
player.notify_self() player.notify_self()
return True return True
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
class PonyExpress(WellsFargo): class PonyExpress(WellsFargo):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -250,8 +265,11 @@ class PonyExpress(WellsFargo):
if self.can_be_used_now: if self.can_be_used_now:
return super().play_card(player, against) return super().play_card(player, against)
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
class Howitzer(Gatling): class Howitzer(Gatling):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -265,8 +283,11 @@ class Howitzer(Gatling):
if self.can_be_used_now: if self.can_be_used_now:
return super().play_card(player, against) return super().play_card(player, against)
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
class CanCan(CatBalou): class CanCan(CatBalou):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -280,8 +301,11 @@ class CanCan(CatBalou):
if self.can_be_used_now: if self.can_be_used_now:
return super().play_card(player, against) return super().play_card(player, against)
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
class Conestoga(Panico): class Conestoga(Panico):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -297,8 +321,11 @@ class Conestoga(Panico):
if self.can_be_used_now: if self.can_be_used_now:
return super().play_card(player, against) return super().play_card(player, against)
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
class Pepperbox(Bang): class Pepperbox(Bang):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -316,8 +343,11 @@ class Pepperbox(Bang):
return True return True
return False return False
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
class FucileDaCaccia(Card): class FucileDaCaccia(Card):
def __init__(self, suit, number): def __init__(self, suit, number):
@ -336,12 +366,14 @@ class FucileDaCaccia(Card):
return True return True
return False return False
else: else:
player.equipment.append(self) if not self.is_duplicate_card(player):
return True player.equipment.append(self)
return True
else:
return False
def get_starting_deck() -> List[Card]: def get_starting_deck() -> List[Card]:
return [ return [
#TODO: aggiungere anche le carte normalmente presenti https://bang.dvgiochi.com/cardslist.php?id=3
Barile(Suit.CLUBS, 'A'), Barile(Suit.CLUBS, 'A'),
Binocolo(Suit.DIAMONDS, 10), Binocolo(Suit.DIAMONDS, 10),
Dinamite(Suit.CLUBS, 10), Dinamite(Suit.CLUBS, 10),

View File

@ -1,4 +1,5 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
import random
class CardEvent(ABC): class CardEvent(ABC):
def __init__(self, name, icon): def __init__(self, name, icon):
@ -7,109 +8,114 @@ class CardEvent(ABC):
class Agguato(CardEvent): class Agguato(CardEvent):
def __init__(self): def __init__(self):
super().__init__('Agguato', '🛁') super().__init__("Agguato", "🛁")
self.desc = 'La distanza base di tra 2 qualsiasi giocatori è 1' self.desc = "La distanza base di tra 2 qualsiasi giocatori è 1"
self.desc_eng = 'The base distance from any 2 players is 1' self.desc_eng = "The base distance from any 2 players is 1"
class Cecchino(CardEvent): class Cecchino(CardEvent):
def __init__(self): #TODO def __init__(self):
super().__init__('Cecchino', '👁') super().__init__("Cecchino", "👁")
self.desc = 'Nel proprio turno i giocatori possono scartare 2 Bang assieme per sparare un bang a cui servono 2 mancato' self.desc = "Nel proprio turno i giocatori possono scartare 2 Bang assieme per sparare un bang che necessita 2 mancato (clicca la carta)"
self.desc_eng = 'During their turn, players can discard 2 Bang! to shoot a bang that requires 2 missed' self.desc_eng = "During their turn, players can discard 2 Bang! to shoot a bang that requires 2 missed (click the card)"
class DeadMan(CardEvent): class DeadMan(CardEvent):
def __init__(self): def __init__(self):
super().__init__('Dead Man', '⚰️') super().__init__("Dead Man", "⚰️")
self.desc = 'Al proprio turno il giocatore che è morto per primo torna in vita con 2 vite e 2 carte' self.desc = "Al proprio turno il giocatore che è morto per primo torna in vita con 2 vite e 2 carte"
self.desc_eng = 'The first player that died return back to life with 2 hp and 2 cards' self.desc_eng = "The first player that died return back to life with 2 hp and 2 cards"
class FratelliDiSangue(CardEvent): class FratelliDiSangue(CardEvent):
def __init__(self):#TODO def __init__(self):
super().__init__('Fratelli Di Sangue', '💉') super().__init__("Fratelli Di Sangue", "💉")
self.desc = 'All\'inizio del proprio turno i giocatori possono perdere 1 vita per darla a un altro giocatore' self.desc = "All'inizio del proprio turno, i giocatori possono perdere 1 vita (tranne l'ultimo) per darla a un altro giocatore"
self.desc_eng = 'At the begin of their turn, payers can lose 1 hp to give it to another player' self.desc_eng = "At the begin of their turn, payers can lose 1 hp (except the last one) to give it to another player"
class IlGiudice(CardEvent): class IlGiudice(CardEvent):
def __init__(self): def __init__(self):
super().__init__('Il Giudice', '👨‍⚖️') super().__init__("Il Giudice", "👨‍⚖️")
self.desc = 'Non si possono equipaggiare carte a se stessi o agli altri' self.desc = "Non si possono equipaggiare carte a se stessi o agli altri"
self.desc_eng = 'You can\'t equip cards on your or other players' self.desc_eng = "You can't equip cards on your or other players"
class Lazo(CardEvent): class Lazo(CardEvent):
def __init__(self): def __init__(self):
super().__init__('Lazo', '📿') super().__init__("Lazo", "📿")
self.desc = 'Le carte equipaggiate non hanno effetto' self.desc = "Le carte equipaggiate non hanno effetto"
self.desc_eng = 'Cards in the equipment slot do not work' self.desc_eng = "Cards in the equipment slot do not work"
class LeggeDelWest(CardEvent): class LeggeDelWest(CardEvent):
def __init__(self): def __init__(self):
super().__init__('Legge Del West', '⚖️') super().__init__("Legge Del West", "⚖️")
self.desc = 'I giocatori mostrano la seconda carta che pescano e sono obbligati a usarla in quel turno (se possibile)' self.desc = "I giocatori mostrano la seconda carta che pescano e sono obbligati a usarla in quel turno (se possibile)"
self.desc_eng = 'Every player shows the second card that they draw and must use it in that round' self.desc_eng = "Every player shows the second card that they draw and must use it in that round (if it is possible)"
class LiquoreForte(CardEvent): class LiquoreForte(CardEvent):
def __init__(self):#TODO def __init__(self):
super().__init__('Liquore Forte', '🥃') super().__init__("Liquore Forte", "🥃")
self.desc = 'I giocatori possono evitare di pescare per recuperare 1 vita' self.desc = "I giocatori possono evitare di pescare per recuperare 1 vita (clicca sulla carta evento per farlo)"
self.desc_eng = 'Players can skip drawing to regain 1 HP' self.desc_eng = "Players can skip drawing to regain 1 HP (click on the event card to use)"
class MinieraAbbandonata(CardEvent): class MinieraAbbandonata(CardEvent):
def __init__(self):#TODO def __init__(self):
super().__init__('Miniera Abbandonata', '') super().__init__("Miniera Abbandonata", "")
self.desc = 'I giocatori pescano dagli scarti e scartano in cima al mazzo' self.desc = "I giocatori pescano dagli scarti nella loro fase 1 e scartano in cima al mazzo nella loro fase 3 (se gli scarti finiscono, è necessario pescare e scartare in cima al mazzo)"
self.desc_eng = 'Players draw from the discarded pile and discard to the deck' #TODO: cambiare anche la descrizione inglese
self.desc_eng = "Players draw from the discarded pile and discard to the top of the deck (if the discards run out, they must draw and discard on top of the deck)"
class PerUnPugnoDiCarte(CardEvent): class PerUnPugnoDiCarte(CardEvent):
def __init__(self):#TODO def __init__(self):
super().__init__('Per Un Pugno Di Carte', '🎴') super().__init__("Per Un Pugno Di Carte", "🎴")
self.desc = 'Il giocatore subisce tanti bang quante carte ha in mano' self.desc = "All'inizio del proprio turno, il giocatore subisce tanti bang quante carte ha in mano"
self.desc_eng = 'On his turn the player is target of as many Bang as how many cards he has in his hand' self.desc_eng = "On the beginning of his turn, the player is target of as many Bang as how many cards he has in his hand"
class Peyote(CardEvent): class Peyote(CardEvent):
def __init__(self):#TODO def __init__(self):
super().__init__('Peyote', '🌵') super().__init__("Peyote", "🌵")
self.desc = 'Invece che pescare il giocatore prova a indovinare il colore del seme, se lo indovina continua' self.desc = "Invece che pescare il giocatore prova a indovinare il colore del seme, se lo indovina aggiunge la carta alla mano e continua provando ad indovinare la carta successiva"
self.desc_eng = 'Instead of drawing, the player tries to guess the color of the suit, if he\'s right he repeats' self.desc_eng = "Instead of drawing, the player tries to guess the color of the suit, if he's right he adds the card to the hand and continues trying to guess the next card"
class Ranch(CardEvent): class Ranch(CardEvent):
def __init__(self):#TODO def __init__(self):
super().__init__('Ranch', '🐮') super().__init__("Ranch", "🐮")
self.desc = 'Dopo aver pescato il giocatore può scartare quante carte vuole dalla mano e pescarne altrettante dal mazzo' self.desc = "Dopo aver pescato il giocatore può scartare quante carte vuole dalla mano e pescarne altrettante dal mazzo"
self.desc_eng = 'After drawing, the player can discard as many cards as he wants from his hand and draw as many from the deck' self.desc_eng = "After drawing, the player can discard as many cards as he wants from his hand and draw as many from the deck"
class Rimbalzo(CardEvent): class Rimbalzo(CardEvent):
def __init__(self):#TODO def __init__(self):
super().__init__('Rimbalzo', '') super().__init__("Rimbalzo", "")
self.desc = 'Il giocatore di turno può giocare bang contro le carte equipaggiate dagli altri giocatori, se non giocano mancato vengono scartate' self.desc = "Il giocatore di turno può giocare bang contro le carte equipaggiate dagli altri giocatori, se non giocano mancato vengono scartate (clicca la carta evento)"
self.desc_eng = 'The player can play bang against the cards equipped by the other players, if they do not play miss they are discarded' self.desc_eng = "The player can play bang against the cards equipped by the other players, if they do not play miss they are discarded (click the event card)"
class RouletteRussa(CardEvent): class RouletteRussa(CardEvent):
def __init__(self):#TODO def __init__(self):
super().__init__('Roulette Russa', '🇷🇺') super().__init__("Roulette Russa", "🇷🇺")
self.desc = 'A partire dallo sceriffo, ogni giocatore scarta 1 mancato, il primo che non lo fa perde 2 vite' self.desc = "A partire dallo sceriffo, ogni giocatore scarta 1 mancato, il primo che non lo fa perde 2 vite"
self.desc_eng = 'Starting from the sheriff, every player discards 1 missed, the first one that doesn\'t loses 2 HP' self.desc_eng = "Starting from the sheriff, every player discards 1 missed, the first one that doesn't loses 2 HP"
class Vendetta(CardEvent): class Vendetta(CardEvent):
def __init__(self): def __init__(self):
super().__init__('Vendetta', '😤') super().__init__("Vendetta", "😤")
self.desc = 'Alla fine del proprio turno il giocatore estrae, se esce ♥️ gioca un altro turno' self.desc = "Alla fine del proprio turno il giocatore estrae dal mazzo, se esce ♥️ gioca un altro turno (ma non estrae di nuovo)"
self.desc_eng = 'When ending the turn, the player flips a card, if it\'s ♥️ he plays another turn' self.desc_eng = "When ending the turn, the player flips a card from the deck, if it's ♥️ he plays another turn (but he does not flip another card)"
def get_all_events(): def get_all_events():
return [ cards = [
Agguato(), Agguato(),
# Cecchino(), Cecchino(),
DeadMan(), DeadMan(),
# FratelliDiSangue(), FratelliDiSangue(),
IlGiudice(), IlGiudice(),
Lazo(), Lazo(),
LeggeDelWest(), LeggeDelWest(),
# LiquoreForte(), LiquoreForte(),
# MinieraAbbandonata(), MinieraAbbandonata(),
# PerUnPugnoDiCarte(), Peyote(),
# Peyote(), Ranch(),
# Ranch(), Rimbalzo(),
# Rimbalzo(), RouletteRussa(),
# RouletteRussa(),
Vendetta(), Vendetta(),
] ]
random.shuffle(cards)
cards.append(PerUnPugnoDiCarte())
for c in cards:
c.expansion = 'fistful-of-cards'
return cards

View File

@ -2,7 +2,7 @@
from typing import List, Set, Dict, Tuple, Optional from typing import List, Set, Dict, Tuple, Optional
import random import random
import socketio import socketio
import bang.players as players import bang.players as pl
import bang.characters as characters import bang.characters as characters
from bang.deck import Deck from bang.deck import Deck
import bang.roles as roles import bang.roles as roles
@ -14,8 +14,8 @@ class Game:
super().__init__() super().__init__()
self.sio = sio self.sio = sio
self.name = name self.name = name
self.players: List[players.Player] = [] self.players: List[pl.Player] = []
self.dead_players: List[players.Player] = [] self.dead_players: List[pl.Player] = []
self.deck: Deck = None self.deck: Deck = None
self.started = False self.started = False
self.turn = 0 self.turn = 0
@ -24,10 +24,13 @@ class Game:
self.initial_players = 0 self.initial_players = 0
self.password = '' self.password = ''
self.expansions = [] self.expansions = []
self.available_expansions = ['dodge_city'] self.available_expansions = ['dodge_city', 'fistful_of_cards']
self.shutting_down = False self.shutting_down = False
self.is_competitive = False self.is_competitive = False
self.disconnect_bot = True self.disconnect_bot = True
self.player_bangs = 0
self.is_russian_roulette_on = False
self.bot_speed = 1.5
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:
@ -59,7 +62,7 @@ class Game:
self.disconnect_bot = not self.disconnect_bot self.disconnect_bot = not self.disconnect_bot
self.notify_room() self.notify_room()
def add_player(self, player: players.Player): def add_player(self, player: pl.Player):
if player.is_bot and len(self.players) >= 8: if player.is_bot and len(self.players) >= 8:
return return
if player in self.players or len(self.players) >= 10: if player in self.players or len(self.players) >= 10:
@ -138,9 +141,10 @@ class Game:
self.sio.emit('chat_message', room=self.name, data=f'_sheriff|{self.players[i].name}') self.sio.emit('chat_message', room=self.name, data=f'_sheriff|{self.players[i].name}')
self.turn = i self.turn = i
self.players[i].notify_self() self.players[i].notify_self()
self.notify_event_card()
def attack_others(self, attacker: players.Player): def attack_others(self, attacker: pl.Player):
attacker.pending_action = players.PendingAction.WAIT attacker.pending_action = pl.PendingAction.WAIT
attacker.notify_self() attacker.notify_self()
self.waiting_for = 0 self.waiting_for = 0
self.readyCount = 0 self.readyCount = 0
@ -150,11 +154,11 @@ class Game:
self.waiting_for += 1 self.waiting_for += 1
p.notify_self() p.notify_self()
if self.waiting_for == 0: if self.waiting_for == 0:
attacker.pending_action = players.PendingAction.PLAY attacker.pending_action = pl.PendingAction.PLAY
attacker.notify_self() attacker.notify_self()
def indian_others(self, attacker: players.Player): def indian_others(self, attacker: pl.Player):
attacker.pending_action = players.PendingAction.WAIT attacker.pending_action = pl.PendingAction.WAIT
attacker.notify_self() attacker.notify_self()
self.waiting_for = 0 self.waiting_for = 0
self.readyCount = 0 self.readyCount = 0
@ -164,60 +168,99 @@ class Game:
self.waiting_for += 1 self.waiting_for += 1
p.notify_self() p.notify_self()
if self.waiting_for == 0: if self.waiting_for == 0:
attacker.pending_action = players.PendingAction.PLAY attacker.pending_action = pl.PendingAction.PLAY
attacker.notify_self() attacker.notify_self()
def attack(self, attacker: players.Player, target_username:str, double:bool=False): def attack(self, attacker: pl.Player, target_username:str, double:bool=False):
if self.get_player_named(target_username).get_banged(attacker=attacker, double=double): if self.get_player_named(target_username).get_banged(attacker=attacker, double=double):
self.readyCount = 0 self.readyCount = 0
self.waiting_for = 1 self.waiting_for = 1
attacker.pending_action = players.PendingAction.WAIT attacker.pending_action = pl.PendingAction.WAIT
attacker.notify_self() attacker.notify_self()
self.get_player_named(target_username).notify_self() self.get_player_named(target_username).notify_self()
def duel(self, attacker: players.Player, target_username:str): def rimbalzo(self, attacker: pl.Player, target_username:str, card_index:int):
if self.get_player_named(target_username).get_banged(attacker=attacker, no_dmg=True, card_index=card_index):
self.readyCount = 0
self.waiting_for = 1
attacker.pending_action = pl.PendingAction.WAIT
attacker.notify_self()
self.get_player_named(target_username).notify_self()
def duel(self, attacker: pl.Player, target_username:str):
if self.get_player_named(target_username).get_dueled(attacker=attacker): if self.get_player_named(target_username).get_dueled(attacker=attacker):
self.readyCount = 0 self.readyCount = 0
self.waiting_for = 1 self.waiting_for = 1
attacker.pending_action = players.PendingAction.WAIT attacker.pending_action = pl.PendingAction.WAIT
attacker.notify_self() attacker.notify_self()
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() for i in range(len(self.players))] 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 = players.PendingAction.CHOOSE 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].available_cards = self.available_cards
self.players[self.turn].notify_self() self.players[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 = players.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)] nextPlayer = self.players[(self.turn + (len(self.players)-len(self.available_cards))) % len(self.players)]
if nextPlayer == self.players[self.turn]: if nextPlayer == self.players[self.turn]:
self.players[self.turn].pending_action = players.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 = players.PendingAction.CHOOSE nextPlayer.pending_action = pl.PendingAction.CHOOSE
self.players[self.turn].choose_text = 'choose_card_to_get'
nextPlayer.available_cards = self.available_cards nextPlayer.available_cards = self.available_cards
nextPlayer.notify_self() nextPlayer.notify_self()
def get_player_named(self, name:str): def get_player_named(self, name:str):
return self.players[self.players_map[name]] return self.players[self.players_map[name]]
def responders_did_respond_resume_turn(self): def responders_did_respond_resume_turn(self, did_lose=False):
self.readyCount += 1 print('did_lose', did_lose)
if self.readyCount == self.waiting_for: if self.player_bangs > 0 and self.check_event(ce.PerUnPugnoDiCarte):
self.waiting_for = 0 self.player_bangs -= 1
self.readyCount = 0 if self.player_bangs > 1:
self.players[self.turn].pending_action = players.PendingAction.PLAY print('bang again')
self.players[self.turn].notify_self() if self.players[self.turn].get_banged(self.deck.event_cards[0]):
self.players[self.turn].notify_self()
else:
self.responders_did_respond_resume_turn()
else:
print('ok play turn now')
self.player_bangs = 0
self.players[self.turn].play_turn()
elif self.is_russian_roulette_on and self.check_event(ce.RouletteRussa):
if did_lose:
print('stop roulette')
self.players[(self.turn+self.player_bangs) % len(self.players)].lives -= 1
self.players[(self.turn+self.player_bangs) % len(self.players)].notify_self()
self.is_russian_roulette_on = False
self.players[self.turn].play_turn()
else:
self.player_bangs += 1
print(f'next in line {self.players[(self.turn+self.player_bangs) % len(self.players)].name}')
if self.players[(self.turn+self.player_bangs) % len(self.players)].get_banged(self.deck.event_cards[0]):
self.players[(self.turn+self.player_bangs) % len(self.players)].notify_self()
else:
self.responders_did_respond_resume_turn(did_lose=True)
else:
self.readyCount += 1
if self.readyCount == self.waiting_for:
self.waiting_for = 0
self.readyCount = 0
self.players[self.turn].pending_action = pl.PendingAction.PLAY
self.players[self.turn].notify_self()
def next_player(self): def next_player(self):
return self.players[(self.turn + 1) % len(self.players)] return self.players[(self.turn + 1) % len(self.players)]
def play_turn(self): def play_turn(self):
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 self.check_event(ce.DeadMan) and len(self.dead_players) > 0:
@ -227,7 +270,21 @@ class Game:
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_map = {c.name: i for i, c in enumerate(self.players)}
self.players[-1].notify_self() self.players[-1].notify_self()
self.players[self.turn].play_turn() elif self.check_event(ce.RouletteRussa):
self.is_russian_roulette_on = True
if self.players[self.turn].get_banged(self.deck.event_cards[0]):
self.players[self.turn].notify_self()
else:
self.responders_did_respond_resume_turn(did_lose=True)
return
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]):
self.players[self.turn].notify_self()
else:
self.responders_did_respond_resume_turn()
else:
self.players[self.turn].play_turn()
def next_turn(self): def next_turn(self):
if self.shutting_down: return if self.shutting_down: return
@ -237,7 +294,10 @@ class Game:
def notify_event_card(self): def notify_event_card(self):
if len(self.deck.event_cards) > 0: if len(self.deck.event_cards) > 0:
self.sio.emit('event_card', room=self.name, data=self.deck.event_cards[0].__dict__) if self.deck.event_cards[0] != None:
self.sio.emit('event_card', room=self.name, data=self.deck.event_cards[0].__dict__)
else:
self.sio.emit('event_card', room=self.name, data=None)
def notify_scrap_pile(self): def notify_scrap_pile(self):
print('scrap') print('scrap')
@ -246,7 +306,7 @@ class Game:
else: else:
self.sio.emit('scrap', room=self.name, data=None) self.sio.emit('scrap', room=self.name, data=None)
def handle_disconnect(self, player: players.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.players:
if self.disconnect_bot and self.started: if self.disconnect_bot and self.started:
@ -266,24 +326,25 @@ class Game:
return True return True
else: return False else: return False
def player_death(self, player: players.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: 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 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):
for i in range(len(player.attacker.hand)): for i in range(len(player.attacker.hand)):
self.deck.scrap(player.attacker.hand.pop()) self.deck.scrap(player.attacker.hand.pop(), True)
for i in range(len(player.attacker.equipment)): for i in range(len(player.attacker.equipment)):
self.deck.scrap(player.attacker.equipment.pop()) self.deck.scrap(player.attacker.equipment.pop(), True)
player.attacker.notify_self() player.attacker.notify_self()
elif player.attacker and (isinstance(player.role, roles.Outlaw) or self.initial_players == 3): elif player.attacker and player.attacker in self.players and (isinstance(player.role, roles.Outlaw) or self.initial_players == 3):
for i in range(3): for i in range(3):
player.attacker.hand.append(self.deck.draw()) player.attacker.hand.append(self.deck.draw(True))
player.attacker.notify_self() player.attacker.notify_self()
print(f'player {player.name} died') print(f'player {player.name} died')
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
index = self.players.index(player) index = self.players.index(player)
died_in_his_turn = self.started and index == self.turn died_in_his_turn = self.started and index == self.turn
if self.started and index <= self.turn: if self.started and index <= self.turn:
@ -303,7 +364,7 @@ class Game:
if self.started: if self.started:
print('Check win status') print('Check win status')
attacker_role = None attacker_role = None
if player.attacker: 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.players, initial_players=self.initial_players, dead_role=player.role, attacker_role=attacker_role)]
if len(winners) > 0: if len(winners) > 0:
@ -318,22 +379,36 @@ class Game:
vulture = [p for p in self.players if isinstance(p.character, characters.VultureSam)] vulture = [p for p in self.players if isinstance(p.character, 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()) self.deck.scrap(player.hand.pop(), True)
for i in range(len(player.equipment)): for i in range(len(player.equipment)):
self.deck.scrap(player.equipment.pop()) self.deck.scrap(player.equipment.pop(), True)
elif len(vulture) == 2:
for i in range(len(player.hand)):
vulture[i%2].hand.append(player.hand.pop())
for i in range(len(player.equipment)):
vulture[i%2].hand.append(player.equipment.pop())
vulture[0].notify_self()
vulture[1].notify_self()
else: else:
for i in range(len(player.hand)): for i in range(len(player.hand)):
vulture[0].hand.append(player.hand.pop()) vulture[0].hand.append(player.hand.pop())
for i in range(len(player.equipment)): for i in range(len(player.equipment)):
vulture[0].hand.append(player.equipment.pop()) vulture[0].hand.append(player.equipment.pop())
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à
if player.attacker and player.attacker in self.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 isinstance(p.character, chd.GregDigger)] greg = [p for p in self.players if isinstance(p.character, 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 isinstance(p.character, chd.HerbHunter)] herb = [p for p in self.players if isinstance(p.character, chd.HerbHunter)]
if len(herb) > 0: if len(herb) > 0:
herb[0].hand.append(self.deck.draw()) herb[0].hand.append(self.deck.draw(True))
herb[0].hand.append(self.deck.draw()) herb[0].hand.append(self.deck.draw(True))
herb[0].notify_self() herb[0].notify_self()
if died_in_his_turn: if died_in_his_turn:
@ -357,7 +432,7 @@ class Game:
if len(self.deck.event_cards) == 0: return False if len(self.deck.event_cards) == 0: return False
return isinstance(self.deck.event_cards[0], ev) return isinstance(self.deck.event_cards[0], ev)
def get_visible_players(self, player: players.Player): def get_visible_players(self, player: pl.Player):
i = self.players.index(player) i = self.players.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
@ -367,6 +442,7 @@ class Game:
'lives': self.players[j].lives, 'lives': self.players[j].lives,
'max_lives': self.players[j].max_lives, 'max_lives': self.players[j].max_lives,
'is_sheriff': isinstance(self.players[j].role, roles.Sheriff), '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] } for j in range(len(self.players)) if i != j]
def notify_all(self): def notify_all(self):

View File

@ -48,6 +48,13 @@ class Player:
self.attacker: Player = None self.attacker: Player = None
self.target_p: str = None self.target_p: str = None
self.is_drawing = False self.is_drawing = False
self.can_play_vendetta = True
self.is_giving_life = False
self.is_using_checchino = False
self.choose_text = 'choose_card_to_get'
self.using_rimbalzo = 0 # 0 no, 1 scegli giocatore, 2 scegli carta
self.can_play_ranch = True
self.is_playing_ranch = False
self.mancato_needed = 0 self.mancato_needed = 0
self.molly_discarded_cards = 0 self.molly_discarded_cards = 0
self.is_bot = bot self.is_bot = bot
@ -59,11 +66,14 @@ class Player:
self.role: r.Role = None self.role: r.Role = None
self.character: chars.Character = None self.character: chars.Character = None
self.real_character: chars.Character = None self.real_character: chars.Character = None
self.is_using_checchino = False
self.lives = 0 self.lives = 0
self.max_lives = 0 self.max_lives = 0
self.is_my_turn = False self.is_my_turn = False
self.is_waiting_for_action = True self.is_waiting_for_action = True
self.has_played_bang = False self.has_played_bang = False
self.can_play_ranch = True
self.is_playing_ranch = False
self.pending_action: PendingAction = None self.pending_action: PendingAction = None
self.available_characters = [] self.available_characters = []
self.was_shot = False self.was_shot = False
@ -146,13 +156,34 @@ 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 isinstance(self.character, chars.CalamityJanet): if self.pending_action == PendingAction.DRAW and self.game.check_event(ce.Peyote):
if cs.Mancato(0, 0).name not in self.expected_response: self.available_cards = [{
self.expected_response.append(cs.Mancato(0, 0).name) 'icon': '🔴'
elif cs.Bang(0, 0).name not in self.expected_response: },{
self.expected_response.append(cs.Bang(0, 0).name) 'icon': ''
elif isinstance(self.character, chars.SuzyLafayette) and len(self.hand) == 0: }]
self.hand.append(self.game.deck.draw()) self.is_drawing = True
self.choose_text = 'choose_guess'
self.pending_action = PendingAction.CHOOSE
elif self.can_play_ranch and self.pending_action == PendingAction.PLAY and self.game.check_event(ce.Ranch):
self.can_play_ranch = False
self.available_cards = [c for c in self.hand]
self.discarded_cards = []
self.available_cards.append({'icon': ''})
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):
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:
self.lives += 1
#TODO Sid dovrebbe poter decidere cosa scartare
self.game.deck.scrap(self.hand.pop(
randrange(0, len(self.hand))), True)
self.game.deck.scrap(self.hand.pop(
randrange(0, len(self.hand))), True)
ser = self.__dict__.copy() ser = self.__dict__.copy()
ser.pop('game') ser.pop('game')
ser.pop('sio') ser.pop('sio')
@ -166,14 +197,6 @@ 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:
print('dying, attacker', self.attacker)
if isinstance(self.character, chars.SidKetchum) and len(self.hand) > 1:
self.lives += 1
self.game.deck.scrap(self.hand.pop(
randrange(0, len(self.hand))))
self.game.deck.scrap(self.hand.pop(
randrange(0, len(self.hand))))
if self.lives <= 0 and self.max_lives > 0: if self.lives <= 0 and self.max_lives > 0:
self.pending_action = PendingAction.WAIT self.pending_action = PendingAction.WAIT
ser['hand'] = [] ser['hand'] = []
@ -196,7 +219,7 @@ class Player:
def bot_logic(self): def bot_logic(self):
if self.game.shutting_down: return if self.game.shutting_down: return
if self.pending_action != None and self.pending_action != PendingAction.WAIT: if self.pending_action != None and self.pending_action != PendingAction.WAIT:
eventlet.sleep(uniform(0.6, 1.5)) eventlet.sleep(uniform(self.game.bot_speed/2-0.1, self.game.bot_speed))
else: else:
return return
if self.pending_action == PendingAction.PICK: if self.pending_action == PendingAction.PICK:
@ -204,45 +227,39 @@ class Player:
elif self.pending_action == PendingAction.DRAW: elif self.pending_action == PendingAction.DRAW:
self.draw('') self.draw('')
elif self.pending_action == PendingAction.PLAY: elif self.pending_action == PendingAction.PLAY:
has_played = False 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])]
if len([c for c in self.hand if (c.is_equipment or c.usable_next_turn) and not self.game.check_event(ce.IlGiudice)]) > 0: 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)]
for i in range(len(self.hand)): 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))]
if self.hand[i].is_equipment or self.hand[i].usable_next_turn: 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]
self.play_card(i) if len(equippables) > 0 and not self.game.check_event(ce.IlGiudice):
has_played = True for c in equippables:
break if self.play_card(self.hand.index(c)):
elif any([isinstance(c, cs.WellsFargo) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or isinstance(c, cs.Birra) for c in self.hand]): return
for i in range(len(self.hand)): elif len(misc) > 0:
c = self.hand[i] for c in misc:
if isinstance(c, cs.WellsFargo) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives): if self.play_card(self.hand.index(c)):
self.play_card(i) return
has_played = True elif len(need_target) > 0:
break for c in need_target:
elif len([c for c in self.hand if c.need_target and not (self.has_played_bang and not any([isinstance(c, cs.Volcanic) for c in self.equipment]))]) > 0: _range = self.get_sight() if c.name == 'Bang!' or c.name == "Pepperbox" else c.range
for i in range(len(self.hand)): others = [p for p in self.game.get_visible_players(self) if _range >= p['dist'] and not (isinstance(self.role, r.Vice) and p['is_sheriff']) and p['lives'] > 0 and not ((isinstance(c, cs.CatBalou) or isinstance(c, cs.Panico)) and p['cards'] == 0) and not (p['is_sheriff'] and isinstance(c, cs.Prigione))]
if self.hand[i].need_target and not (self.has_played_bang and not any([isinstance(c, cs.Volcanic) for c in self.equipment])): if len(others) == 0:
if self.hand[i].need_with and len(self.hand) < 2: continue
continue target = others[randrange(0, len(others))]
_range = self.get_sight() if self.hand[i].name == 'Bang!' or self.hand[i].name == "Pepperbox" else self.hand[i].range if target['is_sheriff'] and isinstance(self.role, r.Renegade):
others = [p for p in self.game.get_visible_players(self) if _range >= p['dist'] and not (isinstance(self.role, r.Vice) and p['is_sheriff'])]
if len(others) == 0:
continue
target = others[randrange(0, len(others))] target = others[randrange(0, len(others))]
if target['is_sheriff'] and isinstance(self.role, r.Renegade): if not c.need_with:
target = others[randrange(0, len(others))] if self.play_card(self.hand.index(c), against=target['name']):
if not self.hand[i].need_with: return
self.play_card(i, against=target['name']) else:
else: if self.play_card(self.hand.index(c), against=target['name'], _with=sample([j for j in range(len(self.hand)) if j != self.hand.index(c)], 1)[0]):
self.play_card(i, against=target['name'], _with=sample([j for j in range(len(self.hand)) if j != i], 1)[0]) return
has_played = True elif len(green_cards) > 0:
break for c in green_cards:
elif any([not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now for c in self.equipment]):
print('hmm', [not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now for c in self.equipment])
for i in range(len(self.equipment)):
c = self.equipment[i]
if not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now: if not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now:
if not c.need_target: if not c.need_target:
self.play_card(len(self.hand)+i) if self.play_card(len(self.hand)+self.equipment.index(c)):
return
else: else:
_range = self.get_sight() if c.name == "Pepperbox" else c.range _range = self.get_sight() if c.name == "Pepperbox" else c.range
others = [p for p in self.game.get_visible_players(self) if _range >= p['dist'] and not (isinstance(self.role, r.Vice) and p['is_sheriff'])] others = [p for p in self.game.get_visible_players(self) if _range >= p['dist'] and not (isinstance(self.role, r.Vice) and p['is_sheriff'])]
@ -251,18 +268,18 @@ class Player:
target = others[randrange(0, len(others))] target = others[randrange(0, len(others))]
if target['is_sheriff'] and isinstance(self.role, r.Renegade): if target['is_sheriff'] and isinstance(self.role, r.Renegade):
target = others[randrange(0, len(others))] target = others[randrange(0, len(others))]
self.play_card(len(self.hand)+i, against=target['name']) if self.play_card(len(self.hand)+self.equipment.index(c), against=target['name']):
has_played = True return
break break
maxcards = self.lives if not isinstance(self.character, chd.SeanMallory) else 10 maxcards = self.lives if not isinstance(self.character, chd.SeanMallory) else 10
if not has_played and len(self.hand) > maxcards: if len(self.hand) > maxcards:
self.scrap(0) self.scrap(0)
else: else:
self.end_turn() self.end_turn()
elif self.pending_action == PendingAction.RESPOND: elif self.pending_action == PendingAction.RESPOND:
did_respond = False did_respond = False
for i in range(len(self.hand)): for i in range(len(self.hand)):
if self.hand[i].name in self.expected_response: if self.hand[i].can_be_used_now and self.hand[i].name in self.expected_response:
self.respond(i) self.respond(i)
did_respond = True did_respond = True
break break
@ -284,10 +301,13 @@ class Player:
else: else:
self.choose(randrange(0, len(target.hand)+len(target.equipment))) self.choose(randrange(0, len(target.hand)+len(target.equipment)))
def play_turn(self): def play_turn(self, can_play_vendetta = True):
if self.lives == 0: if self.lives == 0:
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.is_playing_ranch = False
self.can_play_vendetta = can_play_vendetta
self.sio.emit('chat_message', room=self.game.name, self.sio.emit('chat_message', room=self.game.name,
data=f'_turn|{self.name}') data=f'_turn|{self.name}')
print(f'I {self.name} was notified that it is my turn') print(f'I {self.name} was notified that it is my turn')
@ -296,9 +316,21 @@ class Player:
self.is_waiting_for_action = True self.is_waiting_for_action = True
self.has_played_bang = False self.has_played_bang = False
self.special_use_count = 0 self.special_use_count = 0
if not self.game.check_event(ce.Lazo) and any([isinstance(c, cs.Dinamite) or isinstance(c, cs.Prigione) for c in self.equipment]): 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,
'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]
self.available_cards.append({'icon': ''})
self.choose_text = 'choose_fratelli_di_sangue'
self.pending_action = PendingAction.CHOOSE
self.is_giving_life = True
elif not self.game.check_event(ce.Lazo) and any([isinstance(c, cs.Dinamite) or isinstance(c, cs.Prigione) for c in self.equipment]):
self.is_giving_life = False
self.pending_action = PendingAction.PICK self.pending_action = PendingAction.PICK
else: else:
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.players if p != self])
else: else:
@ -306,16 +338,43 @@ class Player:
self.notify_self() self.notify_self()
def draw(self, pile): def draw(self, pile):
if self.is_my_turn and self.pending_action == PendingAction.PLAY and pile == 'event' and self.game.check_event(ce.Cecchino) and len([c for c in self.hand if c.name == cs.Bang(0,0).name]) >= 2:
self.is_using_checchino = True
self.available_cards = [{
'name': p['name'],
'icon': '⭐️' if p['is_sheriff'] else '🤠',
'alt_text': ''.join(['❤️']*p['lives'])+''.join(['💀']*(p['max_lives']-p['lives']))
} for p in self.game.get_visible_players(self) if p['dist'] <= self.get_sight()]
self.available_cards.append({'icon': ''})
self.choose_text = 'choose_cecchino'
self.pending_action = PendingAction.CHOOSE
self.notify_self()
elif self.is_my_turn and self.pending_action == PendingAction.PLAY and pile == 'event' and self.game.check_event(ce.Rimbalzo) and len([c for c in self.hand if c.name == cs.Bang(0,0).name]) > 0:
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]
self.available_cards.append({'icon': ''})
self.choose_text = 'choose_rimbalzo_player'
self.pending_action = PendingAction.CHOOSE
self.using_rimbalzo = 1
self.notify_self()
if self.pending_action != PendingAction.DRAW: if self.pending_action != PendingAction.DRAW:
return return
if isinstance(self.character, chars.KitCarlson): if pile == 'event' and self.lives < self.max_lives and self.game.check_event(ce.LiquoreForte):
self.lives += 1
self.pending_action = PendingAction.PLAY
self.notify_self()
elif isinstance(self.character, chars.KitCarlson):
self.is_drawing = True self.is_drawing = True
self.available_cards = [self.game.deck.draw() for i in range(3)] 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.pending_action = PendingAction.CHOOSE
self.notify_self() 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 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:
self.is_drawing = True self.is_drawing = True
self.available_cards = self.game.get_player_named(pile).equipment self.available_cards = self.game.get_player_named(pile).equipment
self.choose_text = 'choose_card_to_get'
self.pending_action = PendingAction.CHOOSE self.pending_action = PendingAction.CHOOSE
self.notify_self() self.notify_self()
else: else:
@ -356,7 +415,7 @@ class Player:
pickable_cards = 1 + self.character.pick_mod pickable_cards = 1 + self.character.pick_mod
if self.is_my_turn: if self.is_my_turn:
for i in range(len(self.equipment)): for i in range(len(self.equipment)):
if isinstance(self.equipment[i], cs.Dinamite): if i < len(self.equipment) and isinstance(self.equipment[i], cs.Dinamite):
while pickable_cards > 0: while pickable_cards > 0:
pickable_cards -= 1 pickable_cards -= 1
picked: cs.Card = self.game.deck.pick_and_scrap() picked: cs.Card = self.game.deck.pick_and_scrap()
@ -365,14 +424,13 @@ class Player:
data=f'_flipped|{self.name}|{picked}') data=f'_flipped|{self.name}|{picked}')
if picked.suit == cs.Suit.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0: if picked.suit == cs.Suit.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0:
self.lives -= 3 self.lives -= 3
self.game.deck.scrap(self.equipment.pop(i)) self.game.deck.scrap(self.equipment.pop(i), True)
self.sio.emit('chat_message', room=self.game.name, self.sio.emit('chat_message', room=self.game.name, data=f'_explode|{self.name}')
data=f'_explode|{self.name}') self.heal_if_needed()
if isinstance(self.character, chars.BartCassidy) and self.lives > 0: if isinstance(self.character, chars.BartCassidy) and self.lives > 0:
for i in range(3): for i in range(3):
self.hand.append(self.game.deck.draw()) self.hand.append(self.game.deck.draw(True))
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}')
print(f'{self.name} Boom, -3 hp') print(f'{self.name} Boom, -3 hp')
break break
else: else:
@ -391,11 +449,11 @@ class Player:
self.sio.emit('chat_message', room=self.game.name, self.sio.emit('chat_message', room=self.game.name,
data=f'_flipped|{self.name}|{picked}') data=f'_flipped|{self.name}|{picked}')
if picked.suit != cs.Suit.HEARTS and pickable_cards == 0: if picked.suit != cs.Suit.HEARTS and pickable_cards == 0:
self.game.deck.scrap(self.equipment.pop(i)) self.game.deck.scrap(self.equipment.pop(i), True)
self.end_turn(forced=True) self.end_turn(forced=True)
return return
elif pickable_cards == 0: elif pickable_cards == 0:
self.game.deck.scrap(self.equipment.pop(i)) self.game.deck.scrap(self.equipment.pop(i), True)
break break
break break
if any([isinstance(c, cs.Prigione) for c in self.equipment]): if any([isinstance(c, cs.Prigione) for c in self.equipment]):
@ -440,20 +498,31 @@ class Player:
did_play_card = False 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) 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.suit == cs.Suit.DIAMONDS) and not event_blocks_card:
did_play_card = card.play_card(self, against, withCard) if against == self.name and not isinstance(card, csd.Tequila):
did_play_card = False
else:
did_play_card = card.play_card(self, against, withCard)
if not card.is_equipment and not card.usable_next_turn or event_blocks_card: if not card.is_equipment and not card.usable_next_turn or event_blocks_card:
if did_play_card: if did_play_card:
self.game.deck.scrap(card) self.game.deck.scrap(card, True)
else: else:
self.hand.insert(hand_index, card) self.hand.insert(hand_index, card)
if withCard: if withCard:
self.hand.insert(_with, withCard) self.hand.insert(_with, withCard)
elif card.usable_next_turn and card.can_be_used_now: elif card.usable_next_turn and card.can_be_used_now:
if did_play_card: if did_play_card:
self.game.deck.scrap(card) self.game.deck.scrap(card, True)
else: else:
self.equipment.insert(hand_index-len(self.hand), card) self.equipment.insert(hand_index-len(self.hand), card)
elif card.is_equipment or (card.usable_next_turn and not card.can_be_used_now):
if not did_play_card:
self.hand.insert(hand_index, card)
else:
did_play_card = True
print("did play card:", did_play_card)
self.notify_self() self.notify_self()
if self.is_bot:
return did_play_card or card.is_equipment or (card.usable_next_turn and not card.can_be_used_now)
def choose(self, card_index): def choose(self, card_index):
if self.pending_action != PendingAction.CHOOSE: if self.pending_action != PendingAction.CHOOSE:
@ -471,7 +540,7 @@ class Player:
card.can_be_used_now = False card.can_be_used_now = False
self.hand.append(card) self.hand.append(card)
else: else:
self.game.deck.scrap(card) 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.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 = ''
@ -482,6 +551,73 @@ class Player:
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].name
self.notify_self() self.notify_self()
elif self.is_giving_life and self.game.check_event(ce.FratelliDiSangue):
try:
player = self.game.get_player_named(self.available_cards[card_index]['name'])
player.lives += 1
self.lives -= 1
player.notify_self()
self.sio.emit('chat_message', room=self.game.name, data=f'_fratelli_sangue|{self.name}|{player.name}')
except: pass
self.play_turn()
elif self.is_using_checchino and self.game.check_event(ce.Cecchino):
try:
if self.available_cards[card_index]['name'] != '':
for _ in range(2):
card = next(c for c in self.hand if c.name == cs.Bang(0,0).name)
self.hand.remove(card)
self.game.deck.scrap(card, True)
self.pending_action = PendingAction.PLAY
self.game.attack(self, self.available_cards[card_index]['name'], double=True)
except:
self.pending_action = PendingAction.PLAY
self.is_using_checchino = False
self.notify_self()
elif self.using_rimbalzo > 0 and self.game.check_event(ce.Rimbalzo):
if self.using_rimbalzo == 1 and 'name' in self.available_cards[card_index]:
self.rimbalzo_p = self.available_cards[card_index]['name']
self.available_cards = self.game.get_player_named(self.available_cards[card_index]['name']).equipment
self.choose_text = 'choose_rimbalzo_card'
self.using_rimbalzo = 2
elif self.using_rimbalzo == 2 and 'name' in self.available_cards[card_index].__dict__:
card = next(c for c in self.hand if c.name == cs.Bang(0,0).name)
self.hand.remove(card)
self.game.deck.scrap(card, True)
self.using_rimbalzo = 0
self.available_cards = []
self.pending_action = PendingAction.PLAY
self.game.rimbalzo(self, self.rimbalzo_p, card_index)
else:
self.using_rimbalzo = 0
self.rimbalzo_p = ''
self.pending_action = PendingAction.PLAY
self.notify_self()
elif self.is_playing_ranch and self.game.check_event(ce.Ranch):
if card_index == len(self.available_cards) - 1:
self.hand = [c for c in self.hand if c not in self.discarded_cards]
for i in range(len(self.discarded_cards)):
self.game.deck.scrap(self.discarded_cards[i], True)
self.hand.append(self.game.deck.draw())
self.discarded_cards = []
self.is_playing_ranch = False
self.pending_action = PendingAction.PLAY
else:
self.discarded_cards.append(self.available_cards.pop(card_index))
self.notify_self()
elif self.is_drawing and self.game.check_event(ce.Peyote):
self.is_drawing = False
card = self.game.deck.draw()
self.sio.emit('chat_message', room=self.game.name, data=f"_guess|{self.name}|{self.available_cards[card_index]['icon']}")
self.available_cards = []
if card_index == card.suit%2:
self.hand.append(card)
self.sio.emit('chat_message', room=self.game.name, data=f"_guess_right|{self.name}")
self.pending_action = PendingAction.DRAW
else:
self.game.deck.scrap(card)
self.sio.emit('chat_message', room=self.game.name, data=f"_guess_wrong|{self.name}")
self.pending_action = PendingAction.PLAY
self.notify_self()
# specifico per personaggio # specifico per personaggio
elif self.is_drawing and isinstance(self.character, chars.KitCarlson): elif self.is_drawing and isinstance(self.character, chars.KitCarlson):
self.hand.append(self.available_cards.pop(card_index)) self.hand.append(self.available_cards.pop(card_index))
@ -515,23 +651,59 @@ class Player:
self.mancato_needed -= 1 self.mancato_needed -= 1
self.notify_self() self.notify_self()
if self.mancato_needed <= 0: if self.mancato_needed <= 0:
self.game.responders_did_respond_resume_turn() self.game.responders_did_respond_resume_turn(did_lose=False)
return 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 (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang)) or isinstance(self.character, chd.ElenaFuente)]) == 0\
and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 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.take_damage_response()
self.game.responders_did_respond_resume_turn() self.game.responders_did_respond_resume_turn(did_lose=True)
else: else:
self.pending_action = PendingAction.RESPOND self.pending_action = PendingAction.RESPOND
self.expected_response = self.game.deck.mancato_cards self.expected_response = self.game.deck.mancato_cards.copy()
if isinstance(self.character, chd.ElenaFuente): if isinstance(self.character, 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):
self.expected_response = self.game.deck.all_cards_str self.expected_response = self.game.deck.all_cards_str
self.on_failed_response_cb = self.take_damage_response self.on_failed_response_cb = self.take_damage_response
self.notify_self() self.notify_self()
def get_banged(self, attacker, double=False): 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):
pickable_cards = 2
while pickable_cards > 0:
pickable_cards -= 1
picked: cs.Card = self.game.deck.pick_and_scrap()
print(f'Did pick {picked}')
self.sio.emit('chat_message', room=self.game.name,
data=f'_flipped|{self.name}|{picked}')
if picked.suit == cs.Suit.HEARTS:
self.mancato_needed -= 1
self.notify_self()
if self.mancato_needed <= 0:
self.game.responders_did_respond_resume_turn(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\
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:
self.expected_response.append(cs.Bang(0, 0).name)
elif isinstance(self.character, chd.ElenaFuente):
self.expected_response = self.game.deck.all_cards_str
self.on_failed_response_cb = self.take_no_damage_response
self.notify_self()
def get_banged(self, attacker, double=False, no_dmg=False, card_index=None):
self.attacker = attacker self.attacker = attacker
self.mancato_needed = 1 if not double else 2 self.mancato_needed = 1 if not double else 2
if card_index != None:
self.dmg_card_index = card_index
else:
self.dmg_card_index = -1
for i in range(len(self.equipment)): for i in range(len(self.equipment)):
if self.equipment[i].can_be_used_now: if self.equipment[i].can_be_used_now:
print('usable', self.equipment[i]) print('usable', self.equipment[i])
@ -539,26 +711,38 @@ class Player:
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\ 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\
and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 0: and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 0:
print('Cant defend') print('Cant defend')
self.take_damage_response() if not no_dmg:
self.take_damage_response()
else:
self.take_no_damage_response()
return False return False
else: 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 isinstance(self.character, chars.Jourdonnais):
print('has barrel') print('has barrel')
self.pending_action = PendingAction.PICK self.pending_action = PendingAction.PICK
self.on_pick_cb = self.barrel_pick if not no_dmg:
self.on_pick_cb = self.barrel_pick
else:
self.on_pick_cb = self.barrel_pick_no_dmg
else: else:
print('has mancato') print('has mancato')
self.pending_action = PendingAction.RESPOND self.pending_action = PendingAction.RESPOND
self.expected_response = self.game.deck.mancato_cards self.expected_response = self.game.deck.mancato_cards.copy()
if self.attacker and isinstance(self.attacker.character, chd.BelleStar) or self.game.check_event(ce.Lazo): 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 self.expected_response = self.game.deck.mancato_cards_not_green
if isinstance(self.character, chd.ElenaFuente): elif isinstance(self.character, 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):
self.expected_response = self.game.deck.all_cards_str self.expected_response = self.game.deck.all_cards_str
self.on_failed_response_cb = self.take_damage_response if not no_dmg:
self.on_failed_response_cb = self.take_damage_response
else:
self.on_failed_response_cb = self.take_no_damage_response
return True return True
def get_indians(self, attacker): def get_indians(self, attacker):
self.attacker = 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 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:
print('Cant defend') print('Cant defend')
self.take_damage_response() self.take_damage_response()
@ -567,6 +751,8 @@ class Player:
print('has bang') print('has bang')
self.pending_action = PendingAction.RESPOND self.pending_action = PendingAction.RESPOND
self.expected_response = [cs.Bang(0, 0).name] 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:
self.expected_response.append(cs.Mancato(0, 0).name)
self.event_type = 'indians' self.event_type = 'indians'
self.on_failed_response_cb = self.take_damage_response self.on_failed_response_cb = self.take_damage_response
return True return True
@ -576,39 +762,55 @@ class Player:
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 (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0:
print('Cant defend') print('Cant defend')
self.take_damage_response() self.take_damage_response()
self.game.responders_did_respond_resume_turn() self.game.responders_did_respond_resume_turn(did_lose=True)
return False return False
else: else:
self.pending_action = PendingAction.RESPOND self.pending_action = PendingAction.RESPOND
self.expected_response = [cs.Bang(0, 0).name] 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:
self.expected_response.append(cs.Mancato(0, 0).name)
self.event_type = 'duel' self.event_type = 'duel'
self.on_failed_response_cb = self.take_damage_response self.on_failed_response_cb = self.take_damage_response
return True 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:
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:
self.hand.append(self.game.deck.draw(True))
self.lives += 1 if not isinstance(self.character, 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}')
break
def take_damage_response(self): def take_damage_response(self):
self.lives -= 1 self.lives -= 1
if self.lives > 0: if self.lives > 0:
if isinstance(self.character, chars.BartCassidy): if isinstance(self.character, chars.BartCassidy):
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()) self.hand.append(self.game.deck.draw(True))
elif isinstance(self.character, chars.ElGringo) and self.attacker and len(self.attacker.hand) > 0: elif isinstance(self.character, 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( 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,
data=f'_special_el_gringo|{self.name}|{self.attacker.name}') data=f'_special_el_gringo|{self.name}|{self.attacker.name}')
self.attacker.notify_self() self.attacker.notify_self()
while self.lives <= 0 and len(self.game.players) > 2 and len([c for c in self.hand if isinstance(c, cs.Birra)]) > 0: self.heal_if_needed()
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:
self.hand.append(self.game.deck.draw())
self.lives += 1
self.game.deck.scrap(self.hand.pop(i))
self.sio.emit('chat_message', room=self.game.name,
data=f'_beer_save|{self.name}')
break
self.mancato_needed = 0 self.mancato_needed = 0
self.expected_response = []
self.event_type = ''
self.notify_self()
self.attacker = None
def take_no_damage_response(self):
if self.dmg_card_index != None and self.dmg_card_index != -1 and self.game.check_event(ce.Rimbalzo):
self.game.deck.scrap(self.equipment.pop(self.dmg_card_index))
self.dmg_card_index = -1
self.mancato_needed = 0
self.expected_response = []
self.event_type = '' self.event_type = ''
self.notify_self() self.notify_self()
self.attacker = None self.attacker = None
@ -616,14 +818,14 @@ class Player:
def respond(self, hand_index): def respond(self, hand_index):
if self.pending_action != PendingAction.RESPOND: return if self.pending_action != PendingAction.RESPOND: return
self.pending_action = PendingAction.WAIT self.pending_action = PendingAction.WAIT
if hand_index != -1 and ( if hand_index != -1 and hand_index < (len(self.hand)+len(self.equipment)) and (
((hand_index < len(self.hand) and self.hand[hand_index].name in self.expected_response)) or ((hand_index < len(self.hand) and self.hand[hand_index].name in self.expected_response)) or
self.equipment[hand_index-len(self.hand)].name in self.expected_response): (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)) 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 isinstance(self.character, 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()) self.hand.append(self.game.deck.draw(True))
card.use_card(self) card.use_card(self)
self.game.deck.scrap(card) self.game.deck.scrap(card, True)
self.notify_self() self.notify_self()
self.mancato_needed -= 1 self.mancato_needed -= 1
if self.mancato_needed <= 0: if self.mancato_needed <= 0:
@ -632,24 +834,25 @@ class Player:
if isinstance(self.character, chd.MollyStark) and hand_index < len(self.hand)+1 and not self.is_my_turn: if isinstance(self.character, chd.MollyStark) and hand_index < len(self.hand)+1 and not self.is_my_turn:
self.molly_discarded_cards += 1 self.molly_discarded_cards += 1
else: else:
self.game.responders_did_respond_resume_turn() self.game.responders_did_respond_resume_turn(did_lose=False)
self.event_type = '' self.event_type = ''
self.expected_response = []
else: else:
self.pending_action = PendingAction.RESPOND self.pending_action = PendingAction.RESPOND
self.notify_self() self.notify_self()
else: else:
if isinstance(self.character, chd.MollyStark) and not self.is_my_turn: if isinstance(self.character, chd.MollyStark) and not self.is_my_turn:
for i in range(self.molly_discarded_cards): for i in range(self.molly_discarded_cards):
self.hand.append(self.game.deck.draw()) 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 isinstance(self.attacker.character, chd.MollyStark) and self.is_my_turn: elif self.attacker and self.attacker in self.game.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()) self.attacker.hand.append(self.attacker.game.deck.draw(True))
self.attacker.molly_discarded_cards = 0 self.attacker.molly_discarded_cards = 0
self.attacker.notify_self() self.attacker.notify_self()
self.on_failed_response_cb() self.on_failed_response_cb()
self.game.responders_did_respond_resume_turn() self.game.responders_did_respond_resume_turn(did_lose=True)
if self.mancato_needed <= 0: if self.mancato_needed <= 0:
self.attacker = None self.attacker = None
@ -685,8 +888,8 @@ class Player:
self.scrapped_cards = 0 self.scrapped_cards = 0
self.lives = min(self.lives+1, self.max_lives) 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 isinstance(self.character, chd.JoseDelgrado) and card.is_equipment and self.special_use_count < 2:
self.hand.append(self.game.deck.draw()) self.hand.append(self.game.deck.draw(True))
self.hand.append(self.game.deck.draw()) self.hand.append(self.game.deck.draw(True))
self.special_use_count += 1 self.special_use_count += 1
self.game.deck.scrap(card) self.game.deck.scrap(card)
self.notify_self() self.notify_self()
@ -696,15 +899,15 @@ class Player:
self.special_use_count += 1 self.special_use_count += 1
cards = sorted(data['cards'], reverse=True) cards = sorted(data['cards'], reverse=True)
for c in cards: for c in cards:
self.game.deck.scrap(self.hand.pop(c)) self.game.deck.scrap(self.hand.pop(c), True)
self.notify_self() self.notify_self()
self.game.attack(self, data['against']) self.game.attack(self, data['against'])
def chuck_lose_hp_draw(self): def chuck_lose_hp_draw(self):
if isinstance(self.character, chd.ChuckWengam) and self.lives > 1 and self.is_my_turn: if isinstance(self.character, chd.ChuckWengam) and self.lives > 1 and self.is_my_turn:
self.lives -= 1 self.lives -= 1
self.hand.append(self.game.deck.draw()) self.hand.append(self.game.deck.draw(True))
self.hand.append(self.game.deck.draw()) self.hand.append(self.game.deck.draw(True))
self.notify_self() self.notify_self()
def end_turn(self, forced=False): def end_turn(self, forced=False):
@ -715,11 +918,11 @@ class Player:
print( print(
f"I {self.name} have to many cards in my hand and I can't end the turn") f"I {self.name} have to many cards in my hand and I can't end the turn")
elif self.pending_action == PendingAction.PLAY or forced: elif self.pending_action == PendingAction.PLAY or forced:
if not forced and self.game.check_event(ce.Vendetta): if not forced and self.game.check_event(ce.Vendetta) and self.can_play_vendetta:
picked: cs.Card = self.game.deck.pick_and_scrap() picked: cs.Card = self.game.deck.pick_and_scrap()
self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked}') self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked}')
if picked.suit == cs.Suit.HEARTS: if picked.suit == cs.Suit.HEARTS:
self.play_turn() self.play_turn(can_play_vendetta=False)
return return
self.is_my_turn = False self.is_my_turn = False
for i in range(len(self.equipment)): for i in range(len(self.equipment)):

View File

@ -16,6 +16,15 @@
</option> </option>
</select> </select>
<label for="lang" style="opacity:0" >Language</label> <label for="lang" style="opacity:0" >Language</label>
<div v-if="showUpdateUI" style="position: fixed;bottom: 0;z-index: 1;background: rgba(0,0,0,0.5);padding: 20pt;" class="center-stuff">
<p class="update-dialog__content">
A new version is available. Refresh to load it?
</p>
<div class="update-dialog__actions">
<button @click="update">Update</button>
<button @click="showUpdateUI = false">Cancel</button>
</div>
</div>
</div> </div>
</template> </template>
@ -26,6 +35,7 @@ export default {
name: 'App', name: 'App',
data: () => ({ data: () => ({
isConnected: false, isConnected: false,
c: false,
}), }),
computed: { computed: {
}, },
@ -39,18 +49,32 @@ export default {
}, },
room(data) { room(data) {
this.isInLobby = true; this.isInLobby = true;
this.$router.push({path:'game', query: { code: data.name, pwd: data.password }}) if (data.password)
this.$router.replace({path:'game', query: { code: data.name, pwd: data.password }})
else
this.$router.replace({path:'game', query: { code: data.name }})
}, },
}, },
methods: { methods: {
storeLangPref() { storeLangPref() {
localStorage.setItem('lang', this.$i18n.locale) localStorage.setItem('lang', this.$i18n.locale)
},
async update() {
this.showUpdateUI = false;
await this.$workbox.messageSW({ type: "SKIP_WAITING" });
} }
}, },
mounted() { mounted() {
if (localStorage.getItem('lang')) if (localStorage.getItem('lang'))
this.$i18n.locale = localStorage.getItem('lang') this.$i18n.locale = localStorage.getItem('lang')
}, },
created() {
if (this.$workbox) {
this.$workbox.addEventListener("waiting", () => {
this.showUpdateUI = true;
});
}
}
} }
</script> </script>

View File

@ -87,6 +87,17 @@ export default {
box-shadow: 0 0 0pt 4pt white, 0 0 5pt 4pt #aaa; box-shadow: 0 0 0pt 4pt white, 0 0 5pt 4pt #aaa;
border: 2pt dashed rgb(50 122 172); border: 2pt dashed rgb(50 122 172);
} }
.card.back.fistful-of-cards{
color:white;
background: repeating-linear-gradient(
45deg,
rgb(50 122 172),
rgb(50 122 172) 5px,
rgb(30 102 152) 5px,
rgb(30 102 152) 10px
);
border: 2pt solid rgb(50 122 172);
}
.card h4 { .card h4 {
position: absolute; position: absolute;
text-align: center; text-align: center;
@ -124,12 +135,12 @@ export default {
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root, #app { :root, #app {
background-color: #181a1b; background-color: #181a1b;
color: rgb(174, 194, 211); color: rgb(174, 194, 211);
} }
.card { .card {
background-color: #181a1b; background-color: #181a1b;
color: rgb(174, 194, 211); color: rgb(174, 194, 211);
box-shadow: box-shadow:
0 0 0 3pt #987e51, 0 0 0 3pt #987e51,
0 0 0 6pt #181a1b, 0 0 0 6pt #181a1b,

View File

@ -5,7 +5,7 @@
<div v-if="eventCard" style="position:relative"> <div v-if="eventCard" style="position:relative">
<div class="card fistful-of-cards" style="position:relative; bottom:-3pt;right:-3pt;"/> <div class="card fistful-of-cards" style="position:relative; bottom:-3pt;right:-3pt;"/>
<div class="card fistful-of-cards" style="position:absolute; bottom:-1.5pt;right:-1.5pt;"/> <div class="card fistful-of-cards" style="position:absolute; bottom:-1.5pt;right:-1.5pt;"/>
<card :card="eventCard" :key="eventCard" :class="{'last-event':true,'fistful-of-cards':true}"/> <card :card="eventCard" :key="eventCard" :class="eventClasses" @click.native="event"/>
</div> </div>
<div style="position:relative"> <div style="position:relative">
<div class="card back" style="position:absolute; bottom:-3pt;right:-3pt;"/> <div class="card back" style="position:absolute; bottom:-3pt;right:-3pt;"/>
@ -59,7 +59,12 @@ export default {
this.lastScrap = card this.lastScrap = card
}, },
event_card(card) { event_card(card) {
this.eventCard = card this.eventCard = card == false ? {
name: 'PewPew!',
icon: '🎲',
back: true,
expansion: 'fistful-of-cards',
} : card
}, },
}, },
computed: { computed: {
@ -68,6 +73,14 @@ export default {
name: this.$t('end_turn'), name: this.$t('end_turn'),
icon: '⛔️' icon: '⛔️'
} }
},
eventClasses() {
let classes = {
'last-event':true,
'back':this.eventCard.back
}
classes[this.eventCard.expansion] = true
return classes
} }
}, },
methods: { methods: {
@ -79,6 +92,11 @@ export default {
else if (this.pending_action == 1) else if (this.pending_action == 1)
this.$socket.emit('draw', pile) this.$socket.emit('draw', pile)
} }
},
event() {
if (this.pending_action !== false) {
this.$socket.emit('draw', 'event')
}
} }
}, },
watch: { watch: {

View File

@ -34,8 +34,8 @@
</div> </div>
<div v-if="!started"> <div v-if="!started">
<h3>{{$t("expansions")}}</h3> <h3>{{$t("expansions")}}</h3>
<div v-for="ex in togglable_expansions" v-bind:key="ex"> <div v-for="ex in expansionsStatus" v-bind:key="ex.id">
<PrettyCheck @click.native="toggleExpansions(ex)" :disabled="!isRoomOwner" :value="is_toggled_expansion(ex)" class="p-switch p-fill" style="margin-top:5px; margin-bottom:3px;">{{get_expansion_name(ex)}}</PrettyCheck> <PrettyCheck @click.native="toggleExpansions(ex.id)" :disabled="!isRoomOwner" :checked="ex.enabled" class="p-switch p-fill" style="margin-top:5px; margin-bottom:3px;">{{ex.name}}</PrettyCheck>
<br> <br>
</div> </div>
<h3>{{$t('mods')}}</h3> <h3>{{$t('mods')}}</h3>
@ -137,7 +137,16 @@ export default {
}, },
computed: { computed: {
inviteLink() { inviteLink() {
return `${window.location.origin}/game?code=${this.lobbyName}&pwd=${this.password}` return `${window.location.origin}/game?code=${this.lobbyName}${this.password?`&pwd=${this.password}`:''}`
},
expansionsStatus() {
return this.togglable_expansions.map(x=>{
return {
id: x,
name: x.replace(/(^|_)([a-z])/g, function($0,$1,$2) {return ' ' + $2.toUpperCase()}),
enabled: this.expansions.indexOf(x) !== -1
}
})
}, },
storedUsername() { storedUsername() {
if (localStorage.getItem('username')) if (localStorage.getItem('username'))
@ -174,11 +183,9 @@ export default {
}, },
methods: { methods: {
is_toggled_expansion(ex) { is_toggled_expansion(ex) {
console.log(ex+' '+ this.expansions+ (this.expansions.indexOf(ex) !== -1))
return this.expansions.indexOf(ex) !== -1 return this.expansions.indexOf(ex) !== -1
}, },
get_expansion_name(ex) {
return ex.replace('_', ' ').replace(/\w\S*/g, m => m.charAt(0).toUpperCase()+m.substr(1).toLowerCase())
},
leaveRoom() { leaveRoom() {
window.location.replace(window.location.origin) window.location.replace(window.location.origin)
}, },

View File

@ -38,7 +38,7 @@
<Chooser v-if="is_my_turn && pending_action == 4" :text="$t('wait')" :cards="[]"/> <Chooser v-if="is_my_turn && pending_action == 4" :text="$t('wait')" :cards="[]"/>
<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_card_to_get')" :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" :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')" />
@ -54,7 +54,7 @@
:cards="hand.filter(x => x.is_equipment)" :select="(card) => {joseScrap=false;scrap(card)}" :cancel="() => {joseScrap=false}"/> :cards="hand.filter(x => x.is_equipment)" :select="(card) => {joseScrap=false;scrap(card)}" :cancel="() => {joseScrap=false}"/>
<Chooser v-if="holydayScrap && scrapHand.length < 2" :text="`${$t('discard')} ${2 - scrapHand.length}`" <Chooser v-if="holydayScrap && scrapHand.length < 2" :text="`${$t('discard')} ${2 - scrapHand.length}`"
:cards="notScrappedHand" :select="holydayScrapAdd" :cancel="() => {holydayScrap = false;scrapHand=[]}"/> :cards="notScrappedHand" :select="holydayScrapAdd" :cancel="() => {holydayScrap = false;scrapHand=[]}"/>
<Chooser v-if="holydayScrap && scrapHand.length == 2" :text="$t('card_against')" :cards="otherPlayers" :select="holydayScrapBang" :cancel="() => {holydayScrap = false;scrapHand=[]}"/> <Chooser v-if="holydayScrap && scrapHand.length == 2" :text="$t('card_against')" :cards="visiblePlayers" :select="holydayScrapBang" :cancel="() => {holydayScrap = false;scrapHand=[]}"/>
</div> </div>
</template> </template>
@ -101,6 +101,7 @@ export default {
desc: '', desc: '',
scrapHand: [], scrapHand: [],
sidWantsScrapForHealth: false, sidWantsScrapForHealth: false,
choose_text: '',
joseScrap: false, joseScrap: false,
holydayScrap: false, holydayScrap: false,
special_use_count: 0, special_use_count: 0,
@ -128,6 +129,7 @@ export default {
this.max_lives = self.max_lives this.max_lives = self.max_lives
this.has_played_bang = self.has_played_bang this.has_played_bang = self.has_played_bang
this.special_use_count = self.special_use_count this.special_use_count = self.special_use_count
this.choose_text = self.choose_text
this.is_my_turn = self.is_my_turn this.is_my_turn = self.is_my_turn
if (this.is_my_turn) document.title = this.$t('your_turn')+' | PewPew!' if (this.is_my_turn) document.title = this.$t('your_turn')+' | PewPew!'
else if (this.pending_action == 3) document.title = this.$t('your_response')+' | PewPew!' else if (this.pending_action == 3) document.title = this.$t('your_response')+' | PewPew!'
@ -191,6 +193,7 @@ export default {
name: player.name, name: player.name,
number: player.dist !== undefined ? `${player.dist}` : '', number: player.dist !== undefined ? `${player.dist}` : '',
icon: player.is_sheriff ? '⭐' : '🤠', icon: player.is_sheriff ? '⭐' : '🤠',
alt_text: Array(player.lives+1).join('❤️')+Array(player.max_lives-player.lives+1).join('💀'),
is_character: true, is_character: true,
}}) }})
if (this.card_against && this.card_against.can_target_self) { if (this.card_against && this.card_against.can_target_self) {

View File

@ -38,6 +38,12 @@
"hand": "HAND", "hand": "HAND",
"card_against": "Who will you play your card against?", "card_against": "Who will you play your card against?",
"choose_card_to_get": "Choose a card", "choose_card_to_get": "Choose a card",
"choose_guess": "Guess the color of the suit",
"choose_ranch": "Choose the cards to replace",
"choose_fratelli_di_sangue": "Choose who you want to donate one of your lives",
"choose_cecchino": "Choose who to shoot",
"choose_rimbalzo_player": "Choose the target of the bang",
"choose_rimbalzo_card": "Choose the card to discard the bang to",
"you_died":"YOU DIED", "you_died":"YOU DIED",
"spectate":"SPECTATE", "spectate":"SPECTATE",
"you_win":"YOU WON", "you_win":"YOU WON",
@ -80,7 +86,11 @@
"special_bart_cassidy": "{0} received a compensation because he was injured.", "special_bart_cassidy": "{0} received a compensation because he was injured.",
"special_el_gringo": "{0} stole a card from {1} when he was was injured.", "special_el_gringo": "{0} stole a card from {1} when he was was injured.",
"special_calamity": "{0} played {1} as Bang! against {2}.", "special_calamity": "{0} played {1} as Bang! against {2}.",
"allroles": "In the game there are: {0}." "allroles": "In the game there are: {0}.",
"guess": "{0} guesses {1}.",
"guess_right": "{0} was right.",
"guess_wrong": "{0} was wrong.",
"fratelli_sangue": "{0} gave one of his lives to {1}."
}, },
"foc": { "foc": {
"leggedelwest": "He must play this card on this turn if possible." "leggedelwest": "He must play this card on this turn if possible."

View File

@ -38,6 +38,12 @@
"hand": "MANO", "hand": "MANO",
"card_against": "Contro chi vuoi giocare la carta", "card_against": "Contro chi vuoi giocare la carta",
"choose_card_to_get": "Scegli che carta pescare", "choose_card_to_get": "Scegli che carta pescare",
"choose_guess": "Indovina il colore del seme",
"choose_ranch": "Scegli le carte da sostituire",
"choose_fratelli_di_sangue": "Scegli a chi donare una delle tue vite",
"choose_cecchino": "Scegli contro chi sparare",
"choose_rimbalzo_player": "Scegli contro chi scartare il bang",
"choose_rimbalzo_card": "Scegli contro che carta scartare il bang",
"you_died": "SEI MORTO", "you_died": "SEI MORTO",
"spectate": "SPETTATORE", "spectate": "SPETTATORE",
"you_win": "HAI VINTO", "you_win": "HAI VINTO",
@ -80,7 +86,11 @@
"special_bart_cassidy": "{0} ha ricevuto un risarcimento perchè è stato ferito.", "special_bart_cassidy": "{0} ha ricevuto un risarcimento perchè è stato ferito.",
"special_el_gringo": "{0} rubato una carta a {1} mentre veniva colpito.", "special_el_gringo": "{0} rubato una carta a {1} mentre veniva colpito.",
"special_calamity": "{0} ha giovato {1} come un Bang! contro {2}.", "special_calamity": "{0} ha giovato {1} come un Bang! contro {2}.",
"allroles": "Nella partita ci sono: {0}." "allroles": "Nella partita ci sono: {0}.",
"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}."
}, },
"foc": { "foc": {
"leggedelwest": "Ed è obbligato a usarla nel suo turno, se possibile" "leggedelwest": "Ed è obbligato a usarla nel suo turno, se possibile"

View File

@ -3,15 +3,15 @@ import { Workbox } from "workbox-window";
let wb; let wb;
if ("serviceWorker" in navigator) { if ("serviceWorker" in navigator) {
wb = new Workbox(`${process.env.BASE_URL}service-worker.js`); wb = new Workbox(`${process.env.BASE_URL}service-worker.js`);
wb.addEventListener("controlling", () => { wb.addEventListener("controlling", () => {
window.location.reload(); window.location.reload();
}); });
wb.register(); wb.register();
} else { } else {
wb = null; wb = null;
} }
export default wb; export default wb;