From dd2b7be1997e07871bf8b211a86b8abe0bd82bac Mon Sep 17 00:00:00 2001
From: Annalisa Xamin <82664061+annalisaxamin@users.noreply.github.com>
Date: Sat, 4 Feb 2023 19:30:19 +0000
Subject: [PATCH 01/17] add cards definitions
---
.../expansions/wild_west_show/card_events.py | 77 +++++++++++++++++++
.../expansions/wild_west_show/characters.py | 66 ++++++++++++++++
2 files changed, 143 insertions(+)
create mode 100644 backend/bang/expansions/wild_west_show/card_events.py
create mode 100644 backend/bang/expansions/wild_west_show/characters.py
diff --git a/backend/bang/expansions/wild_west_show/card_events.py b/backend/bang/expansions/wild_west_show/card_events.py
new file mode 100644
index 0000000..4fe6a1d
--- /dev/null
+++ b/backend/bang/expansions/wild_west_show/card_events.py
@@ -0,0 +1,77 @@
+import random
+
+from bang.expansions.fistful_of_cards.card_events import CardEvent
+
+
+class Bavaglio(CardEvent):
+ def __init__(self):
+ super().__init__("Bavaglio", "🤐")
+ # I giocatori non possono parlare (ma possono gesticolare, mugugnare...). Chi parla perde 1 punto vita.
+ # NOT IMPLEMENTED
+
+class Camposanto(CardEvent):
+ def __init__(self):
+ super().__init__("Camposanto", "⚰")
+ # All'inizio del proprio turno, ogni giocatore eliminato torna in gioco con 1 punto vita. Pesca il ruolo a caso fra quelli dei giocatori eliminati.
+
+class DarlingValentine(CardEvent):
+ def __init__(self):
+ super().__init__("Darling Valentine", "💋")
+ # All'inizio del proprio turno, ogni giocatore scarta le carte in mano e ne pesca dal mazzo altrettante.
+
+class DorothyRage(CardEvent):
+ def __init__(self):
+ super().__init__("Dorothy Rage", "👩⚖️")
+ # Nel proprio turno, ogni giocatore può obbligarne un altro a giocare una carta.
+
+class HelenaZontero(CardEvent):
+ def __init__(self):
+ super().__init__("Helena Zontero", "💞")
+ # Quando Helena entra in gioco, "estrai!": se esce Cuori o Quadri, rimescola i ruoli attivi tranne lo Sceriffo, e ridistribuiscili a caso.
+
+class LadyRosaDelTexas(CardEvent):
+ def __init__(self):
+ super().__init__("Lady Rosa del Texas", "🩰")
+ # Nel proprio turno, ogni giocatore può scambiarsi di posto con quello alla sua destra, il quale salta il prossimo turno.
+
+class MissSusanna(CardEvent):
+ def __init__(self):
+ super().__init__("Miss Susanna", "👩🎤")
+ # Nel proprio turno ogni giocatore deve giocare almeno 3 carte. Se non lo fa, perde 1 punto vita.
+
+class RegolamentoDiConti(CardEvent):
+ def __init__(self):
+ super().__init__("Regolamento di conti", "🤠")
+ # Tutte le carte possono essere giocate come se fossero BANG!. Le carte BANG! come se fossero Mancato!
+
+class Sacagaway(CardEvent):
+ def __init__(self):
+ super().__init__("Sacagaway", "🏇")
+ # Tutti i giocatori giocano a carte scoperte (tranne il ruolo!).
+
+class WildWestShow(CardEvent):
+ def __init__(self):
+ super().__init__("Wild West Show", "🎪")
+ # L'obiettivo di ogni giocatore diventa: "Rimani l'ultimo in gioco!"
+
+def get_endgame_card():
+ end_game = WildWestShow()
+ end_game.expansion = 'wild-west-show'
+ return end_game
+
+def get_all_events(rng=random):
+ cards = [
+ Bavaglio(),
+ Camposanto(),
+ DarlingValentine(),
+ DorothyRage(),
+ HelenaZontero(),
+ LadyRosaDelTexas(),
+ MissSusanna(),
+ RegolamentoDiConti(),
+ Sacagaway(),
+ ]
+ rng.shuffle(cards)
+ for c in cards:
+ c.expansion = 'wild-west-show'
+ return cards
\ No newline at end of file
diff --git a/backend/bang/expansions/wild_west_show/characters.py b/backend/bang/expansions/wild_west_show/characters.py
new file mode 100644
index 0000000..2ec8e77
--- /dev/null
+++ b/backend/bang/expansions/wild_west_show/characters.py
@@ -0,0 +1,66 @@
+from typing import List
+from bang.characters import Character
+
+class BigSpencer(Character):
+ def __init__(self):
+ super().__init__("Big Spencer", max_lives=9)
+ # Inizia con 5 carte. Non può giocare Mancato!
+ self.icon = '🫘'
+
+class FlintWestwood(Character):
+ def __init__(self):
+ super().__init__("Flint Westwood", max_lives=4)
+ # Nel suo turno può scambiare una carta dalla mano con 2 carte a caso dalla mano di un altro giocatore.
+ self.icon = '🔫'
+
+class GaryLooter(Character):
+ def __init__(self):
+ super().__init__("Gary Looter", max_lives=5)
+ # Pesca tutte le carte in eccesso scartate dagli altri giocatori a fine turno.
+ self.icon = '🥲'
+
+class GreygoryDeckard(Character):
+ def __init__(self):
+ super().__init__("Greygory Deckard", max_lives=4)
+ # All'inizio del suo turno può pescare 2 personaggi a caso. Ha tutte le abilità dei personaggi pescati.
+ self.icon = '👨🦳'
+
+class JohnPain(Character):
+ def __init__(self):
+ super().__init__("John Pain", max_lives=4)
+ # Se ha meno di 6 carte in mano, quando un giocatore "estrae!" John aggiunge alla mano la carta appena estratta.
+ self.icon = '🤕'
+
+class LeeVanKliff(Character):
+ def __init__(self):
+ super().__init__("Lee Van Kliff", max_lives=4)
+ # Nel suo turno, può scartare un BANG! per ripetere l'effetto di una carta a bordo marrone che ha appena giocato.
+ self.icon = '👨🦲'
+
+class TerenKill(Character):
+ def __init__(self):
+ super().__init__("Teren Kill", max_lives=3)
+ # Ogni volta che sarebbe eliminato "estrai!": se non è Picche, Teren resta a 1 punto vita e pesca 1 carta.
+ self.icon = '👨🦰'
+
+class YoulGrinner(Character):
+ def __init__(self):
+ super().__init__("Youl Grinner", max_lives=4)
+ # Prima di pescare, i giocatori con più carte in mano di lui devono dargli una carta a scelta.
+ self.icon = '🤡'
+
+def all_characters() -> List[Character]:
+ cards = [
+ BigSpencer(),
+ FlintWestwood(),
+ GaryLooter(),
+ GreygoryDeckard(),
+ JohnPain(),
+ LeeVanKliff(),
+ TerenKill(),
+ YoulGrinner(),
+ ]
+ for c in cards:
+ c.expansion_icon = '🎪'
+ c.expansion = 'wild_west_show'
+ return cards
From 035fbb161da3a413e1ff7b7d9eff5fc680b1ef09 Mon Sep 17 00:00:00 2001
From: Annalisa Xamin <82664061+annalisaxamin@users.noreply.github.com>
Date: Sat, 4 Feb 2023 20:19:37 +0000
Subject: [PATCH 02/17] register expansion
---
backend/bang/characters.py | 2 ++
backend/bang/expansions/__init__.py | 5 +++++
2 files changed, 7 insertions(+)
diff --git a/backend/bang/characters.py b/backend/bang/characters.py
index 620599a..5117b81 100644
--- a/backend/bang/characters.py
+++ b/backend/bang/characters.py
@@ -177,4 +177,6 @@ def all_characters(expansions: List[str]):
base_chars.extend(GoldRush.get_characters())
if 'the_valley_of_shadows' in expansions:
base_chars.extend(TheValleyOfShadows.get_characters())
+ if 'wild_west_show' in expansions:
+ base_chars.extend(WildWestShow.get_characters())
return base_chars
\ No newline at end of file
diff --git a/backend/bang/expansions/__init__.py b/backend/bang/expansions/__init__.py
index ebae2dd..220866e 100644
--- a/backend/bang/expansions/__init__.py
+++ b/backend/bang/expansions/__init__.py
@@ -22,3 +22,8 @@ class TheValleyOfShadows():
def get_cards():
from bang.expansions.the_valley_of_shadows import cards
return cards.get_starting_deck()
+
+class WildWestShow():
+ def get_characters():
+ from bang.expansions.wild_west_show import characters
+ return characters.all_characters()
\ No newline at end of file
From d1bd07c717f7b75355e6aef8ed290e3e44cdd592 Mon Sep 17 00:00:00 2001
From: Annalisa Xamin <82664061+annalisaxamin@users.noreply.github.com>
Date: Sat, 4 Feb 2023 20:19:44 +0000
Subject: [PATCH 03/17] add Flint Westwood
---
.../expansions/wild_west_show/characters.py | 25 +++++++++++++------
backend/bang/players.py | 23 ++++++++++++++++-
frontend/src/components/Player.vue | 1 +
3 files changed, 41 insertions(+), 8 deletions(-)
diff --git a/backend/bang/expansions/wild_west_show/characters.py b/backend/bang/expansions/wild_west_show/characters.py
index 2ec8e77..73c94a9 100644
--- a/backend/bang/expansions/wild_west_show/characters.py
+++ b/backend/bang/expansions/wild_west_show/characters.py
@@ -11,8 +11,19 @@ class FlintWestwood(Character):
def __init__(self):
super().__init__("Flint Westwood", max_lives=4)
# Nel suo turno può scambiare una carta dalla mano con 2 carte a caso dalla mano di un altro giocatore.
+ # NOTE: La carta dalla tua mano è a scelta, non a caso. Se il giocatore bersaglio ha una sola carta, ne ricevi solo una.
self.icon = '🔫'
+ def special(self, player, data):
+ if not player.is_my_turn or not any((len(p.hand) > 0 for p in player.game.get_alive_players())) or not super().special(player, data):
+ return False
+ from bang.players import PendingAction
+ player.available_cards = player.hand.copy()
+ player.choose_text = 'choose_flint_special'
+ player.pending_action = PendingAction.CHOOSE
+ player.special_use_count += 1
+ player.notify_self()
+
class GaryLooter(Character):
def __init__(self):
super().__init__("Gary Looter", max_lives=5)
@@ -51,14 +62,14 @@ class YoulGrinner(Character):
def all_characters() -> List[Character]:
cards = [
- BigSpencer(),
+ # BigSpencer(),
FlintWestwood(),
- GaryLooter(),
- GreygoryDeckard(),
- JohnPain(),
- LeeVanKliff(),
- TerenKill(),
- YoulGrinner(),
+ # GaryLooter(),
+ # GreygoryDeckard(),
+ # JohnPain(),
+ # LeeVanKliff(),
+ # TerenKill(),
+ # YoulGrinner(),
]
for c in cards:
c.expansion_icon = '🎪'
diff --git a/backend/bang/players.py b/backend/bang/players.py
index 8bcd78f..034be39 100644
--- a/backend/bang/players.py
+++ b/backend/bang/players.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from enum import IntEnum
import json
-from random import random, randrange, sample, uniform
+from random import random, randrange, sample, uniform, randint
import socketio
import bang.deck as deck
import bang.roles as r
@@ -918,6 +918,27 @@ class Player:
self.pending_action = PendingAction.WAIT
self.game.responders_did_respond_resume_turn()
self.notify_self()
+ elif 'choose_flint_special' == self.choose_text:
+ if card_index < len(self.hand):
+ self.available_cards = [{
+ 'name': p.name,
+ 'icon': p.role.icon if(self.game.initial_players == 3) else '⭐️' if p['is_sheriff'] else '🤠',
+ 'avatar': p.avatar,
+ 'is_character': True,
+ 'is_player': True
+ } for p in self.game.get_alive_players() if p.name != self.name and len(p.hand) > 0]
+ self.choose_text = f'choose_flint_special;{card_index}'
+ self.notify_self()
+ elif 'choose_flint_special' in self.choose_text:
+ if card_index < len(self.available_cards):
+ my_card = self.hand.pop(int(self.choose_text.split(';')[1]))
+ other_player = self.game.get_player_named(self.available_cards[card_index]['name'])
+ for i in range(min(2, len(other_player.hand))):
+ self.hand.append(other_player.hand.pop(randint(0, len(other_player.hand)-1)))
+ other_player.hand.append(my_card)
+ other_player.notify_self()
+ self.pending_action = PendingAction.PLAY
+ self.notify_self()
elif self.game.check_event(ceh.NuovaIdentita) and self.choose_text == 'choose_nuova_identita':
if card_index == 1: # the other character
self.character = self.not_chosen_character
diff --git a/frontend/src/components/Player.vue b/frontend/src/components/Player.vue
index 685616e..c7ea4d7 100644
--- a/frontend/src/components/Player.vue
+++ b/frontend/src/components/Player.vue
@@ -36,6 +36,7 @@
+
{{$t('hand')}}
From e68be77edc8d75a19c9fc1adffce5e16c20b42f1 Mon Sep 17 00:00:00 2001
From: Annalisa Xamin <82664061+annalisaxamin@users.noreply.github.com>
Date: Sat, 4 Feb 2023 20:28:19 +0000
Subject: [PATCH 04/17] add choose_flint_special localization
---
frontend/src/i18n/en.json | 1 +
frontend/src/i18n/it.json | 1 +
2 files changed, 2 insertions(+)
diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json
index 3bd627c..2cb0f2c 100644
--- a/frontend/src/i18n/en.json
+++ b/frontend/src/i18n/en.json
@@ -77,6 +77,7 @@
"choose_ricercato": "Choose who you will play Wanted against.",
"choose_birra_function": "Choose between getting 1 gold nugget by discarding beer or if you want to play the beer.",
"choose_play_as_bang": "Choose which card to play as Bang!",
+ "choose_flint_special": "Choose which card to swap.",
"emporio_others": "{0} is choosing which card to get from the General Store",
"you_died": "YOU DIED",
"spectate": "SPECTATE",
diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json
index afca9c4..4222422 100644
--- a/frontend/src/i18n/it.json
+++ b/frontend/src/i18n/it.json
@@ -77,6 +77,7 @@
"choose_ricercato": "Scegli il giocatore su cui vuoi giocare Ricercato",
"choose_birra_function": "Scegli tra ottenere 1 pepita scartando la birra oppure giocare la birra.",
"choose_play_as_bang": "Scegli che carta giocare come Bang!",
+ "choose_flint_special": "Scegli che carta scabiare.",
"emporio_others": "{0} sta scegliendo che carta prendere dall'emporio",
"you_died": "SEI MORTO",
"spectate": "SPETTATORE",
From d089cce48dd40ae03ad2cadfd564ee8a149eca0a Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 26 Feb 2023 16:14:56 +0000
Subject: [PATCH 05/17] add camposanto DarlingValentine
---
backend/bang/deck.py | 4 ++++
.../expansions/wild_west_show/card_events.py | 1 -
backend/bang/game.py | 21 ++++++++++++++-----
backend/bang/players.py | 6 ++++++
backend/server.py | 3 +++
frontend/src/components/Card.vue | 6 +++++-
frontend/src/components/Lobby.vue | 2 +-
frontend/src/utils/emoji-map.js | 1 +
frontend/src/utils/expansions-map.js | 6 ++++++
9 files changed, 42 insertions(+), 8 deletions(-)
diff --git a/backend/bang/deck.py b/backend/bang/deck.py
index 5c49d6d..cf6aedf 100644
--- a/backend/bang/deck.py
+++ b/backend/bang/deck.py
@@ -3,6 +3,7 @@ import random
import bang.cards as cs
import bang.expansions.fistful_of_cards.card_events as ce
import bang.expansions.high_noon.card_events as ceh
+import bang.expansions.wild_west_show.card_events as cew
import bang.expansions.gold_rush.shop_cards as grc
from globals import G
@@ -33,6 +34,9 @@ class Deck:
if 'high_noon' in game.expansions:
self.event_cards.extend(ceh.get_all_events(game.rng))
endgame_cards.append(ceh.get_endgame_card())
+ if 'wild_west_show' in game.expansions:
+ self.event_cards.extend(cew.get_all_events(game.rng))
+ endgame_cards.append(cew.get_endgame_card())
if len(self.event_cards) > 0:
game.rng.shuffle(self.event_cards)
self.event_cards = self.event_cards[:12]
diff --git a/backend/bang/expansions/wild_west_show/card_events.py b/backend/bang/expansions/wild_west_show/card_events.py
index 4fe6a1d..bc98b5c 100644
--- a/backend/bang/expansions/wild_west_show/card_events.py
+++ b/backend/bang/expansions/wild_west_show/card_events.py
@@ -61,7 +61,6 @@ def get_endgame_card():
def get_all_events(rng=random):
cards = [
- Bavaglio(),
Camposanto(),
DarlingValentine(),
DorothyRage(),
diff --git a/backend/bang/game.py b/backend/bang/game.py
index 82f006e..816add5 100644
--- a/backend/bang/game.py
+++ b/backend/bang/game.py
@@ -12,6 +12,7 @@ from bang.deck import Deck
import bang.roles as roles
import bang.expansions.fistful_of_cards.card_events as ce
import bang.expansions.high_noon.card_events as ceh
+import bang.expansions.wild_west_show.card_events as cew
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
@@ -61,7 +62,7 @@ class Game:
self.initial_players = 0
self.password = ''
self.expansions: List[str] = []
- self.available_expansions = ['dodge_city', 'fistful_of_cards', 'high_noon', 'gold_rush', 'the_valley_of_shadows']
+ self.available_expansions = ['dodge_city', 'fistful_of_cards', 'high_noon', 'gold_rush', 'the_valley_of_shadows', 'wild_west_show']
self.shutting_down = False
self.is_competitive = False
self.disconnect_bot = True
@@ -78,6 +79,7 @@ class Game:
self.attack_in_progress = False
self.characters_to_distribute = 2 # personaggi da dare a inizio partita
self.debug = self.name == 'debug'
+ self.dead_roles: List[roles.Role] = []
self.is_changing_pwd = False
self.is_hidden = False
self.rng = random.Random()
@@ -113,6 +115,7 @@ class Game:
self.incremental_turn = 0
self.turn = 0
self.pending_winners = []
+ self.dead_roles: List[roles.Role] = []
for p in self.players:
p.reset()
p.notify_self()
@@ -579,12 +582,16 @@ class Game:
Metrics.send_metric('incremental_turn', points=[self.incremental_turn], tags=[f'game:{self.SEED}'])
if self.players[self.turn].is_dead:
pl = sorted(self.get_dead_players(), key=lambda x:x.death_turn)[0]
- if self.check_event(ce.DeadMan) and not self.did_resuscitate_deadman and pl == self.players[self.turn]:
+ if self.check_event([ce.DeadMan, cew.Camposanto]) and not self.did_resuscitate_deadman and pl == self.players[self.turn]:
print(f'{self.name}: {self.players[self.turn]} is dead, revive')
- self.did_resuscitate_deadman = True
+ if self.check_event(ce.DeadMan):
+ self.did_resuscitate_deadman = True
+ pl.lives = 2
+ elif self.check_event(cew.Camposanto):
+ pl.lives = 1
+ pl.set_role = self.dead_roles.pop(random.randint(0, len(self.dead_roles)-1))
pl.is_dead = False
pl.is_ghost = False
- pl.lives = 2
self.deck.draw(player=pl)
self.deck.draw(player=pl)
if (ghost := next((c for c in pl.equipment if isinstance(c, tvosc.Fantasma)), None)) is not None:
@@ -762,6 +769,7 @@ class Game:
# if not disconnected:
# self.dead_players.append(corpse)
self.notify_room()
+ self.dead_roles.append(player.role)
G.sio.emit('chat_message', room=self.name, data=f'_died|{player.name}')
for p in self.players:
if not p.is_bot:
@@ -845,7 +853,10 @@ class Game:
def check_event(self, ev):
if self.deck is None or len(self.deck.event_cards) == 0: return False
- return isinstance(self.deck.event_cards[0], ev)
+ if isinstance(ev, type):
+ return isinstance(self.deck.event_cards[0], ev)
+ else:
+ return any(isinstance(self.deck.event_cards[0], evc) for evc in ev)
def get_visible_players(self, player: pl.Player): # returns a dictionary because we need to add the distance
pls = self.get_alive_players()
diff --git a/backend/bang/players.py b/backend/bang/players.py
index 034be39..509edf2 100644
--- a/backend/bang/players.py
+++ b/backend/bang/players.py
@@ -11,6 +11,7 @@ import bang.characters as chars
import bang.expansions.dodge_city.characters as chd
import bang.expansions.fistful_of_cards.card_events as ce
import bang.expansions.high_noon.card_events as ceh
+import bang.expansions.wild_west_show.card_events as cew
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
@@ -453,6 +454,11 @@ class Player:
self.has_played_bang = False
self.special_use_count = 0
self.bang_used = 0
+ if self.game.check_event(cew.DarlingValentine):
+ hand = len(self.hand)
+ for _ in range(hand):
+ self.game.deck.scrap(self.hand.pop(0), True, player=self)
+ self.game.deck.draw(True, player=self)
if self.game.check_event(ceh.MezzogiornoDiFuoco):
self.lives -= 1
if any((isinstance(c, grc.Talismano) for c in self.gold_rush_equipment)):
diff --git a/backend/server.py b/backend/server.py
index c42dda1..6a21aa8 100644
--- a/backend/server.py
+++ b/backend/server.py
@@ -631,11 +631,14 @@ def chat_message(sid, msg, pl=None):
sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'🚨 {ses.name} is in debug mode and changed event'})
import bang.expansions.fistful_of_cards.card_events as ce
import bang.expansions.high_noon.card_events as ceh
+ import bang.expansions.wild_west_show.card_events as cew
chs = []
chs.extend(ce.get_all_events())
chs.append(ce.get_endgame_card())
chs.extend(ceh.get_all_events())
chs.append(ceh.get_endgame_card())
+ chs.extend(cew.get_all_events())
+ chs.append(cew.get_endgame_card())
ses.game.deck.event_cards.insert(int(cmd[1]), [c for c in chs if c is not None and c.name == ' '.join(cmd[2:])][0])
ses.game.notify_event_card()
elif '/removecard' in msg:
diff --git a/frontend/src/components/Card.vue b/frontend/src/components/Card.vue
index 9fd488b..fc83483 100644
--- a/frontend/src/components/Card.vue
+++ b/frontend/src/components/Card.vue
@@ -118,6 +118,10 @@ export default {
box-shadow:
0 0 0 3pt #6aa16e, 0 0 0 6pt var(--bg-color), 0 0 5pt 6pt #aaa
}
+.card.wild-west-show{
+ box-shadow: 0 0 0pt 4pt var(--bg-color), 0 0 5pt 4pt #aaa;
+ border: 2pt dotted #987e51;
+}
.card.high-noon{
box-shadow: 0 0 0pt 4pt var(--bg-color), 0 0 5pt 4pt #aaa;
border: 2pt dotted rgb(198 78 45);
@@ -230,7 +234,7 @@ export default {
.card.must-be-used {
filter: drop-shadow(0 0 5px red);
}
-.fistful-of-cards .emoji, .high-noon .emoji, .exp-pack .emoji{
+.fistful-of-cards .emoji, .high-noon .emoji, .card.wild-west-show .emoji, .exp-pack .emoji{
top:auto !important;
bottom:15% !important;
}
diff --git a/frontend/src/components/Lobby.vue b/frontend/src/components/Lobby.vue
index b9e06b1..15fd7a7 100644
--- a/frontend/src/components/Lobby.vue
+++ b/frontend/src/components/Lobby.vue
@@ -159,7 +159,7 @@ Card
password: '',
togglable_expansions: [],
expansions: [],
- beta_expansions: ['the_valley_of_shadows'],
+ beta_expansions: ['the_valley_of_shadows', 'wild_west_show'],
hasToSetUsername: false,
is_competitive: false,
disconnect_bot: false,
diff --git a/frontend/src/utils/emoji-map.js b/frontend/src/utils/emoji-map.js
index 7e61c32..ec5ec17 100644
--- a/frontend/src/utils/emoji-map.js
+++ b/frontend/src/utils/emoji-map.js
@@ -4,4 +4,5 @@ export const emojiMap = {
'high_noon': '🔥',
'fistful_of_cards': '🎴',
'the_valley_of_shadows': '👻',
+ 'wild_west_show': '🎪',
}
\ No newline at end of file
diff --git a/frontend/src/utils/expansions-map.js b/frontend/src/utils/expansions-map.js
index ae6a70e..b8b61d8 100644
--- a/frontend/src/utils/expansions-map.js
+++ b/frontend/src/utils/expansions-map.js
@@ -28,5 +28,11 @@ export const expansionsMap = {
icon: '👻',
back: true,
expansion: 'the-valley-of-shadows',
+ },
+ 'wild_west_show': {
+ name: 'Wild West Show',
+ icon: '🎪',
+ back: true,
+ expansion: 'wild-west-show'
}
}
\ No newline at end of file
From c4d23b6e379799336a684509536f241c931f361e Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 26 Feb 2023 16:39:36 +0000
Subject: [PATCH 06/17] add elena zontero
---
.../expansions/wild_west_show/card_events.py | 46 +++++++++++++------
backend/bang/game.py | 9 ++++
2 files changed, 41 insertions(+), 14 deletions(-)
diff --git a/backend/bang/expansions/wild_west_show/card_events.py b/backend/bang/expansions/wild_west_show/card_events.py
index bc98b5c..59009d8 100644
--- a/backend/bang/expansions/wild_west_show/card_events.py
+++ b/backend/bang/expansions/wild_west_show/card_events.py
@@ -3,56 +3,74 @@ import random
from bang.expansions.fistful_of_cards.card_events import CardEvent
-class Bavaglio(CardEvent):
- def __init__(self):
- super().__init__("Bavaglio", "🤐")
- # I giocatori non possono parlare (ma possono gesticolare, mugugnare...). Chi parla perde 1 punto vita.
- # NOT IMPLEMENTED
+# class Bavaglio(CardEvent):
+# def __init__(self):
+# super().__init__("Bavaglio", "🤐")
+# # I giocatori non possono parlare (ma possono gesticolare, mugugnare...). Chi parla perde 1 punto vita.
+# # NOT IMPLEMENTED
class Camposanto(CardEvent):
+ """
+ All'inizio del proprio turno, ogni giocatore eliminato torna in gioco con 1 punto vita. Pesca il ruolo a caso fra quelli dei giocatori eliminati.
+ """
def __init__(self):
super().__init__("Camposanto", "⚰")
- # All'inizio del proprio turno, ogni giocatore eliminato torna in gioco con 1 punto vita. Pesca il ruolo a caso fra quelli dei giocatori eliminati.
class DarlingValentine(CardEvent):
+ """
+ All'inizio del proprio turno, ogni giocatore scarta le carte in mano e ne pesca dal mazzo altrettante.
+ """
def __init__(self):
super().__init__("Darling Valentine", "💋")
- # All'inizio del proprio turno, ogni giocatore scarta le carte in mano e ne pesca dal mazzo altrettante.
class DorothyRage(CardEvent):
+ """
+ Nel proprio turno, ogni giocatore può obbligarne un altro a giocare una carta.
+ """
def __init__(self):
super().__init__("Dorothy Rage", "👩⚖️")
- # Nel proprio turno, ogni giocatore può obbligarne un altro a giocare una carta.
class HelenaZontero(CardEvent):
+ """
+ Quando Helena entra in gioco, "estrai!": se esce Cuori o Quadri, rimescola i ruoli attivi tranne lo Sceriffo, e ridistribuiscili a caso.
+ """
def __init__(self):
super().__init__("Helena Zontero", "💞")
- # Quando Helena entra in gioco, "estrai!": se esce Cuori o Quadri, rimescola i ruoli attivi tranne lo Sceriffo, e ridistribuiscili a caso.
class LadyRosaDelTexas(CardEvent):
+ """
+ Nel proprio turno, ogni giocatore può scambiarsi di posto con quello alla sua destra, il quale salta il prossimo turno.
+ """
def __init__(self):
super().__init__("Lady Rosa del Texas", "🩰")
- # Nel proprio turno, ogni giocatore può scambiarsi di posto con quello alla sua destra, il quale salta il prossimo turno.
class MissSusanna(CardEvent):
+ """
+ Nel proprio turno ogni giocatore deve giocare almeno 3 carte. Se non lo fa, perde 1 punto vita.
+ """
def __init__(self):
super().__init__("Miss Susanna", "👩🎤")
- # Nel proprio turno ogni giocatore deve giocare almeno 3 carte. Se non lo fa, perde 1 punto vita.
class RegolamentoDiConti(CardEvent):
+ """
+ Tutte le carte possono essere giocate come se fossero BANG!. Le carte BANG! come se fossero Mancato!
+ """
def __init__(self):
super().__init__("Regolamento di conti", "🤠")
- # Tutte le carte possono essere giocate come se fossero BANG!. Le carte BANG! come se fossero Mancato!
class Sacagaway(CardEvent):
+ """
+ Tutti i giocatori giocano a carte scoperte (tranne il ruolo!).
+ """
def __init__(self):
super().__init__("Sacagaway", "🏇")
- # Tutti i giocatori giocano a carte scoperte (tranne il ruolo!).
class WildWestShow(CardEvent):
+ """
+ L'obiettivo di ogni giocatore diventa: "Rimani l'ultimo in gioco!"
+ """
def __init__(self):
super().__init__("Wild West Show", "🎪")
- # L'obiettivo di ogni giocatore diventa: "Rimani l'ultimo in gioco!"
def get_endgame_card():
end_game = WildWestShow()
diff --git a/backend/bang/game.py b/backend/bang/game.py
index 816add5..9032ddf 100644
--- a/backend/bang/game.py
+++ b/backend/bang/game.py
@@ -610,6 +610,15 @@ class Game:
if len(self.deck.event_cards) > 0 and self.deck.event_cards[0] is not None:
print(f'{self.name}: flip new 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(cew.HelenaZontero):
+ c = self.deck.pick_and_scrap()
+ G.sio.emit('chat_message', room=self.name, data=f'_flipped|Helena Zontero|{c.name}|{c.num_suit()}')
+ if c.check_suit(self, [cs.Suit.HEARTS, cs.Suit.DIAMONDS]):
+ pls = (p for p in self.players if not isinstance(p.role, roles.Sheriff))
+ newroles = [p.role for p in pls]
+ random.shuffle(newroles)
+ for p in pls:
+ p.set_role(newroles.pop())
if self.check_event(ce.DeadMan):
self.did_resuscitate_deadman = False
elif self.check_event(ce.RouletteRussa):
From 5811821ccf3f45d657fbf9a26b81aabb434a8df8 Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 5 Mar 2023 16:49:52 +0000
Subject: [PATCH 07/17] add tests
---
.../expansions/wild_west_show/card_events.py | 2 +-
backend/bang/game.py | 3 +-
backend/tests/__init__.py | 38 +++++++++++-
backend/tests/wild_west_show_events_test.py | 60 +++++++++++++++++++
4 files changed, 100 insertions(+), 3 deletions(-)
create mode 100644 backend/tests/wild_west_show_events_test.py
diff --git a/backend/bang/expansions/wild_west_show/card_events.py b/backend/bang/expansions/wild_west_show/card_events.py
index 59009d8..016bdba 100644
--- a/backend/bang/expansions/wild_west_show/card_events.py
+++ b/backend/bang/expansions/wild_west_show/card_events.py
@@ -63,7 +63,7 @@ class Sacagaway(CardEvent):
Tutti i giocatori giocano a carte scoperte (tranne il ruolo!).
"""
def __init__(self):
- super().__init__("Sacagaway", "🏇")
+ super().__init__("Sacagaway", "🌄")
class WildWestShow(CardEvent):
"""
diff --git a/backend/bang/game.py b/backend/bang/game.py
index 9032ddf..452aa50 100644
--- a/backend/bang/game.py
+++ b/backend/bang/game.py
@@ -614,7 +614,8 @@ class Game:
c = self.deck.pick_and_scrap()
G.sio.emit('chat_message', room=self.name, data=f'_flipped|Helena Zontero|{c.name}|{c.num_suit()}')
if c.check_suit(self, [cs.Suit.HEARTS, cs.Suit.DIAMONDS]):
- pls = (p for p in self.players if not isinstance(p.role, roles.Sheriff))
+ G.sio.emit('chat_message', room=self.name, data=f'_swapped_roles|Helena Zontero|{c.name}|{c.num_suit()}')
+ pls = [p for p in self.players if not isinstance(p.role, roles.Sheriff)]
newroles = [p.role for p in pls]
random.shuffle(newroles)
for p in pls:
diff --git a/backend/tests/__init__.py b/backend/tests/__init__.py
index e79239c..fe53a50 100644
--- a/backend/tests/__init__.py
+++ b/backend/tests/__init__.py
@@ -1,3 +1,39 @@
+import pytest
+from bang.characters import Character
+from bang.game import Game
+from bang.players import Player
from tests.dummy_socket import DummySocket
from globals import G
-G.sio = DummySocket()
\ No newline at end of file
+G.sio = DummySocket()
+
+
+def started_game(expansions, players=4):
+ g = Game('test')
+ g.expansions = expansions
+ ps = [Player(f'p{i}', f'p{i}') for i in range(players)]
+ for p in ps:
+ g.add_player(p)
+ g.start_game()
+ for p in ps:
+ p.available_characters = [Character('test_char', 4)]
+ p.set_character(p.available_characters[0].name)
+ return g
+
+
+def set_events(g: Game, event_cards):
+ g.deck.event_cards = event_cards
+
+
+def current_player(g: Game):
+ return g.players[g.turn]
+
+
+def next_player(g: Game):
+ return g.players[(g.turn + 1) % len(g.players)]
+
+
+def current_player_with_cards(g: Game, cards):
+ p = current_player(g)
+ p.draw('')
+ p.hand = cards
+ return p
\ No newline at end of file
diff --git a/backend/tests/wild_west_show_events_test.py b/backend/tests/wild_west_show_events_test.py
new file mode 100644
index 0000000..3a7e4ba
--- /dev/null
+++ b/backend/tests/wild_west_show_events_test.py
@@ -0,0 +1,60 @@
+
+from tests import started_game, set_events, current_player, next_player, current_player_with_cards
+
+from bang.expansions.wild_west_show.card_events import *
+from bang.cards import Card, Suit
+
+
+# test Camposanto
+def test_camposanto():
+ g = started_game(['wild_west_show'], 4)
+ set_events(g, [Camposanto()])
+ current_player_with_cards(g, []).end_turn()
+ p = current_player_with_cards(g, [])
+ p.lives = 0
+ p.notify_self()
+ p1 = current_player_with_cards(g, [])
+ p1.lives = 0
+ p1.notify_self()
+ current_player_with_cards(g, []).end_turn()
+ current_player_with_cards(g, []).end_turn()
+ assert p.is_my_turn
+ assert p.lives == 1
+ current_player_with_cards(g, []).end_turn()
+ assert p1.is_my_turn
+ assert p1.lives == 1
+
+
+# test DarlingValentine
+def test_darling_valentine():
+ g = started_game(['wild_west_show'], 4)
+ set_events(g, [DarlingValentine()])
+ p = next_player(g)
+ hand = p.hand.copy()
+ current_player_with_cards(g, []).end_turn()
+ assert hand != current_player(g).hand
+
+
+# test DorothyRage
+
+# test HelenaZontero
+def test_helena_zontero():
+ g = started_game(['wild_west_show'], 6)
+ set_events(g, [None, HelenaZontero()])
+ roles = [p.role.name for p in g.players]
+ for i in range(5):
+ current_player_with_cards(g, []).end_turn()
+ g.deck.cards = [Card(Suit.HEARTS, 'card', 0)]*5
+ current_player_with_cards(g, []).end_turn()
+ roles2 = [p.role.name for p in g.players]
+ assert roles != roles2
+
+# test LadyRosaDelTexas
+
+# test MissSusanna
+
+# test RegolamentoDiConti
+
+# test Sacagaway
+
+# test WildWestShow
\ No newline at end of file
From 9598a6f81196b4b60baa519bdd080ec9ddb8218a Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 5 Mar 2023 17:14:52 +0000
Subject: [PATCH 08/17] add Sacagaway
---
backend/bang/deck.py | 7 ++++--
.../expansions/wild_west_show/card_events.py | 8 +++---
backend/bang/game.py | 2 ++
frontend/src/components/Lobby.vue | 4 +--
frontend/src/components/TinyHand.vue | 25 ++++++++++++++-----
5 files changed, 32 insertions(+), 14 deletions(-)
diff --git a/backend/bang/deck.py b/backend/bang/deck.py
index cf6aedf..547d55c 100644
--- a/backend/bang/deck.py
+++ b/backend/bang/deck.py
@@ -1,4 +1,4 @@
-from typing import List, Set, Dict, Tuple, Optional
+from typing import List, Set, Dict, Tuple, Optional, TYPE_CHECKING
import random
import bang.cards as cs
import bang.expansions.fistful_of_cards.card_events as ce
@@ -7,8 +7,10 @@ import bang.expansions.wild_west_show.card_events as cew
import bang.expansions.gold_rush.shop_cards as grc
from globals import G
+if TYPE_CHECKING:
+ from bang.game import Game
class Deck:
- def __init__(self, game):
+ def __init__(self, game: 'Game'):
super().__init__()
self.cards: List[cs.Card] = cs.get_starting_deck(game.expansions)
self.mancato_cards: List[str] = []
@@ -58,6 +60,7 @@ class Deck:
if len(self.event_cards) > 0 and not (isinstance(self.event_cards[0], ce.PerUnPugnoDiCarte) or isinstance(self.event_cards[0], ceh.MezzogiornoDiFuoco)):
self.event_cards.append(self.event_cards.pop(0))
self.game.notify_event_card()
+ self.game.notify_all()
def fill_gold_rush_shop(self):
if not any((c is None for c in self.shop_cards)):
diff --git a/backend/bang/expansions/wild_west_show/card_events.py b/backend/bang/expansions/wild_west_show/card_events.py
index 016bdba..678bf08 100644
--- a/backend/bang/expansions/wild_west_show/card_events.py
+++ b/backend/bang/expansions/wild_west_show/card_events.py
@@ -81,11 +81,11 @@ def get_all_events(rng=random):
cards = [
Camposanto(),
DarlingValentine(),
- DorothyRage(),
+ # DorothyRage(),
HelenaZontero(),
- LadyRosaDelTexas(),
- MissSusanna(),
- RegolamentoDiConti(),
+ # LadyRosaDelTexas(),
+ # MissSusanna(),
+ # RegolamentoDiConti(),
Sacagaway(),
]
rng.shuffle(cards)
diff --git a/backend/bang/game.py b/backend/bang/game.py
index 452aa50..a317370 100644
--- a/backend/bang/game.py
+++ b/backend/bang/game.py
@@ -895,9 +895,11 @@ class Game:
def notify_all(self):
if self.started and self.replay_speed > 0:
+ show_cards = self.check_event(cew.Sacagaway)
data = [{
'name': p.name,
'ncards': len(p.hand),
+ 'hand_cards': [c.__dict__ for c in p.hand] if show_cards else [],
'equipment': [e.__dict__ for e in p.equipment],
'gold_rush_equipment': [e.__dict__ for e in p.gold_rush_equipment],
'lives': p.lives,
diff --git a/frontend/src/components/Lobby.vue b/frontend/src/components/Lobby.vue
index 15fd7a7..230f7fb 100644
--- a/frontend/src/components/Lobby.vue
+++ b/frontend/src/components/Lobby.vue
@@ -38,7 +38,7 @@
-
+ {{getActionEmoji(p)}}
@@ -24,6 +34,9 @@ export default {
animation-duration: 2s;
animation-iteration-count: infinite;
}
+.zoomable:hover {
+ z-index: 1;
+}
@keyframes updown {
0% {
top: 0;
From 9f5d03743786d6665ea80b828f7f3195b4570f90 Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 5 Mar 2023 17:31:23 +0000
Subject: [PATCH 09/17] add miss suzanna
---
backend/bang/game.py | 2 +-
backend/bang/players.py | 7 +++++++
backend/tests/wild_west_show_events_test.py | 20 ++++++++++++++++++--
3 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/backend/bang/game.py b/backend/bang/game.py
index a317370..deedb1c 100644
--- a/backend/bang/game.py
+++ b/backend/bang/game.py
@@ -619,7 +619,7 @@ class Game:
newroles = [p.role for p in pls]
random.shuffle(newroles)
for p in pls:
- p.set_role(newroles.pop())
+ p.set_role(newroles.pop(random.randint(0, len(newroles)-1)))
if self.check_event(ce.DeadMan):
self.did_resuscitate_deadman = False
elif self.check_event(ce.RouletteRussa):
diff --git a/backend/bang/players.py b/backend/bang/players.py
index 509edf2..623f7eb 100644
--- a/backend/bang/players.py
+++ b/backend/bang/players.py
@@ -89,6 +89,7 @@ class Player:
self.is_bot = bot
self.discord_token = discord_token
self.discord_id = None
+ self.played_cards = 0
self.avatar = ''
if self.is_bot:
self.avatar = robot_pictures[randrange(len(robot_pictures))]
@@ -440,6 +441,7 @@ class Player:
return self.end_turn(forced=True)
self.scrapped_cards = 0
self.setaccio_count = 0
+ self.played_cards = 0
self.can_play_ranch = True
self.is_playing_ranch = False
self.can_play_vendetta = can_play_vendetta
@@ -762,6 +764,8 @@ class Player:
if not self.game.is_replay:
Metrics.send_metric('play_card', points=[1], tags=[f'success:{did_play_card}', f'card:{card.name}', f'bot:{self.is_bot}', f'exp:{card.expansion if "expansion" in card.__dict__ else "vanilla"}'])
print("did play card:", did_play_card)
+ if did_play_card:
+ self.played_cards += 1
self.notify_self()
if self.is_bot:
return did_play_card or card.is_equipment or (card.usable_next_turn and not card.can_be_used_now)
@@ -1563,6 +1567,9 @@ class Player:
for i in range(len(self.equipment)):
self.game.deck.scrap(self.equipment.pop(), True)
self.is_my_turn = False
+ if self.played_cards < 3 and self.game.check_event(cew.MissSusanna):
+ self.lives -= 1
+ self.played_cards = 0
self.can_play_again_don_bell = True
self.committed_suit_manette = None
self.pending_action = PendingAction.WAIT
diff --git a/backend/tests/wild_west_show_events_test.py b/backend/tests/wild_west_show_events_test.py
index 3a7e4ba..f4f0763 100644
--- a/backend/tests/wild_west_show_events_test.py
+++ b/backend/tests/wild_west_show_events_test.py
@@ -39,10 +39,10 @@ def test_darling_valentine():
# test HelenaZontero
def test_helena_zontero():
- g = started_game(['wild_west_show'], 6)
+ g = started_game(['wild_west_show'], 8)
set_events(g, [None, HelenaZontero()])
roles = [p.role.name for p in g.players]
- for i in range(5):
+ for i in range(len(g.players)-1):
current_player_with_cards(g, []).end_turn()
g.deck.cards = [Card(Suit.HEARTS, 'card', 0)]*5
current_player_with_cards(g, []).end_turn()
@@ -52,6 +52,22 @@ def test_helena_zontero():
# test LadyRosaDelTexas
# test MissSusanna
+def test_miss_suzanna():
+ g = started_game(['wild_west_show'], 4)
+ set_events(g, [MissSusanna()])
+ p = current_player_with_cards(g, [])
+ p.end_turn()
+ assert p.lives == 4 # sceriffo 5-1
+ p = current_player_with_cards(g, [Card(0,'card',0)]*4)
+ p.play_card(0)
+ p.play_card(0)
+ p.play_card(0)
+ p.end_turn()
+ assert p.lives == 4
+ p = current_player_with_cards(g, [])
+ p.end_turn()
+ assert p.lives == 3
+
# test RegolamentoDiConti
From 47a099d6248ab3d54ae0db7249f1b84aae272bff Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 5 Mar 2023 17:46:26 +0000
Subject: [PATCH 10/17] add wild-west-show endgame
---
backend/bang/deck.py | 2 +-
backend/bang/game.py | 3 +++
backend/tests/wild_west_show_events_test.py | 10 +++++++++-
3 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/backend/bang/deck.py b/backend/bang/deck.py
index 547d55c..2b77836 100644
--- a/backend/bang/deck.py
+++ b/backend/bang/deck.py
@@ -57,7 +57,7 @@ class Deck:
print(f'Deck initialized with {len(self.cards)} cards')
def flip_event(self):
- if len(self.event_cards) > 0 and not (isinstance(self.event_cards[0], ce.PerUnPugnoDiCarte) or isinstance(self.event_cards[0], ceh.MezzogiornoDiFuoco)):
+ if len(self.event_cards) > 0 and not (isinstance(self.event_cards[0], ce.PerUnPugnoDiCarte) or isinstance(self.event_cards[0], ceh.MezzogiornoDiFuoco) or isinstance(self.event_cards[0], cew.WildWestShow)):
self.event_cards.append(self.event_cards.pop(0))
self.game.notify_event_card()
self.game.notify_all()
diff --git a/backend/bang/game.py b/backend/bang/game.py
index deedb1c..6c1d739 100644
--- a/backend/bang/game.py
+++ b/backend/bang/game.py
@@ -649,6 +649,9 @@ class Game:
if self.waiting_for != 0:
return
self.dalton_on = False
+ elif self.check_event(cew.WildWestShow):
+ for p in self.players:
+ p.set_role(roles.Renegade())
if self.check_event(ce.PerUnPugnoDiCarte) and len(self.players[self.turn].hand) > 0:
self.player_bangs = len(self.players[self.turn].hand)
diff --git a/backend/tests/wild_west_show_events_test.py b/backend/tests/wild_west_show_events_test.py
index f4f0763..6279d91 100644
--- a/backend/tests/wild_west_show_events_test.py
+++ b/backend/tests/wild_west_show_events_test.py
@@ -3,6 +3,7 @@ from tests import started_game, set_events, current_player, next_player, current
from bang.expansions.wild_west_show.card_events import *
from bang.cards import Card, Suit
+import bang.roles as roles
# test Camposanto
@@ -73,4 +74,11 @@ def test_miss_suzanna():
# test Sacagaway
-# test WildWestShow
\ No newline at end of file
+# test WildWestShow
+def test_miss_suzanna():
+ g = started_game(['wild_west_show'], 8)
+ set_events(g, [None, WildWestShow()])
+ for i in range(len(g.players)):
+ current_player_with_cards(g, []).end_turn()
+ for p in g.players:
+ assert isinstance(p.role, roles.Renegade)
\ No newline at end of file
From e33c2c3c48d72af2c404f4720802ed04472ee200 Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 5 Mar 2023 17:57:31 +0000
Subject: [PATCH 11/17] add RegolamentoDiConti
---
backend/bang/expansions/wild_west_show/card_events.py | 6 +++---
backend/bang/players.py | 6 ++++++
backend/tests/wild_west_show_events_test.py | 10 +++++++++-
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/backend/bang/expansions/wild_west_show/card_events.py b/backend/bang/expansions/wild_west_show/card_events.py
index 678bf08..6a72611 100644
--- a/backend/bang/expansions/wild_west_show/card_events.py
+++ b/backend/bang/expansions/wild_west_show/card_events.py
@@ -56,7 +56,7 @@ class RegolamentoDiConti(CardEvent):
Tutte le carte possono essere giocate come se fossero BANG!. Le carte BANG! come se fossero Mancato!
"""
def __init__(self):
- super().__init__("Regolamento di conti", "🤠")
+ super().__init__("Regolamento di Conti", "🤠")
class Sacagaway(CardEvent):
"""
@@ -84,8 +84,8 @@ def get_all_events(rng=random):
# DorothyRage(),
HelenaZontero(),
# LadyRosaDelTexas(),
- # MissSusanna(),
- # RegolamentoDiConti(),
+ MissSusanna(),
+ RegolamentoDiConti(),
Sacagaway(),
]
rng.shuffle(cards)
diff --git a/backend/bang/players.py b/backend/bang/players.py
index 623f7eb..3565a86 100644
--- a/backend/bang/players.py
+++ b/backend/bang/players.py
@@ -519,6 +519,12 @@ class Player:
self.choose_text = 'choose_cecchino'
self.pending_action = PendingAction.CHOOSE
self.notify_self()
+ if self.is_my_turn and self.pending_action == PendingAction.PLAY and pile == 'event' and self.game.check_event(cew.RegolamentoDiConti) and len(self.hand) > 0:
+ if not self.has_played_bang and any((self.get_sight() >= p['dist'] for p in self.game.get_visible_players(self))):
+ self.available_cards = self.hand.copy()
+ self.pending_action = PendingAction.CHOOSE
+ self.choose_text = 'choose_play_as_bang'
+ self.notify_self()
elif self.is_my_turn and self.pending_action == PendingAction.PLAY and pile == 'event' and self.game.check_event(ce.Rimbalzo) and any((c.name == cs.Bang(0,0).name for c in self.hand)):
self.available_cards = [{
'name': p.name,
diff --git a/backend/tests/wild_west_show_events_test.py b/backend/tests/wild_west_show_events_test.py
index 6279d91..a8813d1 100644
--- a/backend/tests/wild_west_show_events_test.py
+++ b/backend/tests/wild_west_show_events_test.py
@@ -4,6 +4,7 @@ from tests import started_game, set_events, current_player, next_player, current
from bang.expansions.wild_west_show.card_events import *
from bang.cards import Card, Suit
import bang.roles as roles
+from bang.players import PendingAction
# test Camposanto
@@ -52,6 +53,7 @@ def test_helena_zontero():
# test LadyRosaDelTexas
+
# test MissSusanna
def test_miss_suzanna():
g = started_game(['wild_west_show'], 4)
@@ -71,8 +73,14 @@ def test_miss_suzanna():
# test RegolamentoDiConti
+def test_miss_suzanna():
+ g = started_game(['wild_west_show'], 4)
+ set_events(g, [None, RegolamentoDiConti()])
+ p = current_player_with_cards(g, [Card(0,'card',0)]*4)
+ p.draw('event')
+ assert p.pending_action == PendingAction.CHOOSE
+ p.choose(0)
-# test Sacagaway
# test WildWestShow
def test_miss_suzanna():
From 3b568c987f9c27765038021f09161a2d0d46da2f Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 5 Mar 2023 18:08:01 +0000
Subject: [PATCH 12/17] add Lady Rosa del Texas
---
backend/bang/expansions/wild_west_show/card_events.py | 2 +-
backend/bang/players.py | 7 +++++++
backend/tests/wild_west_show_events_test.py | 8 +++++++-
3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/backend/bang/expansions/wild_west_show/card_events.py b/backend/bang/expansions/wild_west_show/card_events.py
index 6a72611..666f1e1 100644
--- a/backend/bang/expansions/wild_west_show/card_events.py
+++ b/backend/bang/expansions/wild_west_show/card_events.py
@@ -83,7 +83,7 @@ def get_all_events(rng=random):
DarlingValentine(),
# DorothyRage(),
HelenaZontero(),
- # LadyRosaDelTexas(),
+ LadyRosaDelTexas(),
MissSusanna(),
RegolamentoDiConti(),
Sacagaway(),
diff --git a/backend/bang/players.py b/backend/bang/players.py
index 3565a86..81c483d 100644
--- a/backend/bang/players.py
+++ b/backend/bang/players.py
@@ -525,6 +525,13 @@ class Player:
self.pending_action = PendingAction.CHOOSE
self.choose_text = 'choose_play_as_bang'
self.notify_self()
+ elif self.is_my_turn and self.pending_action == PendingAction.PLAY and pile == 'event' and self.game.check_event(cew.LadyRosaDelTexas):
+ nextp = self.game.next_player()
+ i, j = self.game.players_map[self.name], self.game.players_map[nextp.name]
+ self.game.players[i], self.game.players[j] = nextp, self
+ self.game.players_map[self.name], self.game.players_map[nextp.name] = j, i
+ self.game.turn = j
+ self.game.notify_all()
elif self.is_my_turn and self.pending_action == PendingAction.PLAY and pile == 'event' and self.game.check_event(ce.Rimbalzo) and any((c.name == cs.Bang(0,0).name for c in self.hand)):
self.available_cards = [{
'name': p.name,
diff --git a/backend/tests/wild_west_show_events_test.py b/backend/tests/wild_west_show_events_test.py
index a8813d1..505d460 100644
--- a/backend/tests/wild_west_show_events_test.py
+++ b/backend/tests/wild_west_show_events_test.py
@@ -52,7 +52,13 @@ def test_helena_zontero():
assert roles != roles2
# test LadyRosaDelTexas
-
+def test_miss_suzanna():
+ g = started_game(['wild_west_show'], 4)
+ set_events(g, [None, LadyRosaDelTexas()])
+ p = current_player_with_cards(g, [Card(0,'card',0)]*4)
+ t = g.turn
+ p.draw('event')
+ assert g.turn == t+1
# test MissSusanna
def test_miss_suzanna():
From 8f645cf82aed48b2d258e29e65a5030db3753837 Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 5 Mar 2023 18:22:15 +0000
Subject: [PATCH 13/17] add bigspencer
---
.../expansions/wild_west_show/characters.py | 38 +++++++++++++------
backend/bang/players.py | 7 ++++
2 files changed, 34 insertions(+), 11 deletions(-)
diff --git a/backend/bang/expansions/wild_west_show/characters.py b/backend/bang/expansions/wild_west_show/characters.py
index 73c94a9..3f76558 100644
--- a/backend/bang/expansions/wild_west_show/characters.py
+++ b/backend/bang/expansions/wild_west_show/characters.py
@@ -2,16 +2,20 @@ from typing import List
from bang.characters import Character
class BigSpencer(Character):
+ """
+ Inizia con 5 carte. Non può giocare Mancato!
+ """
def __init__(self):
super().__init__("Big Spencer", max_lives=9)
- # Inizia con 5 carte. Non può giocare Mancato!
self.icon = '🫘'
class FlintWestwood(Character):
+ """
+ Nel suo turno può scambiare una carta dalla mano con 2 carte a caso dalla mano di un altro giocatore.
+ > NOTE: La carta dalla tua mano è a scelta, non a caso. Se il giocatore bersaglio ha una sola carta, ne ricevi solo una.
+ """
def __init__(self):
super().__init__("Flint Westwood", max_lives=4)
- # Nel suo turno può scambiare una carta dalla mano con 2 carte a caso dalla mano di un altro giocatore.
- # NOTE: La carta dalla tua mano è a scelta, non a caso. Se il giocatore bersaglio ha una sola carta, ne ricevi solo una.
self.icon = '🔫'
def special(self, player, data):
@@ -25,44 +29,56 @@ class FlintWestwood(Character):
player.notify_self()
class GaryLooter(Character):
+ """
+ Pesca tutte le carte in eccesso scartate dagli altri giocatori a fine turno.
+ """
def __init__(self):
super().__init__("Gary Looter", max_lives=5)
- # Pesca tutte le carte in eccesso scartate dagli altri giocatori a fine turno.
self.icon = '🥲'
class GreygoryDeckard(Character):
+ """
+ All'inizio del suo turno può pescare 2 personaggi a caso. Ha tutte le abilità dei personaggi pescati.
+ """
def __init__(self):
super().__init__("Greygory Deckard", max_lives=4)
- # All'inizio del suo turno può pescare 2 personaggi a caso. Ha tutte le abilità dei personaggi pescati.
- self.icon = '👨🦳'
+ self.icon = '👨🦳'
class JohnPain(Character):
+ """
+ Se ha meno di 6 carte in mano, quando un giocatore "estrae!" John aggiunge alla mano la carta appena estratta.
+ """
def __init__(self):
super().__init__("John Pain", max_lives=4)
- # Se ha meno di 6 carte in mano, quando un giocatore "estrae!" John aggiunge alla mano la carta appena estratta.
self.icon = '🤕'
class LeeVanKliff(Character):
+ """
+ Nel suo turno, può scartare un BANG! per ripetere l'effetto di una carta a bordo marrone che ha appena giocato.
+ """
def __init__(self):
super().__init__("Lee Van Kliff", max_lives=4)
- # Nel suo turno, può scartare un BANG! per ripetere l'effetto di una carta a bordo marrone che ha appena giocato.
self.icon = '👨🦲'
class TerenKill(Character):
+ """
+ Ogni volta che sarebbe eliminato "estrai!": se non è Picche, Teren resta a 1 punto vita e pesca 1 carta.
+ """
def __init__(self):
super().__init__("Teren Kill", max_lives=3)
- # Ogni volta che sarebbe eliminato "estrai!": se non è Picche, Teren resta a 1 punto vita e pesca 1 carta.
self.icon = '👨🦰'
class YoulGrinner(Character):
+ """
+ Prima di pescare, i giocatori con più carte in mano di lui devono dargli una carta a scelta.
+ """
def __init__(self):
super().__init__("Youl Grinner", max_lives=4)
- # Prima di pescare, i giocatori con più carte in mano di lui devono dargli una carta a scelta.
self.icon = '🤡'
def all_characters() -> List[Character]:
cards = [
- # BigSpencer(),
+ BigSpencer(),
FlintWestwood(),
# GaryLooter(),
# GreygoryDeckard(),
diff --git a/backend/bang/players.py b/backend/bang/players.py
index 81c483d..d7ed5c9 100644
--- a/backend/bang/players.py
+++ b/backend/bang/players.py
@@ -12,6 +12,7 @@ import bang.expansions.dodge_city.characters as chd
import bang.expansions.fistful_of_cards.card_events as ce
import bang.expansions.high_noon.card_events as ceh
import bang.expansions.wild_west_show.card_events as cew
+import bang.expansions.wild_west_show.characters as chw
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
@@ -1132,6 +1133,8 @@ class Player:
self.expected_response = self.game.deck.mancato_cards.copy()
if self.character.check(self.game, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response:
self.expected_response.append(cs.Bang(0, 0).name)
+ if self.character.check(chw.BigSpencer):
+ self.expected_response = []
self.on_failed_response_cb = self.take_damage_response
self.notify_self()
@@ -1162,6 +1165,8 @@ class Player:
self.expected_response = self.game.deck.mancato_cards.copy()
if self.character.check(self.game, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response:
self.expected_response.append(cs.Bang(0, 0).name)
+ if self.character.check(chw.BigSpencer):
+ self.expected_response = []
self.on_failed_response_cb = self.take_no_damage_response
self.notify_self()
@@ -1258,6 +1263,8 @@ class Player:
self.expected_response = self.game.deck.mancato_cards_not_green_or_blue.copy()
if self.character.check(self.game, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response:
self.expected_response.append(cs.Bang(0, 0).name)
+ if self.character.check(chw.BigSpencer):
+ self.expected_response = []
if self.can_escape(card_name, with_mancato=False):
self.expected_response.append(tvosc.Fuga(0, 0).name)
if not no_dmg:
From 499763ffca317c86de0a3d95e068d6253116e19d Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 5 Mar 2023 18:30:05 +0000
Subject: [PATCH 14/17] add john pain
---
backend/bang/deck.py | 12 +++++++++++-
backend/bang/expansions/wild_west_show/characters.py | 2 +-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/backend/bang/deck.py b/backend/bang/deck.py
index 2b77836..4dd4f2b 100644
--- a/backend/bang/deck.py
+++ b/backend/bang/deck.py
@@ -4,6 +4,7 @@ import bang.cards as cs
import bang.expansions.fistful_of_cards.card_events as ce
import bang.expansions.high_noon.card_events as ceh
import bang.expansions.wild_west_show.card_events as cew
+import bang.expansions.wild_west_show.characters as chw
import bang.expansions.gold_rush.shop_cards as grc
from globals import G
@@ -83,7 +84,16 @@ class Deck:
def pick_and_scrap(self) -> cs.Card:
card = self.cards.pop(0)
- self.scrap_pile.append(card)
+ jpain = None
+ for p in self.game.players:
+ if isinstance(p, chw.JohnPain) and len(p.hand) < 6:
+ jpain = p
+ break
+ if jpain:
+ jpain.hand.append(card)
+ jpain.notify_self()
+ else:
+ self.scrap_pile.append(card)
if len(self.cards) == 0:
self.reshuffle()
self.game.notify_scrap_pile()
diff --git a/backend/bang/expansions/wild_west_show/characters.py b/backend/bang/expansions/wild_west_show/characters.py
index 3f76558..a7a1737 100644
--- a/backend/bang/expansions/wild_west_show/characters.py
+++ b/backend/bang/expansions/wild_west_show/characters.py
@@ -82,7 +82,7 @@ def all_characters() -> List[Character]:
FlintWestwood(),
# GaryLooter(),
# GreygoryDeckard(),
- # JohnPain(),
+ JohnPain(),
# LeeVanKliff(),
# TerenKill(),
# YoulGrinner(),
From e4f9cfc886e3733453a2e91734defe3d55e5cf26 Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 5 Mar 2023 19:49:34 +0000
Subject: [PATCH 15/17] fix johnpain, bigspencer and tests
---
backend/bang/deck.py | 2 +-
backend/bang/players.py | 6 +++---
backend/tests/wild_west_show_events_test.py | 10 +++++-----
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/backend/bang/deck.py b/backend/bang/deck.py
index 4dd4f2b..0cd14ab 100644
--- a/backend/bang/deck.py
+++ b/backend/bang/deck.py
@@ -86,7 +86,7 @@ class Deck:
card = self.cards.pop(0)
jpain = None
for p in self.game.players:
- if isinstance(p, chw.JohnPain) and len(p.hand) < 6:
+ if p.character.check(self.game, chw.JohnPain) and len(p.hand) < 6:
jpain = p
break
if jpain:
diff --git a/backend/bang/players.py b/backend/bang/players.py
index d7ed5c9..8907a58 100644
--- a/backend/bang/players.py
+++ b/backend/bang/players.py
@@ -1133,7 +1133,7 @@ class Player:
self.expected_response = self.game.deck.mancato_cards.copy()
if self.character.check(self.game, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response:
self.expected_response.append(cs.Bang(0, 0).name)
- if self.character.check(chw.BigSpencer):
+ if self.character.check(self.game, chw.BigSpencer):
self.expected_response = []
self.on_failed_response_cb = self.take_damage_response
self.notify_self()
@@ -1165,7 +1165,7 @@ class Player:
self.expected_response = self.game.deck.mancato_cards.copy()
if self.character.check(self.game, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response:
self.expected_response.append(cs.Bang(0, 0).name)
- if self.character.check(chw.BigSpencer):
+ if self.character.check(self.game, chw.BigSpencer):
self.expected_response = []
self.on_failed_response_cb = self.take_no_damage_response
self.notify_self()
@@ -1263,7 +1263,7 @@ class Player:
self.expected_response = self.game.deck.mancato_cards_not_green_or_blue.copy()
if self.character.check(self.game, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response:
self.expected_response.append(cs.Bang(0, 0).name)
- if self.character.check(chw.BigSpencer):
+ if self.character.check(self.game, chw.BigSpencer):
self.expected_response = []
if self.can_escape(card_name, with_mancato=False):
self.expected_response.append(tvosc.Fuga(0, 0).name)
diff --git a/backend/tests/wild_west_show_events_test.py b/backend/tests/wild_west_show_events_test.py
index 505d460..2f46b7d 100644
--- a/backend/tests/wild_west_show_events_test.py
+++ b/backend/tests/wild_west_show_events_test.py
@@ -52,9 +52,9 @@ def test_helena_zontero():
assert roles != roles2
# test LadyRosaDelTexas
-def test_miss_suzanna():
+def test_LadyRosaDelTexas():
g = started_game(['wild_west_show'], 4)
- set_events(g, [None, LadyRosaDelTexas()])
+ set_events(g, [LadyRosaDelTexas()])
p = current_player_with_cards(g, [Card(0,'card',0)]*4)
t = g.turn
p.draw('event')
@@ -79,9 +79,9 @@ def test_miss_suzanna():
# test RegolamentoDiConti
-def test_miss_suzanna():
+def test_RegolamentoDiConti():
g = started_game(['wild_west_show'], 4)
- set_events(g, [None, RegolamentoDiConti()])
+ set_events(g, [RegolamentoDiConti()])
p = current_player_with_cards(g, [Card(0,'card',0)]*4)
p.draw('event')
assert p.pending_action == PendingAction.CHOOSE
@@ -89,7 +89,7 @@ def test_miss_suzanna():
# test WildWestShow
-def test_miss_suzanna():
+def test_WildWestShow():
g = started_game(['wild_west_show'], 8)
set_events(g, [None, WildWestShow()])
for i in range(len(g.players)):
From d3a056cc6aa7ae29a9695fece64400ebc14a5b02 Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sat, 11 Mar 2023 22:51:34 +0200
Subject: [PATCH 16/17] add terenkill and youlgrinner
---
.../expansions/wild_west_show/characters.py | 4 +--
backend/bang/players.py | 12 +++++++
backend/tests/__init__.py | 4 +--
.../tests/wild_west_show_characters_test.py | 34 +++++++++++++++++++
backend/tests/wild_west_show_events_test.py | 2 +-
5 files changed, 51 insertions(+), 5 deletions(-)
create mode 100644 backend/tests/wild_west_show_characters_test.py
diff --git a/backend/bang/expansions/wild_west_show/characters.py b/backend/bang/expansions/wild_west_show/characters.py
index a7a1737..b8d28d1 100644
--- a/backend/bang/expansions/wild_west_show/characters.py
+++ b/backend/bang/expansions/wild_west_show/characters.py
@@ -84,8 +84,8 @@ def all_characters() -> List[Character]:
# GreygoryDeckard(),
JohnPain(),
# LeeVanKliff(),
- # TerenKill(),
- # YoulGrinner(),
+ TerenKill(),
+ YoulGrinner(),
]
for c in cards:
c.expansion_icon = '🎪'
diff --git a/backend/bang/players.py b/backend/bang/players.py
index 8907a58..afd5a43 100644
--- a/backend/bang/players.py
+++ b/backend/bang/players.py
@@ -265,6 +265,12 @@ class Player:
if isinstance(self.gold_rush_equipment[i], grc.Zaino):
self.gold_rush_equipment[i].play_card(self, None)
return # play card will notify the player
+ if self.character.check(self.game, chw.TerenKill):
+ picked: cs.Card = self.game.deck.pick_and_scrap()
+ 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]):
+ self.lives = 1
+ self.game.deck.draw(True, player=self)
if self.character.check(self.game, chars.SidKetchum) and len(self.hand) > 1 and self.lives == 0:
if self.game.players[self.game.turn] != self:
self.game.players[self.game.turn].pending_action = PendingAction.WAIT
@@ -573,6 +579,12 @@ class Player:
self.notify_self()
else:
self.pending_action = PendingAction.PLAY
+ if self.character.check(self.game, chw.YoulGrinner):
+ hsize = len(self.hand)
+ for p in self.game.get_alive_players():
+ if p != self and len(p.hand) > hsize:
+ G.sio.emit('card_drawn', room=self.game.name, data={'player': self.name, 'pile': p.name})
+ self.hand.append(p.hand.pop(randint(0, len(p.hand)-1)))
num = 2 if not self.character.check(self.game, chd.BillNoface) else self.max_lives-self.lives+1
if self.character.check(self.game, chd.PixiePete): num += 1
if self.character.check(self.game, tvosch.TucoFranziskaner) and not any((True for c in self.equipment if not c.usable_next_turn)): num += 2
diff --git a/backend/tests/__init__.py b/backend/tests/__init__.py
index fe53a50..dfa24b0 100644
--- a/backend/tests/__init__.py
+++ b/backend/tests/__init__.py
@@ -7,7 +7,7 @@ from globals import G
G.sio = DummySocket()
-def started_game(expansions, players=4):
+def started_game(expansions, players=4, character=Character('test_char', 4)):
g = Game('test')
g.expansions = expansions
ps = [Player(f'p{i}', f'p{i}') for i in range(players)]
@@ -15,7 +15,7 @@ def started_game(expansions, players=4):
g.add_player(p)
g.start_game()
for p in ps:
- p.available_characters = [Character('test_char', 4)]
+ p.available_characters = [character]
p.set_character(p.available_characters[0].name)
return g
diff --git a/backend/tests/wild_west_show_characters_test.py b/backend/tests/wild_west_show_characters_test.py
new file mode 100644
index 0000000..ca3ec32
--- /dev/null
+++ b/backend/tests/wild_west_show_characters_test.py
@@ -0,0 +1,34 @@
+
+from tests import started_game, set_events, current_player, next_player, current_player_with_cards
+
+from bang.expansions.wild_west_show.characters import *
+from bang.cards import Card, Suit
+import bang.roles as roles
+from bang.players import PendingAction
+
+
+# test TerenKill
+def test_TerenKill():
+ g = started_game(['wild_west_show'], 4, TerenKill())
+ p = current_player_with_cards(g, [])
+ p.lives = 0
+ g.deck.cards = [Card(Suit.HEARTS, 'card', 0), Card(Suit.HEARTS, 'card', 0)]
+ p.notify_self()
+ assert p.lives == 1
+ assert len(p.hand) == 1
+ p.lives = 0
+ g.deck.cards = [Card(Suit.SPADES, 'card', 0), Card(Suit.HEARTS, 'card', 0)]
+ p.notify_self()
+ assert p.lives == 0
+
+
+# test YoulGrinner
+def test_YoulGrinner():
+ g = started_game(['wild_west_show'], 4, YoulGrinner())
+ p = current_player(g)
+ p.hand = []
+ p.draw('')
+ assert len(p.hand) == 5
+ for pl in g.players:
+ if pl != p:
+ assert len(pl.hand) == 3
diff --git a/backend/tests/wild_west_show_events_test.py b/backend/tests/wild_west_show_events_test.py
index 2f46b7d..4a85cbc 100644
--- a/backend/tests/wild_west_show_events_test.py
+++ b/backend/tests/wild_west_show_events_test.py
@@ -58,7 +58,7 @@ def test_LadyRosaDelTexas():
p = current_player_with_cards(g, [Card(0,'card',0)]*4)
t = g.turn
p.draw('event')
- assert g.turn == t+1
+ assert g.turn == (t+1)%len(g.players)
# test MissSusanna
def test_miss_suzanna():
From 555e48a10a613072f4f240785c975422f50067dd Mon Sep 17 00:00:00 2001
From: Alberto Xamin
Date: Sun, 12 Mar 2023 11:44:09 +0000
Subject: [PATCH 17/17] allow for alpha status
---
backend/tests/__init__.py | 2 +-
frontend/src/components/Card.vue | 450 ++++----
frontend/src/components/Lobby.vue | 1432 +++++++++++++++-----------
frontend/src/utils/expansions-map.js | 8 +-
4 files changed, 1098 insertions(+), 794 deletions(-)
diff --git a/backend/tests/__init__.py b/backend/tests/__init__.py
index dfa24b0..02a3aa6 100644
--- a/backend/tests/__init__.py
+++ b/backend/tests/__init__.py
@@ -36,4 +36,4 @@ def current_player_with_cards(g: Game, cards):
p = current_player(g)
p.draw('')
p.hand = cards
- return p
\ No newline at end of file
+ return p
diff --git a/frontend/src/components/Card.vue b/frontend/src/components/Card.vue
index fc83483..a1540f7 100644
--- a/frontend/src/components/Card.vue
+++ b/frontend/src/components/Card.vue
@@ -1,271 +1,299 @@
-
-
{{cardName}}
-
-
{{emoji}}
-
{{card.alt_text}}
-
{{number}}{{suit}}
-
{{card.expansion_icon}}
-
+
+
{{ cardName }}
+
+
{{ emoji }}
+
{{ card.alt_text }}
+
+ {{ number
+ }}{{ suit }}
+
+
+ {{ card.expansion_icon }}
+
+
\ No newline at end of file
diff --git a/frontend/src/components/Lobby.vue b/frontend/src/components/Lobby.vue
index 230f7fb..61eab6b 100644
--- a/frontend/src/components/Lobby.vue
+++ b/frontend/src/components/Lobby.vue
@@ -1,622 +1,896 @@
-