From 09c98fc09a1e0277056bd449df38aeb70a79e9b1 Mon Sep 17 00:00:00 2001 From: Alberto Xamin Date: Tue, 22 Dec 2020 17:36:45 +0100 Subject: [PATCH] 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: {