Merge pull request #412 from albertoxamin/test-save
Add some form of persistency during restarts
This commit is contained in:
commit
9be6b0f387
1
.gitignore
vendored
1
.gitignore
vendored
@ -141,3 +141,4 @@ frontend/package-lock.json
|
||||
bang-workspace.code-workspace
|
||||
|
||||
.vscode/
|
||||
backend/save/*
|
@ -20,8 +20,11 @@ COPY --from=pybuilder /code /dist
|
||||
# copy the frontend static files from the builder
|
||||
COPY --from=builder ./dist /dist/
|
||||
WORKDIR /dist
|
||||
# create dir for save
|
||||
RUN mkdir save
|
||||
EXPOSE 5001
|
||||
|
||||
ENV PATH=/root/.local/bin:${PATH}
|
||||
VOLUME /dist/save
|
||||
|
||||
ENTRYPOINT ["python", "/dist/server.py"]
|
||||
|
@ -4,6 +4,7 @@ import bang.expansions.high_noon.card_events as ceh
|
||||
from abc import ABC, abstractmethod
|
||||
from enum import IntEnum
|
||||
import bang.roles as r
|
||||
from globals import G
|
||||
|
||||
class Suit(IntEnum):
|
||||
DIAMONDS = 0 # ♦
|
||||
@ -84,10 +85,10 @@ class Card(ABC):
|
||||
player.equipment.append(self)
|
||||
self.can_be_used_now = False
|
||||
if against:
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
data=f'_play_card_against|{player.name}|{self.name}|{against}')
|
||||
else:
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
data=f'_play_card|{player.name}|{self.name}')
|
||||
return True
|
||||
|
||||
@ -154,7 +155,7 @@ class Prigione(Card):
|
||||
return False
|
||||
if against != None and not isinstance(player.game.get_player_named(against).role, r.Sheriff):
|
||||
self.can_be_used_now = False
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
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).notify_self()
|
||||
@ -268,7 +269,7 @@ class Birra(Card):
|
||||
player.lives = min(player.lives+1, player.max_lives)
|
||||
return True
|
||||
elif len(player.game.get_alive_players()) == 2 or player.lives == player.max_lives:
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
data=f'_spilled_beer|{player.name}|{self.name}')
|
||||
return True
|
||||
return False
|
||||
@ -305,7 +306,7 @@ class Diligenza(Card):
|
||||
# self.desc_eng = "Draw 2 cards from the deck."
|
||||
|
||||
def play_card(self, player, against, _with=None):
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
data=f'_diligenza|{player.name}|{self.name}')
|
||||
for i in range(2):
|
||||
player.hand.append(player.game.deck.draw(True))
|
||||
@ -382,7 +383,7 @@ class Mancato(Card):
|
||||
return False
|
||||
if player.game.check_event(ceh.Sermone):
|
||||
return False
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
data=f'_special_calamity|{player.name}|{self.name}|{against}')
|
||||
player.bang_used += 1
|
||||
player.has_played_bang = True if not player.game.check_event(ceh.Sparatoria) else player.bang_used > 1
|
||||
@ -421,7 +422,7 @@ class Saloon(Card):
|
||||
self.alt_text = "👥🍺"
|
||||
|
||||
def play_card(self, player, against, _with=None):
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
data=f'_saloon|{player.name}|{self.name}')
|
||||
for p in player.game.get_alive_players():
|
||||
p.lives = min(p.lives+1, p.max_lives)
|
||||
@ -438,7 +439,7 @@ class WellsFargo(Card):
|
||||
self.alt_text = "🎴🎴🎴"
|
||||
|
||||
def play_card(self, player, against, _with=None):
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
data=f'_wellsfargo|{player.name}|{self.name}')
|
||||
for i in range(3):
|
||||
player.hand.append(player.game.deck.draw(True))
|
||||
|
@ -1,6 +1,7 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from bang.expansions import *
|
||||
from typing import List
|
||||
from globals import G
|
||||
|
||||
class Character(ABC):
|
||||
def __init__(self, name: str, max_lives: int, sight_mod: int = 0, visibility_mod: int = 0, pick_mod: int = 0, desc: str = ''):
|
||||
@ -25,7 +26,7 @@ class Character(ABC):
|
||||
import bang.expansions.high_noon.card_events as ceh
|
||||
if player.game.check_event(ceh.Sbornia):
|
||||
return False
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_use_special|{player.name}|{self.name}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_use_special|{player.name}|{self.name}')
|
||||
return True
|
||||
|
||||
class BartCassidy(Character):
|
||||
|
@ -1,5 +1,6 @@
|
||||
from bang.cards import *
|
||||
import bang.expansions.fistful_of_cards.card_events as ce
|
||||
from globals import G
|
||||
|
||||
class Binocolo(Mirino):
|
||||
def __init__(self, suit, number):
|
||||
@ -88,7 +89,7 @@ class Rissa(CatBalou):
|
||||
player.event_type = 'rissa'
|
||||
print(f'rissa targets: {player.rissa_targets}')
|
||||
super().play_card(player, against=player.rissa_targets.pop(0).name)
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_play_card|{player.name}|{self.name}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card|{player.name}|{self.name}')
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -123,7 +124,7 @@ class Tequila(Card):
|
||||
|
||||
def play_card(self, player, against, _with=None):
|
||||
if against != None and _with != None:
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_play_card_for|{player.name}|{self.name}|{against}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card_for|{player.name}|{self.name}|{against}')
|
||||
player.game.deck.scrap(_with)
|
||||
player.game.get_player_named(against).lives = min(player.game.get_player_named(against).lives+1, player.game.get_player_named(against).max_lives)
|
||||
player.game.get_player_named(against).notify_self()
|
||||
@ -322,7 +323,7 @@ class CanCan(CatBalou):
|
||||
|
||||
def play_card(self, player, against, _with=None):
|
||||
if self.can_be_used_now:
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{player.name}|{self.name}|{against}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{player.name}|{self.name}|{against}')
|
||||
return super().play_card(player, against)
|
||||
else:
|
||||
if not self.is_duplicate_card(player) and not player.game.check_event(ce.IlGiudice):
|
||||
|
@ -1,6 +1,7 @@
|
||||
from bang.cards import *
|
||||
import bang.roles as r
|
||||
import bang.players as pl
|
||||
from globals import G
|
||||
|
||||
class ShopCardKind(IntEnum):
|
||||
BROWN = 0 # Se l’equipaggiamento ha il bordo marrone, applicane subito l’effetto e poi scartalo.
|
||||
@ -16,14 +17,14 @@ class ShopCard(Card):
|
||||
|
||||
def play_card(self, player, against, _with=None):
|
||||
if self.kind == ShopCardKind.BROWN:
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_purchase_card|{player.name}|{self.name}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_purchase_card|{player.name}|{self.name}')
|
||||
return True
|
||||
elif self.kind == ShopCardKind.BLACK: # equip it
|
||||
if not self.is_duplicate_card(player):
|
||||
self.reset_card()
|
||||
self.can_be_used_now = True
|
||||
player.gold_rush_equipment.append(self)
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_purchase_card|{player.name}|{self.name}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_purchase_card|{player.name}|{self.name}')
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@ -102,7 +103,7 @@ class Rum(ShopCard):
|
||||
num = 5 if player.character.check(player.game, c.LuckyDuke) else 4
|
||||
for i in range(num):
|
||||
c = player.game.deck.pick_and_scrap()
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_flipped|{player.name}|{c.name}|{c.num_suit()}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_flipped|{player.name}|{c.name}|{c.num_suit()}')
|
||||
suits.add(c.suit)
|
||||
player.lives = min(player.lives+len(suits), player.max_lives)
|
||||
return super().play_card(player, against, _with)
|
||||
@ -113,7 +114,7 @@ class UnionPacific(ShopCard):
|
||||
self.icon = '🚆️'
|
||||
|
||||
def play_card(self, player, against=None, _with=None):
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
data=f'_UnionPacific|{player.name}|{self.name}')
|
||||
for i in range(4):
|
||||
player.hand.append(player.game.deck.draw(True))
|
||||
@ -162,7 +163,7 @@ class Ricercato(ShopCard):
|
||||
self.can_target_self = True
|
||||
|
||||
def play_card(self, player, against=None, _with=None):
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_purchase_card|{player.name}|{self.name}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_purchase_card|{player.name}|{self.name}')
|
||||
player.available_cards = [{
|
||||
'name': p.name,
|
||||
'icon': p.role.icon if(player.game.initial_players == 3) else '🤠',
|
||||
@ -187,7 +188,7 @@ class Setaccio(ShopCard):
|
||||
return super().play_card(player, against, _with)
|
||||
else:
|
||||
if player.gold_nuggets >= 1 and player.setaccio_count < 2:
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_play_card|{player.name}|{self.name}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card|{player.name}|{self.name}')
|
||||
player.gold_nuggets -= 1
|
||||
player.setaccio_count += 1
|
||||
player.hand.append(player.game.deck.draw(True))
|
||||
@ -224,7 +225,7 @@ class Zaino(ShopCard):
|
||||
return super().play_card(player, against, _with)
|
||||
else:
|
||||
if player.gold_nuggets >= 2:
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_play_card|{player.name}|{self.name}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card|{player.name}|{self.name}')
|
||||
player.gold_nuggets -= 2
|
||||
player.lives = min(player.lives + 1, player.max_lives)
|
||||
player.notify_self()
|
||||
|
@ -3,6 +3,7 @@ import bang.roles as r
|
||||
import bang.players as pl
|
||||
from bang.cards import Card, Suit, Bang, Mancato
|
||||
import bang.expansions.fistful_of_cards.card_events as ce
|
||||
from globals import G
|
||||
|
||||
class Fantasma(Card):
|
||||
def __init__(self, suit, number):
|
||||
@ -46,7 +47,7 @@ class SerpenteASonagli(Card):
|
||||
return False
|
||||
if against != None:
|
||||
self.can_be_used_now = False
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
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).notify_self()
|
||||
@ -69,7 +70,7 @@ class Taglia(Card):
|
||||
return False
|
||||
if against != None:
|
||||
self.can_be_used_now = False
|
||||
player.sio.emit('chat_message', room=player.game.name,
|
||||
G.sio.emit('chat_message', room=player.game.name,
|
||||
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).notify_self()
|
||||
|
@ -14,7 +14,10 @@ import bang.expansions.fistful_of_cards.card_events as ce
|
||||
import bang.expansions.high_noon.card_events as ceh
|
||||
import bang.expansions.gold_rush.shop_cards as grc
|
||||
import bang.expansions.gold_rush.characters as grch
|
||||
import bang.expansions.the_valley_of_shadows.cards as tvosc
|
||||
from metrics import Metrics
|
||||
from globals import G
|
||||
|
||||
|
||||
debug_commands = [
|
||||
{'cmd':'/debug', 'help':'Toggles the debug mode'},
|
||||
@ -45,9 +48,8 @@ debug_commands = [
|
||||
]
|
||||
|
||||
class Game:
|
||||
def __init__(self, name, sio:socketio):
|
||||
def __init__(self, name):
|
||||
super().__init__()
|
||||
self.sio = sio
|
||||
self.name = name
|
||||
self.players: List[pl.Player] = []
|
||||
self.spectators: List[pl.Player] = []
|
||||
@ -81,6 +83,7 @@ class Game:
|
||||
self.rng = random.Random()
|
||||
self.rpc_log = []
|
||||
self.is_replay = False
|
||||
self.replay_speed = 1
|
||||
|
||||
def shuffle_players(self):
|
||||
if not self.started:
|
||||
@ -117,13 +120,14 @@ class Game:
|
||||
self.notify_room()
|
||||
|
||||
def replay(self, log, speed=1.0, fast_forward = -1):
|
||||
from tests.dummy_socket import DummySocket
|
||||
self.players = []
|
||||
self.is_hidden = True
|
||||
self.is_replay = True
|
||||
self.replay_speed = speed
|
||||
for i in range(len(log)-1):
|
||||
print('replay:', i, 'of', len(log)-3, '->', log[i])
|
||||
if len(self.spectators) == 0:
|
||||
break
|
||||
if (log[i] == "@@@"):
|
||||
eventlet.sleep(10)
|
||||
if self.is_replay:
|
||||
@ -134,7 +138,7 @@ class Game:
|
||||
self.expansions = json.loads(cmd[4].replace("'",'"'))
|
||||
pnames = json.loads(cmd[3].replace("'",'"'))
|
||||
for p in pnames:
|
||||
self.add_player(pl.Player(p, p, DummySocket(self.sio), bot=False))
|
||||
self.add_player(pl.Player(p, 'a', bot=False))
|
||||
continue
|
||||
if cmd[1] == 'start_game':
|
||||
self.start_game(int(cmd[2]))
|
||||
@ -173,7 +177,7 @@ class Game:
|
||||
if i == fast_forward:
|
||||
self.replay_speed = 1.0
|
||||
self.notify_room()
|
||||
eventlet.sleep(max(self.replay_speed, 0.1))
|
||||
eventlet.sleep(max(self.replay_speed, 0.001))
|
||||
eventlet.sleep(6)
|
||||
if self.is_replay:
|
||||
self.reset()
|
||||
@ -181,7 +185,7 @@ class Game:
|
||||
|
||||
def notify_room(self, sid=None):
|
||||
if any((p.character == None for p in self.players)) or sid:
|
||||
self.sio.emit('room', room=self.name if not sid else sid, data={
|
||||
G.sio.emit('room', room=self.name if not sid else sid, data={
|
||||
'name': self.name,
|
||||
'started': self.started,
|
||||
'players': [{'name':p.name, 'ready': p.character != None, 'is_bot': p.is_bot, 'avatar': p.avatar} for p in self.players],
|
||||
@ -192,12 +196,12 @@ class Game:
|
||||
'available_expansions': self.available_expansions,
|
||||
'is_replay': self.is_replay,
|
||||
})
|
||||
self.sio.emit('debug', room=self.name, data=self.debug)
|
||||
G.sio.emit('debug', room=self.name, data=self.debug)
|
||||
if self.debug:
|
||||
self.sio.emit('commands', room=self.name, data=[x for x in debug_commands if 'admin' not in x])
|
||||
G.sio.emit('commands', room=self.name, data=[x for x in debug_commands if 'admin' not in x])
|
||||
else:
|
||||
self.sio.emit('commands', room=self.name, data=[{'cmd':'/debug', 'help':'Toggles the debug mode'}])
|
||||
self.sio.emit('spectators', room=self.name, data=len(self.spectators))
|
||||
G.sio.emit('commands', room=self.name, data=[{'cmd':'/debug', 'help':'Toggles the debug mode'}])
|
||||
G.sio.emit('spectators', room=self.name, data=len(self.spectators))
|
||||
|
||||
def toggle_expansion(self, expansion_name):
|
||||
if not self.started:
|
||||
@ -217,7 +221,7 @@ class Game:
|
||||
self.notify_room()
|
||||
|
||||
def feature_flags(self):
|
||||
if 'the_valley_of_shadows' not in self.expansions:
|
||||
if 'the_valley_of_shadows' not in self.expansions and 'the_valley_of_shadows' not in self.available_expansions :
|
||||
self.available_expansions.append('the_valley_of_shadows')
|
||||
self.notify_room()
|
||||
|
||||
@ -235,7 +239,7 @@ class Game:
|
||||
self.players.append(player)
|
||||
print(f'{self.name}: Added player {player.name} to game')
|
||||
self.notify_room()
|
||||
self.sio.emit('chat_message', room=self.name, data=f'_joined|{player.name}')
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_joined|{player.name}')
|
||||
|
||||
def set_private(self):
|
||||
if not self.is_changing_pwd:
|
||||
@ -254,7 +258,7 @@ class Game:
|
||||
if not any((p.character == None for p in self.players)):
|
||||
for i in range(len(self.players)):
|
||||
print(self.name, self.players[i].name, self.players[i].character)
|
||||
self.sio.emit('chat_message', room=self.name, data=f'_choose_character|{self.players[i].name}|{self.players[i].character.name}')
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_choose_character|{self.players[i].name}|{self.players[i].character.name}')
|
||||
self.players[i].prepare()
|
||||
for k in range(self.players[i].max_lives):
|
||||
self.players[i].hand.append(self.deck.draw())
|
||||
@ -265,7 +269,7 @@ class Game:
|
||||
for x in current_roles:
|
||||
if (x not in cr):
|
||||
cr += '|' +x + '|' + str(current_roles.count(x))
|
||||
self.sio.emit('chat_message', room=self.name, data=f'_allroles{cr}')
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_allroles{cr}')
|
||||
self.play_turn()
|
||||
|
||||
def choose_characters(self):
|
||||
@ -286,8 +290,8 @@ class Game:
|
||||
self.rpc_log = [f';players;{len(self.players)};{[p.name for p in self.players]};{self.expansions}', f';start_game;{SEED}']
|
||||
self.rng = random.Random(SEED)
|
||||
self.players_map = {c.name: i for i, c in enumerate(self.players)}
|
||||
self.sio.emit('chat_message', room=self.name, data=f'_starting')
|
||||
self.sio.emit('start', room=self.name)
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_starting')
|
||||
G.sio.emit('start', room=self.name)
|
||||
self.started = True
|
||||
self.someone_won = False
|
||||
self.attack_in_progress = False
|
||||
@ -319,7 +323,7 @@ class Game:
|
||||
self.players[i].set_role(available_roles[i])
|
||||
if isinstance(available_roles[i], roles.Sheriff) or (len(available_roles) == 3 and isinstance(available_roles[i], roles.Vice)):
|
||||
if isinstance(available_roles[i], roles.Sheriff):
|
||||
self.sio.emit('chat_message', room=self.name, data=f'_sheriff|{self.players[i].name}')
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_sheriff|{self.players[i].name}')
|
||||
self.turn = i
|
||||
self.players[i].notify_self()
|
||||
self.notify_event_card()
|
||||
@ -420,13 +424,13 @@ class Game:
|
||||
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.sio.emit('emporio', room=self.name, data=json.dumps(
|
||||
G.sio.emit('emporio', room=self.name, data=json.dumps(
|
||||
{'name':self.players[self.turn].name,'cards': self.available_cards}, default=lambda o: o.__dict__))
|
||||
self.players[self.turn].notify_self()
|
||||
|
||||
def respond_emporio(self, player, i):
|
||||
card = self.available_cards.pop(i)
|
||||
player.sio.emit('chat_message', room=self.name, data=f'_choose_emporio|{player.name}|{card.name}')
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_choose_emporio|{player.name}|{card.name}')
|
||||
player.hand.append(card)
|
||||
player.available_cards = []
|
||||
player.pending_action = pl.PendingAction.WAIT
|
||||
@ -436,18 +440,18 @@ class Game:
|
||||
if len(self.available_cards) == 1:
|
||||
nextPlayer.hand.append(self.available_cards.pop())
|
||||
nextPlayer.notify_self()
|
||||
self.sio.emit('emporio', room=self.name, data='{"name":"","cards":[]}')
|
||||
G.sio.emit('emporio', room=self.name, data='{"name":"","cards":[]}')
|
||||
self.players[self.turn].pending_action = pl.PendingAction.PLAY
|
||||
self.players[self.turn].notify_self()
|
||||
elif nextPlayer == self.players[self.turn]:
|
||||
self.sio.emit('emporio', room=self.name, data='{"name":"","cards":[]}')
|
||||
G.sio.emit('emporio', room=self.name, data='{"name":"","cards":[]}')
|
||||
self.players[self.turn].pending_action = pl.PendingAction.PLAY
|
||||
self.players[self.turn].notify_self()
|
||||
else:
|
||||
nextPlayer.pending_action = pl.PendingAction.CHOOSE
|
||||
nextPlayer.choose_text = 'choose_card_to_get'
|
||||
nextPlayer.available_cards = self.available_cards
|
||||
self.sio.emit('emporio', room=self.name, data=json.dumps(
|
||||
G.sio.emit('emporio', room=self.name, data=json.dumps(
|
||||
{'name':nextPlayer.name,'cards': self.available_cards}, default=lambda o: o.__dict__))
|
||||
nextPlayer.notify_self()
|
||||
|
||||
@ -533,15 +537,15 @@ class Game:
|
||||
if p.win_status and not (isinstance(p.role, roles.Renegade) and p.is_dead):
|
||||
if not self.someone_won:
|
||||
self.someone_won = True
|
||||
self.sio.emit('chat_message', room=self.name, data=f'_won|{p.name}|{p.role.name}')
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_won|{p.name}|{p.role.name}')
|
||||
if not self.is_replay:
|
||||
Metrics.send_metric('player_win', points=[1], tags=[f"char:{p.character.name}", f"role:{p.role.name}"])
|
||||
p.notify_self()
|
||||
if hasattr(self.sio, 'is_fake'):
|
||||
if hasattr(G.sio, 'is_fake'):
|
||||
print('announces_winners(): Running for tests, you will have to call reset manually!')
|
||||
return
|
||||
for i in range(5):
|
||||
self.sio.emit('chat_message', room=self.name, data=f'_lobby_reset|{5-i}')
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_lobby_reset|{5-i}')
|
||||
eventlet.sleep(1)
|
||||
return self.reset()
|
||||
|
||||
@ -563,6 +567,11 @@ class Game:
|
||||
pl.lives = 2
|
||||
pl.hand.append(self.deck.draw())
|
||||
pl.hand.append(self.deck.draw())
|
||||
if any((True for c in pl.equipment if isinstance(c, tvosc.Fantasma))):
|
||||
for c in pl.equipment:
|
||||
if isinstance(c, tvosc.Fantasma):
|
||||
self.deck.scrap(pl.equipment.pop(c))
|
||||
break
|
||||
pl.notify_self()
|
||||
elif self.check_event(ceh.CittaFantasma) or self.players[self.turn].is_ghost:
|
||||
print(f'{self.name}: {self.players[self.turn]} is dead, event ghost')
|
||||
@ -575,7 +584,7 @@ class Game:
|
||||
self.deck.flip_event()
|
||||
if len(self.deck.event_cards) > 0 and self.deck.event_cards[0] != None:
|
||||
print(f'{self.name}: flip new event {self.deck.event_cards[0].name}')
|
||||
self.sio.emit('chat_message', room=self.name, data={'color': f'orange','text':f'_flip_event|{self.deck.event_cards[0].name}'})
|
||||
G.sio.emit('chat_message', room=self.name, data={'color': f'orange','text':f'_flip_event|{self.deck.event_cards[0].name}'})
|
||||
if self.check_event(ce.DeadMan):
|
||||
self.did_resuscitate_deadman = False
|
||||
elif self.check_event(ce.RouletteRussa):
|
||||
@ -592,7 +601,7 @@ class Game:
|
||||
for p in hurt_players:
|
||||
if p.lives != p.max_lives:
|
||||
p.lives += 1
|
||||
self.sio.emit('chat_message', room=self.name, data=f'_doctor_heal|{p.name}')
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_doctor_heal|{p.name}')
|
||||
p.notify_self()
|
||||
elif self.check_event(ceh.IDalton):
|
||||
self.waiting_for = 0
|
||||
@ -633,29 +642,29 @@ class Game:
|
||||
if len(self.deck.event_cards) > 0:
|
||||
room = self.name if sid == None else sid
|
||||
if self.deck.event_cards[0] != None:
|
||||
self.sio.emit('event_card', room=room, data=self.deck.event_cards[0].__dict__)
|
||||
G.sio.emit('event_card', room=room, data=self.deck.event_cards[0].__dict__)
|
||||
else:
|
||||
self.sio.emit('event_card', room=room, data=None)
|
||||
G.sio.emit('event_card', room=room, data=None)
|
||||
|
||||
def notify_gold_rush_shop(self, sid=None):
|
||||
if 'gold_rush' in self.expansions and self.deck and self.deck.shop_cards and len(self.deck.shop_cards) > 0:
|
||||
room = self.name if sid == None else sid
|
||||
print(f'{self.name}: gold_rush_shop room={room}, data={self.deck.shop_cards}')
|
||||
self.sio.emit('gold_rush_shop', room=room, data=json.dumps(self.deck.shop_cards, default=lambda o: o.__dict__))
|
||||
G.sio.emit('gold_rush_shop', room=room, data=json.dumps(self.deck.shop_cards, default=lambda o: o.__dict__))
|
||||
|
||||
def notify_scrap_pile(self, sid=None):
|
||||
print(f'{self.name}: scrap')
|
||||
room = self.name if sid == None else sid
|
||||
if self.deck.peek_scrap_pile():
|
||||
self.sio.emit('scrap', room=room, data=self.deck.peek_scrap_pile().__dict__)
|
||||
G.sio.emit('scrap', room=room, data=self.deck.peek_scrap_pile().__dict__)
|
||||
else:
|
||||
self.sio.emit('scrap', room=room, data=None)
|
||||
G.sio.emit('scrap', room=room, data=None)
|
||||
|
||||
def handle_disconnect(self, player: pl.Player):
|
||||
print(f'{self.name}: player {player.name} left the game')
|
||||
if player in self.spectators:
|
||||
self.spectators.remove(player)
|
||||
self.sio.emit('spectators', room=self.name, data=len(self.spectators))
|
||||
G.sio.emit('spectators', room=self.name, data=len(self.spectators))
|
||||
return False
|
||||
if player.is_bot and not self.started:
|
||||
player.game = None
|
||||
@ -675,7 +684,7 @@ class Game:
|
||||
player.was_player = False
|
||||
if len(player.available_characters) > 0:
|
||||
player.set_available_character(player.available_characters)
|
||||
player.bot_spin()
|
||||
G.sio.start_background_task(player.bot_spin)
|
||||
else:
|
||||
self.player_death(player=player, disconnected=True)
|
||||
# else:
|
||||
@ -735,9 +744,20 @@ class Game:
|
||||
# if not disconnected:
|
||||
# self.dead_players.append(corpse)
|
||||
self.notify_room()
|
||||
self.sio.emit('chat_message', room=self.name, data=f'_died|{player.name}')
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_died|{player.name}')
|
||||
if self.started:
|
||||
self.sio.emit('chat_message', room=self.name, data=f'_died_role|{player.name}|{player.role.name}')
|
||||
G.sio.emit('chat_message', room=self.name, data=f'_died_role|{player.name}|{player.role.name}')
|
||||
if not isinstance(player.role, roles.Sheriff) and not self.initial_players == 3:
|
||||
G.sio.emit('notify_dead_role', room=self.name, data={
|
||||
'name': player.name,
|
||||
'lives': 0,
|
||||
'max_lives': player.max_lives,
|
||||
'is_ghost': player.is_ghost,
|
||||
'is_bot': player.is_bot,
|
||||
'icon': '🤠',
|
||||
'avatar': player.avatar,
|
||||
'role': player.role.__dict__,
|
||||
})
|
||||
for p in self.players:
|
||||
if not p.is_bot:
|
||||
p.notify_self()
|
||||
@ -835,7 +855,7 @@ class Game:
|
||||
return [p for p in self.players if p.is_dead and (include_ghosts or not p.is_ghost)]
|
||||
|
||||
def notify_all(self):
|
||||
if self.started:
|
||||
if self.started and self.replay_speed > 0:
|
||||
data = [{
|
||||
'name': p.name,
|
||||
'ncards': len(p.hand),
|
||||
@ -854,4 +874,4 @@ class Game:
|
||||
'is_ghost': p.is_ghost,
|
||||
'is_bot': p.is_bot,
|
||||
} for p in self.get_alive_players()]
|
||||
self.sio.emit('players_update', room=self.name, data=data)
|
||||
G.sio.emit('players_update', room=self.name, data=data)
|
||||
|
@ -13,9 +13,10 @@ import bang.expansions.high_noon.card_events as ceh
|
||||
import bang.expansions.gold_rush.shop_cards as grc
|
||||
import bang.expansions.gold_rush.characters as grch
|
||||
import bang.expansions.the_valley_of_shadows.cards as tvosc
|
||||
import eventlet
|
||||
from typing import List
|
||||
from metrics import Metrics
|
||||
from globals import G
|
||||
import sys
|
||||
|
||||
robot_pictures = [
|
||||
'https://i.imgur.com/40rAFIb.jpg',
|
||||
@ -63,25 +64,24 @@ class Player:
|
||||
else:
|
||||
self.avatar = f'https://cdn.discordapp.com/avatars/{res["id"]}/{res["avatar"]}.png'
|
||||
if self.game:
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_change_username|{self.name}|{res["username"]}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_change_username|{self.name}|{res["username"]}')
|
||||
self.name = res['username']
|
||||
self.discord_id = res['id']
|
||||
if self.is_admin():
|
||||
if self.game: self.game.feature_flags()
|
||||
self.sio.emit('chat_message', room=self.sid, data={'color':'green', 'text':'(you are admin)'})
|
||||
G.sio.emit('chat_message', room=self.sid, data={'color':'green', 'text':'(you are admin)'})
|
||||
if self.game:
|
||||
self.game.notify_room()
|
||||
self.sio.emit('me', data=self.name, room=self.sid)
|
||||
G.sio.emit('me', data=self.name, room=self.sid)
|
||||
else:
|
||||
print('error getting avatar', r.status_code, r.text)
|
||||
print(r)
|
||||
|
||||
def __init__(self, name, sid, sio, bot=False, discord_token=None):
|
||||
def __init__(self, name, sid, bot=False, discord_token=None):
|
||||
import bang.game as g
|
||||
super().__init__()
|
||||
self.name = name
|
||||
self.sid = sid
|
||||
self.sio = sio
|
||||
self.is_bot = bot
|
||||
self.discord_token = discord_token
|
||||
self.discord_id = None
|
||||
@ -89,7 +89,7 @@ class Player:
|
||||
if self.is_bot:
|
||||
self.avatar = robot_pictures[randrange(len(robot_pictures))]
|
||||
if self.discord_token:
|
||||
sio.start_background_task(self.get_avatar)
|
||||
G.sio.start_background_task(self.get_avatar)
|
||||
self.game: g = None
|
||||
self.reset()
|
||||
|
||||
@ -150,12 +150,13 @@ class Player:
|
||||
print(f'I {self.name} joined {self.game}')
|
||||
|
||||
def disconnect(self):
|
||||
if self.is_admin() and self.game.debug and self.game.started and getattr(sys, 'gettrace', None)(): return False
|
||||
return self.game.handle_disconnect(self)
|
||||
|
||||
def set_role(self, role: r.Role):
|
||||
self.role = role
|
||||
print(f'{self.name}: I am a {role.name}, my goal is "{role.goal}"')
|
||||
self.sio.emit('role', room=self.sid, data=json.dumps(
|
||||
G.sio.emit('role', room=self.sid, data=json.dumps(
|
||||
role, default=lambda o: o.__dict__))
|
||||
|
||||
def set_character(self, character: str):
|
||||
@ -174,14 +175,14 @@ class Player:
|
||||
self.real_character = self.character
|
||||
self.available_characters = []
|
||||
print(f'{self.name}: I chose character {self.character.name}')
|
||||
self.sio.emit('chat_message', room=self.game.name,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_did_choose_character|{self.name}')
|
||||
self.game.notify_character_selection()
|
||||
elif self.real_character and isinstance(self.real_character, chd.VeraCuster):
|
||||
self.character = next(
|
||||
x for x in self.available_characters if x.name == character)
|
||||
self.available_characters = []
|
||||
self.sio.emit('chat_message', room=self.game.name,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_did_choose_character|{self.name}')
|
||||
self.pending_action = PendingAction.DRAW
|
||||
self.notify_self()
|
||||
@ -199,7 +200,7 @@ class Player:
|
||||
self.available_characters = available
|
||||
print(f'{self.name}: I have to choose between {available}')
|
||||
if not self.is_bot:
|
||||
self.sio.emit('characters', room=self.sid, data=json.dumps(
|
||||
G.sio.emit('characters', room=self.sid, data=json.dumps(
|
||||
available, default=lambda o: o.__dict__))
|
||||
else:
|
||||
char_name = available[randrange(0, len(available))].name
|
||||
@ -217,7 +218,7 @@ class Player:
|
||||
'message':message
|
||||
}
|
||||
print('notifying card')
|
||||
self.sio.emit('notify_card', room=self.sid, data=mess)
|
||||
G.sio.emit('notify_card', room=self.sid, data=mess)
|
||||
|
||||
def notify_self(self):
|
||||
if any((True for c in self.equipment if isinstance(c, tvosc.Fantasma))):
|
||||
@ -272,7 +273,6 @@ class Player:
|
||||
|
||||
ser = self.__dict__.copy()
|
||||
ser.pop('game')
|
||||
ser.pop('sio')
|
||||
ser.pop('sid')
|
||||
ser.pop('on_pick_cb')
|
||||
ser.pop('discord_token')
|
||||
@ -292,16 +292,16 @@ class Player:
|
||||
self.pending_action = PendingAction.WAIT
|
||||
ser['hand'] = []
|
||||
ser['equipment'] = []
|
||||
self.sio.emit('self', room=self.sid, data=json.dumps(ser, default=lambda o: o.__dict__))
|
||||
G.sio.emit('self', room=self.sid, data=json.dumps(ser, default=lambda o: o.__dict__))
|
||||
self.game.player_death(self)
|
||||
if self.game and self.game.started: # falso quando un bot viene eliminato dalla partita
|
||||
self.sio.emit('self_vis', room=self.sid, data=json.dumps(self.game.get_visible_players(self), default=lambda o: o.__dict__))
|
||||
G.sio.emit('self_vis', room=self.sid, data=json.dumps(self.game.get_visible_players(self), default=lambda o: o.__dict__))
|
||||
self.game.notify_all()
|
||||
self.sio.emit('self', room=self.sid, data=json.dumps(ser, default=lambda o: o.__dict__))
|
||||
G.sio.emit('self', room=self.sid, data=json.dumps(ser, default=lambda o: o.__dict__))
|
||||
|
||||
def bot_spin(self):
|
||||
while self.is_bot and self.game != None and not self.game.shutting_down:
|
||||
eventlet.sleep(max(0.2, uniform(self.game.bot_speed/2-0.1, self.game.bot_speed)))
|
||||
G.sio.sleep(max(0.2, uniform(self.game.bot_speed/2-0.1, self.game.bot_speed)))
|
||||
if self.lives > 0 or self.is_ghost:
|
||||
self.bot_logic()
|
||||
|
||||
@ -441,7 +441,7 @@ class Player:
|
||||
self.is_playing_ranch = False
|
||||
self.can_play_vendetta = can_play_vendetta
|
||||
if not again:
|
||||
self.sio.emit('chat_message', room=self.game.name,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_turn|{self.name}')
|
||||
print(f'{self.name}: I was notified that it is my turn')
|
||||
self.was_shot = False
|
||||
@ -461,7 +461,7 @@ class Player:
|
||||
self.hand.append(self.game.deck.draw(True))
|
||||
if self.character.check(self.game, chars.BartCassidy) and self.lives > 0:
|
||||
self.hand.append(self.game.deck.draw(True))
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}')
|
||||
self.heal_if_needed()
|
||||
if self.lives <= 0:
|
||||
return self.notify_self()
|
||||
@ -557,11 +557,11 @@ class Player:
|
||||
for i in range(num):
|
||||
if i == 0 and pile == 'scrap' and self.character.check(self.game, chars.PedroRamirez):
|
||||
self.hand.append(self.game.deck.draw_from_scrap_pile())
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_draw_from_scrap|{self.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_draw_from_scrap|{self.name}')
|
||||
elif i == 0 and type(pile) == str and pile != self.name and pile in self.game.players_map and self.character.check(self.game, chars.JesseJones) and len(self.game.get_player_named(pile).hand) > 0:
|
||||
self.hand.append(self.game.get_player_named(pile).hand.pop( randrange(0, len(self.game.get_player_named(pile).hand))))
|
||||
self.game.get_player_named(pile).notify_self()
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_draw_from_player|{self.name}|{pile}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_draw_from_player|{self.name}|{pile}')
|
||||
elif i == 1:
|
||||
card: cs.Card = self.game.deck.draw()
|
||||
if (self.character.check(self.game, chars.BlackJack) or self.game.check_event(ce.LeggeDelWest)):
|
||||
@ -602,7 +602,7 @@ class Player:
|
||||
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,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_flipped|{self.name}|{picked.name}|{picked.num_suit()}')
|
||||
if picked.check_suit(self.game, [cs.Suit.SPADES]) and 2 <= picked.number <= 9 and pickable_cards == 0:
|
||||
self.lives -= 3
|
||||
@ -616,12 +616,12 @@ class Player:
|
||||
self.hand.append(self.game.deck.draw())
|
||||
self.attacker = None
|
||||
self.game.deck.scrap(self.equipment.pop(i), True)
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_explode|{self.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_explode|{self.name}')
|
||||
self.heal_if_needed()
|
||||
if self.character.check(self.game, chars.BartCassidy) and self.lives > 0:
|
||||
for i in range(3):
|
||||
self.hand.append(self.game.deck.draw(True))
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}')
|
||||
print(f'{self.name} Boom, -3 hp')
|
||||
break
|
||||
else:
|
||||
@ -637,16 +637,16 @@ class Player:
|
||||
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,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_flipped|{self.name}|{picked.name}|{picked.num_suit()}')
|
||||
if not picked.check_suit(self.game, [cs.Suit.HEARTS]) and pickable_cards == 0:
|
||||
self.game.deck.scrap(self.equipment.pop(i), True)
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_prison_turn|{self.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_prison_turn|{self.name}')
|
||||
self.end_turn(forced=True)
|
||||
return
|
||||
elif pickable_cards == 0:
|
||||
self.game.deck.scrap(self.equipment.pop(i), True)
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_prison_free|{self.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_prison_free|{self.name}')
|
||||
break
|
||||
break
|
||||
for i in range(len(self.equipment)):
|
||||
@ -655,13 +655,13 @@ class Player:
|
||||
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,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_flipped|{self.name}|{picked.name}|{picked.num_suit()}')
|
||||
if not picked.check_suit(self.game, [cs.Suit.SPADES]):
|
||||
break
|
||||
elif pickable_cards == 0:
|
||||
self.lives -= 1
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_snake_bit|{self.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_snake_bit|{self.name}')
|
||||
break
|
||||
if any((isinstance(c, cs.Prigione) for c in self.equipment)):
|
||||
self.notify_self() #TODO perchè solo le prigioni? e multiple dinamiti come si comportano con veracuster?
|
||||
@ -725,7 +725,7 @@ class Player:
|
||||
self.hand.insert(hand_index, card)
|
||||
if withCard:
|
||||
self.hand.insert(_with, withCard)
|
||||
self.sio.emit('cant_play_card', room=self.sid)
|
||||
G.sio.emit('cant_play_card', room=self.sid)
|
||||
elif (card.usable_next_turn and card.can_be_used_now) or (isinstance(card, grc.ShopCard) and card.kind == grc.ShopCardKind.BLACK):
|
||||
if did_play_card:
|
||||
self.game.deck.scrap(card, True)
|
||||
@ -773,7 +773,7 @@ class Player:
|
||||
self.notify_self()
|
||||
elif self.choose_text == 'choose_ricercato':
|
||||
player = self.game.get_player_named(self.available_cards[card_index]['name'])
|
||||
player.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{self.name}|Ricercato|{player.name}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{self.name}|Ricercato|{player.name}')
|
||||
if any((isinstance(c, grc.Ricercato) for c in player.gold_rush_equipment)):
|
||||
self.game.deck.shop_deck.append(grc.Ricercato())
|
||||
else:
|
||||
@ -793,20 +793,20 @@ class Player:
|
||||
self.notify_self()
|
||||
elif self.choose_text == 'choose_bicchierino':
|
||||
player = self.game.get_player_named(self.available_cards[card_index]['name'])
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_play_card_for|{self.name}|{"Bicchierino"}|{player.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_play_card_for|{self.name}|{"Bicchierino"}|{player.name}')
|
||||
player.lives = min(player.lives+1, player.max_lives)
|
||||
self.pending_action = PendingAction.PLAY
|
||||
self.notify_self()
|
||||
elif self.choose_text == 'choose_birra_function':
|
||||
if card_index == 0:
|
||||
self.gold_nuggets += 1
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_get_nugget|{self.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_get_nugget|{self.name}')
|
||||
else:
|
||||
cs.Birra(1,1).play_card(self, skipChecks=True)
|
||||
self.pending_action = PendingAction.PLAY
|
||||
self.notify_self()
|
||||
elif self.choose_text == 'choose_bottiglia':
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_play_card|{self.name}|{"Bottiglia"}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_play_card|{self.name}|{"Bottiglia"}')
|
||||
if isinstance(self.available_cards[card_index], cs.Birra):
|
||||
self.lives = min(self.lives+1, self.max_lives)
|
||||
else:
|
||||
@ -814,7 +814,7 @@ class Player:
|
||||
self.pending_action = PendingAction.PLAY
|
||||
self.notify_self()
|
||||
elif self.choose_text == 'choose_complice':
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_play_card|{self.name}|{"Bottiglia"}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_play_card|{self.name}|{"Bottiglia"}')
|
||||
self.hand.append(self.available_cards[card_index])
|
||||
self.pending_action = PendingAction.PLAY
|
||||
self.notify_self()
|
||||
@ -835,7 +835,7 @@ class Player:
|
||||
player = self.game.get_player_named(self.choose_text.split('|')[1])
|
||||
player.gold_rush_equipment.remove(self.available_cards[card_index])
|
||||
self.game.deck.shop_deck.append(self.available_cards[card_index])
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_gold_rush_pay_discard|{self.name}|{player.name}|{self.available_cards[card_index].name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_gold_rush_pay_discard|{self.name}|{player.name}|{self.available_cards[card_index].name}')
|
||||
player.notify_self()
|
||||
self.pending_action = PendingAction.PLAY
|
||||
self.notify_self()
|
||||
@ -845,7 +845,7 @@ class Player:
|
||||
player.equipment.append(self.game.deck.scrap_pile.pop(-1))
|
||||
player.notify_self()
|
||||
self.game.notify_all()
|
||||
self.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{self.name}|Fantasma|{player.name}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{self.name}|Fantasma|{player.name}')
|
||||
self.pending_action = PendingAction.PLAY
|
||||
self.notify_self()
|
||||
elif 'choose_sventagliata' in self.choose_text:
|
||||
@ -854,8 +854,8 @@ class Player:
|
||||
player = self.game.get_player_named(self.available_cards[card_index]['name'])
|
||||
player.game.attack(self, og, card_name='Sventagliata')
|
||||
player.game.attack(self, player.name, card_name='Sventagliata')
|
||||
self.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{self.name}|Sventagliata|{og}')
|
||||
self.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{self.name}|Sventagliata|{player.name}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{self.name}|Sventagliata|{og}')
|
||||
G.sio.emit('chat_message', room=player.game.name, data=f'_play_card_against|{self.name}|Sventagliata|{player.name}')
|
||||
self.pending_action = PendingAction.PLAY
|
||||
self.notify_self()
|
||||
elif 'choose_tornado' in self.choose_text:
|
||||
@ -899,11 +899,11 @@ class Player:
|
||||
self.real_character = self.character
|
||||
self.max_lives = self.character.max_lives + self.role.health_mod
|
||||
self.lives = 2
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_choose_character|{self.name}|{self.character.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_choose_character|{self.name}|{self.character.name}')
|
||||
self.play_turn(again = True)
|
||||
elif self.game.check_event(ceh.Manette) and self.choose_text == 'choose_manette':
|
||||
self.committed_suit_manette = cs.Suit(card_index)
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_choose_manette|{self.name}|{"♦♣♥♠"[card_index]}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_choose_manette|{self.name}|{"♦♣♥♠"[card_index]}')
|
||||
self.pending_action = PendingAction.PLAY
|
||||
self.notify_self()
|
||||
elif self.is_giving_life and self.game.check_event(ce.FratelliDiSangue):
|
||||
@ -918,7 +918,7 @@ class Player:
|
||||
if any((isinstance(c, grc.Stivali) for c in self.gold_rush_equipment)):
|
||||
self.hand.append(self.game.deck.draw())
|
||||
player.notify_self()
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_fratelli_sangue|{self.name}|{player.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_fratelli_sangue|{self.name}|{player.name}')
|
||||
except: pass
|
||||
self.play_turn(again = True)
|
||||
elif self.is_using_checchino and self.game.check_event(ce.Cecchino):
|
||||
@ -975,15 +975,15 @@ class Player:
|
||||
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']}")
|
||||
G.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}")
|
||||
G.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}")
|
||||
G.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
|
||||
@ -1051,7 +1051,7 @@ class Player:
|
||||
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,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_flipped|{self.name}|{picked.name}|{picked.num_suit()}')
|
||||
if picked.check_suit(self.game, [cs.Suit.HEARTS]):
|
||||
self.mancato_needed -= 1
|
||||
@ -1081,7 +1081,7 @@ class Player:
|
||||
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,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_flipped|{self.name}|{picked.name}|{picked.num_suit()}')
|
||||
if picked.check_suit(self.game, [cs.Suit.HEARTS]):
|
||||
self.mancato_needed -= 1
|
||||
@ -1213,34 +1213,34 @@ class Player:
|
||||
self.lives += 1 if not self.character.check(self.game, chd.TequilaJoe) else 2
|
||||
self.lives = min(self.lives, self.max_lives)
|
||||
self.game.deck.scrap(self.hand.pop(i), True)
|
||||
self.sio.emit('chat_message', room=self.game.name,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_beer_save|{self.name}')
|
||||
break
|
||||
|
||||
def take_damage_response(self):
|
||||
self.lives -= 1
|
||||
self.sio.emit('hurt', room=self.sid, data=f'')
|
||||
G.sio.emit('hurt', room=self.sid, data=f'')
|
||||
if self.lives > 0:
|
||||
if self.character.check(self.game, chars.BartCassidy):
|
||||
self.sio.emit('chat_message', room=self.game.name,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_special_bart_cassidy|{self.name}')
|
||||
self.hand.append(self.game.deck.draw(True))
|
||||
elif self.character.check(self.game, chars.ElGringo) and self.attacker and self.attacker in self.game.get_alive_players() and len(self.attacker.hand) > 0:
|
||||
self.hand.append(self.attacker.hand.pop(randrange(0, len(self.attacker.hand))))
|
||||
self.hand[-1].reset_card()
|
||||
self.sio.emit('chat_message', room=self.game.name,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_special_el_gringo|{self.name}|{self.attacker.name}')
|
||||
self.attacker.notify_self()
|
||||
if isinstance(self.attacker, Player) and not self.game.check_event(ce.Lazo):
|
||||
if any((isinstance(c, tvosc.Taglia) for c in self.equipment)):
|
||||
self.attacker.hand.append(self.game.deck.draw(True))
|
||||
self.sio.emit('chat_message', room=self.game.name,
|
||||
G.sio.emit('chat_message', room=self.game.name,
|
||||
data=f'_taglia_reward|{self.name}|{self.attacker.name}')
|
||||
self.attacker.notify_self()
|
||||
if len(self.hand) > 0 and any((isinstance(cd, tvosc.Shotgun) for cd in self.attacker.equipment)):
|
||||
c = self.hand.pop(randrange(0, len(self.hand)))
|
||||
self.game.deck.scrap(c, True)
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_shotgun_scrap|{self.name}|{c.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_shotgun_scrap|{self.name}|{c.name}')
|
||||
if self.attacker and 'gold_rush' in self.game.expansions:
|
||||
if (isinstance(self.attacker, Player)):
|
||||
self.attacker.gold_nuggets += 1
|
||||
@ -1285,7 +1285,7 @@ class Player:
|
||||
self.hand.append(self.game.deck.draw(True))
|
||||
card.use_card(self)
|
||||
print(f'{self.game.name}: {self.name} responded with {card.name}')
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_respond|{self.name}|{card.name}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_respond|{self.name}|{card.name}')
|
||||
self.game.deck.scrap(card, True)
|
||||
self.notify_self()
|
||||
self.mancato_needed -= 1
|
||||
@ -1448,14 +1448,14 @@ class Player:
|
||||
##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()
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked.name}|{picked.num_suit()}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked.name}|{picked.num_suit()}')
|
||||
if picked.check_suit(self.game, [cs.Suit.HEARTS]):
|
||||
self.play_turn(can_play_vendetta=False)
|
||||
return
|
||||
##Don Bell##
|
||||
if not forced and self.character.check(self.game, grch.DonBell) and self.can_play_again_don_bell:
|
||||
picked: cs.Card = self.game.deck.pick_and_scrap()
|
||||
self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked.name}|{picked.num_suit()}')
|
||||
G.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked.name}|{picked.num_suit()}')
|
||||
self.can_play_again_don_bell = False
|
||||
if picked.check_suit(self.game, [cs.Suit.HEARTS, cs.Suit.DIAMONDS]):
|
||||
self.play_turn(can_play_vendetta=False)
|
||||
|
6
backend/globals.py
Normal file
6
backend/globals.py
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
class G:
|
||||
sio = None
|
||||
|
||||
def __init__(self):
|
||||
pass
|
@ -20,10 +20,16 @@ sys.setrecursionlimit(10**6) # this should prevents bots from stopping
|
||||
import logging
|
||||
logging.basicConfig(filename='out.log', level='ERROR')
|
||||
from functools import wraps
|
||||
from globals import G
|
||||
|
||||
Metrics.init()
|
||||
|
||||
sio = socketio.Server(cors_allowed_origins="*")
|
||||
G.sio = sio
|
||||
|
||||
import faulthandler
|
||||
|
||||
faulthandler.enable()
|
||||
|
||||
static_files={
|
||||
'/': {'content_type': 'text/html', 'filename': 'index.html'},
|
||||
@ -54,20 +60,24 @@ def send_to_debug(error):
|
||||
if g.debug or any((p.is_admin() for p in g.players)):
|
||||
sio.emit('chat_message', room=g.name, data={'color': f'red','text':json.dumps({'ERROR':error}), 'type':'json'})
|
||||
|
||||
save_lock = False
|
||||
def bang_handler(func):
|
||||
@wraps(func)
|
||||
def wrapper_func(*args, **kwargs):
|
||||
global save_lock
|
||||
save_lock = True
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
print(traceback.format_exc())
|
||||
send_to_debug(traceback.format_exc())
|
||||
save_lock = False
|
||||
return wrapper_func
|
||||
|
||||
def advertise_lobbies():
|
||||
sio.emit('lobbies', room='lobby', data=[{'name': g.name, 'players': len(g.players), 'locked': g.password != ''} for g in games if not g.started and len(g.players) < 10 and not g.is_hidden])
|
||||
sio.emit('spectate_lobbies', room='lobby', data=[{'name': g.name, 'players': len(g.players), 'locked': g.password != ''} for g in games if g.started and not g.is_hidden])
|
||||
sio.emit('spectate_lobbies', room='lobby', data=[{'name': g.name, 'players': len(g.players), 'locked': g.password != ''} for g in games if g.started and not g.is_hidden and len(g.players) > 0])
|
||||
Metrics.send_metric('lobbies', points=[sum(not g.is_replay for g in games)])
|
||||
Metrics.send_metric('online_players', points=[online_players])
|
||||
|
||||
@ -114,7 +124,7 @@ def set_username(sid, username):
|
||||
ses = sio.get_session(sid)
|
||||
if not isinstance(ses, Player):
|
||||
dt = username["discord_token"] if 'discord_token' in username else None
|
||||
sio.save_session(sid, Player(username["name"], sid, sio, discord_token=dt))
|
||||
sio.save_session(sid, Player(username["name"], sid, discord_token=dt))
|
||||
print(f'{sid} is now {username}')
|
||||
advertise_lobbies()
|
||||
elif ses.game == None or not ses.game.started:
|
||||
@ -138,7 +148,7 @@ def get_me(sid, room):
|
||||
sio.get_session(sid).game.notify_room()
|
||||
else:
|
||||
dt = room["discord_token"] if 'discord_token' in room else None
|
||||
sio.save_session(sid, Player('player', sid, sio, discord_token=dt))
|
||||
sio.save_session(sid, Player('player', sid, discord_token=dt))
|
||||
if 'replay' in room and room['replay'] != None:
|
||||
create_room(sid, room['replay'])
|
||||
sid = sio.get_session(sid)
|
||||
@ -153,16 +163,16 @@ def get_me(sid, room):
|
||||
if 'ffw' not in room:
|
||||
sid.game.replay(log)
|
||||
else:
|
||||
sid.game.replay(log, speed=0.1, fast_forward=int(room['ffw']))
|
||||
sid.game.replay(log, speed=0, fast_forward=int(room['ffw']))
|
||||
return
|
||||
de_games = [g for g in games if g.name == room['name']]
|
||||
if len(de_games) == 1 and not de_games[0].started:
|
||||
join_room(sid, room)
|
||||
elif len(de_games) == 1 and de_games[0].started:
|
||||
print('room exists')
|
||||
if room['username'] != None and any((p.name == room['username'] for p in de_games[0].players if (p.is_bot or (dt != None and p.discord_token == dt)))):
|
||||
if room['username'] != None and any((p.name == room['username'] for p in de_games[0].players if (p.is_bot or (dt != None and p.discord_token == dt) or p.sid == None))):
|
||||
print('getting inside the bot')
|
||||
bot = [p for p in de_games[0].players if p.is_bot and p.name == room['username'] ][0]
|
||||
bot = [p for p in de_games[0].players if (p.is_bot or (dt != None and p.discord_token == dt) or p.sid == None) and p.name == room['username']][0]
|
||||
bot.sid = sid
|
||||
bot.is_bot = False
|
||||
sio.enter_room(sid, de_games[0].name)
|
||||
@ -193,7 +203,7 @@ def get_me(sid, room):
|
||||
sio.emit('me', data={'error':'Wrong password/Cannot connect'}, room=sid)
|
||||
else:
|
||||
sio.emit('me', data=sio.get_session(sid).name, room=sid)
|
||||
if room['username'] == None or any((p.name == room['username'] for p in sio.get_session(sid).game.players)):
|
||||
if room['username'] == None or any((p.name == room['username'] for p in sio.get_session(sid).game.players if not ((dt != None and p.discord_token == dt) or p.sid == None))):
|
||||
sio.emit('change_username', room=sid)
|
||||
else:
|
||||
sio.emit('chat_message', room=sio.get_session(sid).game.name, data=f"_change_username|{sio.get_session(sid).name}|{room['username']}")
|
||||
@ -225,7 +235,7 @@ def create_room(sid, room_name):
|
||||
room_name += f'_{random.randint(0,100)}'
|
||||
sio.leave_room(sid, 'lobby')
|
||||
sio.enter_room(sid, room_name)
|
||||
g = Game(room_name, sio)
|
||||
g = Game(room_name)
|
||||
g.add_player(sio.get_session(sid))
|
||||
if room_name in blacklist:
|
||||
g.is_hidden = True
|
||||
@ -289,7 +299,8 @@ Sockets for the status page
|
||||
@sio.event
|
||||
@bang_handler
|
||||
def get_all_rooms(sid, deploy_key):
|
||||
if ('DEPLOY_KEY' in os.environ and deploy_key == os.environ['DEPLOY_KEY']) or sio.get_session(sid).is_admin():
|
||||
ses = sio.get_session(sid)
|
||||
if ('DEPLOY_KEY' in os.environ and deploy_key == os.environ['DEPLOY_KEY']) or (isinstance(ses, Player) and ses.is_admin()):
|
||||
sio.emit('all_rooms', room=sid, data=[{
|
||||
'name': g.name,
|
||||
'hidden': g.is_hidden,
|
||||
@ -306,13 +317,25 @@ def get_all_rooms(sid, deploy_key):
|
||||
@sio.event
|
||||
@bang_handler
|
||||
def kick(sid, data):
|
||||
if ('DEPLOY_KEY' in os.environ and data['key'] == os.environ['DEPLOY_KEY']) or sio.get_session(sid).is_admin():
|
||||
ses = sio.get_session(sid)
|
||||
if ('DEPLOY_KEY' in os.environ and 'key' in data and data['key'] == os.environ['DEPLOY_KEY']) or (isinstance(ses, Player) and ses.is_admin()):
|
||||
sio.emit('kicked', room=data['sid'])
|
||||
|
||||
@sio.event
|
||||
@bang_handler
|
||||
def reset(sid, data):
|
||||
global games
|
||||
ses = sio.get_session(sid)
|
||||
if ('DEPLOY_KEY' in os.environ and 'key' in data and data['key'] == os.environ['DEPLOY_KEY']) or (isinstance(ses, Player) and ses.is_admin()):
|
||||
for g in games:
|
||||
sio.emit('kicked', room=g.name)
|
||||
games = []
|
||||
|
||||
@sio.event
|
||||
@bang_handler
|
||||
def hide_toogle(sid, data):
|
||||
if ('DEPLOY_KEY' in os.environ and data['key'] == os.environ['DEPLOY_KEY']) or sio.get_session(sid).is_admin():
|
||||
ses = sio.get_session(sid)
|
||||
if ('DEPLOY_KEY' in os.environ and 'key' in data and data['key'] == os.environ['DEPLOY_KEY']) or (isinstance(ses, Player) and ses.is_admin()):
|
||||
game = [g for g in games if g.name==data['room']]
|
||||
if len(games) > 0:
|
||||
game[0].is_hidden = not game[0].is_hidden
|
||||
@ -436,14 +459,14 @@ def chat_message(sid, msg, pl=None):
|
||||
if '/addbot' in msg and not ses.game.started:
|
||||
if len(msg.split()) > 1:
|
||||
# for _ in range(int(msg.split()[1])):
|
||||
# ses.game.add_player(Player(f'AI_{random.randint(0,1000)}', 'bot', sio, bot=True))
|
||||
# ses.game.add_player(Player(f'AI_{random.randint(0,1000)}', 'bot', bot=True))
|
||||
sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'Only 1 bot at the time'})
|
||||
else:
|
||||
bot = Player(f'AI_{random.randint(0,10)}', 'bot', sio, bot=True)
|
||||
bot = Player(f'AI_{random.randint(0,10)}', 'bot', bot=True)
|
||||
while any((p for p in ses.game.players if p.name == bot.name)):
|
||||
bot = Player(f'AI_{random.randint(0,10)}', 'bot', sio, bot=True)
|
||||
bot = Player(f'AI_{random.randint(0,10)}', 'bot', bot=True)
|
||||
ses.game.add_player(bot)
|
||||
bot.bot_spin()
|
||||
sio.start_background_task(bot.bot_spin)
|
||||
return
|
||||
if '/replay' in msg and not '/replayspeed' in msg and not '/replaypov' in msg:
|
||||
_cmd = msg.split()
|
||||
@ -456,7 +479,7 @@ def chat_message(sid, msg, pl=None):
|
||||
ses.game.replay(log)
|
||||
if len(_cmd) == 3:
|
||||
line = int(_cmd[2])
|
||||
ses.game.replay(log, speed=0.1, fast_forward=line)
|
||||
ses.game.replay(log, speed=0, fast_forward=line)
|
||||
return
|
||||
if '/replayspeed' in msg:
|
||||
_cmd = msg.split()
|
||||
@ -469,11 +492,8 @@ def chat_message(sid, msg, pl=None):
|
||||
name = ' '.join(_cmd[1:])
|
||||
for p in ses.game.players:
|
||||
if p.sid == ses.sid:
|
||||
from tests.dummy_socket import DummySocket
|
||||
p.sio = DummySocket()
|
||||
p.sid = ''
|
||||
pl = ses.game.get_player_named(name)
|
||||
pl.sio = sio
|
||||
pl.sid = ses.sid
|
||||
pl.set_role(pl.role)
|
||||
pl.notify_self()
|
||||
@ -666,7 +686,7 @@ def chat_message(sid, msg, pl=None):
|
||||
ses.is_bot = not ses.is_bot
|
||||
if (ses.is_bot):
|
||||
ses.was_player = True
|
||||
ses.bot_spin()
|
||||
sio.start_background_task(ses.bot_spin)
|
||||
elif '/arcadekick' in msg and ses.game.started:
|
||||
if not any((p.pending_action != PendingAction.WAIT for p in ses.game.players)):
|
||||
sio.emit('chat_message', room=ses.game.name, data={'color': f'','text':f'KICKING THE ARCADE CABINET'})
|
||||
@ -763,11 +783,12 @@ def discord_auth(sid, data):
|
||||
if res.status_code == 200:
|
||||
sio.emit('discord_auth_succ', room=sid, data=res.json())
|
||||
|
||||
|
||||
def pool_metrics():
|
||||
while True:
|
||||
sio.sleep(60)
|
||||
Metrics.send_metric('lobbies', points=[sum(not g.is_replay for g in games)])
|
||||
Metrics.send_metric('online_players', points=[online_players])
|
||||
pool_metrics()
|
||||
|
||||
import urllib.parse
|
||||
class CustomProxyFix(object):
|
||||
@ -790,7 +811,30 @@ class CustomProxyFix(object):
|
||||
|
||||
discord_ci = '1059452581027532880'
|
||||
discord_cs = 'Mc8ZlMQhayzi1eOqWFtGHs3L0iXCzaEu'
|
||||
import pickle
|
||||
def save_games():
|
||||
global save_lock
|
||||
while True:
|
||||
sio.sleep(2)
|
||||
if not save_lock:
|
||||
if not os.path.exists("save"):
|
||||
os.mkdir("save")
|
||||
with open('./save/games.pickle', 'wb') as f:
|
||||
pickle.dump([g for g in games if g.started and not g.is_replay and not g.is_hidden], f)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if os.path.exists('./save/games.pickle'):
|
||||
try:
|
||||
with open('./save/games.pickle', 'rb') as file:
|
||||
games = pickle.load(file)
|
||||
for g in games:
|
||||
for p in g.players:
|
||||
if p.sid != 'bot':
|
||||
sio.start_background_task(p.disconnect)
|
||||
else:
|
||||
sio.start_background_task(p.bot_spin)
|
||||
except:
|
||||
pass
|
||||
sio.start_background_task(save_games)
|
||||
sio.start_background_task(pool_metrics)
|
||||
eventlet.wsgi.server(eventlet.listen(('', 5001)), CustomProxyFix(app))
|
||||
|
@ -0,0 +1,3 @@
|
||||
from tests.dummy_socket import DummySocket
|
||||
from globals import G
|
||||
G.sio = DummySocket()
|
@ -1,16 +1,15 @@
|
||||
from random import randint
|
||||
from bang.characters import Character
|
||||
from bang.cards import *
|
||||
from tests.dummy_socket import DummySocket
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player, PendingAction
|
||||
|
||||
# test card Barile
|
||||
def test_barile():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -43,9 +42,9 @@ def test_barile():
|
||||
|
||||
#test card Volcanic
|
||||
def test_volcanic():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -67,9 +66,9 @@ def test_volcanic():
|
||||
|
||||
# test card Dinamite
|
||||
def test_dinamite():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -103,9 +102,9 @@ def test_dinamite():
|
||||
|
||||
# test mirino
|
||||
def test_mirino():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(4)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(4)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -121,9 +120,9 @@ def test_mirino():
|
||||
|
||||
# test mustang
|
||||
def test_mustang():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -139,9 +138,9 @@ def test_mustang():
|
||||
|
||||
# test Prigione
|
||||
def test_prigione():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(4)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(4)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -171,9 +170,9 @@ def test_prigione():
|
||||
|
||||
# test all weapons ranges
|
||||
def test_all_weapons():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(4)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(4)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -195,9 +194,9 @@ def test_all_weapons():
|
||||
|
||||
# test bang
|
||||
def test_bang():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -214,9 +213,9 @@ def test_bang():
|
||||
|
||||
# test birra
|
||||
def test_birra_2p():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -231,9 +230,9 @@ def test_birra_2p():
|
||||
|
||||
# test birra
|
||||
def test_birra_3p():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -262,9 +261,9 @@ def test_birra_3p():
|
||||
|
||||
# test CatBalou
|
||||
def test_catbalou():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -282,9 +281,9 @@ def test_catbalou():
|
||||
|
||||
# test Diligenza
|
||||
def test_diligenza():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(4)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(4)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -298,9 +297,9 @@ def test_diligenza():
|
||||
|
||||
# test Duello
|
||||
def test_duello():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -326,9 +325,9 @@ def test_duello():
|
||||
|
||||
# test Emporio
|
||||
def test_emporio():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(7)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(7)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -352,9 +351,9 @@ def test_emporio():
|
||||
|
||||
# test Gatling
|
||||
def test_gatling():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(7)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(7)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -386,9 +385,9 @@ def test_gatling():
|
||||
|
||||
# test Indiani
|
||||
def test_indiani():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(7)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(7)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -420,9 +419,9 @@ def test_indiani():
|
||||
|
||||
# test Mancato
|
||||
def test_mancato():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -442,9 +441,9 @@ def test_mancato():
|
||||
|
||||
# test Panico
|
||||
def test_panico():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -461,9 +460,9 @@ def test_panico():
|
||||
|
||||
# test Saloon
|
||||
def test_saloon():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(8)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(8)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -480,9 +479,9 @@ def test_saloon():
|
||||
|
||||
# test WellsFargo
|
||||
def test_wells_fargo():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(4)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(4)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
|
@ -1,15 +1,14 @@
|
||||
from random import randint
|
||||
from bang.characters import *
|
||||
from tests.dummy_socket import DummySocket
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player, PendingAction
|
||||
from bang.cards import *
|
||||
|
||||
def test_bartcassidy():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -29,9 +28,9 @@ def test_bartcassidy():
|
||||
assert len(g.players[(g.turn+1)%2].hand) == 1
|
||||
|
||||
def test_blackjack():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(1)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(1)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -62,9 +61,9 @@ def test_blackjack():
|
||||
g.players[g.turn].end_turn()
|
||||
|
||||
def test_calamityjanet():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -89,9 +88,9 @@ def test_calamityjanet():
|
||||
assert g.players[(g.turn+1)%2].lives == 1
|
||||
|
||||
def test_ElGringo():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -112,9 +111,9 @@ def test_ElGringo():
|
||||
assert len(g.players[g.turn].hand) == 0
|
||||
|
||||
def test_JesseJones():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -133,9 +132,9 @@ def test_JesseJones():
|
||||
assert len(g.players[g.turn].hand) == 2
|
||||
|
||||
def test_Jourdonnais():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -153,9 +152,9 @@ def test_Jourdonnais():
|
||||
assert g.players[(g.turn+1)%2].pending_action == PendingAction.PICK
|
||||
|
||||
def test_KitCarlson():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -176,9 +175,9 @@ def test_KitCarlson():
|
||||
assert g.players[g.turn].pending_action == PendingAction.PLAY
|
||||
|
||||
def test_LuckyDuke():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -198,9 +197,9 @@ def test_LuckyDuke():
|
||||
assert g.players[g.turn].pending_action == PendingAction.DRAW
|
||||
|
||||
def test_PaulRegret():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -214,9 +213,9 @@ def test_PaulRegret():
|
||||
assert pls[0]['dist'] > g.players[0].get_sight()
|
||||
|
||||
def test_PedroRamirez():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -237,9 +236,9 @@ def test_PedroRamirez():
|
||||
assert isinstance(g.players[g.turn].hand[0], Bang)
|
||||
|
||||
def test_RoseDoolan():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -256,9 +255,9 @@ def test_RoseDoolan():
|
||||
assert pls[0]['dist'] <= g.players[1].get_sight()
|
||||
|
||||
def test_SidKetchum():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -278,9 +277,9 @@ def test_SidKetchum():
|
||||
assert g.players[g.turn].lives == 2
|
||||
|
||||
def test_SlabTheKiller():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -301,9 +300,9 @@ def test_SlabTheKiller():
|
||||
assert g.players[(g.turn+1)%2].lives == 3
|
||||
|
||||
def test_SuzyLafayette():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -318,9 +317,9 @@ def test_SuzyLafayette():
|
||||
g.players[g.turn].end_turn()
|
||||
|
||||
def test_VultureSam():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -341,9 +340,9 @@ def test_VultureSam():
|
||||
return
|
||||
|
||||
def test_WillyTheKid():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
|
@ -3,7 +3,7 @@ from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
|
||||
def test_card_flip():
|
||||
g = Game('test', DummySocket())
|
||||
g = Game('test')
|
||||
g.deck = Deck(g)
|
||||
l = len(g.deck.cards)
|
||||
assert g.deck.pick_and_scrap() != None
|
||||
@ -11,7 +11,7 @@ def test_card_flip():
|
||||
assert len(g.deck.scrap_pile) == 1
|
||||
|
||||
def test_draw():
|
||||
g = Game('test', DummySocket())
|
||||
g = Game('test')
|
||||
g.deck = Deck(g)
|
||||
l = len(g.deck.cards)
|
||||
assert g.deck.draw(True) != None
|
||||
@ -19,7 +19,7 @@ def test_draw():
|
||||
assert len(g.deck.scrap_pile) == 0
|
||||
|
||||
def test_reshuffle():
|
||||
g = Game('test', DummySocket())
|
||||
g = Game('test')
|
||||
g.deck = Deck(g)
|
||||
l = len(g.deck.cards)
|
||||
for i in range(80):
|
||||
@ -28,7 +28,7 @@ def test_reshuffle():
|
||||
assert len(g.deck.scrap_pile) == 1
|
||||
|
||||
def test_draw_from_scrap():
|
||||
g = Game('test', DummySocket())
|
||||
g = Game('test')
|
||||
g.deck = Deck(g)
|
||||
l = len(g.deck.cards)
|
||||
assert g.deck.pick_and_scrap() != None
|
||||
|
@ -1,4 +1,3 @@
|
||||
from tests.dummy_socket import DummySocket
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player, PendingAction
|
||||
@ -7,13 +6,13 @@ from bang.cards import *
|
||||
|
||||
# test that game can start
|
||||
def test_game_start():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
p1 = Player('p1', 'p1', sio)
|
||||
|
||||
g = Game('test')
|
||||
p1 = Player('p1', 'p1')
|
||||
g.add_player(p1)
|
||||
p2 = Player('p2', 'p2', sio)
|
||||
p2 = Player('p2', 'p2')
|
||||
g.add_player(p2)
|
||||
p3 = Player('p3', 'p3', sio)
|
||||
p3 = Player('p3', 'p3')
|
||||
g.add_player(p3)
|
||||
assert p1.role == None
|
||||
assert p2.role == None
|
||||
@ -37,20 +36,20 @@ def test_game_start():
|
||||
|
||||
# test that dodge_city is added to games with more than 8 players
|
||||
def test_dodge_city():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
|
||||
g = Game('test')
|
||||
for i in range(9):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
assert 'dodge_city' in g.expansions
|
||||
|
||||
# test that a game with 2 players has only renegade as role
|
||||
def test_renegade_only():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
p1 = Player('p1', 'p1', sio)
|
||||
|
||||
g = Game('test')
|
||||
p1 = Player('p1', 'p1')
|
||||
g.add_player(p1)
|
||||
p2 = Player('p2', 'p2', sio)
|
||||
p2 = Player('p2', 'p2')
|
||||
g.add_player(p2)
|
||||
g.start_game()
|
||||
assert isinstance(g.players[0].role, Renegade)
|
||||
@ -58,10 +57,10 @@ def test_renegade_only():
|
||||
|
||||
# test that a game with 3 player has Renegade, Vice and Outlaw as roles
|
||||
def test_renegade_vice_outlaw():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
|
||||
g = Game('test')
|
||||
for i in range(3):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
roles = {p.role.name for p in g.players}
|
||||
@ -69,10 +68,10 @@ def test_renegade_vice_outlaw():
|
||||
|
||||
# test that a game with 4 players has all roles except the deputy
|
||||
def test_4_players_roles():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
|
||||
g = Game('test')
|
||||
for i in range(4):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
roles = {p.role.name for p in g.players}
|
||||
@ -80,10 +79,10 @@ def test_4_players_roles():
|
||||
|
||||
# test that a game with 5 players has all roles
|
||||
def test_5_players_roles():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
|
||||
g = Game('test')
|
||||
for i in range(5):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
roles = {p.role.name for p in g.players}
|
||||
|
@ -1,5 +1,4 @@
|
||||
from bang.characters import Character
|
||||
from tests.dummy_socket import DummySocket
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player, PendingAction
|
||||
@ -8,10 +7,9 @@ from bang.cards import *
|
||||
|
||||
# test that a game with 3 player the deputy kills renegade and wins
|
||||
def test_3p_deputy_win():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
g = Game('test')
|
||||
for i in range(3):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
for p in g.players:
|
||||
@ -33,10 +31,9 @@ def test_3p_deputy_win():
|
||||
|
||||
# test that a game with 3 player the renegade kills the outlaw and wins
|
||||
def test_3p_renegade_win():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
g = Game('test')
|
||||
for i in range(3):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
for p in g.players:
|
||||
@ -60,10 +57,9 @@ def test_3p_renegade_win():
|
||||
|
||||
# test that a game with 3 player the outlaw kills the deputy and wins
|
||||
def test_3p_outlaw_win():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
g = Game('test')
|
||||
for i in range(3):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
for p in g.players:
|
||||
@ -87,10 +83,9 @@ def test_3p_outlaw_win():
|
||||
|
||||
# test that a game with 4 player the outlaw kills the sheriff and win
|
||||
def test_4p_outlaw_win():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
g = Game('test')
|
||||
for i in range(4):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
for p in g.players:
|
||||
@ -116,10 +111,9 @@ def test_4p_outlaw_win():
|
||||
|
||||
# test that a game with 5 player the renegade kills all the other players and wins
|
||||
def test_5p_renegade_gatling_win():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
g = Game('test')
|
||||
for i in range(5):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
for p in g.players:
|
||||
@ -148,10 +142,9 @@ def test_5p_renegade_gatling_win():
|
||||
|
||||
# test that a game with 5 player the renegade kills all the other players and wins
|
||||
def test_5p_renegade_indiani_win():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
g = Game('test')
|
||||
for i in range(5):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
for p in g.players:
|
||||
@ -180,10 +173,9 @@ def test_5p_renegade_indiani_win():
|
||||
|
||||
# test that a game with 5 player the renegade kills the sheriff but it isn't the last alive player and the outlaws wins
|
||||
def test_5p_outlaw_death_win():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
g = Game('test')
|
||||
for i in range(5):
|
||||
p = Player(f'p{i}', f'p{i}', sio)
|
||||
p = Player(f'p{i}', f'p{i}')
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
for p in g.players:
|
||||
|
@ -1,7 +1,6 @@
|
||||
from random import randint
|
||||
from bang.characters import Character
|
||||
from bang.expansions.the_valley_of_shadows.cards import *
|
||||
from tests.dummy_socket import DummySocket
|
||||
from bang.deck import Deck
|
||||
from bang.game import Game
|
||||
from bang.players import Player, PendingAction
|
||||
@ -9,9 +8,8 @@ import bang.cards as cs
|
||||
|
||||
# test UltimoGiro
|
||||
def test_ultimo_giro():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -28,9 +26,8 @@ def test_ultimo_giro():
|
||||
|
||||
# test Tomahawk
|
||||
def test_tomahawk():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(6)]
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(6)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -48,9 +45,8 @@ def test_tomahawk():
|
||||
|
||||
# test Fantasma
|
||||
def test_fantasma():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -73,9 +69,8 @@ def test_fantasma():
|
||||
|
||||
# test SerpenteASonagli
|
||||
def test_serpente_a_sonagli():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -107,10 +102,9 @@ def test_serpente_a_sonagli():
|
||||
|
||||
# test RitornoDiFiamma
|
||||
def test_ritorno_di_fiamma():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
g = Game('test')
|
||||
g.expansions = ['the_valley_of_shadows']
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -144,9 +138,8 @@ def test_ritorno_di_fiamma():
|
||||
|
||||
# test RitornoDiFiamma with gatling
|
||||
def test_ritorno_di_fiamma_gatling():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
g.expansions = ['the_valley_of_shadows']
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
@ -177,9 +170,8 @@ def test_ritorno_di_fiamma_gatling():
|
||||
|
||||
# test Taglia
|
||||
def test_taglia():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(3)]
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(3)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -201,9 +193,8 @@ def test_taglia():
|
||||
|
||||
# test Bandidos
|
||||
def test_bandidos():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -233,9 +224,8 @@ def test_bandidos():
|
||||
|
||||
# test Poker
|
||||
def test_poker():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
@ -265,9 +255,8 @@ def test_poker():
|
||||
|
||||
# test Tornado
|
||||
def test_tornado():
|
||||
sio = DummySocket()
|
||||
g = Game('test', sio)
|
||||
ps = [Player(f'p{i}', f'p{i}', sio) for i in range(2)]
|
||||
g = Game('test')
|
||||
ps = [Player(f'p{i}', f'p{i}') for i in range(2)]
|
||||
for p in ps:
|
||||
g.add_player(p)
|
||||
g.start_game()
|
||||
|
153
frontend/src/components/DeadRoleNotification.vue
Normal file
153
frontend/src/components/DeadRoleNotification.vue
Normal file
@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<div id="overlay" class="center-stuff">
|
||||
<h1>{{text}}</h1>
|
||||
<div>
|
||||
<Card v-if="playerCard" :card="playerCard" />
|
||||
<Card v-if="playerRole" :card="playerRole" class="back"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Card from '@/components/Card.vue'
|
||||
|
||||
export default {
|
||||
name: 'DeadRoleNotification',
|
||||
components: {
|
||||
Card,
|
||||
},
|
||||
props: {
|
||||
playerCard: Object,
|
||||
playerRole: Object
|
||||
},
|
||||
data: () => ({
|
||||
|
||||
}),
|
||||
computed: {
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
mounted() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
#overlay {
|
||||
position: fixed; /* Sit on top of the page content */
|
||||
width: 100%; /* Full width (cover the whole page) */
|
||||
height: 100%; /* Full height (cover the whole page) */
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0,0,0,0.7); /* Black background with opacity */
|
||||
z-index: 2; /* Specify a stack order in case you're using a different order for other elements */
|
||||
/* display: flex; */
|
||||
color: white;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#overlay>div {
|
||||
margin:auto;
|
||||
position: relative;
|
||||
top:35%;
|
||||
text-align: center;
|
||||
width: 72pt;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
.card {
|
||||
width: 72pt;
|
||||
min-width:72pt;
|
||||
height: 120pt;
|
||||
position: absolute;
|
||||
}
|
||||
.card.avatarred{
|
||||
animation: slide-in-fwd-bottom 2s ease, puff-out-center 1s ease 2s, make-invisible 10s step-start 3s;
|
||||
}
|
||||
.card.back {
|
||||
animation: make-visible 3s step-end, wobble-ver-left 2s ease 3s;
|
||||
}
|
||||
@keyframes make-invisible {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes make-visible {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@keyframes wobble-ver-left {
|
||||
0% {
|
||||
transform:translateY(0) rotate(0);
|
||||
transform-origin:50% 50%;
|
||||
}
|
||||
15% {
|
||||
transform:translateY(-30px) rotate(-6deg);
|
||||
}
|
||||
30% {
|
||||
transform:translateY(15px) rotate(6deg);
|
||||
}
|
||||
45% {
|
||||
transform:translateY(-15px) rotate(-3.6deg);
|
||||
}
|
||||
60% {
|
||||
transform:translateY(9px) rotate(2.4deg);
|
||||
}
|
||||
75% {
|
||||
transform:translateY(-6px) rotate(-1.2deg);
|
||||
}
|
||||
100% {
|
||||
transform:translateY(0) rotate(0);
|
||||
transform-origin:50% 50%;
|
||||
}
|
||||
}
|
||||
@keyframes slide-in-fwd-bottom {
|
||||
0% {
|
||||
transform:translateZ(-1400px) translateY(800px);
|
||||
opacity:0;
|
||||
}
|
||||
100% {
|
||||
transform:translateZ(0) translateY(0);
|
||||
opacity:1;
|
||||
}
|
||||
}
|
||||
@keyframes puff-out-center {
|
||||
|
||||
0% {
|
||||
transform:scale(1);
|
||||
filter:blur(0);
|
||||
opacity:1;
|
||||
}
|
||||
100% {
|
||||
transform:scale(2);
|
||||
filter:blur(4px);
|
||||
opacity:0;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #0000;
|
||||
color: white;
|
||||
border: 2px solid white;
|
||||
transition-duration: 0.2s;
|
||||
width: 100pt;
|
||||
height: 24pt;
|
||||
border-radius: 12pt;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: white; /* Green */
|
||||
color: black;
|
||||
}
|
||||
</style>
|
@ -90,9 +90,12 @@
|
||||
<transition name="bounce">
|
||||
<div v-if="displayAdminStatus" id="admin-status">
|
||||
<input type="button" @click="displayAdminStatus = false" value="close"/>
|
||||
<Status deploy_key="ok"/>
|
||||
<Status deploy_key="ok" :onpage="false"/>
|
||||
</div>
|
||||
</transition>
|
||||
<transition name="bounce">
|
||||
<DeadRoleNotification v-if="deadRoleData" :playerCard="deadRoleData" :playerRole="deadRoleData.role"/>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -107,6 +110,7 @@ import Deck from './Deck.vue'
|
||||
import TinyHand from './TinyHand.vue'
|
||||
import FullScreenInput from './FullScreenInput.vue'
|
||||
import Status from './Status.vue'
|
||||
import DeadRoleNotification from './DeadRoleNotification.vue'
|
||||
|
||||
export default {
|
||||
name: 'Lobby',
|
||||
@ -119,7 +123,8 @@ export default {
|
||||
TinyHand,
|
||||
PrettyCheck,
|
||||
FullScreenInput,
|
||||
Status
|
||||
Status,
|
||||
DeadRoleNotification
|
||||
},
|
||||
data: () => ({
|
||||
username: '',
|
||||
@ -147,6 +152,7 @@ export default {
|
||||
displayAdminStatus: false,
|
||||
is_replay: false,
|
||||
turn: -1,
|
||||
deadRoleData: null,
|
||||
}),
|
||||
sockets: {
|
||||
room(data) {
|
||||
@ -174,6 +180,12 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
notify_dead_role(data) {
|
||||
this.deadRoleData = data
|
||||
setTimeout(() => {
|
||||
this.deadRoleData = null
|
||||
}, 4000);
|
||||
},
|
||||
debug(data) {
|
||||
this.debug_mode = data;
|
||||
},
|
||||
@ -191,28 +203,10 @@ export default {
|
||||
this.$router.push('/')
|
||||
}
|
||||
this.username = username
|
||||
// this.$socket.emit('get_cards', 'dodge_city')
|
||||
},
|
||||
mount_status() {
|
||||
this.displayAdminStatus = true
|
||||
},
|
||||
// cards_info(data) {
|
||||
// data = JSON.parse(data)
|
||||
// let bigthing = {}
|
||||
// let bigthing_eng = {}
|
||||
// data.forEach(x => {
|
||||
// bigthing[x.name] = {
|
||||
// name:x.name,
|
||||
// desc:x.desc,
|
||||
// }
|
||||
// bigthing_eng[x.name] = {
|
||||
// name:x.name,
|
||||
// desc:x.desc_eng,
|
||||
// }
|
||||
// })
|
||||
// console.log(JSON.stringify(bigthing))
|
||||
// console.log(JSON.stringify(bigthing_eng))
|
||||
// },
|
||||
change_username() {
|
||||
this.hasToSetUsername = true
|
||||
},
|
||||
@ -333,6 +327,7 @@ export default {
|
||||
icon: icon,
|
||||
is_character: true,
|
||||
avatar: player.avatar,
|
||||
is_player: true
|
||||
}
|
||||
},
|
||||
startGame() {
|
||||
|
@ -92,6 +92,7 @@ export default {
|
||||
icon: '🤠',
|
||||
is_character: true,
|
||||
avatar: this.discordPic,
|
||||
is_player: true
|
||||
}
|
||||
},
|
||||
version() {
|
||||
|
@ -245,6 +245,7 @@ export default {
|
||||
icon: this.noStar ? player.icon : player.is_sheriff ? '⭐' : '🤠',
|
||||
avatar: player.avatar,
|
||||
is_character: true,
|
||||
is_player: true
|
||||
}})
|
||||
return vis
|
||||
},
|
||||
@ -267,6 +268,7 @@ export default {
|
||||
alt_text: Array(player.lives+1).join('❤️')+Array(player.max_lives-player.lives+1).join('💀'),
|
||||
avatar: player.avatar,
|
||||
is_character: true,
|
||||
is_player: true
|
||||
}})
|
||||
if (this.card_against && this.card_against.can_target_self) {
|
||||
vis.push({
|
||||
@ -274,6 +276,7 @@ export default {
|
||||
number: 0,
|
||||
icon: this.$t('you'),
|
||||
is_character: true,
|
||||
is_player: true
|
||||
})
|
||||
}
|
||||
return vis
|
||||
|
@ -3,6 +3,7 @@
|
||||
<h1 id="status">PewPew! Server Status</h1>
|
||||
<h2>Rooms {{rooms.length}}</h2>
|
||||
<button @click="refresh">reload</button>
|
||||
<button @click="reset">RESET</button>
|
||||
<ul>
|
||||
<li v-for="r in rooms" :key="r">
|
||||
<p style="margin:0"><b>name:</b> {{r.name}}</p>
|
||||
@ -37,7 +38,7 @@ export default {
|
||||
props: {
|
||||
onpage: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data:()=>({
|
||||
@ -60,6 +61,11 @@ export default {
|
||||
refresh(){
|
||||
this.$socket.emit('get_all_rooms', this.deploy_key)
|
||||
},
|
||||
reset(){
|
||||
if (confirm('ARE YOU SURE? KICK EVERYONE AND RESET LOBBIES?'))
|
||||
this.$socket.emit('reset', {'key':this.deploy_key})
|
||||
this.refresh();
|
||||
},
|
||||
hide(room_name){
|
||||
this.$socket.emit('hide_toogle', {'key':this.deploy_key, 'room':room_name})
|
||||
setTimeout((()=>{
|
||||
|
Loading…
Reference in New Issue
Block a user