From 374e7828ccb8487b0a767016de50ba898307d1fe Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sat, 19 Dec 2020 18:39:57 +0100 Subject: [PATCH 01/43] fix sync checkbox --- backend/bang/expansions/dodge_city/cards.py | 1 - frontend/src/components/Lobby.vue | 17 ++++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/backend/bang/expansions/dodge_city/cards.py b/backend/bang/expansions/dodge_city/cards.py index a431a58..981a48d 100644 --- a/backend/bang/expansions/dodge_city/cards.py +++ b/backend/bang/expansions/dodge_city/cards.py @@ -341,7 +341,6 @@ class FucileDaCaccia(Card): def get_starting_deck() -> List[Card]: return [ - #TODO: aggiungere anche le carte normalmente presenti https://bang.dvgiochi.com/cardslist.php?id=3 Barile(Suit.CLUBS, 'A'), Binocolo(Suit.DIAMONDS, 10), Dinamite(Suit.CLUBS, 10), diff --git a/frontend/src/components/Lobby.vue b/frontend/src/components/Lobby.vue index 567acbb..3633532 100644 --- a/frontend/src/components/Lobby.vue +++ b/frontend/src/components/Lobby.vue @@ -34,8 +34,8 @@

{{$t("expansions")}}

-
- {{get_expansion_name(ex)}} +
+ {{ex.name}}

{{$t('mods')}}

@@ -139,6 +139,15 @@ export default { inviteLink() { return `${window.location.origin}/game?code=${this.lobbyName}&pwd=${this.password}` }, + expansionsStatus() { + return this.togglable_expansions.map(x=>{ + return { + id: x, + name: x.replace(/(^|_)([a-z])/g, function($0,$1,$2) {return ' ' + $2.toUpperCase()}), + enabled: this.expansions.indexOf(x) !== -1 + } + }) + }, storedUsername() { if (localStorage.getItem('username')) return localStorage.getItem('username') @@ -174,11 +183,9 @@ export default { }, methods: { is_toggled_expansion(ex) { + console.log(ex+' '+ this.expansions+ (this.expansions.indexOf(ex) !== -1)) return this.expansions.indexOf(ex) !== -1 }, - get_expansion_name(ex) { - return ex.replace('_', ' ').replace(/\w\S*/g, m => m.charAt(0).toUpperCase()+m.substr(1).toLowerCase()) - }, leaveRoom() { window.location.replace(window.location.origin) }, From b2ba24906e5e7595613dad33aad40aaf3d69d4d0 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sat, 19 Dec 2020 19:31:59 +0100 Subject: [PATCH 02/43] routing improvements --- frontend/src/App.vue | 5 ++++- frontend/src/components/Lobby.vue | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index df07892..3de9eb3 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -39,7 +39,10 @@ export default { }, room(data) { this.isInLobby = true; - this.$router.push({path:'game', query: { code: data.name, pwd: data.password }}) + if (data.password) + this.$router.replace({path:'game', query: { code: data.name, pwd: data.password }}) + else + this.$router.replace({path:'game', query: { code: data.name }}) }, }, methods: { diff --git a/frontend/src/components/Lobby.vue b/frontend/src/components/Lobby.vue index 3633532..7f01be0 100644 --- a/frontend/src/components/Lobby.vue +++ b/frontend/src/components/Lobby.vue @@ -137,7 +137,7 @@ export default { }, computed: { inviteLink() { - return `${window.location.origin}/game?code=${this.lobbyName}&pwd=${this.password}` + return `${window.location.origin}/game?code=${this.lobbyName}${this.password?`&pwd=${this.password}`:''}` }, expansionsStatus() { return this.togglable_expansions.map(x=>{ From f29be68425a269bd948f3bec0b7757fb14fb3a41 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sat, 19 Dec 2020 19:46:35 +0100 Subject: [PATCH 03/43] service worker stuff --- frontend/src/App.vue | 21 +++++++++++++++++++++ frontend/src/registerServiceWorker.js | 12 ++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 3de9eb3..dce6cda 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -16,6 +16,15 @@ +
+

+ A new version is available. Refresh to load it? +

+
+ + +
+
@@ -26,6 +35,7 @@ export default { name: 'App', data: () => ({ isConnected: false, + c: false, }), computed: { }, @@ -48,12 +58,23 @@ export default { methods: { storeLangPref() { localStorage.setItem('lang', this.$i18n.locale) + }, + async update() { + this.showUpdateUI = false; + await this.$workbox.messageSW({ type: "SKIP_WAITING" }); } }, mounted() { if (localStorage.getItem('lang')) this.$i18n.locale = localStorage.getItem('lang') }, + created() { + if (this.$workbox) { + this.$workbox.addEventListener("waiting", () => { + this.showUpdateUI = true; + }); + } + } } diff --git a/frontend/src/registerServiceWorker.js b/frontend/src/registerServiceWorker.js index 95c424e..837d167 100644 --- a/frontend/src/registerServiceWorker.js +++ b/frontend/src/registerServiceWorker.js @@ -3,15 +3,15 @@ import { Workbox } from "workbox-window"; let wb; if ("serviceWorker" in navigator) { - wb = new Workbox(`${process.env.BASE_URL}service-worker.js`); + wb = new Workbox(`${process.env.BASE_URL}service-worker.js`); - wb.addEventListener("controlling", () => { - window.location.reload(); - }); + wb.addEventListener("controlling", () => { + window.location.reload(); + }); - wb.register(); + wb.register(); } else { - wb = null; + wb = null; } export default wb; \ No newline at end of file From 37f5ddd755a6a824453b593e4cf615ed08dde3d6 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sat, 19 Dec 2020 19:59:54 +0100 Subject: [PATCH 04/43] add liquore forte --- backend/bang/expansions/fistful_of_cards/card_events.py | 8 ++++---- backend/bang/game.py | 2 +- backend/bang/players.py | 6 +++++- frontend/src/components/Deck.vue | 7 ++++++- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 528d3b3..59d3ec8 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -48,10 +48,10 @@ class LeggeDelWest(CardEvent): self.desc_eng = 'Every player shows the second card that they draw and must use it in that round' class LiquoreForte(CardEvent): - def __init__(self):#TODO + def __init__(self): super().__init__('Liquore Forte', '🥃') - self.desc = 'I giocatori possono evitare di pescare per recuperare 1 vita' - self.desc_eng = 'Players can skip drawing to regain 1 HP' + self.desc = 'I giocatori possono evitare di pescare per recuperare 1 vita (clicca sulla carta evento per farlo)' + self.desc_eng = 'Players can skip drawing to regain 1 HP (click on the event card to use)' class MinieraAbbandonata(CardEvent): def __init__(self):#TODO @@ -104,7 +104,7 @@ def get_all_events(): IlGiudice(), Lazo(), LeggeDelWest(), - # LiquoreForte(), + LiquoreForte(), # MinieraAbbandonata(), # PerUnPugnoDiCarte(), # Peyote(), diff --git a/backend/bang/game.py b/backend/bang/game.py index 6057456..cfad973 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -24,7 +24,7 @@ class Game: self.initial_players = 0 self.password = '' self.expansions = [] - self.available_expansions = ['dodge_city'] + self.available_expansions = ['dodge_city', 'fistful_of_cards'] self.shutting_down = False self.is_competitive = False self.disconnect_bot = True diff --git a/backend/bang/players.py b/backend/bang/players.py index 2cea122..bfdea52 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -308,7 +308,11 @@ class Player: def draw(self, pile): if self.pending_action != PendingAction.DRAW: return - if isinstance(self.character, chars.KitCarlson): + if pile == 'event' and self.lives < self.max_lives and self.game.check_event(ce.LiquoreForte): + self.lives += 1 + self.pending_action = PendingAction.PLAY + self.notify_self() + elif isinstance(self.character, chars.KitCarlson): self.is_drawing = True self.available_cards = [self.game.deck.draw() for i in range(3)] self.pending_action = PendingAction.CHOOSE diff --git a/frontend/src/components/Deck.vue b/frontend/src/components/Deck.vue index 16766a3..f2e68c0 100644 --- a/frontend/src/components/Deck.vue +++ b/frontend/src/components/Deck.vue @@ -5,7 +5,7 @@
- +
@@ -79,6 +79,11 @@ export default { else if (this.pending_action == 1) this.$socket.emit('draw', pile) } + }, + event() { + if (this.pending_action !== false && this.pending_action < 2) { + this.$socket.emit('draw', 'event') + } } }, watch: { From 20e4ea51963a8527241653e15c3c0cb8809deee7 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 12:55:56 +0100 Subject: [PATCH 05/43] add peyote --- .../fistful_of_cards/card_events.py | 92 +++++++++---------- backend/bang/players.py | 21 +++++ frontend/src/i18n/en.json | 5 +- frontend/src/i18n/it.json | 5 +- 4 files changed, 75 insertions(+), 48 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 59d3ec8..01dd366 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -7,93 +7,93 @@ class CardEvent(ABC): class Agguato(CardEvent): def __init__(self): - super().__init__('Agguato', '🛁') - self.desc = 'La distanza base di tra 2 qualsiasi giocatori è 1' - self.desc_eng = 'The base distance from any 2 players is 1' + super().__init__("Agguato", "🛁") + self.desc = "La distanza base di tra 2 qualsiasi giocatori è 1" + self.desc_eng = "The base distance from any 2 players is 1" class Cecchino(CardEvent): def __init__(self): #TODO - super().__init__('Cecchino', '👁') - self.desc = 'Nel proprio turno i giocatori possono scartare 2 Bang assieme per sparare un bang a cui servono 2 mancato' - self.desc_eng = 'During their turn, players can discard 2 Bang! to shoot a bang that requires 2 missed' + super().__init__("Cecchino", "👁") + self.desc = "Nel proprio turno i giocatori possono scartare 2 Bang assieme per sparare un bang a cui servono 2 mancato" + self.desc_eng = "During their turn, players can discard 2 Bang! to shoot a bang that requires 2 missed" class DeadMan(CardEvent): def __init__(self): - super().__init__('Dead Man', '⚰️') - self.desc = 'Al proprio turno il giocatore che è morto per primo torna in vita con 2 vite e 2 carte' - self.desc_eng = 'The first player that died return back to life with 2 hp and 2 cards' + super().__init__("Dead Man", "⚰️") + self.desc = "Al proprio turno il giocatore che è morto per primo torna in vita con 2 vite e 2 carte" + self.desc_eng = "The first player that died return back to life with 2 hp and 2 cards" class FratelliDiSangue(CardEvent): def __init__(self):#TODO - super().__init__('Fratelli Di Sangue', '💉') - self.desc = 'All\'inizio del proprio turno i giocatori possono perdere 1 vita per darla a un altro giocatore' - self.desc_eng = 'At the begin of their turn, payers can lose 1 hp to give it to another player' + super().__init__("Fratelli Di Sangue", "💉") + self.desc = "All'inizio del proprio turno i giocatori possono perdere 1 vita per darla a un altro giocatore" + self.desc_eng = "At the begin of their turn, payers can lose 1 hp to give it to another player" class IlGiudice(CardEvent): def __init__(self): - super().__init__('Il Giudice', '👨‍⚖️') - self.desc = 'Non si possono equipaggiare carte a se stessi o agli altri' - self.desc_eng = 'You can\'t equip cards on your or other players' + super().__init__("Il Giudice", "👨‍⚖️") + self.desc = "Non si possono equipaggiare carte a se stessi o agli altri" + self.desc_eng = "You can't equip cards on your or other players" class Lazo(CardEvent): def __init__(self): - super().__init__('Lazo', '📿') - self.desc = 'Le carte equipaggiate non hanno effetto' - self.desc_eng = 'Cards in the equipment slot do not work' + super().__init__("Lazo", "📿") + self.desc = "Le carte equipaggiate non hanno effetto" + self.desc_eng = "Cards in the equipment slot do not work" class LeggeDelWest(CardEvent): def __init__(self): - super().__init__('Legge Del West', '⚖️') - self.desc = 'I giocatori mostrano la seconda carta che pescano e sono obbligati a usarla in quel turno (se possibile)' - self.desc_eng = 'Every player shows the second card that they draw and must use it in that round' + super().__init__("Legge Del West", "⚖️") + self.desc = "I giocatori mostrano la seconda carta che pescano e sono obbligati a usarla in quel turno (se possibile)" + self.desc_eng = "Every player shows the second card that they draw and must use it in that round" class LiquoreForte(CardEvent): def __init__(self): - super().__init__('Liquore Forte', '🥃') - self.desc = 'I giocatori possono evitare di pescare per recuperare 1 vita (clicca sulla carta evento per farlo)' - self.desc_eng = 'Players can skip drawing to regain 1 HP (click on the event card to use)' + super().__init__("Liquore Forte", "🥃") + self.desc = "I giocatori possono evitare di pescare per recuperare 1 vita (clicca sulla carta evento per farlo)" + self.desc_eng = "Players can skip drawing to regain 1 HP (click on the event card to use)" class MinieraAbbandonata(CardEvent): def __init__(self):#TODO - super().__init__('Miniera Abbandonata', '⛏') - self.desc = 'I giocatori pescano dagli scarti e scartano in cima al mazzo' - self.desc_eng = 'Players draw from the discarded pile and discard to the deck' + super().__init__("Miniera Abbandonata", "⛏") + self.desc = "I giocatori pescano dagli scarti e scartano in cima al mazzo" + self.desc_eng = "Players draw from the discarded pile and discard to the deck" class PerUnPugnoDiCarte(CardEvent): def __init__(self):#TODO - super().__init__('Per Un Pugno Di Carte', '🎴') - self.desc = 'Il giocatore subisce tanti bang quante carte ha in mano' - self.desc_eng = 'On his turn the player is target of as many Bang as how many cards he has in his hand' + super().__init__("Per Un Pugno Di Carte", "🎴") + self.desc = "Il giocatore subisce tanti bang quante carte ha in mano" + self.desc_eng = "On his turn the player is target of as many Bang as how many cards he has in his hand" class Peyote(CardEvent): def __init__(self):#TODO - super().__init__('Peyote', '🌵') - self.desc = 'Invece che pescare il giocatore prova a indovinare il colore del seme, se lo indovina continua' - self.desc_eng = 'Instead of drawing, the player tries to guess the color of the suit, if he\'s right he repeats' + super().__init__("Peyote", "🌵") + self.desc = "Invece che pescare il giocatore prova a indovinare il colore del seme, se lo indovina continua" + self.desc_eng = "Instead of drawing, the player tries to guess the color of the suit, if he's right he repeats" class Ranch(CardEvent): def __init__(self):#TODO - super().__init__('Ranch', '🐮') - self.desc = 'Dopo aver pescato il giocatore può scartare quante carte vuole dalla mano e pescarne altrettante dal mazzo' - self.desc_eng = 'After drawing, the player can discard as many cards as he wants from his hand and draw as many from the deck' + super().__init__("Ranch", "🐮") + self.desc = "Dopo aver pescato il giocatore può scartare quante carte vuole dalla mano e pescarne altrettante dal mazzo" + self.desc_eng = "After drawing, the player can discard as many cards as he wants from his hand and draw as many from the deck" class Rimbalzo(CardEvent): def __init__(self):#TODO - super().__init__('Rimbalzo', '⏮') - self.desc = 'Il giocatore di turno può giocare bang contro le carte equipaggiate dagli altri giocatori, se non giocano mancato vengono scartate' - self.desc_eng = 'The player can play bang against the cards equipped by the other players, if they do not play miss they are discarded' + super().__init__("Rimbalzo", "⏮") + self.desc = "Il giocatore di turno può giocare bang contro le carte equipaggiate dagli altri giocatori, se non giocano mancato vengono scartate" + self.desc_eng = "The player can play bang against the cards equipped by the other players, if they do not play miss they are discarded" class RouletteRussa(CardEvent): def __init__(self):#TODO - super().__init__('Roulette Russa', '🇷🇺') - self.desc = 'A partire dallo sceriffo, ogni giocatore scarta 1 mancato, il primo che non lo fa perde 2 vite' - self.desc_eng = 'Starting from the sheriff, every player discards 1 missed, the first one that doesn\'t loses 2 HP' + super().__init__("Roulette Russa", "🇷🇺") + self.desc = "A partire dallo sceriffo, ogni giocatore scarta 1 mancato, il primo che non lo fa perde 2 vite" + self.desc_eng = "Starting from the sheriff, every player discards 1 missed, the first one that doesn't loses 2 HP" class Vendetta(CardEvent): def __init__(self): - super().__init__('Vendetta', '😤') - self.desc = 'Alla fine del proprio turno il giocatore estrae, se esce ♥️ gioca un altro turno' - self.desc_eng = 'When ending the turn, the player flips a card, if it\'s ♥️ he plays another turn' + super().__init__("Vendetta", "😤") + self.desc = "Alla fine del proprio turno il giocatore estrae, se esce ♥️ gioca un altro turno" + self.desc_eng = "When ending the turn, the player flips a card, if it's ♥️ he plays another turn" def get_all_events(): return [ @@ -107,7 +107,7 @@ def get_all_events(): LiquoreForte(), # MinieraAbbandonata(), # PerUnPugnoDiCarte(), - # Peyote(), + Peyote(), # Ranch(), # Rimbalzo(), # RouletteRussa(), diff --git a/backend/bang/players.py b/backend/bang/players.py index bfdea52..0e2d65a 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -146,6 +146,14 @@ class Player: self.sio.emit('notify_card', room=self.sid, data=mess) def notify_self(self): + if self.pending_action == PendingAction.DRAW and self.game.check_event(ce.Peyote): + self.available_cards = [{ + 'icon': '🔴' + },{ + 'icon': '⚫' + }] + self.is_drawing = True + self.pending_action = PendingAction.CHOOSE if isinstance(self.character, chars.CalamityJanet): if cs.Mancato(0, 0).name not in self.expected_response: self.expected_response.append(cs.Mancato(0, 0).name) @@ -486,6 +494,19 @@ class Player: while self.target_p == self.name or len(self.game.players[self.game.players_map[self.target_p]].hand) + len(self.game.players[self.game.players_map[self.target_p]].equipment) == 0: self.target_p = self.game.players[self.game.players_map[self.target_p]+1].name self.notify_self() + elif self.is_drawing and self.game.check_event(ce.Peyote): + self.is_drawing = False + card = self.game.deck.draw() + self.hand.append(card) + self.sio.emit('chat_message', room=self.game.name, data=f"_guess|{self.name}|{self.available_cards[card_index]['icon']}") + self.available_cards = [] + if card_index == card.suit%2: + self.sio.emit('chat_message', room=self.game.name, data=f"_guess_right|{self.name}") + self.pending_action = PendingAction.DRAW + else: + self.sio.emit('chat_message', room=self.game.name, data=f"_guess_wrong|{self.name}") + self.pending_action = PendingAction.PLAY + self.notify_self() # specifico per personaggio elif self.is_drawing and isinstance(self.character, chars.KitCarlson): self.hand.append(self.available_cards.pop(card_index)) diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index b8a782e..5b780f3 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -80,7 +80,10 @@ "special_bart_cassidy": "{0} received a compensation because he was injured.", "special_el_gringo": "{0} stole a card from {1} when he was was injured.", "special_calamity": "{0} played {1} as Bang! against {2}.", - "allroles": "In the game there are: {0}." + "allroles": "In the game there are: {0}.", + "guess": "{0} guesses {1}.", + "guess_right": "{0} was right.", + "guess_wrong": "{0} was wrong." }, "foc": { "leggedelwest": "He must play this card on this turn if possible." diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index 720945b..9eaa065 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -80,7 +80,10 @@ "special_bart_cassidy": "{0} ha ricevuto un risarcimento perchè è stato ferito.", "special_el_gringo": "{0} rubato una carta a {1} mentre veniva colpito.", "special_calamity": "{0} ha giovato {1} come un Bang! contro {2}.", - "allroles": "Nella partita ci sono: {0}." + "allroles": "Nella partita ci sono: {0}.", + "guess": "{0} pensa sia {1}.", + "guess_right": "{0} ha indovinato.", + "guess_wrong": "{0} ha sbagliato." }, "foc": { "leggedelwest": "Ed è obbligato a usarla nel suo turno, se possibile" From 6aafd48e16925f1e5454232a994e9a361d72f157 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 13:06:10 +0100 Subject: [PATCH 06/43] Miniera abbandonata --- backend/bang/deck.py | 17 +++++++++++++---- .../expansions/fistful_of_cards/card_events.py | 8 ++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/backend/bang/deck.py b/backend/bang/deck.py index f484e8b..dd07c24 100644 --- a/backend/bang/deck.py +++ b/backend/bang/deck.py @@ -42,8 +42,12 @@ class Deck: return None def pick_and_scrap(self) -> cs.Card: - card = self.cards.pop(0) - self.scrap_pile.append(card) + if self.game.check_event(ce.MinieraAbbandonata) and len(self.scrap_pile) > 0: + card = self.draw_from_scrap_pile() + self.put_on_top(card) + else: + card = self.cards.pop(0) + self.scrap_pile.append(card) if len(self.cards) == 0: self.reshuffle() self.game.notify_scrap_pile() @@ -53,6 +57,8 @@ class Deck: self.cards.insert(0, card) def draw(self) -> cs.Card: + if self.game.check_event(ce.MinieraAbbandonata) and len(self.scrap_pile) > 0: + return self.draw_from_scrap_pile() card = self.cards.pop(0) if len(self.cards) == 0: self.reshuffle() @@ -74,5 +80,8 @@ class Deck: def scrap(self, card: cs.Card): if card.usable_next_turn: card.can_be_used_now = False - self.scrap_pile.append(card) - self.game.notify_scrap_pile() + if self.game.check_event(ce.MinieraAbbandonata): + self.put_on_top(card) + else: + self.scrap_pile.append(card) + self.game.notify_scrap_pile() diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 01dd366..e5d2c71 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -54,7 +54,7 @@ class LiquoreForte(CardEvent): self.desc_eng = "Players can skip drawing to regain 1 HP (click on the event card to use)" class MinieraAbbandonata(CardEvent): - def __init__(self):#TODO + def __init__(self): super().__init__("Miniera Abbandonata", "⛏") self.desc = "I giocatori pescano dagli scarti e scartano in cima al mazzo" self.desc_eng = "Players draw from the discarded pile and discard to the deck" @@ -62,11 +62,11 @@ class MinieraAbbandonata(CardEvent): class PerUnPugnoDiCarte(CardEvent): def __init__(self):#TODO super().__init__("Per Un Pugno Di Carte", "🎴") - self.desc = "Il giocatore subisce tanti bang quante carte ha in mano" + self.desc = "Nel suo turno giocatore subisce tanti bang quante carte ha in mano" self.desc_eng = "On his turn the player is target of as many Bang as how many cards he has in his hand" class Peyote(CardEvent): - def __init__(self):#TODO + def __init__(self): super().__init__("Peyote", "🌵") self.desc = "Invece che pescare il giocatore prova a indovinare il colore del seme, se lo indovina continua" self.desc_eng = "Instead of drawing, the player tries to guess the color of the suit, if he's right he repeats" @@ -105,7 +105,7 @@ def get_all_events(): Lazo(), LeggeDelWest(), LiquoreForte(), - # MinieraAbbandonata(), + MinieraAbbandonata(), # PerUnPugnoDiCarte(), Peyote(), # Ranch(), From f47c8fb053ad1d54aea849b9ea87ec9f9590f9b3 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 13:32:09 +0100 Subject: [PATCH 07/43] per un pugno di carte --- .../expansions/fistful_of_cards/card_events.py | 4 ++-- backend/bang/game.py | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index e5d2c71..86cd342 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -60,7 +60,7 @@ class MinieraAbbandonata(CardEvent): self.desc_eng = "Players draw from the discarded pile and discard to the deck" class PerUnPugnoDiCarte(CardEvent): - def __init__(self):#TODO + def __init__(self): super().__init__("Per Un Pugno Di Carte", "🎴") self.desc = "Nel suo turno giocatore subisce tanti bang quante carte ha in mano" self.desc_eng = "On his turn the player is target of as many Bang as how many cards he has in his hand" @@ -106,7 +106,7 @@ def get_all_events(): LeggeDelWest(), LiquoreForte(), MinieraAbbandonata(), - # PerUnPugnoDiCarte(), + PerUnPugnoDiCarte(), Peyote(), # Ranch(), # Rimbalzo(), diff --git a/backend/bang/game.py b/backend/bang/game.py index cfad973..7c03837 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -28,6 +28,7 @@ class Game: self.shutting_down = False self.is_competitive = False self.disconnect_bot = True + self.player_bangs = 0 def notify_room(self, sid=None): if len([p for p in self.players if p.character == None]) != 0 or sid: @@ -207,6 +208,14 @@ class Game: return self.players[self.players_map[name]] def responders_did_respond_resume_turn(self): + if self.player_bangs > 0 and self.check_event(ce.PerUnPugnoDiCarte): + self.player_bangs -= 1 + if self.player_bangs > 1: + self.players[self.turn].get_banged('') + self.players[self.turn].notify_self() + else: + self.player_bangs = 0 + self.players[self.turn].play_turn() self.readyCount += 1 if self.readyCount == self.waiting_for: self.waiting_for = 0 @@ -218,6 +227,7 @@ class Game: return self.players[(self.turn + 1) % len(self.players)] def play_turn(self): + self.player_bangs = 0 if isinstance(self.players[self.turn].role, roles.Sheriff): self.deck.flip_event() if self.check_event(ce.DeadMan) and len(self.dead_players) > 0: @@ -227,7 +237,12 @@ class Game: self.players[-1].hand.append(self.deck.draw()) self.players_map = {c.name: i for i, c in enumerate(self.players)} self.players[-1].notify_self() - self.players[self.turn].play_turn() + if self.check_event(ce.PerUnPugnoDiCarte): + self.player_bangs = len(self.players[self.turn].hand) + self.players[self.turn].get_banged('') + self.players[self.turn].notify_self() + else: + self.players[self.turn].play_turn() def next_turn(self): if self.shutting_down: return From 622d8d7330ddccef0c6ac50843bea57fcc2dc62a Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 14:19:50 +0100 Subject: [PATCH 08/43] roulette russa --- .../fistful_of_cards/card_events.py | 4 +- backend/bang/game.py | 98 ++++++++++++------- backend/bang/players.py | 12 +-- 3 files changed, 72 insertions(+), 42 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 86cd342..5d414fc 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -84,7 +84,7 @@ class Rimbalzo(CardEvent): self.desc_eng = "The player can play bang against the cards equipped by the other players, if they do not play miss they are discarded" class RouletteRussa(CardEvent): - def __init__(self):#TODO + def __init__(self): super().__init__("Roulette Russa", "🇷🇺") self.desc = "A partire dallo sceriffo, ogni giocatore scarta 1 mancato, il primo che non lo fa perde 2 vite" self.desc_eng = "Starting from the sheriff, every player discards 1 missed, the first one that doesn't loses 2 HP" @@ -110,6 +110,6 @@ def get_all_events(): Peyote(), # Ranch(), # Rimbalzo(), - # RouletteRussa(), + RouletteRussa(), Vendetta(), ] \ No newline at end of file diff --git a/backend/bang/game.py b/backend/bang/game.py index 7c03837..3b2a3a5 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -2,7 +2,7 @@ from typing import List, Set, Dict, Tuple, Optional import random import socketio -import bang.players as players +import bang.players as pl import bang.characters as characters from bang.deck import Deck import bang.roles as roles @@ -14,8 +14,8 @@ class Game: super().__init__() self.sio = sio self.name = name - self.players: List[players.Player] = [] - self.dead_players: List[players.Player] = [] + self.players: List[pl.Player] = [] + self.dead_players: List[pl.Player] = [] self.deck: Deck = None self.started = False self.turn = 0 @@ -29,6 +29,7 @@ class Game: self.is_competitive = False self.disconnect_bot = True self.player_bangs = 0 + self.is_russian_roulette_on = False def notify_room(self, sid=None): if len([p for p in self.players if p.character == None]) != 0 or sid: @@ -60,7 +61,7 @@ class Game: self.disconnect_bot = not self.disconnect_bot self.notify_room() - def add_player(self, player: players.Player): + def add_player(self, player: pl.Player): if player.is_bot and len(self.players) >= 8: return if player in self.players or len(self.players) >= 10: @@ -140,8 +141,8 @@ class Game: self.turn = i self.players[i].notify_self() - def attack_others(self, attacker: players.Player): - attacker.pending_action = players.PendingAction.WAIT + def attack_others(self, attacker: pl.Player): + attacker.pending_action = pl.PendingAction.WAIT attacker.notify_self() self.waiting_for = 0 self.readyCount = 0 @@ -151,11 +152,11 @@ class Game: self.waiting_for += 1 p.notify_self() if self.waiting_for == 0: - attacker.pending_action = players.PendingAction.PLAY + attacker.pending_action = pl.PendingAction.PLAY attacker.notify_self() - def indian_others(self, attacker: players.Player): - attacker.pending_action = players.PendingAction.WAIT + def indian_others(self, attacker: pl.Player): + attacker.pending_action = pl.PendingAction.WAIT attacker.notify_self() self.waiting_for = 0 self.readyCount = 0 @@ -165,63 +166,83 @@ class Game: self.waiting_for += 1 p.notify_self() if self.waiting_for == 0: - attacker.pending_action = players.PendingAction.PLAY + attacker.pending_action = pl.PendingAction.PLAY attacker.notify_self() - def attack(self, attacker: players.Player, target_username:str, double:bool=False): + def attack(self, attacker: pl.Player, target_username:str, double:bool=False): if self.get_player_named(target_username).get_banged(attacker=attacker, double=double): self.readyCount = 0 self.waiting_for = 1 - attacker.pending_action = players.PendingAction.WAIT + attacker.pending_action = pl.PendingAction.WAIT attacker.notify_self() self.get_player_named(target_username).notify_self() - def duel(self, attacker: players.Player, target_username:str): + def duel(self, attacker: pl.Player, target_username:str): if self.get_player_named(target_username).get_dueled(attacker=attacker): self.readyCount = 0 self.waiting_for = 1 - attacker.pending_action = players.PendingAction.WAIT + attacker.pending_action = pl.PendingAction.WAIT attacker.notify_self() self.get_player_named(target_username).notify_self() def emporio(self): self.available_cards = [self.deck.draw() for i in range(len(self.players))] - self.players[self.turn].pending_action = players.PendingAction.CHOOSE + self.players[self.turn].pending_action = pl.PendingAction.CHOOSE self.players[self.turn].available_cards = self.available_cards self.players[self.turn].notify_self() def respond_emporio(self, player, i): player.hand.append(self.available_cards.pop(i)) player.available_cards = [] - player.pending_action = players.PendingAction.WAIT + player.pending_action = pl.PendingAction.WAIT player.notify_self() nextPlayer = self.players[(self.turn + (len(self.players)-len(self.available_cards))) % len(self.players)] if nextPlayer == self.players[self.turn]: - self.players[self.turn].pending_action = players.PendingAction.PLAY + self.players[self.turn].pending_action = pl.PendingAction.PLAY self.players[self.turn].notify_self() else: - nextPlayer.pending_action = players.PendingAction.CHOOSE + nextPlayer.pending_action = pl.PendingAction.CHOOSE nextPlayer.available_cards = self.available_cards nextPlayer.notify_self() def get_player_named(self, name:str): return self.players[self.players_map[name]] - def responders_did_respond_resume_turn(self): + def responders_did_respond_resume_turn(self, did_lose=False): + print('did_lose', did_lose) if self.player_bangs > 0 and self.check_event(ce.PerUnPugnoDiCarte): self.player_bangs -= 1 if self.player_bangs > 1: - self.players[self.turn].get_banged('') - self.players[self.turn].notify_self() + print('bang again') + if self.players[self.turn].get_banged(self.deck.event_cards[0]): + self.players[self.turn].notify_self() + else: + self.responders_did_respond_resume_turn() else: + print('ok play turn now') self.player_bangs = 0 self.players[self.turn].play_turn() - self.readyCount += 1 - if self.readyCount == self.waiting_for: - self.waiting_for = 0 - self.readyCount = 0 - self.players[self.turn].pending_action = players.PendingAction.PLAY - self.players[self.turn].notify_self() + elif self.is_russian_roulette_on and self.check_event(ce.RouletteRussa): + if did_lose: + print('stop roulette') + self.players[(self.turn+self.player_bangs) % len(self.players)].lives -= 1 + self.players[(self.turn+self.player_bangs) % len(self.players)].notify_self() + self.is_russian_roulette_on = False + self.players[self.turn].play_turn() + else: + self.player_bangs += 1 + print(f'next in line {self.players[(self.turn+self.player_bangs) % len(self.players)].name}') + if self.players[(self.turn+self.player_bangs) % len(self.players)].get_banged(self.deck.event_cards[0]): + self.players[(self.turn+self.player_bangs) % len(self.players)].notify_self() + else: + self.responders_did_respond_resume_turn(did_lose=True) + else: + self.readyCount += 1 + if self.readyCount == self.waiting_for: + self.waiting_for = 0 + self.readyCount = 0 + self.players[self.turn].pending_action = pl.PendingAction.PLAY + self.players[self.turn].notify_self() def next_player(self): return self.players[(self.turn + 1) % len(self.players)] @@ -237,10 +258,19 @@ class Game: self.players[-1].hand.append(self.deck.draw()) self.players_map = {c.name: i for i, c in enumerate(self.players)} self.players[-1].notify_self() + elif self.check_event(ce.RouletteRussa): + self.is_russian_roulette_on = True + if self.players[self.turn].get_banged(self.deck.event_cards[0]): + self.players[self.turn].notify_self() + else: + self.responders_did_respond_resume_turn(did_lose=True) + return if self.check_event(ce.PerUnPugnoDiCarte): self.player_bangs = len(self.players[self.turn].hand) - self.players[self.turn].get_banged('') - self.players[self.turn].notify_self() + if self.players[self.turn].get_banged(self.deck.event_cards[0]): + self.players[self.turn].notify_self() + else: + self.responders_did_respond_resume_turn() else: self.players[self.turn].play_turn() @@ -261,7 +291,7 @@ class Game: else: self.sio.emit('scrap', room=self.name, data=None) - def handle_disconnect(self, player: players.Player): + def handle_disconnect(self, player: pl.Player): print(f'player {player.name} left the game {self.name}') if player in self.players: if self.disconnect_bot and self.started: @@ -281,17 +311,17 @@ class Game: return True else: return False - def player_death(self, player: players.Player, disconnected=False): + def player_death(self, player: pl.Player, disconnected=False): if not player in self.players: return import bang.expansions.dodge_city.characters as chd print(player.attacker) - if player.attacker and isinstance(player.attacker.role, roles.Sheriff) and isinstance(player.role, roles.Vice): + if player.attacker and player.attacker in self.players and isinstance(player.attacker.role, roles.Sheriff) and isinstance(player.role, roles.Vice): for i in range(len(player.attacker.hand)): self.deck.scrap(player.attacker.hand.pop()) for i in range(len(player.attacker.equipment)): self.deck.scrap(player.attacker.equipment.pop()) player.attacker.notify_self() - elif player.attacker and (isinstance(player.role, roles.Outlaw) or self.initial_players == 3): + elif player.attacker and player.attacker in self.players and (isinstance(player.role, roles.Outlaw) or self.initial_players == 3): for i in range(3): player.attacker.hand.append(self.deck.draw()) player.attacker.notify_self() @@ -372,7 +402,7 @@ class Game: if len(self.deck.event_cards) == 0: return False return isinstance(self.deck.event_cards[0], ev) - def get_visible_players(self, player: players.Player): + def get_visible_players(self, player: pl.Player): i = self.players.index(player) sight = player.get_sight() mindist = 99 if not self.check_event(ce.Agguato) else 1 diff --git a/backend/bang/players.py b/backend/bang/players.py index 0e2d65a..84405e4 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -540,12 +540,12 @@ class Player: self.mancato_needed -= 1 self.notify_self() if self.mancato_needed <= 0: - self.game.responders_did_respond_resume_turn() + self.game.responders_did_respond_resume_turn(did_lose=False) return if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang)) or isinstance(self.character, chd.ElenaFuente)]) == 0\ and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 0: self.take_damage_response() - self.game.responders_did_respond_resume_turn() + self.game.responders_did_respond_resume_turn(did_lose=True) else: self.pending_action = PendingAction.RESPOND self.expected_response = self.game.deck.mancato_cards @@ -575,7 +575,7 @@ class Player: print('has mancato') self.pending_action = PendingAction.RESPOND self.expected_response = self.game.deck.mancato_cards - if self.attacker and isinstance(self.attacker.character, chd.BelleStar) or self.game.check_event(ce.Lazo): + if self.attacker and self.attacker in self.game.players and isinstance(self.attacker.character, chd.BelleStar) or self.game.check_event(ce.Lazo): self.expected_response = self.game.deck.mancato_cards_not_green if isinstance(self.character, chd.ElenaFuente): self.expected_response = self.game.deck.all_cards_str @@ -601,7 +601,7 @@ class Player: if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Bang) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0: print('Cant defend') self.take_damage_response() - self.game.responders_did_respond_resume_turn() + self.game.responders_did_respond_resume_turn(did_lose=True) return False else: self.pending_action = PendingAction.RESPOND @@ -657,7 +657,7 @@ class Player: if isinstance(self.character, chd.MollyStark) and hand_index < len(self.hand)+1 and not self.is_my_turn: self.molly_discarded_cards += 1 else: - self.game.responders_did_respond_resume_turn() + self.game.responders_did_respond_resume_turn(did_lose=False) self.event_type = '' else: self.pending_action = PendingAction.RESPOND @@ -674,7 +674,7 @@ class Player: self.attacker.molly_discarded_cards = 0 self.attacker.notify_self() self.on_failed_response_cb() - self.game.responders_did_respond_resume_turn() + self.game.responders_did_respond_resume_turn(did_lose=True) if self.mancato_needed <= 0: self.attacker = None From 2e73b96499a2090efa38f7bb1f9d4c6a8d1b724a Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 14:51:23 +0100 Subject: [PATCH 09/43] fratelli di sangue --- .../fistful_of_cards/card_events.py | 4 ++-- backend/bang/players.py | 22 ++++++++++++++++++- frontend/src/i18n/en.json | 3 ++- frontend/src/i18n/it.json | 3 ++- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 5d414fc..782fa18 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -24,7 +24,7 @@ class DeadMan(CardEvent): self.desc_eng = "The first player that died return back to life with 2 hp and 2 cards" class FratelliDiSangue(CardEvent): - def __init__(self):#TODO + def __init__(self): super().__init__("Fratelli Di Sangue", "💉") self.desc = "All'inizio del proprio turno i giocatori possono perdere 1 vita per darla a un altro giocatore" self.desc_eng = "At the begin of their turn, payers can lose 1 hp to give it to another player" @@ -100,7 +100,7 @@ def get_all_events(): Agguato(), # Cecchino(), DeadMan(), - # FratelliDiSangue(), + FratelliDiSangue(), IlGiudice(), Lazo(), LeggeDelWest(), diff --git a/backend/bang/players.py b/backend/bang/players.py index 84405e4..6c45107 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -48,6 +48,7 @@ class Player: self.attacker: Player = None self.target_p: str = None self.is_drawing = False + self.is_giving_life = False self.mancato_needed = 0 self.molly_discarded_cards = 0 self.is_bot = bot @@ -304,9 +305,19 @@ class Player: self.is_waiting_for_action = True self.has_played_bang = False self.special_use_count = 0 - if not self.game.check_event(ce.Lazo) and any([isinstance(c, cs.Dinamite) or isinstance(c, cs.Prigione) for c in self.equipment]): + if self.game.check_event(ce.FratelliDiSangue) and self.lives > 1 and not self.is_giving_life and len([p for p in self.game.players if p != self and p.lives < p.max_lives]): + self.available_cards = [{ + 'name': p.name, + 'icon': isinstance(p.role, r.Sheriff), + } for p in self.game.players if p != self and p.lives < p.max_lives] + self.available_cards.append({'icon': '❌'}) + self.pending_action = PendingAction.CHOOSE + self.is_giving_life = True + elif not self.game.check_event(ce.Lazo) and any([isinstance(c, cs.Dinamite) or isinstance(c, cs.Prigione) for c in self.equipment]): + self.is_giving_life = False self.pending_action = PendingAction.PICK else: + self.is_giving_life = False if isinstance(self.real_character, chd.VeraCuster): self.set_available_character([p.character for p in self.game.players if p != self]) else: @@ -494,6 +505,15 @@ class Player: while self.target_p == self.name or len(self.game.players[self.game.players_map[self.target_p]].hand) + len(self.game.players[self.game.players_map[self.target_p]].equipment) == 0: self.target_p = self.game.players[self.game.players_map[self.target_p]+1].name self.notify_self() + elif self.is_giving_life and self.game.check_event(ce.FratelliDiSangue): + try: + player = self.game.get_player_named(self.available_cards[card_index]['name']) + player.lives += 1 + self.lives -= 1 + player.notify_self() + self.sio.emit('chat_message', room=self.game.name, data=f'_fratelli_sangue|{self.name}|{player.name}') + except: pass + self.play_turn() elif self.is_drawing and self.game.check_event(ce.Peyote): self.is_drawing = False card = self.game.deck.draw() diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 5b780f3..69c916f 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -83,7 +83,8 @@ "allroles": "In the game there are: {0}.", "guess": "{0} guesses {1}.", "guess_right": "{0} was right.", - "guess_wrong": "{0} was wrong." + "guess_wrong": "{0} was wrong.", + "fratelli_sangue": "{0} gave one of his lives to {1}." }, "foc": { "leggedelwest": "He must play this card on this turn if possible." diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index 9eaa065..773bb29 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -83,7 +83,8 @@ "allroles": "Nella partita ci sono: {0}.", "guess": "{0} pensa sia {1}.", "guess_right": "{0} ha indovinato.", - "guess_wrong": "{0} ha sbagliato." + "guess_wrong": "{0} ha sbagliato.", + "fratelli_sangue": "{0} ha donato una delle sue vite a {1}." }, "foc": { "leggedelwest": "Ed è obbligato a usarla nel suo turno, se possibile" From 9eafeb4569ca2b707f13a713cff7ef3ee38d7928 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 15:03:33 +0100 Subject: [PATCH 10/43] bot recursion fix and bot lazo fix --- backend/__init__.py | 3 +++ backend/bang/players.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/__init__.py b/backend/__init__.py index 82c5a01..5a9e914 100644 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -8,6 +8,9 @@ import socketio from bang.game import Game from bang.players import Player +import sys +sys.setrecursionlimit(10**6) # this should prevents bots from stopping + sio = socketio.Server(cors_allowed_origins="*") static_files={ '/': {'content_type': 'text/html', 'filename': 'index.html'}, diff --git a/backend/bang/players.py b/backend/bang/players.py index 6c45107..e575166 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -227,7 +227,7 @@ class Player: self.play_card(i) has_played = True break - elif len([c for c in self.hand if c.need_target and not (self.has_played_bang and not any([isinstance(c, cs.Volcanic) for c in self.equipment]))]) > 0: + elif len([c for c in self.hand if c.need_target and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo)))]) > 0: for i in range(len(self.hand)): if self.hand[i].need_target and not (self.has_played_bang and not any([isinstance(c, cs.Volcanic) for c in self.equipment])): if self.hand[i].need_with and len(self.hand) < 2: @@ -245,7 +245,7 @@ class Player: self.play_card(i, against=target['name'], _with=sample([j for j in range(len(self.hand)) if j != i], 1)[0]) has_played = True break - elif any([not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now for c in self.equipment]): + elif any([not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now for c in self.equipment if not self.game.check_event(ce.Lazo)]): print('hmm', [not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now for c in self.equipment]) for i in range(len(self.equipment)): c = self.equipment[i] From 52bdd01cf300fad868033986e619f8d694b96906 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 15:18:53 +0100 Subject: [PATCH 11/43] change bot speed --- backend/__init__.py | 2 ++ backend/bang/game.py | 1 + backend/bang/players.py | 10 +++++----- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/backend/__init__.py b/backend/__init__.py index 5a9e914..1739ee7 100644 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -208,6 +208,8 @@ def chat_message(sid, msg): ses.game.reset() elif '/startgame' in msg and not ses.game.started: ses.game.start_game() + elif '/setbotspeed' in msg: + ses.game.bot_speed = float(msg.split()[1]) elif '/addex' in msg and not ses.game.started: cmd = msg.split() if len(cmd) == 2: diff --git a/backend/bang/game.py b/backend/bang/game.py index 3b2a3a5..a2811c2 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -30,6 +30,7 @@ class Game: self.disconnect_bot = True self.player_bangs = 0 self.is_russian_roulette_on = False + self.bot_speed = 1.5 def notify_room(self, sid=None): if len([p for p in self.players if p.character == None]) != 0 or sid: diff --git a/backend/bang/players.py b/backend/bang/players.py index e575166..5e16c4e 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -205,7 +205,7 @@ class Player: def bot_logic(self): if self.game.shutting_down: return if self.pending_action != None and self.pending_action != PendingAction.WAIT: - eventlet.sleep(uniform(0.6, 1.5)) + eventlet.sleep(uniform(self.game.bot_speed/2-0.1, self.game.bot_speed)) else: return if self.pending_action == PendingAction.PICK: @@ -264,7 +264,7 @@ class Player: has_played = True break maxcards = self.lives if not isinstance(self.character, chd.SeanMallory) else 10 - if not has_played and len(self.hand) > maxcards: + if len(self.hand) > maxcards: self.scrap(0) else: self.end_turn() @@ -379,7 +379,7 @@ class Player: pickable_cards = 1 + self.character.pick_mod if self.is_my_turn: for i in range(len(self.equipment)): - if isinstance(self.equipment[i], cs.Dinamite): + if i < len(self.equipment) and isinstance(self.equipment[i], cs.Dinamite): while pickable_cards > 0: pickable_cards -= 1 picked: cs.Card = self.game.deck.pick_and_scrap() @@ -637,7 +637,7 @@ class Player: self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}') self.hand.append(self.game.deck.draw()) - elif isinstance(self.character, chars.ElGringo) and self.attacker and len(self.attacker.hand) > 0: + elif isinstance(self.character, chars.ElGringo) and self.attacker and self.attacker in self.game.players and len(self.attacker.hand) > 0: self.hand.append(self.attacker.hand.pop( randrange(0, len(self.attacker.hand)))) self.sio.emit('chat_message', room=self.game.name, @@ -688,7 +688,7 @@ class Player: self.hand.append(self.game.deck.draw()) self.molly_discarded_cards = 0 self.notify_self() - elif self.attacker and isinstance(self.attacker.character, chd.MollyStark) and self.is_my_turn: + elif self.attacker and self.attacker in self.game.players and isinstance(self.attacker.character, chd.MollyStark) and self.is_my_turn: for i in range(self.attacker.molly_discarded_cards): self.attacker.hand.append(self.attacker.game.deck.draw()) self.attacker.molly_discarded_cards = 0 From 9313419bf5e5129049f92093042a0c6061fc5825 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 15:57:51 +0100 Subject: [PATCH 12/43] debug change character --- backend/__init__.py | 7 +++++++ backend/bang/game.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/__init__.py b/backend/__init__.py index 1739ee7..94adfd4 100644 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -219,6 +219,13 @@ def chat_message(sid, msg): ses.game.notify_room() else: sio.emit('chat_message', room=sid, data={'color': f'','text':f'{msg} bad format'}) + elif '/setcharacter' in msg: + import bang.characters as characters + cmd = msg.split() + if len(cmd) >= 2: + chs = characters.all_characters(ses.game.expansions) + ses.character = [c for c in chs if c.name == ' '.join(cmd[1:])][0] + ses.notify_self() elif '/gameinfo' in msg: sio.emit('chat_message', room=sid, data={'color': f'','text':f'info: {ses.game.__dict__}'}) elif '/meinfo' in msg: diff --git a/backend/bang/game.py b/backend/bang/game.py index a2811c2..0d17244 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -349,7 +349,7 @@ class Game: if self.started: print('Check win status') attacker_role = None - if player.attacker: + if player.attacker and player.attacker in self.players: attacker_role = player.attacker.role winners = [p for p in self.players if p.role != None and p.role.on_player_death(self.players, initial_players=self.initial_players, dead_role=player.role, attacker_role=attacker_role)] if len(winners) > 0: From bba253f7ef9ca3412ee0ba59890a0005b48e6a8a Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 16:10:06 +0100 Subject: [PATCH 13/43] fix for everyone calamity janet? --- backend/bang/players.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/backend/bang/players.py b/backend/bang/players.py index 5e16c4e..ca96b3b 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -155,11 +155,6 @@ class Player: }] self.is_drawing = True self.pending_action = PendingAction.CHOOSE - if isinstance(self.character, chars.CalamityJanet): - if cs.Mancato(0, 0).name not in self.expected_response: - self.expected_response.append(cs.Mancato(0, 0).name) - elif cs.Bang(0, 0).name not in self.expected_response: - self.expected_response.append(cs.Bang(0, 0).name) elif isinstance(self.character, chars.SuzyLafayette) and len(self.hand) == 0: self.hand.append(self.game.deck.draw()) ser = self.__dict__.copy() @@ -569,7 +564,9 @@ class Player: else: self.pending_action = PendingAction.RESPOND self.expected_response = self.game.deck.mancato_cards - if isinstance(self.character, chd.ElenaFuente): + if isinstance(self.character, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: + self.expected_response.append(cs.Bang(0, 0).name) + elif isinstance(self.character, chd.ElenaFuente): self.expected_response = self.game.deck.all_cards_str self.on_failed_response_cb = self.take_damage_response self.notify_self() @@ -597,7 +594,9 @@ class Player: self.expected_response = self.game.deck.mancato_cards if self.attacker and self.attacker in self.game.players and isinstance(self.attacker.character, chd.BelleStar) or self.game.check_event(ce.Lazo): self.expected_response = self.game.deck.mancato_cards_not_green - if isinstance(self.character, chd.ElenaFuente): + elif isinstance(self.character, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: + self.expected_response.append(cs.Bang(0, 0).name) + elif isinstance(self.character, chd.ElenaFuente): self.expected_response = self.game.deck.all_cards_str self.on_failed_response_cb = self.take_damage_response return True @@ -612,6 +611,8 @@ class Player: print('has bang') self.pending_action = PendingAction.RESPOND self.expected_response = [cs.Bang(0, 0).name] + if isinstance(self.character, chars.CalamityJanet) and cs.Mancato(0, 0).name not in self.expected_response: + self.expected_response.append(cs.Mancato(0, 0).name) self.event_type = 'indians' self.on_failed_response_cb = self.take_damage_response return True @@ -626,6 +627,8 @@ class Player: else: self.pending_action = PendingAction.RESPOND self.expected_response = [cs.Bang(0, 0).name] + if isinstance(self.character, chars.CalamityJanet) and cs.Mancato(0, 0).name not in self.expected_response: + self.expected_response.append(cs.Mancato(0, 0).name) self.event_type = 'duel' self.on_failed_response_cb = self.take_damage_response return True From fda0508f0a221c8a640f88596e24384b9ae318a9 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 16:19:14 +0100 Subject: [PATCH 14/43] also update real character --- backend/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/__init__.py b/backend/__init__.py index 94adfd4..2f5fd44 100644 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -225,6 +225,7 @@ def chat_message(sid, msg): if len(cmd) >= 2: chs = characters.all_characters(ses.game.expansions) ses.character = [c for c in chs if c.name == ' '.join(cmd[1:])][0] + ses.real_character = ses.character ses.notify_self() elif '/gameinfo' in msg: sio.emit('chat_message', room=sid, data={'color': f'','text':f'info: {ses.game.__dict__}'}) From c1c88f5f648630cdae66738fe378ce0651d8f647 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 17:22:00 +0100 Subject: [PATCH 15/43] vendetta fix --- backend/bang/players.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/bang/players.py b/backend/bang/players.py index ca96b3b..6a8df9f 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -48,6 +48,7 @@ class Player: self.attacker: Player = None self.target_p: str = None self.is_drawing = False + self.can_play_vendetta = True self.is_giving_life = False self.mancato_needed = 0 self.molly_discarded_cards = 0 @@ -288,10 +289,11 @@ class Player: else: self.choose(randrange(0, len(target.hand)+len(target.equipment))) - def play_turn(self): + def play_turn(self, can_play_vendetta = True): if self.lives == 0: return self.end_turn(forced=True) self.scrapped_cards = 0 + self.can_play_vendetta = can_play_vendetta self.sio.emit('chat_message', room=self.game.name, data=f'_turn|{self.name}') print(f'I {self.name} was notified that it is my turn') @@ -763,11 +765,11 @@ class Player: print( f"I {self.name} have to many cards in my hand and I can't end the turn") elif self.pending_action == PendingAction.PLAY or forced: - if not forced and self.game.check_event(ce.Vendetta): + if not forced and self.game.check_event(ce.Vendetta) and self.can_play_vendetta: picked: cs.Card = self.game.deck.pick_and_scrap() self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked}') if picked.suit == cs.Suit.HEARTS: - self.play_turn() + self.play_turn(can_play_vendetta=False) return self.is_my_turn = False for i in range(len(self.equipment)): From 8db9cac4e6c063d7da893cecdad7bb97a0801472 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 17:52:41 +0100 Subject: [PATCH 16/43] fix calamity array reference --- backend/bang/players.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/bang/players.py b/backend/bang/players.py index 6a8df9f..1b708a3 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -565,7 +565,7 @@ class Player: self.game.responders_did_respond_resume_turn(did_lose=True) else: self.pending_action = PendingAction.RESPOND - self.expected_response = self.game.deck.mancato_cards + self.expected_response = self.game.deck.mancato_cards.copy() if isinstance(self.character, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: self.expected_response.append(cs.Bang(0, 0).name) elif isinstance(self.character, chd.ElenaFuente): @@ -593,7 +593,7 @@ class Player: else: print('has mancato') self.pending_action = PendingAction.RESPOND - self.expected_response = self.game.deck.mancato_cards + self.expected_response = self.game.deck.mancato_cards.copy() if self.attacker and self.attacker in self.game.players and isinstance(self.attacker.character, chd.BelleStar) or self.game.check_event(ce.Lazo): self.expected_response = self.game.deck.mancato_cards_not_green elif isinstance(self.character, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: @@ -659,6 +659,7 @@ class Player: data=f'_beer_save|{self.name}') break self.mancato_needed = 0 + self.expected_response = [] self.event_type = '' self.notify_self() self.attacker = None @@ -684,6 +685,7 @@ class Player: else: self.game.responders_did_respond_resume_turn(did_lose=False) self.event_type = '' + self.expected_response = [] else: self.pending_action = PendingAction.RESPOND self.notify_self() From b94b7655c0d0f97da06193cf68262da0487b0c88 Mon Sep 17 00:00:00 2001 From: Giulio Date: Sun, 20 Dec 2020 20:24:49 +0100 Subject: [PATCH 17/43] ignore vscode stuff --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 6e83984..566ac6e 100644 --- a/.gitignore +++ b/.gitignore @@ -139,3 +139,5 @@ cython_debug/ frontend/package-lock.json bang-workspace.code-workspace + +.vscode/ From 93c090ef5856b467d7eddaebcce7650762c5ee4b Mon Sep 17 00:00:00 2001 From: Giulio Date: Sun, 20 Dec 2020 20:38:48 +0100 Subject: [PATCH 18/43] revenge description updated --- backend/bang/expansions/fistful_of_cards/card_events.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 782fa18..0a3dabb 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -92,8 +92,8 @@ class RouletteRussa(CardEvent): class Vendetta(CardEvent): def __init__(self): super().__init__("Vendetta", "😤") - self.desc = "Alla fine del proprio turno il giocatore estrae, se esce ♥️ gioca un altro turno" - self.desc_eng = "When ending the turn, the player flips a card, if it's ♥️ he plays another turn" + self.desc = "Alla fine del proprio turno il giocatore estrae dal mazzo, se esce ♥️ gioca un altro turno (ma non estrae di nuovo)" + self.desc_eng = "When ending the turn, the player flips a card from the deck, if it's ♥️ he plays another turn (but he does not flip another card)" def get_all_events(): return [ From ea74a7f91096b1f5457fe8526dee56dccefa5249 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 20:48:46 +0100 Subject: [PATCH 19/43] fix some bot errors --- backend/bang/game.py | 1 + backend/bang/players.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/bang/game.py b/backend/bang/game.py index 0d17244..ba4dd00 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -330,6 +330,7 @@ class Game: if (self.waiting_for > 0): self.responders_did_respond_resume_turn() + if not player in self.players: return index = self.players.index(player) died_in_his_turn = self.started and index == self.turn if self.started and index <= self.turn: diff --git a/backend/bang/players.py b/backend/bang/players.py index 1b708a3..4c300f6 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -223,7 +223,7 @@ class Player: self.play_card(i) has_played = True break - elif len([c for c in self.hand if c.need_target and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo)))]) > 0: + elif len([c for c in self.hand if c.need_target and c.can_be_used_now and not (c.is_equipment and self.game.check_event(ce.IlGiudice)) and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo)))]) > 0: for i in range(len(self.hand)): if self.hand[i].need_target and not (self.has_played_bang and not any([isinstance(c, cs.Volcanic) for c in self.equipment])): if self.hand[i].need_with and len(self.hand) < 2: @@ -267,7 +267,7 @@ class Player: elif self.pending_action == PendingAction.RESPOND: did_respond = False for i in range(len(self.hand)): - if self.hand[i].name in self.expected_response: + if self.hand[i].can_be_used_now and self.hand[i].name in self.expected_response: self.respond(i) did_respond = True break @@ -305,7 +305,8 @@ class Player: if self.game.check_event(ce.FratelliDiSangue) and self.lives > 1 and not self.is_giving_life and len([p for p in self.game.players if p != self and p.lives < p.max_lives]): self.available_cards = [{ 'name': p.name, - 'icon': isinstance(p.role, r.Sheriff), + 'icon': '⭐️' if isinstance(p.role, r.Sheriff) else '🤠', + 'alt_text': ''.join(['❤️']*p.lives)+''.join(['💀']*(p.max_lives-p.lives)) } for p in self.game.players if p != self and p.lives < p.max_lives] self.available_cards.append({'icon': '❌'}) self.pending_action = PendingAction.CHOOSE @@ -460,7 +461,10 @@ class Player: did_play_card = False event_blocks_card = (self.game.check_event(ce.IlGiudice) and (card.is_equipment or (card.usable_next_turn and not card.can_be_used_now))) or (self.game.check_event(ce.Lazo) and card.usable_next_turn and card.can_be_used_now) if not(against != None and isinstance(self.game.get_player_named(against).character, chd.ApacheKid) and card.suit == cs.Suit.DIAMONDS) and not event_blocks_card: - did_play_card = card.play_card(self, against, withCard) + if against == self.name and not isinstance(card, csd.Tequila): + did_play_card = False + else: + did_play_card = card.play_card(self, against, withCard) if not card.is_equipment and not card.usable_next_turn or event_blocks_card: if did_play_card: self.game.deck.scrap(card) From 323bd80179c1df5e7d41d1fa14b3918a8d4a007c Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 21:13:54 +0100 Subject: [PATCH 20/43] fix logica per un pugno di carte --- backend/bang/deck.py | 5 ++--- backend/bang/expansions/fistful_of_cards/card_events.py | 9 ++++++--- backend/bang/game.py | 2 +- backend/bang/players.py | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/backend/bang/deck.py b/backend/bang/deck.py index dd07c24..b539e0a 100644 --- a/backend/bang/deck.py +++ b/backend/bang/deck.py @@ -22,15 +22,14 @@ class Deck: self.event_cards: List[ce.CardEvent] = [] if 'fistful_of_cards' in game.expansions: self.event_cards.extend(ce.get_all_events()) - random.shuffle(self.event_cards) random.shuffle(self.cards) self.scrap_pile: List[cs.Card] = [] print(f'Deck initialized with {len(self.cards)} cards') def flip_event(self): - if len(self.event_cards) > 0: + if len(self.event_cards) > 0 and not isinstance(self.event_cards[0], ce.PerUnPugnoDiCarte): self.event_cards.append(self.event_cards.pop(0)) - self.game.notify_event_card() + self.game.notify_event_card() def peek(self, n_cards: int) -> list: return self.cards[:n_cards] diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 0a3dabb..644d378 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -1,4 +1,5 @@ from abc import ABC, abstractmethod +import random class CardEvent(ABC): def __init__(self, name, icon): @@ -96,7 +97,7 @@ class Vendetta(CardEvent): self.desc_eng = "When ending the turn, the player flips a card from the deck, if it's ♥️ he plays another turn (but he does not flip another card)" def get_all_events(): - return [ + cards = [ Agguato(), # Cecchino(), DeadMan(), @@ -106,10 +107,12 @@ def get_all_events(): LeggeDelWest(), LiquoreForte(), MinieraAbbandonata(), - PerUnPugnoDiCarte(), Peyote(), # Ranch(), # Rimbalzo(), RouletteRussa(), Vendetta(), - ] \ No newline at end of file + ] + random.shuffle(cards) + cards.append(PerUnPugnoDiCarte()) + return cards \ No newline at end of file diff --git a/backend/bang/game.py b/backend/bang/game.py index ba4dd00..4c93bd4 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -266,7 +266,7 @@ class Game: else: self.responders_did_respond_resume_turn(did_lose=True) return - if self.check_event(ce.PerUnPugnoDiCarte): + if self.check_event(ce.PerUnPugnoDiCarte) and len(self.players[self.turn].hand) > 0: self.player_bangs = len(self.players[self.turn].hand) if self.players[self.turn].get_banged(self.deck.event_cards[0]): self.players[self.turn].notify_self() diff --git a/backend/bang/players.py b/backend/bang/players.py index 4c300f6..56ce288 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -671,9 +671,9 @@ class Player: def respond(self, hand_index): if self.pending_action != PendingAction.RESPOND: return self.pending_action = PendingAction.WAIT - if hand_index != -1 and ( + if hand_index != -1 and hand_index < (len(self.hand)+len(self.equipment)) and ( ((hand_index < len(self.hand) and self.hand[hand_index].name in self.expected_response)) or - self.equipment[hand_index-len(self.hand)].name in self.expected_response): + (hand_index-len(self.hand) < len(self.equipment) and self.equipment[hand_index-len(self.hand)].name in self.expected_response)): card = self.hand.pop(hand_index) if hand_index < len(self.hand) else self.equipment.pop(hand_index-len(self.hand)) if isinstance(self.character, chd.MollyStark) and hand_index < len(self.hand)+1 and not self.is_my_turn and self.event_type != 'duel': self.hand.append(self.game.deck.draw()) From 2589bf20c95bfbecfa9c00d1a3c4cd5c2be9a364 Mon Sep 17 00:00:00 2001 From: Giulio Date: Sun, 20 Dec 2020 21:33:00 +0100 Subject: [PATCH 21/43] updated descriptions --- .../fistful_of_cards/card_events.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 644d378..5ce2297 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -15,7 +15,7 @@ class Agguato(CardEvent): class Cecchino(CardEvent): def __init__(self): #TODO super().__init__("Cecchino", "👁") - self.desc = "Nel proprio turno i giocatori possono scartare 2 Bang assieme per sparare un bang a cui servono 2 mancato" + self.desc = "Nel proprio turno i giocatori possono scartare 2 Bang assieme per sparare un bang che necessita 2 mancato" self.desc_eng = "During their turn, players can discard 2 Bang! to shoot a bang that requires 2 missed" class DeadMan(CardEvent): @@ -27,8 +27,8 @@ class DeadMan(CardEvent): class FratelliDiSangue(CardEvent): def __init__(self): super().__init__("Fratelli Di Sangue", "💉") - self.desc = "All'inizio del proprio turno i giocatori possono perdere 1 vita per darla a un altro giocatore" - self.desc_eng = "At the begin of their turn, payers can lose 1 hp to give it to another player" + self.desc = "All'inizio del proprio turno, i giocatori possono perdere 1 vita (tranne l'ultimo) per darla a un altro giocatore" + self.desc_eng = "At the begin of their turn, payers can lose 1 hp (except the last one) to give it to another player" class IlGiudice(CardEvent): def __init__(self): @@ -46,7 +46,7 @@ class LeggeDelWest(CardEvent): def __init__(self): super().__init__("Legge Del West", "⚖️") self.desc = "I giocatori mostrano la seconda carta che pescano e sono obbligati a usarla in quel turno (se possibile)" - self.desc_eng = "Every player shows the second card that they draw and must use it in that round" + self.desc_eng = "Every player shows the second card that they draw and must use it in that round (if it is possible)" class LiquoreForte(CardEvent): def __init__(self): @@ -57,20 +57,20 @@ class LiquoreForte(CardEvent): class MinieraAbbandonata(CardEvent): def __init__(self): super().__init__("Miniera Abbandonata", "⛏") - self.desc = "I giocatori pescano dagli scarti e scartano in cima al mazzo" - self.desc_eng = "Players draw from the discarded pile and discard to the deck" + self.desc = "I giocatori pescano dagli scarti e scartano in cima al mazzo (se gli scarti finiscono, è necessario pescare e scartare in cima al mazzo)" + self.desc_eng = "Players draw from the discarded pile and discard to the top of the deck (if the discards run out, they must draw and discard on top of the deck)" class PerUnPugnoDiCarte(CardEvent): def __init__(self): super().__init__("Per Un Pugno Di Carte", "🎴") - self.desc = "Nel suo turno giocatore subisce tanti bang quante carte ha in mano" - self.desc_eng = "On his turn the player is target of as many Bang as how many cards he has in his hand" + self.desc = "All'inizio del proprio turno, il giocatore subisce tanti bang quante carte ha in mano" + self.desc_eng = "On the beginning of his turn, the player is target of as many Bang as how many cards he has in his hand" class Peyote(CardEvent): def __init__(self): super().__init__("Peyote", "🌵") - self.desc = "Invece che pescare il giocatore prova a indovinare il colore del seme, se lo indovina continua" - self.desc_eng = "Instead of drawing, the player tries to guess the color of the suit, if he's right he repeats" + self.desc = "Invece che pescare il giocatore prova a indovinare il colore del seme, se lo indovina aggiunge la carta alla mano e continua provando ad indovinare la carta successiva" + self.desc_eng = "Instead of drawing, the player tries to guess the color of the suit, if he's right he adds the card to the hand and continues trying to guess the next card" class Ranch(CardEvent): def __init__(self):#TODO From ee26ff5d0100ac5b60b96e2a515afc29f71e8c5b Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 22:21:58 +0100 Subject: [PATCH 22/43] ranch --- .../fistful_of_cards/card_events.py | 4 +-- backend/bang/players.py | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 5ce2297..06b47b4 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -73,7 +73,7 @@ class Peyote(CardEvent): self.desc_eng = "Instead of drawing, the player tries to guess the color of the suit, if he's right he adds the card to the hand and continues trying to guess the next card" class Ranch(CardEvent): - def __init__(self):#TODO + def __init__(self): super().__init__("Ranch", "🐮") self.desc = "Dopo aver pescato il giocatore può scartare quante carte vuole dalla mano e pescarne altrettante dal mazzo" self.desc_eng = "After drawing, the player can discard as many cards as he wants from his hand and draw as many from the deck" @@ -108,7 +108,7 @@ def get_all_events(): LiquoreForte(), MinieraAbbandonata(), Peyote(), - # Ranch(), + Ranch(), # Rimbalzo(), RouletteRussa(), Vendetta(), diff --git a/backend/bang/players.py b/backend/bang/players.py index 56ce288..45140a9 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -50,6 +50,8 @@ class Player: self.is_drawing = False self.can_play_vendetta = True self.is_giving_life = False + self.can_play_ranch = True + self.is_playing_ranch = False self.mancato_needed = 0 self.molly_discarded_cards = 0 self.is_bot = bot @@ -66,6 +68,8 @@ class Player: self.is_my_turn = False self.is_waiting_for_action = True self.has_played_bang = False + self.can_play_ranch = True + self.is_playing_ranch = False self.pending_action: PendingAction = None self.available_characters = [] self.was_shot = False @@ -156,6 +160,13 @@ class Player: }] self.is_drawing = True self.pending_action = PendingAction.CHOOSE + elif self.can_play_ranch and self.pending_action == PendingAction.PLAY and self.game.check_event(ce.Ranch): + self.can_play_ranch = False + self.available_cards = [c for c in self.hand] + self.discarded_cards = [] + self.available_cards.append({'icon': '✅'}) + self.is_playing_ranch = True + self.pending_action = PendingAction.CHOOSE elif isinstance(self.character, chars.SuzyLafayette) and len(self.hand) == 0: self.hand.append(self.game.deck.draw()) ser = self.__dict__.copy() @@ -293,6 +304,8 @@ class Player: if self.lives == 0: return self.end_turn(forced=True) self.scrapped_cards = 0 + self.can_play_ranch = True + self.is_playing_ranch = False self.can_play_vendetta = can_play_vendetta self.sio.emit('chat_message', room=self.game.name, data=f'_turn|{self.name}') @@ -515,6 +528,18 @@ class Player: self.sio.emit('chat_message', room=self.game.name, data=f'_fratelli_sangue|{self.name}|{player.name}') except: pass self.play_turn() + elif self.is_playing_ranch and self.game.check_event(ce.Ranch): + if card_index == len(self.available_cards) - 1: + self.hand = [c for c in self.hand if c not in self.discarded_cards] + for i in range(len(self.discarded_cards)): + self.game.deck.scrap(self.discarded_cards[i]) + self.hand.append(self.game.deck.draw()) + self.discarded_cards = [] + self.is_playing_ranch = False + self.pending_action = PendingAction.PLAY + else: + self.discarded_cards.append(self.available_cards.pop(card_index)) + self.notify_self() elif self.is_drawing and self.game.check_event(ce.Peyote): self.is_drawing = False card = self.game.deck.draw() From 48f4605b0b12c92d9535db249f0f20054f709182 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 22:58:17 +0100 Subject: [PATCH 23/43] add cecchino --- .../fistful_of_cards/card_events.py | 8 +++--- backend/bang/players.py | 25 +++++++++++++++++++ frontend/src/components/Deck.vue | 2 +- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 06b47b4..231ed8d 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -13,10 +13,10 @@ class Agguato(CardEvent): self.desc_eng = "The base distance from any 2 players is 1" class Cecchino(CardEvent): - def __init__(self): #TODO + def __init__(self): super().__init__("Cecchino", "👁") - self.desc = "Nel proprio turno i giocatori possono scartare 2 Bang assieme per sparare un bang che necessita 2 mancato" - self.desc_eng = "During their turn, players can discard 2 Bang! to shoot a bang that requires 2 missed" + self.desc = "Nel proprio turno i giocatori possono scartare 2 Bang assieme per sparare un bang che necessita 2 mancato (clicca la carta)" + self.desc_eng = "During their turn, players can discard 2 Bang! to shoot a bang that requires 2 missed (click the card)" class DeadMan(CardEvent): def __init__(self): @@ -99,7 +99,7 @@ class Vendetta(CardEvent): def get_all_events(): cards = [ Agguato(), - # Cecchino(), + Cecchino(), DeadMan(), FratelliDiSangue(), IlGiudice(), diff --git a/backend/bang/players.py b/backend/bang/players.py index 45140a9..8c1ce27 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -50,6 +50,7 @@ class Player: self.is_drawing = False self.can_play_vendetta = True self.is_giving_life = False + self.is_using_checchino = False self.can_play_ranch = True self.is_playing_ranch = False self.mancato_needed = 0 @@ -63,6 +64,7 @@ class Player: self.role: r.Role = None self.character: chars.Character = None self.real_character: chars.Character = None + self.is_using_checchino = False self.lives = 0 self.max_lives = 0 self.is_my_turn = False @@ -336,6 +338,17 @@ class Player: self.notify_self() def draw(self, pile): + if self.is_my_turn and self.pending_action == PendingAction.PLAY and pile == 'event' and self.game.check_event(ce.Cecchino) and len([c for c in self.hand if c.name == cs.Bang(0,0).name]) >= 2: + self.is_using_checchino = True + self.available_cards = [{ + 'name': p['name'], + 'icon': '⭐️' if p['is_sheriff'] else '🤠', + 'alt_text': ''.join(['❤️']*p['lives'])+''.join(['💀']*(p['max_lives']-p['lives'])) + } for p in self.game.get_visible_players(self) if p['dist'] <= self.get_sight()] + self.available_cards.append({'icon': '❌'}) + self.pending_action = PendingAction.CHOOSE + self.is_giving_life = True + self.notify_self() if self.pending_action != PendingAction.DRAW: return if pile == 'event' and self.lives < self.max_lives and self.game.check_event(ce.LiquoreForte): @@ -528,6 +541,18 @@ class Player: self.sio.emit('chat_message', room=self.game.name, data=f'_fratelli_sangue|{self.name}|{player.name}') except: pass self.play_turn() + elif self.is_using_checchino and self.game.check_event(ce.Cecchino): + try: + if self.available_cards[card_index]['name'] != '': + for _ in range(2): + card = next(c for c in self.hand if c.name == cs.Bang(0,0).name) + self.hand.remove(card) + self.game.deck.scrap(card) + self.game.attack(self, self.available_cards[card_index]['name'], double=True) + except: pass + self.is_using_checchino = False + self.pending_action = PendingAction.PLAY + self.notify_self() elif self.is_playing_ranch and self.game.check_event(ce.Ranch): if card_index == len(self.available_cards) - 1: self.hand = [c for c in self.hand if c not in self.discarded_cards] diff --git a/frontend/src/components/Deck.vue b/frontend/src/components/Deck.vue index f2e68c0..2e3089c 100644 --- a/frontend/src/components/Deck.vue +++ b/frontend/src/components/Deck.vue @@ -81,7 +81,7 @@ export default { } }, event() { - if (this.pending_action !== false && this.pending_action < 2) { + if (this.pending_action !== false) { this.$socket.emit('draw', 'event') } } From 174d037d8cc44b0402b37e214f88a0d10bbfe3aa Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Sun, 20 Dec 2020 23:10:44 +0100 Subject: [PATCH 24/43] debug stuff --- backend/__init__.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/backend/__init__.py b/backend/__init__.py index 2f5fd44..bdf4dec 100644 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -220,6 +220,7 @@ def chat_message(sid, msg): else: sio.emit('chat_message', room=sid, data={'color': f'','text':f'{msg} bad format'}) elif '/setcharacter' in msg: + sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'🚨 {ses.name} is in debug mode and changed character'}) import bang.characters as characters cmd = msg.split() if len(cmd) >= 2: @@ -227,6 +228,20 @@ def chat_message(sid, msg): ses.character = [c for c in chs if c.name == ' '.join(cmd[1:])][0] ses.real_character = ses.character ses.notify_self() + elif '/removecard' in msg: + sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'🚨 {ses.name} is in debug mode and removed a card'}) + cmd = msg.split() + if len(cmd) == 2: + ses.hand.pop(int(cmd[1])) + ses.notify_self() + elif '/getcard' in msg: + sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'🚨 {ses.name} is in debug mode and got a card'}) + import bang.cards as cs + cmd = msg.split() + if len(cmd) >= 2: + cards = cs.get_starting_deck(ses.game.expansions) + ses.hand.append = [c for c in cards if c.name == ' '.join(cmd[1:])][0] + ses.notify_self() elif '/gameinfo' in msg: sio.emit('chat_message', room=sid, data={'color': f'','text':f'info: {ses.game.__dict__}'}) elif '/meinfo' in msg: From e2a5147dc63eb0f95596282a284b213fde415efe Mon Sep 17 00:00:00 2001 From: Giulio Date: Mon, 21 Dec 2020 00:35:05 +0100 Subject: [PATCH 25/43] fix getcard --- backend/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/__init__.py b/backend/__init__.py index bdf4dec..45fee6f 100644 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -240,7 +240,7 @@ def chat_message(sid, msg): cmd = msg.split() if len(cmd) >= 2: cards = cs.get_starting_deck(ses.game.expansions) - ses.hand.append = [c for c in cards if c.name == ' '.join(cmd[1:])][0] + ses.hand.append([c for c in cards if c.name == ' '.join(cmd[1:])][0]) ses.notify_self() elif '/gameinfo' in msg: sio.emit('chat_message', room=sid, data={'color': f'','text':f'info: {ses.game.__dict__}'}) From 0a2d5ac2d1d99fd31341ebd8d34b28c4032e6f9c Mon Sep 17 00:00:00 2001 From: Giulio Date: Mon, 21 Dec 2020 00:37:58 +0100 Subject: [PATCH 26/43] added control of two Vulture Sam --- backend/bang/game.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/bang/game.py b/backend/bang/game.py index 4c93bd4..17a8d56 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -368,6 +368,13 @@ class Game: self.deck.scrap(player.hand.pop()) for i in range(len(player.equipment)): self.deck.scrap(player.equipment.pop()) + elif len(vulture) == 2: + for i in range(len(player.hand)): + vulture[i%2].hand.append(player.hand.pop()) + for i in range(len(player.equipment)): + vulture[i%2].hand.append(player.equipment.pop()) + vulture[0].notify_self() + vulture[1].notify_self() else: for i in range(len(player.hand)): vulture[0].hand.append(player.hand.pop()) From 9e24b8ff71b349819664518b34efb4501d122220 Mon Sep 17 00:00:00 2001 From: Giulio Date: Mon, 21 Dec 2020 00:38:25 +0100 Subject: [PATCH 27/43] fix Suzy Lafayette --- backend/bang/players.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/bang/players.py b/backend/bang/players.py index 8c1ce27..7edf092 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -169,7 +169,7 @@ class Player: self.available_cards.append({'icon': '✅'}) self.is_playing_ranch = True self.pending_action = PendingAction.CHOOSE - elif isinstance(self.character, chars.SuzyLafayette) and len(self.hand) == 0: + elif isinstance(self.character, chars.SuzyLafayette) and len(self.hand) == 0 and ( not self.is_my_turn or self.pending_action == PendingAction.PLAY): self.hand.append(self.game.deck.draw()) ser = self.__dict__.copy() ser.pop('game') From 79d75374f21f19e6795f93abde35a9661b799a4f Mon Sep 17 00:00:00 2001 From: Giulio Date: Mon, 21 Dec 2020 01:16:40 +0100 Subject: [PATCH 28/43] fix Vulture Sam sheriff killing his deputy --- backend/bang/game.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/bang/game.py b/backend/bang/game.py index 17a8d56..1746715 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -381,6 +381,13 @@ class Game: for i in range(len(player.equipment)): vulture[0].hand.append(player.equipment.pop()) vulture[0].notify_self() + + #se Vulture Sam è uno sceriffo e ha appena ucciso il suo Vice, deve scartare le carte che ha pescato con la sua abilità + if player.attacker and player.attacker in self.players and isinstance(player.attacker.role, roles.Sheriff) and isinstance(player.role, roles.Vice): + for i in range(len(player.attacker.hand)): + self.deck.scrap(player.attacker.hand.pop()) + player.attacker.notify_self() + greg = [p for p in self.players if isinstance(p.character, chd.GregDigger)] if len(greg) > 0: greg[0].lives = min(greg[0].lives+2, greg[0].max_lives) From 623afcc20144cc06ed25f5fcf9e46abc72f19723 Mon Sep 17 00:00:00 2001 From: Giulio Date: Tue, 22 Dec 2020 00:29:49 +0100 Subject: [PATCH 29/43] fix for green cards and equipment the cards could be overwritten before --- backend/bang/cards.py | 10 ++- backend/bang/expansions/dodge_city/cards.py | 77 +++++++++++++++------ backend/bang/players.py | 4 ++ 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/backend/bang/cards.py b/backend/bang/cards.py index 91faeac..b1553fd 100644 --- a/backend/bang/cards.py +++ b/backend/bang/cards.py @@ -58,12 +58,7 @@ class Card(ABC): if not has_weapon: player.equipment.append(self) elif self.name in [c.name for c in player.equipment if not isinstance(c, Dinamite)]: - for i in range(len(player.equipment)): - print('tipo',type(self)) - if type(player.equipment[i]) == type(self): - player.game.deck.scrap(player.equipment[i]) - player.equipment[i] = self - break + return False else: player.equipment.append(self) if against: @@ -77,6 +72,9 @@ class Card(ABC): def use_card(self, player): pass + def is_duplicate_card(self, player): + return self.name in [c.name for c in player.equipment] + class Barile(Card): def __init__(self, suit, number): diff --git a/backend/bang/expansions/dodge_city/cards.py b/backend/bang/expansions/dodge_city/cards.py index 981a48d..051ada6 100644 --- a/backend/bang/expansions/dodge_city/cards.py +++ b/backend/bang/expansions/dodge_city/cards.py @@ -152,8 +152,11 @@ class Bibbia(Schivata): pass return False else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False class Cappello(Mancato): def __init__(self, suit, number): @@ -168,8 +171,11 @@ class Cappello(Mancato): pass return False else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False class PlaccaDiFerro(Cappello): def __init__(self, suit, number): @@ -195,8 +201,11 @@ class Pugnale(Pugno): if self.can_be_used_now: return super().play_card(player, against=against) else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False class Derringer(Pugnale): def __init__(self, suit, number): @@ -212,8 +221,11 @@ class Derringer(Pugnale): player.hand.append(player.game.deck.draw()) return super().play_card(player, against=against) else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False def use_card(self, player): player.hand.append(player.game.deck.draw()) @@ -235,8 +247,11 @@ class Borraccia(Card): player.notify_self() return True else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False class PonyExpress(WellsFargo): def __init__(self, suit, number): @@ -250,8 +265,11 @@ class PonyExpress(WellsFargo): if self.can_be_used_now: return super().play_card(player, against) else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False class Howitzer(Gatling): def __init__(self, suit, number): @@ -265,8 +283,11 @@ class Howitzer(Gatling): if self.can_be_used_now: return super().play_card(player, against) else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False class CanCan(CatBalou): def __init__(self, suit, number): @@ -280,8 +301,11 @@ class CanCan(CatBalou): if self.can_be_used_now: return super().play_card(player, against) else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False class Conestoga(Panico): def __init__(self, suit, number): @@ -297,8 +321,11 @@ class Conestoga(Panico): if self.can_be_used_now: return super().play_card(player, against) else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False class Pepperbox(Bang): def __init__(self, suit, number): @@ -316,8 +343,11 @@ class Pepperbox(Bang): return True return False else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False class FucileDaCaccia(Card): def __init__(self, suit, number): @@ -336,8 +366,11 @@ class FucileDaCaccia(Card): return True return False else: - player.equipment.append(self) - return True + if not self.is_duplicate_card(player): + player.equipment.append(self) + return True + else: + return False def get_starting_deck() -> List[Card]: return [ diff --git a/backend/bang/players.py b/backend/bang/players.py index 7edf092..7a787f6 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -503,6 +503,10 @@ class Player: self.game.deck.scrap(card) else: self.equipment.insert(hand_index-len(self.hand), card) + elif card.is_equipment or (card.usable_next_turn and not card.can_be_used_now): + if not did_play_card: + self.hand.insert(hand_index, card) + print("did play card:", did_play_card) self.notify_self() def choose(self, card_index): From c9efd63ef2698ac4e0d401bb45a8a0fe4a739944 Mon Sep 17 00:00:00 2001 From: Giulio Date: Tue, 22 Dec 2020 01:55:27 +0100 Subject: [PATCH 30/43] fix mine --- backend/bang/deck.py | 16 +++--- .../fistful_of_cards/card_events.py | 3 +- backend/bang/game.py | 18 +++---- backend/bang/players.py | 49 ++++++++++--------- 4 files changed, 42 insertions(+), 44 deletions(-) diff --git a/backend/bang/deck.py b/backend/bang/deck.py index b539e0a..8d4a418 100644 --- a/backend/bang/deck.py +++ b/backend/bang/deck.py @@ -41,12 +41,8 @@ class Deck: return None def pick_and_scrap(self) -> cs.Card: - if self.game.check_event(ce.MinieraAbbandonata) and len(self.scrap_pile) > 0: - card = self.draw_from_scrap_pile() - self.put_on_top(card) - else: - card = self.cards.pop(0) - self.scrap_pile.append(card) + card = self.cards.pop(0) + self.scrap_pile.append(card) if len(self.cards) == 0: self.reshuffle() self.game.notify_scrap_pile() @@ -55,8 +51,8 @@ class Deck: def put_on_top(self, card: cs.Card): self.cards.insert(0, card) - def draw(self) -> cs.Card: - if self.game.check_event(ce.MinieraAbbandonata) and len(self.scrap_pile) > 0: + def draw(self, ignore_event = False) -> cs.Card: + if self.game.check_event(ce.MinieraAbbandonata) and len(self.scrap_pile) > 0 and not ignore_event: return self.draw_from_scrap_pile() card = self.cards.pop(0) if len(self.cards) == 0: @@ -76,10 +72,10 @@ class Deck: else: return self.draw() - def scrap(self, card: cs.Card): + def scrap(self, card: cs.Card, ignore_event = False): if card.usable_next_turn: card.can_be_used_now = False - if self.game.check_event(ce.MinieraAbbandonata): + if self.game.check_event(ce.MinieraAbbandonata) and not ignore_event: self.put_on_top(card) else: self.scrap_pile.append(card) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 231ed8d..6058215 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -57,7 +57,8 @@ class LiquoreForte(CardEvent): class MinieraAbbandonata(CardEvent): def __init__(self): super().__init__("Miniera Abbandonata", "⛏") - self.desc = "I giocatori pescano dagli scarti e scartano in cima al mazzo (se gli scarti finiscono, è necessario pescare e scartare in cima al mazzo)" + self.desc = "I giocatori pescano dagli scarti nella loro fase 1 e scartano in cima al mazzo nella loro fase 3 (se gli scarti finiscono, è necessario pescare e scartare in cima al mazzo)" + #TODO: cambiare anche la descrizione inglese self.desc_eng = "Players draw from the discarded pile and discard to the top of the deck (if the discards run out, they must draw and discard on top of the deck)" class PerUnPugnoDiCarte(CardEvent): diff --git a/backend/bang/game.py b/backend/bang/game.py index 1746715..142d290 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -187,7 +187,7 @@ class Game: self.get_player_named(target_username).notify_self() def emporio(self): - self.available_cards = [self.deck.draw() for i in range(len(self.players))] + self.available_cards = [self.deck.draw(True) for i in range(len(self.players))] self.players[self.turn].pending_action = pl.PendingAction.CHOOSE self.players[self.turn].available_cards = self.available_cards self.players[self.turn].notify_self() @@ -318,13 +318,13 @@ class Game: print(player.attacker) if player.attacker and player.attacker in self.players and isinstance(player.attacker.role, roles.Sheriff) and isinstance(player.role, roles.Vice): for i in range(len(player.attacker.hand)): - self.deck.scrap(player.attacker.hand.pop()) + self.deck.scrap(player.attacker.hand.pop(), True) for i in range(len(player.attacker.equipment)): - self.deck.scrap(player.attacker.equipment.pop()) + self.deck.scrap(player.attacker.equipment.pop(), True) player.attacker.notify_self() elif player.attacker and player.attacker in self.players and (isinstance(player.role, roles.Outlaw) or self.initial_players == 3): for i in range(3): - player.attacker.hand.append(self.deck.draw()) + player.attacker.hand.append(self.deck.draw(True)) player.attacker.notify_self() print(f'player {player.name} died') if (self.waiting_for > 0): @@ -365,9 +365,9 @@ class Game: vulture = [p for p in self.players if isinstance(p.character, characters.VultureSam)] if len(vulture) == 0: for i in range(len(player.hand)): - self.deck.scrap(player.hand.pop()) + self.deck.scrap(player.hand.pop(), True) for i in range(len(player.equipment)): - self.deck.scrap(player.equipment.pop()) + self.deck.scrap(player.equipment.pop(), True) elif len(vulture) == 2: for i in range(len(player.hand)): vulture[i%2].hand.append(player.hand.pop()) @@ -385,7 +385,7 @@ class Game: #se Vulture Sam è uno sceriffo e ha appena ucciso il suo Vice, deve scartare le carte che ha pescato con la sua abilità if player.attacker and player.attacker in self.players and isinstance(player.attacker.role, roles.Sheriff) and isinstance(player.role, roles.Vice): for i in range(len(player.attacker.hand)): - self.deck.scrap(player.attacker.hand.pop()) + self.deck.scrap(player.attacker.hand.pop(), True) player.attacker.notify_self() greg = [p for p in self.players if isinstance(p.character, chd.GregDigger)] @@ -393,8 +393,8 @@ class Game: greg[0].lives = min(greg[0].lives+2, greg[0].max_lives) herb = [p for p in self.players if isinstance(p.character, chd.HerbHunter)] if len(herb) > 0: - herb[0].hand.append(self.deck.draw()) - herb[0].hand.append(self.deck.draw()) + herb[0].hand.append(self.deck.draw(True)) + herb[0].hand.append(self.deck.draw(True)) herb[0].notify_self() if died_in_his_turn: diff --git a/backend/bang/players.py b/backend/bang/players.py index 7a787f6..00533f2 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -170,7 +170,7 @@ class Player: self.is_playing_ranch = True self.pending_action = PendingAction.CHOOSE elif isinstance(self.character, chars.SuzyLafayette) and len(self.hand) == 0 and ( not self.is_my_turn or self.pending_action == PendingAction.PLAY): - self.hand.append(self.game.deck.draw()) + self.hand.append(self.game.deck.draw(True)) ser = self.__dict__.copy() ser.pop('game') ser.pop('sio') @@ -188,10 +188,11 @@ class Player: print('dying, attacker', self.attacker) if isinstance(self.character, chars.SidKetchum) and len(self.hand) > 1: self.lives += 1 + #TODO Sid dovrebbe poter decidere cosa scartare self.game.deck.scrap(self.hand.pop( - randrange(0, len(self.hand)))) + randrange(0, len(self.hand))), True) self.game.deck.scrap(self.hand.pop( - randrange(0, len(self.hand)))) + randrange(0, len(self.hand))), True) if self.lives <= 0 and self.max_lives > 0: self.pending_action = PendingAction.WAIT ser['hand'] = [] @@ -412,12 +413,12 @@ class Player: data=f'_flipped|{self.name}|{picked}') if picked.suit == cs.Suit.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0: self.lives -= 3 - self.game.deck.scrap(self.equipment.pop(i)) + self.game.deck.scrap(self.equipment.pop(i), True) self.sio.emit('chat_message', room=self.game.name, data=f'_explode|{self.name}') if isinstance(self.character, chars.BartCassidy) and self.lives > 0: for i in range(3): - self.hand.append(self.game.deck.draw()) + self.hand.append(self.game.deck.draw(True)) self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}') print(f'{self.name} Boom, -3 hp') @@ -438,11 +439,11 @@ class Player: self.sio.emit('chat_message', room=self.game.name, data=f'_flipped|{self.name}|{picked}') if picked.suit != cs.Suit.HEARTS and pickable_cards == 0: - self.game.deck.scrap(self.equipment.pop(i)) + self.game.deck.scrap(self.equipment.pop(i), True) self.end_turn(forced=True) return elif pickable_cards == 0: - self.game.deck.scrap(self.equipment.pop(i)) + self.game.deck.scrap(self.equipment.pop(i), True) break break if any([isinstance(c, cs.Prigione) for c in self.equipment]): @@ -493,14 +494,14 @@ class Player: did_play_card = card.play_card(self, against, withCard) if not card.is_equipment and not card.usable_next_turn or event_blocks_card: if did_play_card: - self.game.deck.scrap(card) + self.game.deck.scrap(card, True) else: self.hand.insert(hand_index, card) if withCard: self.hand.insert(_with, withCard) elif card.usable_next_turn and card.can_be_used_now: if did_play_card: - self.game.deck.scrap(card) + self.game.deck.scrap(card, True) else: self.equipment.insert(hand_index-len(self.hand), card) elif card.is_equipment or (card.usable_next_turn and not card.can_be_used_now): @@ -525,7 +526,7 @@ class Player: card.can_be_used_now = False self.hand.append(card) else: - self.game.deck.scrap(card) + self.game.deck.scrap(card, True) if self.event_type != 'rissa' or (self.event_type == 'rissa' and self.target_p == [p.name for p in self.game.players if p != self and (len(p.hand)+len(p.equipment)) > 0][-1]): self.event_type = '' self.target_p = '' @@ -551,7 +552,7 @@ class Player: for _ in range(2): card = next(c for c in self.hand if c.name == cs.Bang(0,0).name) self.hand.remove(card) - self.game.deck.scrap(card) + self.game.deck.scrap(card, True) self.game.attack(self, self.available_cards[card_index]['name'], double=True) except: pass self.is_using_checchino = False @@ -561,7 +562,7 @@ class Player: if card_index == len(self.available_cards) - 1: self.hand = [c for c in self.hand if c not in self.discarded_cards] for i in range(len(self.discarded_cards)): - self.game.deck.scrap(self.discarded_cards[i]) + self.game.deck.scrap(self.discarded_cards[i], True) self.hand.append(self.game.deck.draw()) self.discarded_cards = [] self.is_playing_ranch = False @@ -699,7 +700,7 @@ class Player: if isinstance(self.character, chars.BartCassidy): self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}') - self.hand.append(self.game.deck.draw()) + self.hand.append(self.game.deck.draw(True)) elif isinstance(self.character, chars.ElGringo) and self.attacker and self.attacker in self.game.players and len(self.attacker.hand) > 0: self.hand.append(self.attacker.hand.pop( randrange(0, len(self.attacker.hand)))) @@ -710,9 +711,9 @@ class Player: for i in range(len(self.hand)): if isinstance(self.hand[i], cs.Birra): if isinstance(self.character, chd.MollyStark) and not self.is_my_turn: - self.hand.append(self.game.deck.draw()) + self.hand.append(self.game.deck.draw(True)) self.lives += 1 - self.game.deck.scrap(self.hand.pop(i)) + self.game.deck.scrap(self.hand.pop(i), True) self.sio.emit('chat_message', room=self.game.name, data=f'_beer_save|{self.name}') break @@ -730,9 +731,9 @@ class Player: (hand_index-len(self.hand) < len(self.equipment) and self.equipment[hand_index-len(self.hand)].name in self.expected_response)): card = self.hand.pop(hand_index) if hand_index < len(self.hand) else self.equipment.pop(hand_index-len(self.hand)) if isinstance(self.character, chd.MollyStark) and hand_index < len(self.hand)+1 and not self.is_my_turn and self.event_type != 'duel': - self.hand.append(self.game.deck.draw()) + self.hand.append(self.game.deck.draw(True)) card.use_card(self) - self.game.deck.scrap(card) + self.game.deck.scrap(card, True) self.notify_self() self.mancato_needed -= 1 if self.mancato_needed <= 0: @@ -750,12 +751,12 @@ class Player: else: if isinstance(self.character, chd.MollyStark) and not self.is_my_turn: for i in range(self.molly_discarded_cards): - self.hand.append(self.game.deck.draw()) + self.hand.append(self.game.deck.draw(True)) self.molly_discarded_cards = 0 self.notify_self() elif self.attacker and self.attacker in self.game.players and isinstance(self.attacker.character, chd.MollyStark) and self.is_my_turn: for i in range(self.attacker.molly_discarded_cards): - self.attacker.hand.append(self.attacker.game.deck.draw()) + self.attacker.hand.append(self.attacker.game.deck.draw(True)) self.attacker.molly_discarded_cards = 0 self.attacker.notify_self() self.on_failed_response_cb() @@ -795,8 +796,8 @@ class Player: self.scrapped_cards = 0 self.lives = min(self.lives+1, self.max_lives) elif isinstance(self.character, chd.JoseDelgrado) and card.is_equipment and self.special_use_count < 2: - self.hand.append(self.game.deck.draw()) - self.hand.append(self.game.deck.draw()) + self.hand.append(self.game.deck.draw(True)) + self.hand.append(self.game.deck.draw(True)) self.special_use_count += 1 self.game.deck.scrap(card) self.notify_self() @@ -806,15 +807,15 @@ class Player: self.special_use_count += 1 cards = sorted(data['cards'], reverse=True) for c in cards: - self.game.deck.scrap(self.hand.pop(c)) + self.game.deck.scrap(self.hand.pop(c), True) self.notify_self() self.game.attack(self, data['against']) def chuck_lose_hp_draw(self): if isinstance(self.character, chd.ChuckWengam) and self.lives > 1 and self.is_my_turn: self.lives -= 1 - self.hand.append(self.game.deck.draw()) - self.hand.append(self.game.deck.draw()) + self.hand.append(self.game.deck.draw(True)) + self.hand.append(self.game.deck.draw(True)) self.notify_self() def end_turn(self, forced=False): From 83359eb49761274217acb267193c9b30e50377cc Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 14:40:55 +0100 Subject: [PATCH 31/43] fix stuff --- backend/__init__.py | 8 +++++++- backend/bang/cards.py | 1 + backend/bang/game.py | 2 +- backend/bang/players.py | 37 ++++++++++++++++++++----------------- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/backend/__init__.py b/backend/__init__.py index 45fee6f..b49947d 100644 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -232,7 +232,10 @@ def chat_message(sid, msg): sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'🚨 {ses.name} is in debug mode and removed a card'}) cmd = msg.split() if len(cmd) == 2: - ses.hand.pop(int(cmd[1])) + if len(ses.hand) > int(cmd[1]): + ses.hand.pop(int(cmd[1])) + else: + ses.hand.pop(int(cmd[1])-len(ses.hand)) ses.notify_self() elif '/getcard' in msg: sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'🚨 {ses.name} is in debug mode and got a card'}) @@ -246,6 +249,9 @@ def chat_message(sid, msg): sio.emit('chat_message', room=sid, data={'color': f'','text':f'info: {ses.game.__dict__}'}) elif '/meinfo' in msg: sio.emit('chat_message', room=sid, data={'color': f'','text':f'info: {ses.__dict__}'}) + elif '/mebot' in msg: + ses.is_bot = not ses.is_bot + ses.notify_self() else: sio.emit('chat_message', room=sid, data={'color': f'','text':f'{msg} COMMAND NOT FOUND'}) else: diff --git a/backend/bang/cards.py b/backend/bang/cards.py index b1553fd..20816d4 100644 --- a/backend/bang/cards.py +++ b/backend/bang/cards.py @@ -122,6 +122,7 @@ class Prigione(Card): 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() + return True return False class Remington(Card): diff --git a/backend/bang/game.py b/backend/bang/game.py index 142d290..ccba5a6 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -187,7 +187,7 @@ class Game: self.get_player_named(target_username).notify_self() def emporio(self): - self.available_cards = [self.deck.draw(True) for i in range(len(self.players))] + self.available_cards = [self.deck.draw(True) for i in range(len([p for p in self.players if p.lives > 0]))] self.players[self.turn].pending_action = pl.PendingAction.CHOOSE self.players[self.turn].available_cards = self.available_cards self.players[self.turn].notify_self() diff --git a/backend/bang/players.py b/backend/bang/players.py index 00533f2..863c4c6 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -223,37 +223,35 @@ class Player: elif self.pending_action == PendingAction.DRAW: self.draw('') elif self.pending_action == PendingAction.PLAY: - has_played = False - if len([c for c in self.hand if (c.is_equipment or c.usable_next_turn) and not self.game.check_event(ce.IlGiudice)]) > 0: - for i in range(len(self.hand)): - if self.hand[i].is_equipment or self.hand[i].usable_next_turn: - self.play_card(i) - has_played = True - break + equippables = [c for c in self.hand if (c.is_equipment or c.usable_next_turn) and not isinstance(c, cs.Prigione) and not self.game.check_event(ce.IlGiudice) and not any([type(c) == type(x) for x in self.equipment])] + if len(equippables) > 0: + for c in equippables: + if self.play_card(self.hand.index(c)): + return elif any([isinstance(c, cs.WellsFargo) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or isinstance(c, cs.Birra) for c in self.hand]): for i in range(len(self.hand)): c = self.hand[i] if isinstance(c, cs.WellsFargo) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives): - self.play_card(i) - has_played = True - break + if self.play_card(i): + return elif len([c for c in self.hand if c.need_target and c.can_be_used_now and not (c.is_equipment and self.game.check_event(ce.IlGiudice)) and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo)))]) > 0: for i in range(len(self.hand)): if self.hand[i].need_target and not (self.has_played_bang and not any([isinstance(c, cs.Volcanic) for c in self.equipment])): if self.hand[i].need_with and len(self.hand) < 2: continue _range = self.get_sight() if self.hand[i].name == 'Bang!' or self.hand[i].name == "Pepperbox" else self.hand[i].range - others = [p for p in self.game.get_visible_players(self) if _range >= p['dist'] and not (isinstance(self.role, r.Vice) and p['is_sheriff'])] + others = [p for p in self.game.get_visible_players(self) if _range >= p['dist'] and not (isinstance(self.role, r.Vice) and p['is_sheriff']) and p['lives'] > 0] if len(others) == 0: continue target = others[randrange(0, len(others))] if target['is_sheriff'] and isinstance(self.role, r.Renegade): target = others[randrange(0, len(others))] if not self.hand[i].need_with: - self.play_card(i, against=target['name']) + if self.play_card(i, against=target['name']): + return else: - self.play_card(i, against=target['name'], _with=sample([j for j in range(len(self.hand)) if j != i], 1)[0]) - has_played = True + if self.play_card(i, against=target['name'], _with=sample([j for j in range(len(self.hand)) if j != i], 1)[0]): + return break elif any([not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now for c in self.equipment if not self.game.check_event(ce.Lazo)]): print('hmm', [not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now for c in self.equipment]) @@ -261,7 +259,8 @@ class Player: c = self.equipment[i] if not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now: if not c.need_target: - self.play_card(len(self.hand)+i) + if self.play_card(len(self.hand)+i): + return else: _range = self.get_sight() if c.name == "Pepperbox" else c.range others = [p for p in self.game.get_visible_players(self) if _range >= p['dist'] and not (isinstance(self.role, r.Vice) and p['is_sheriff'])] @@ -270,8 +269,8 @@ class Player: target = others[randrange(0, len(others))] if target['is_sheriff'] and isinstance(self.role, r.Renegade): target = others[randrange(0, len(others))] - self.play_card(len(self.hand)+i, against=target['name']) - has_played = True + if self.play_card(len(self.hand)+i, against=target['name']): + return break maxcards = self.lives if not isinstance(self.character, chd.SeanMallory) else 10 if len(self.hand) > maxcards: @@ -507,8 +506,12 @@ class Player: elif card.is_equipment or (card.usable_next_turn and not card.can_be_used_now): if not did_play_card: self.hand.insert(hand_index, card) + else: + did_play_card = True print("did play card:", did_play_card) self.notify_self() + if self.is_bot: + return did_play_card or card.is_equipment or (card.usable_next_turn and not card.can_be_used_now) def choose(self, card_index): if self.pending_action != PendingAction.CHOOSE: From db2173beea4a9d6434ea3dd91cb235432c4d4939 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 15:11:47 +0100 Subject: [PATCH 32/43] easier to read --- backend/bang/game.py | 1 + backend/bang/players.py | 59 +++++++++++++++++++---------------------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/backend/bang/game.py b/backend/bang/game.py index ccba5a6..f7d67e5 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -428,6 +428,7 @@ class Game: 'lives': self.players[j].lives, 'max_lives': self.players[j].max_lives, 'is_sheriff': isinstance(self.players[j].role, roles.Sheriff), + 'cards': len(self.players[j].hand)+len(self.players[j].equipment) } for j in range(len(self.players)) if i != j] def notify_all(self): diff --git a/backend/bang/players.py b/backend/bang/players.py index 863c4c6..3b1073d 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -223,43 +223,38 @@ class Player: elif self.pending_action == PendingAction.DRAW: self.draw('') elif self.pending_action == PendingAction.PLAY: - equippables = [c for c in self.hand if (c.is_equipment or c.usable_next_turn) and not isinstance(c, cs.Prigione) and not self.game.check_event(ce.IlGiudice) and not any([type(c) == type(x) for x in self.equipment])] - if len(equippables) > 0: + equippables = [c for c in self.hand if (c.is_equipment or c.usable_next_turn) and not isinstance(c, cs.Prigione) and not any([type(c) == type(x) for x in self.equipment])] + misc = [c for c in self.hand if isinstance(c, cs.WellsFargo) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives)] + need_target = [c for c in self.hand if c.need_target and c.can_be_used_now and not (c.need_with and len(self.hand) < 2) and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo)))] + green_cards = [c for c in self.equipment if not self.game.check_event(ce.Lazo) and not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now] + if len(equippables) > 0 and not self.game.check_event(ce.IlGiudice): for c in equippables: if self.play_card(self.hand.index(c)): return - elif any([isinstance(c, cs.WellsFargo) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or isinstance(c, cs.Birra) for c in self.hand]): - for i in range(len(self.hand)): - c = self.hand[i] - if isinstance(c, cs.WellsFargo) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives): - if self.play_card(i): - return - elif len([c for c in self.hand if c.need_target and c.can_be_used_now and not (c.is_equipment and self.game.check_event(ce.IlGiudice)) and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo)))]) > 0: - for i in range(len(self.hand)): - if self.hand[i].need_target and not (self.has_played_bang and not any([isinstance(c, cs.Volcanic) for c in self.equipment])): - if self.hand[i].need_with and len(self.hand) < 2: - continue - _range = self.get_sight() if self.hand[i].name == 'Bang!' or self.hand[i].name == "Pepperbox" else self.hand[i].range - others = [p for p in self.game.get_visible_players(self) if _range >= p['dist'] and not (isinstance(self.role, r.Vice) and p['is_sheriff']) and p['lives'] > 0] - if len(others) == 0: - continue + elif len(misc) > 0: + for c in misc: + if self.play_card(self.hand.index(c)): + return + elif len(need_target) > 0: + for c in need_target: + _range = self.get_sight() if c.name == 'Bang!' or c.name == "Pepperbox" else c.range + others = [p for p in self.game.get_visible_players(self) if _range >= p['dist'] and not (isinstance(self.role, r.Vice) and p['is_sheriff']) and p['lives'] > 0 and not ((isinstance(c, cs.CatBalou) or isinstance(c, cs.Panico)) and p['cards'] == 0) and not (p['is_sheriff'] and isinstance(c, cs.Prigione))] + if len(others) == 0: + continue + target = others[randrange(0, len(others))] + if target['is_sheriff'] and isinstance(self.role, r.Renegade): target = others[randrange(0, len(others))] - if target['is_sheriff'] and isinstance(self.role, r.Renegade): - target = others[randrange(0, len(others))] - if not self.hand[i].need_with: - if self.play_card(i, against=target['name']): - return - else: - if self.play_card(i, against=target['name'], _with=sample([j for j in range(len(self.hand)) if j != i], 1)[0]): - return - break - elif any([not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now for c in self.equipment if not self.game.check_event(ce.Lazo)]): - print('hmm', [not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now for c in self.equipment]) - for i in range(len(self.equipment)): - c = self.equipment[i] + if not c.need_with: + if self.play_card(self.hand.index(c), against=target['name']): + return + else: + if self.play_card(self.hand.index(c), against=target['name'], _with=sample([j for j in range(len(self.hand)) if j != self.hand.index(c)], 1)[0]): + return + elif len(green_cards) > 0: + for c in green_cards: if not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now: if not c.need_target: - if self.play_card(len(self.hand)+i): + if self.play_card(len(self.hand)+self.equipment.index(c)): return else: _range = self.get_sight() if c.name == "Pepperbox" else c.range @@ -269,7 +264,7 @@ class Player: target = others[randrange(0, len(others))] if target['is_sheriff'] and isinstance(self.role, r.Renegade): target = others[randrange(0, len(others))] - if self.play_card(len(self.hand)+i, against=target['name']): + if self.play_card(len(self.hand)+self.equipment.index(c), against=target['name']): return break maxcards = self.lives if not isinstance(self.character, chd.SeanMallory) else 10 From c772577ee881d58bcbfdd31a0a1c779caf3870b8 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 15:18:34 +0100 Subject: [PATCH 33/43] show lives when shooting and stuff --- frontend/src/components/Player.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/components/Player.vue b/frontend/src/components/Player.vue index e88ef3c..fdbbcd2 100644 --- a/frontend/src/components/Player.vue +++ b/frontend/src/components/Player.vue @@ -191,6 +191,7 @@ export default { name: player.name, number: player.dist !== undefined ? `${player.dist}⛰` : '', icon: player.is_sheriff ? '⭐' : '🤠', + alt_text: Array(player.lives+1).join('❤️')+Array(player.max_lives-player.lives+1).join('💀'), is_character: true, }}) if (this.card_against && this.card_against.can_target_self) { From ea5be9b535243c6021ce5f1f30ab00cb8c7b4eb1 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 15:21:01 +0100 Subject: [PATCH 34/43] fix peyote --- backend/bang/players.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/bang/players.py b/backend/bang/players.py index 3b1073d..43f8b2f 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -571,13 +571,14 @@ class Player: elif self.is_drawing and self.game.check_event(ce.Peyote): self.is_drawing = False card = self.game.deck.draw() - self.hand.append(card) self.sio.emit('chat_message', room=self.game.name, data=f"_guess|{self.name}|{self.available_cards[card_index]['icon']}") self.available_cards = [] if card_index == card.suit%2: + self.hand.append(card) self.sio.emit('chat_message', room=self.game.name, data=f"_guess_right|{self.name}") self.pending_action = PendingAction.DRAW else: + self.game.deck.scrap(card) self.sio.emit('chat_message', room=self.game.name, data=f"_guess_wrong|{self.name}") self.pending_action = PendingAction.PLAY self.notify_self() From 363293a76b32cef3dbbaa5d10139373a150169e8 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 15:37:08 +0100 Subject: [PATCH 35/43] healing on boom --- backend/bang/players.py | 48 +++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/backend/bang/players.py b/backend/bang/players.py index 43f8b2f..4f48e05 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -171,6 +171,15 @@ class Player: self.pending_action = PendingAction.CHOOSE elif isinstance(self.character, chars.SuzyLafayette) and len(self.hand) == 0 and ( not self.is_my_turn or self.pending_action == PendingAction.PLAY): self.hand.append(self.game.deck.draw(True)) + if self.lives <= 0 and self.max_lives > 0: + print('dying, attacker', self.attacker) + if isinstance(self.character, chars.SidKetchum) and len(self.hand) > 1: + self.lives += 1 + #TODO Sid dovrebbe poter decidere cosa scartare + self.game.deck.scrap(self.hand.pop( + randrange(0, len(self.hand))), True) + self.game.deck.scrap(self.hand.pop( + randrange(0, len(self.hand))), True) ser = self.__dict__.copy() ser.pop('game') ser.pop('sio') @@ -184,15 +193,6 @@ class Player: ser['sight'] = self.get_sight() ser['lives'] = max(ser['lives'], 0) - if self.lives <= 0 and self.max_lives > 0: - print('dying, attacker', self.attacker) - if isinstance(self.character, chars.SidKetchum) and len(self.hand) > 1: - self.lives += 1 - #TODO Sid dovrebbe poter decidere cosa scartare - self.game.deck.scrap(self.hand.pop( - randrange(0, len(self.hand))), True) - self.game.deck.scrap(self.hand.pop( - randrange(0, len(self.hand))), True) if self.lives <= 0 and self.max_lives > 0: self.pending_action = PendingAction.WAIT ser['hand'] = [] @@ -408,13 +408,12 @@ class Player: if picked.suit == cs.Suit.SPADES and 2 <= picked.number <= 9 and pickable_cards == 0: self.lives -= 3 self.game.deck.scrap(self.equipment.pop(i), True) - self.sio.emit('chat_message', room=self.game.name, - data=f'_explode|{self.name}') + self.sio.emit('chat_message', room=self.game.name, data=f'_explode|{self.name}') + self.heal_if_needed() if isinstance(self.character, 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}') + self.sio.emit('chat_message', room=self.game.name, data=f'_special_bart_cassidy|{self.name}') print(f'{self.name} Boom, -3 hp') break else: @@ -693,6 +692,18 @@ class Player: self.on_failed_response_cb = self.take_damage_response return True + def heal_if_needed(self): + while self.lives <= 0 and len(self.game.players) > 2 and len([c for c in self.hand if isinstance(c, cs.Birra)]) > 0: + for i in range(len(self.hand)): + if isinstance(self.hand[i], cs.Birra): + if isinstance(self.character, chd.MollyStark) and not self.is_my_turn: + self.hand.append(self.game.deck.draw(True)) + self.lives += 1 if not isinstance(self.character, chd.TequilaJoe) else 2 + self.game.deck.scrap(self.hand.pop(i), True) + self.sio.emit('chat_message', room=self.game.name, + data=f'_beer_save|{self.name}') + break + def take_damage_response(self): self.lives -= 1 if self.lives > 0: @@ -706,16 +717,7 @@ class Player: self.sio.emit('chat_message', room=self.game.name, data=f'_special_el_gringo|{self.name}|{self.attacker.name}') self.attacker.notify_self() - while self.lives <= 0 and len(self.game.players) > 2 and len([c for c in self.hand if isinstance(c, cs.Birra)]) > 0: - for i in range(len(self.hand)): - if isinstance(self.hand[i], cs.Birra): - if isinstance(self.character, chd.MollyStark) and not self.is_my_turn: - self.hand.append(self.game.deck.draw(True)) - self.lives += 1 - self.game.deck.scrap(self.hand.pop(i), True) - self.sio.emit('chat_message', room=self.game.name, - data=f'_beer_save|{self.name}') - break + self.heal_if_needed() self.mancato_needed = 0 self.expected_response = [] self.event_type = '' From c57f101b83d8c0d23c9c9a7acf9540e2363501d2 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 15:50:38 +0100 Subject: [PATCH 36/43] fix doc holyday --- frontend/src/components/Player.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Player.vue b/frontend/src/components/Player.vue index fdbbcd2..698001c 100644 --- a/frontend/src/components/Player.vue +++ b/frontend/src/components/Player.vue @@ -54,7 +54,7 @@ :cards="hand.filter(x => x.is_equipment)" :select="(card) => {joseScrap=false;scrap(card)}" :cancel="() => {joseScrap=false}"/> - +
From 2b1691fc3f22cd2ba91b5ecb27c776ea156755bf Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 16:15:34 +0100 Subject: [PATCH 37/43] start fistful of cards on the second round --- backend/bang/deck.py | 2 ++ backend/bang/game.py | 6 +++++- frontend/src/components/Card.vue | 19 +++++++++++++++---- frontend/src/components/Deck.vue | 8 ++++++-- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/backend/bang/deck.py b/backend/bang/deck.py index 8d4a418..136127d 100644 --- a/backend/bang/deck.py +++ b/backend/bang/deck.py @@ -22,6 +22,8 @@ class Deck: self.event_cards: List[ce.CardEvent] = [] if 'fistful_of_cards' in game.expansions: self.event_cards.extend(ce.get_all_events()) + self.event_cards.insert(0, None) + self.event_cards.insert(0, None) # 2 perchè iniziale, e primo flip dallo sceriffo random.shuffle(self.cards) self.scrap_pile: List[cs.Card] = [] print(f'Deck initialized with {len(self.cards)} cards') diff --git a/backend/bang/game.py b/backend/bang/game.py index f7d67e5..78c576c 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -141,6 +141,7 @@ class Game: self.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() def attack_others(self, attacker: pl.Player): attacker.pending_action = pl.PendingAction.WAIT @@ -283,7 +284,10 @@ class Game: def notify_event_card(self): if len(self.deck.event_cards) > 0: - self.sio.emit('event_card', room=self.name, data=self.deck.event_cards[0].__dict__) + if self.deck.event_cards[0] != None: + self.sio.emit('event_card', room=self.name, data=self.deck.event_cards[0].__dict__) + else: + self.sio.emit('event_card', room=self.name, data=None) def notify_scrap_pile(self): print('scrap') diff --git a/frontend/src/components/Card.vue b/frontend/src/components/Card.vue index 65a339f..091739e 100644 --- a/frontend/src/components/Card.vue +++ b/frontend/src/components/Card.vue @@ -87,6 +87,17 @@ export default { box-shadow: 0 0 0pt 4pt white, 0 0 5pt 4pt #aaa; border: 2pt dashed rgb(50 122 172); } +.card.back.fistful-of-cards{ + color:white; + background: repeating-linear-gradient( + 45deg, + rgb(50 122 172), + rgb(50 122 172) 5px, + rgb(30 102 152) 5px, + rgb(30 102 152) 10px + ); + border: 2pt solid rgb(50 122 172); +} .card h4 { position: absolute; text-align: center; @@ -124,12 +135,12 @@ export default { } @media (prefers-color-scheme: dark) { :root, #app { - background-color: #181a1b; - color: rgb(174, 194, 211); - } + background-color: #181a1b; + color: rgb(174, 194, 211); + } .card { background-color: #181a1b; - color: rgb(174, 194, 211); + color: rgb(174, 194, 211); box-shadow: 0 0 0 3pt #987e51, 0 0 0 6pt #181a1b, diff --git a/frontend/src/components/Deck.vue b/frontend/src/components/Deck.vue index 2e3089c..53e6b77 100644 --- a/frontend/src/components/Deck.vue +++ b/frontend/src/components/Deck.vue @@ -5,7 +5,7 @@
- +
@@ -59,7 +59,11 @@ export default { this.lastScrap = card }, event_card(card) { - this.eventCard = card + this.eventCard = card == false ? { + name: 'PewPew!', + icon: '🎲', + back: true + } : card }, }, computed: { From 09c98fc09a1e0277056bd449df38aeb70a79e9b1 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 17:36:45 +0100 Subject: [PATCH 38/43] add rimbalzo --- .../fistful_of_cards/card_events.py | 6 +- backend/bang/game.py | 8 ++ backend/bang/players.py | 93 +++++++++++++++++-- frontend/src/components/Deck.vue | 13 ++- 4 files changed, 109 insertions(+), 11 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index 6058215..d739c09 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -80,7 +80,7 @@ class Ranch(CardEvent): self.desc_eng = "After drawing, the player can discard as many cards as he wants from his hand and draw as many from the deck" class Rimbalzo(CardEvent): - def __init__(self):#TODO + def __init__(self): super().__init__("Rimbalzo", "⏮") self.desc = "Il giocatore di turno può giocare bang contro le carte equipaggiate dagli altri giocatori, se non giocano mancato vengono scartate" self.desc_eng = "The player can play bang against the cards equipped by the other players, if they do not play miss they are discarded" @@ -110,10 +110,12 @@ def get_all_events(): MinieraAbbandonata(), Peyote(), Ranch(), - # Rimbalzo(), + Rimbalzo(), RouletteRussa(), Vendetta(), ] random.shuffle(cards) cards.append(PerUnPugnoDiCarte()) + for c in cards: + c.expansion = 'fistful-of-cards' return cards \ No newline at end of file diff --git a/backend/bang/game.py b/backend/bang/game.py index 78c576c..fe03c09 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -179,6 +179,14 @@ class Game: attacker.notify_self() self.get_player_named(target_username).notify_self() + def rimbalzo(self, attacker: pl.Player, target_username:str, card_index:int): + if self.get_player_named(target_username).get_banged(attacker=attacker, no_dmg=True, card_index=card_index): + self.readyCount = 0 + self.waiting_for = 1 + attacker.pending_action = pl.PendingAction.WAIT + attacker.notify_self() + self.get_player_named(target_username).notify_self() + def duel(self, attacker: pl.Player, target_username:str): if self.get_player_named(target_username).get_dueled(attacker=attacker): self.readyCount = 0 diff --git a/backend/bang/players.py b/backend/bang/players.py index 4f48e05..a31cdae 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -51,6 +51,7 @@ class Player: self.can_play_vendetta = True self.is_giving_life = False self.is_using_checchino = False + self.using_rimbalzo = 0 # 0 no, 1 scegli giocatore, 2 scegli carta self.can_play_ranch = True self.is_playing_ranch = False self.mancato_needed = 0 @@ -342,7 +343,15 @@ class Player: } for p in self.game.get_visible_players(self) if p['dist'] <= self.get_sight()] self.available_cards.append({'icon': '❌'}) self.pending_action = PendingAction.CHOOSE - self.is_giving_life = True + self.notify_self() + elif self.is_my_turn and self.pending_action == PendingAction.PLAY and pile == 'event' and self.game.check_event(ce.Rimbalzo) and len([c for c in self.hand if c.name == cs.Bang(0,0).name]) > 0: + self.available_cards = [{ + 'name': p.name, + 'icon': '⭐️' if isinstance(p.role, r.Sheriff) else '🤠' + } for p in self.game.players if len(p.equipment) > 0 and p != self] + self.available_cards.append({'icon': '❌'}) + self.pending_action = PendingAction.CHOOSE + self.using_rimbalzo = 1 self.notify_self() if self.pending_action != PendingAction.DRAW: return @@ -550,10 +559,29 @@ class Player: card = next(c for c in self.hand if c.name == cs.Bang(0,0).name) self.hand.remove(card) self.game.deck.scrap(card, True) + self.pending_action = PendingAction.PLAY self.game.attack(self, self.available_cards[card_index]['name'], double=True) - except: pass + except: + self.pending_action = PendingAction.PLAY self.is_using_checchino = False - self.pending_action = PendingAction.PLAY + self.notify_self() + elif self.using_rimbalzo > 0 and self.game.check_event(ce.Rimbalzo): + if self.using_rimbalzo == 1 and 'name' in self.available_cards[card_index]: + self.rimbalzo_p = self.available_cards[card_index]['name'] + self.available_cards = self.game.get_player_named(self.available_cards[card_index]['name']).equipment + self.using_rimbalzo = 2 + elif self.using_rimbalzo == 2 and 'name' in self.available_cards[card_index].__dict__: + card = next(c for c in self.hand if c.name == cs.Bang(0,0).name) + self.hand.remove(card) + self.game.deck.scrap(card, True) + self.using_rimbalzo = 0 + self.available_cards = [] + self.pending_action = PendingAction.PLAY + self.game.rimbalzo(self, self.rimbalzo_p, card_index) + else: + self.using_rimbalzo = 0 + self.rimbalzo_p = '' + self.pending_action = PendingAction.PLAY self.notify_self() elif self.is_playing_ranch and self.game.check_event(ce.Ranch): if card_index == len(self.available_cards) - 1: @@ -630,9 +658,41 @@ class Player: self.on_failed_response_cb = self.take_damage_response self.notify_self() - def get_banged(self, attacker, double=False): + def barrel_pick_no_dmg(self): + pickable_cards = 1 + self.character.pick_mod + if len([c for c in self.equipment if isinstance(c, cs.Barile)]) > 0 and isinstance(self.character, chars.Jourdonnais): + pickable_cards = 2 + while pickable_cards > 0: + pickable_cards -= 1 + picked: cs.Card = self.game.deck.pick_and_scrap() + print(f'Did pick {picked}') + self.sio.emit('chat_message', room=self.game.name, + data=f'_flipped|{self.name}|{picked}') + if picked.suit == cs.Suit.HEARTS: + self.mancato_needed -= 1 + self.notify_self() + if self.mancato_needed <= 0: + self.game.responders_did_respond_resume_turn(did_lose=False) + return + if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang)) or isinstance(self.character, chd.ElenaFuente)]) == 0\ + and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 0: + self.take_no_damage_response() + self.game.responders_did_respond_resume_turn(did_lose=True) + else: + self.pending_action = PendingAction.RESPOND + self.expected_response = self.game.deck.mancato_cards.copy() + if isinstance(self.character, chars.CalamityJanet) and cs.Bang(0, 0).name not in self.expected_response: + self.expected_response.append(cs.Bang(0, 0).name) + elif isinstance(self.character, chd.ElenaFuente): + self.expected_response = self.game.deck.all_cards_str + self.on_failed_response_cb = self.take_no_damage_response + self.notify_self() + + def get_banged(self, attacker, double=False, no_dmg=False, card_index=None): self.attacker = attacker self.mancato_needed = 1 if not double else 2 + if card_index != None: + self.dmg_card_index = None for i in range(len(self.equipment)): if self.equipment[i].can_be_used_now: print('usable', self.equipment[i]) @@ -640,13 +700,19 @@ class Player: and len([c for c in self.hand if isinstance(c, cs.Mancato) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Bang)) or isinstance(self.character, chd.ElenaFuente)]) == 0\ and len([c for c in self.equipment if c.can_be_used_now and isinstance(c, cs.Mancato)]) == 0: print('Cant defend') - self.take_damage_response() + if not no_dmg: + self.take_damage_response() + else: + self.take_no_damage_response() return False else: if (not self.game.check_event(ce.Lazo) and len([c for c in self.equipment if isinstance(c, cs.Barile)]) > 0) or isinstance(self.character, chars.Jourdonnais): print('has barrel') self.pending_action = PendingAction.PICK - self.on_pick_cb = self.barrel_pick + if not no_dmg: + self.on_pick_cb = self.barrel_pick + else: + self.on_pick_cb = self.barrel_pick_no_dmg else: print('has mancato') self.pending_action = PendingAction.RESPOND @@ -657,7 +723,10 @@ class Player: self.expected_response.append(cs.Bang(0, 0).name) elif isinstance(self.character, chd.ElenaFuente): self.expected_response = self.game.deck.all_cards_str - self.on_failed_response_cb = self.take_damage_response + if not no_dmg: + self.on_failed_response_cb = self.take_damage_response + else: + self.on_failed_response_cb = self.take_no_damage_response return True def get_indians(self, attacker): @@ -724,6 +793,16 @@ class Player: self.notify_self() self.attacker = None + def take_no_damage_response(self): + if self.dmg_card_index != None and self.dmg_card_index != -1 and self.game.check_event(ce.Rimbalzo): + self.game.deck.scrap(self.equipment.pop(self.dmg_card_index)) + self.dmg_card_index = -1 + self.mancato_needed = 0 + self.expected_response = [] + self.event_type = '' + self.notify_self() + self.attacker = None + def respond(self, hand_index): if self.pending_action != PendingAction.RESPOND: return self.pending_action = PendingAction.WAIT diff --git a/frontend/src/components/Deck.vue b/frontend/src/components/Deck.vue index 53e6b77..2b0ed6a 100644 --- a/frontend/src/components/Deck.vue +++ b/frontend/src/components/Deck.vue @@ -5,7 +5,7 @@
- +
@@ -62,7 +62,8 @@ export default { this.eventCard = card == false ? { name: 'PewPew!', icon: '🎲', - back: true + back: true, + expansion: 'fistful-of-cards', } : card }, }, @@ -72,6 +73,14 @@ export default { name: this.$t('end_turn'), icon: '⛔️' } + }, + eventClasses() { + let classes = { + 'last-event':true, + 'back':this.eventCard.back + } + classes[this.eventCard.expansion] = true + return classes } }, methods: { From e045bacc5255e11d56784020503b2a86cb0e3259 Mon Sep 17 00:00:00 2001 From: Giulio Date: Tue, 22 Dec 2020 17:46:07 +0100 Subject: [PATCH 39/43] fix bot: Prigione - Giudice --- backend/bang/players.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/bang/players.py b/backend/bang/players.py index a31cdae..8b19f81 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -226,7 +226,7 @@ class Player: elif self.pending_action == PendingAction.PLAY: equippables = [c for c in self.hand if (c.is_equipment or c.usable_next_turn) and not isinstance(c, cs.Prigione) and not any([type(c) == type(x) for x in self.equipment])] misc = [c for c in self.hand if isinstance(c, cs.WellsFargo) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives)] - need_target = [c for c in self.hand if c.need_target and c.can_be_used_now and not (c.need_with and len(self.hand) < 2) and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo)))] + need_target = [c for c in self.hand if c.need_target and c.can_be_used_now and not (c.need_with and len(self.hand) < 2) and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo))) and not ( isinstance(c, cs.Prigione) and self.game.check_event(ce.IlGiudice))] green_cards = [c for c in self.equipment if not self.game.check_event(ce.Lazo) and not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now] if len(equippables) > 0 and not self.game.check_event(ce.IlGiudice): for c in equippables: From f15102ad101bd12d20f10ee670440f4159cb707d Mon Sep 17 00:00:00 2001 From: Giulio Date: Tue, 22 Dec 2020 19:17:51 +0100 Subject: [PATCH 40/43] fix bot: Pony Express - Giudice --- backend/bang/players.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/bang/players.py b/backend/bang/players.py index 8b19f81..94ee0fd 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -225,7 +225,7 @@ class Player: self.draw('') elif self.pending_action == PendingAction.PLAY: equippables = [c for c in self.hand if (c.is_equipment or c.usable_next_turn) and not isinstance(c, cs.Prigione) and not any([type(c) == type(x) for x in self.equipment])] - misc = [c for c in self.hand if isinstance(c, cs.WellsFargo) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives)] + misc = [c for c in self.hand if (isinstance(c, cs.WellsFargo) and not c.usable_next_turn) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives)] need_target = [c for c in self.hand if c.need_target and c.can_be_used_now and not (c.need_with and len(self.hand) < 2) and not (self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and not self.game.check_event(ce.Lazo))) and not ( isinstance(c, cs.Prigione) and self.game.check_event(ce.IlGiudice))] green_cards = [c for c in self.equipment if not self.game.check_event(ce.Lazo) and not isinstance(c, cs.Mancato) and c.usable_next_turn and c.can_be_used_now] if len(equippables) > 0 and not self.game.check_event(ce.IlGiudice): From 2beb1563ae6a8fcbdb140e7ed9dad0e840a71180 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 21:52:06 +0100 Subject: [PATCH 41/43] fix rimbalzo --- backend/bang/expansions/fistful_of_cards/card_events.py | 4 ++-- backend/bang/players.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/bang/expansions/fistful_of_cards/card_events.py b/backend/bang/expansions/fistful_of_cards/card_events.py index d739c09..ed14be4 100644 --- a/backend/bang/expansions/fistful_of_cards/card_events.py +++ b/backend/bang/expansions/fistful_of_cards/card_events.py @@ -82,8 +82,8 @@ class Ranch(CardEvent): class Rimbalzo(CardEvent): def __init__(self): super().__init__("Rimbalzo", "⏮") - self.desc = "Il giocatore di turno può giocare bang contro le carte equipaggiate dagli altri giocatori, se non giocano mancato vengono scartate" - self.desc_eng = "The player can play bang against the cards equipped by the other players, if they do not play miss they are discarded" + self.desc = "Il giocatore di turno può giocare bang contro le carte equipaggiate dagli altri giocatori, se non giocano mancato vengono scartate (clicca la carta evento)" + self.desc_eng = "The player can play bang against the cards equipped by the other players, if they do not play miss they are discarded (click the event card)" class RouletteRussa(CardEvent): def __init__(self): diff --git a/backend/bang/players.py b/backend/bang/players.py index 94ee0fd..ca33173 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -692,7 +692,9 @@ class Player: self.attacker = attacker self.mancato_needed = 1 if not double else 2 if card_index != None: - self.dmg_card_index = None + self.dmg_card_index = card_index + else: + self.dmg_card_index = -1 for i in range(len(self.equipment)): if self.equipment[i].can_be_used_now: print('usable', self.equipment[i]) From 2a7ffcbf4383d17f46b5c28c86deffb2a471aa1e Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 21:56:09 +0100 Subject: [PATCH 42/43] fix apache indiani --- backend/bang/players.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/bang/players.py b/backend/bang/players.py index ca33173..cbfe907 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -733,6 +733,7 @@ class Player: def get_indians(self, attacker): self.attacker = attacker + if isinstance(self.character, chd.ApacheKid): return False if not self.game.is_competitive and len([c for c in self.hand if isinstance(c, cs.Bang) or (isinstance(self.character, chars.CalamityJanet) and isinstance(c, cs.Mancato))]) == 0: print('Cant defend') self.take_damage_response() From 25bf088c3eea4763aff8aa807c3507db5a82828d Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 23:28:57 +0100 Subject: [PATCH 43/43] text for card choose --- backend/bang/game.py | 2 ++ backend/bang/players.py | 9 +++++++++ frontend/src/components/Player.vue | 4 +++- frontend/src/i18n/en.json | 6 ++++++ frontend/src/i18n/it.json | 6 ++++++ 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/backend/bang/game.py b/backend/bang/game.py index fe03c09..b4a210b 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -198,6 +198,7 @@ class Game: def emporio(self): self.available_cards = [self.deck.draw(True) for i in range(len([p for p in self.players if p.lives > 0]))] self.players[self.turn].pending_action = pl.PendingAction.CHOOSE + self.players[self.turn].choose_text = 'choose_card_to_get' self.players[self.turn].available_cards = self.available_cards self.players[self.turn].notify_self() @@ -212,6 +213,7 @@ class Game: self.players[self.turn].notify_self() else: nextPlayer.pending_action = pl.PendingAction.CHOOSE + self.players[self.turn].choose_text = 'choose_card_to_get' nextPlayer.available_cards = self.available_cards nextPlayer.notify_self() diff --git a/backend/bang/players.py b/backend/bang/players.py index cbfe907..cb0297a 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -51,6 +51,7 @@ class Player: self.can_play_vendetta = True self.is_giving_life = False self.is_using_checchino = False + self.choose_text = 'choose_card_to_get' self.using_rimbalzo = 0 # 0 no, 1 scegli giocatore, 2 scegli carta self.can_play_ranch = True self.is_playing_ranch = False @@ -162,6 +163,7 @@ class Player: 'icon': '⚫' }] self.is_drawing = True + self.choose_text = 'choose_guess' self.pending_action = PendingAction.CHOOSE elif self.can_play_ranch and self.pending_action == PendingAction.PLAY and self.game.check_event(ce.Ranch): self.can_play_ranch = False @@ -169,6 +171,7 @@ class Player: self.discarded_cards = [] self.available_cards.append({'icon': '✅'}) self.is_playing_ranch = True + self.choose_text = 'choose_ranch' self.pending_action = PendingAction.CHOOSE elif isinstance(self.character, chars.SuzyLafayette) and len(self.hand) == 0 and ( not self.is_my_turn or self.pending_action == PendingAction.PLAY): self.hand.append(self.game.deck.draw(True)) @@ -320,6 +323,7 @@ class Player: 'alt_text': ''.join(['❤️']*p.lives)+''.join(['💀']*(p.max_lives-p.lives)) } for p in self.game.players if p != self and p.lives < p.max_lives] self.available_cards.append({'icon': '❌'}) + self.choose_text = 'choose_fratelli_di_sangue' self.pending_action = PendingAction.CHOOSE self.is_giving_life = True elif not self.game.check_event(ce.Lazo) and any([isinstance(c, cs.Dinamite) or isinstance(c, cs.Prigione) for c in self.equipment]): @@ -342,6 +346,7 @@ class Player: 'alt_text': ''.join(['❤️']*p['lives'])+''.join(['💀']*(p['max_lives']-p['lives'])) } for p in self.game.get_visible_players(self) if p['dist'] <= self.get_sight()] self.available_cards.append({'icon': '❌'}) + self.choose_text = 'choose_cecchino' self.pending_action = PendingAction.CHOOSE self.notify_self() elif self.is_my_turn and self.pending_action == PendingAction.PLAY and pile == 'event' and self.game.check_event(ce.Rimbalzo) and len([c for c in self.hand if c.name == cs.Bang(0,0).name]) > 0: @@ -350,6 +355,7 @@ class Player: 'icon': '⭐️' if isinstance(p.role, r.Sheriff) else '🤠' } for p in self.game.players if len(p.equipment) > 0 and p != self] self.available_cards.append({'icon': '❌'}) + self.choose_text = 'choose_rimbalzo_player' self.pending_action = PendingAction.CHOOSE self.using_rimbalzo = 1 self.notify_self() @@ -362,11 +368,13 @@ class Player: elif isinstance(self.character, chars.KitCarlson): self.is_drawing = True self.available_cards = [self.game.deck.draw() for i in range(3)] + self.choose_text = 'choose_card_to_get' self.pending_action = PendingAction.CHOOSE self.notify_self() elif isinstance(self.character, chd.PatBrennan) and type(pile) == str and pile != self.name and pile in self.game.players_map and len(self.game.get_player_named(pile).equipment) > 0: self.is_drawing = True self.available_cards = self.game.get_player_named(pile).equipment + self.choose_text = 'choose_card_to_get' self.pending_action = PendingAction.CHOOSE self.notify_self() else: @@ -569,6 +577,7 @@ class Player: if self.using_rimbalzo == 1 and 'name' in self.available_cards[card_index]: self.rimbalzo_p = self.available_cards[card_index]['name'] self.available_cards = self.game.get_player_named(self.available_cards[card_index]['name']).equipment + self.choose_text = 'choose_rimbalzo_card' self.using_rimbalzo = 2 elif self.using_rimbalzo == 2 and 'name' in self.available_cards[card_index].__dict__: card = next(c for c in self.hand if c.name == cs.Bang(0,0).name) diff --git a/frontend/src/components/Player.vue b/frontend/src/components/Player.vue index 698001c..78fc6f3 100644 --- a/frontend/src/components/Player.vue +++ b/frontend/src/components/Player.vue @@ -38,7 +38,7 @@ - + @@ -101,6 +101,7 @@ export default { desc: '', scrapHand: [], sidWantsScrapForHealth: false, + choose_text: '', joseScrap: false, holydayScrap: false, special_use_count: 0, @@ -128,6 +129,7 @@ export default { this.max_lives = self.max_lives this.has_played_bang = self.has_played_bang this.special_use_count = self.special_use_count + this.choose_text = self.choose_text this.is_my_turn = self.is_my_turn if (this.is_my_turn) document.title = this.$t('your_turn')+' | PewPew!' else if (this.pending_action == 3) document.title = this.$t('your_response')+' | PewPew!' diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 69c916f..b2e6efd 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -38,6 +38,12 @@ "hand": "HAND", "card_against": "Who will you play your card against?", "choose_card_to_get": "Choose a card", + "choose_guess": "Guess the color of the suit", + "choose_ranch": "Choose the cards to replace", + "choose_fratelli_di_sangue": "Choose who you want to donate one of your lives", + "choose_cecchino": "Choose who to shoot", + "choose_rimbalzo_player": "Choose the target of the bang", + "choose_rimbalzo_card": "Choose the card to discard the bang to", "you_died":"YOU DIED", "spectate":"SPECTATE", "you_win":"YOU WON", diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index 773bb29..304a123 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -38,6 +38,12 @@ "hand": "MANO", "card_against": "Contro chi vuoi giocare la carta", "choose_card_to_get": "Scegli che carta pescare", + "choose_guess": "Indovina il colore del seme", + "choose_ranch": "Scegli le carte da sostituire", + "choose_fratelli_di_sangue": "Scegli a chi donare una delle tue vite", + "choose_cecchino": "Scegli contro chi sparare", + "choose_rimbalzo_player": "Scegli contro chi scartare il bang", + "choose_rimbalzo_card": "Scegli contro che carta scartare il bang", "you_died": "SEI MORTO", "spectate": "SPETTATORE", "you_win": "HAI VINTO",