diff --git a/backend/__init__.py b/backend/__init__.py index 7eed5be..2472603 100644 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -312,7 +312,13 @@ def chat_message(sid, msg): cmd = msg.split() if len(cmd) >= 3: sio.emit('chat_message', room=ses.game.name, data={'color': f'red','text':f'🚨 {ses.name} is in debug mode and changed event'}) - chs = ses.game.deck.event_cards + import bang.expansions.fistful_of_cards.card_events as ce + import bang.expansions.high_noon.card_events as ceh + chs = [] + chs.extend(ce.get_all_events()) + chs.append(ce.get_endgame_card()) + chs.extend(ceh.get_all_events()) + chs.append(ceh.get_endgame_card()) ses.game.deck.event_cards.insert(int(cmd[1]), [c for c in chs if c!=None and c.name == ' '.join(cmd[2:])][0]) ses.game.notify_event_card() elif '/removecard' in msg: @@ -429,5 +435,21 @@ def get_characters(sid): cards = ch.all_characters(['dodge_city']) sio.emit('characters_info', room=sid, data=json.dumps(cards, default=lambda o: o.__dict__)) +@sio.event +def get_highnooncards(sid): + import bang.expansions.high_noon.card_events as ceh + chs = [] + chs.extend(ceh.get_all_events()) + chs.append(ceh.get_endgame_card()) + sio.emit('highnooncards_info', room=sid, data=json.dumps(chs, default=lambda o: o.__dict__)) + +@sio.event +def get_foccards(sid): + import bang.expansions.fistful_of_cards.card_events as ce + chs = [] + chs.extend(ce.get_all_events()) + chs.append(ce.get_endgame_card()) + sio.emit('foccards_info', room=sid, data=json.dumps(chs, default=lambda o: o.__dict__)) + if __name__ == '__main__': eventlet.wsgi.server(eventlet.listen(('', 5001)), app) diff --git a/backend/bang/expansions/high_noon/card_events.py b/backend/bang/expansions/high_noon/card_events.py index 2f42167..7f79fca 100644 --- a/backend/bang/expansions/high_noon/card_events.py +++ b/backend/bang/expansions/high_noon/card_events.py @@ -71,13 +71,13 @@ class Manette(CardEvent): def __init__(self): super().__init__("Manette", "🔗") #self.desc = "Dopo aver pescato in fase 1, il giocatore di turno dichiara un seme: potrà usare solamente carte di quel seme nel suo turno" - #self.desc_eng = "" + #self.desc_eng = "After drawing in phase 1, the player declares a suit. He will be able to use only cards of that suit for that turn" class NuovaIdentita(CardEvent): def __init__(self): super().__init__("Nuova Identita", "🕶") #self.desc = "All'inizio del proprio turno, ogni giocatore potrà decidere se sostituire il suo personaggio attuale con quello era stato proposto ad inizio partita, se lo fa riparte con 2 punti vita" - #self.desc_eng = "" + #self.desc_eng = "At the beginning of their turn, each player can choose to change its character with the other shown at the game start. If he does so he restarts from 2 HP." class CittaFantasma(CardEvent): def __init__(self): @@ -110,7 +110,7 @@ def get_all_events(): Sermone(), Sete(), Sparatoria(), - # Manette(), + Manette(), NuovaIdentita(), ] random.shuffle(cards) diff --git a/backend/bang/game.py b/backend/bang/game.py index 1710b06..a6f2725 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -44,6 +44,26 @@ class Game: self.characters_to_distribute = 2 # personaggi da dare a inizio partita self.debug = False + def reset(self): + print('resetting lobby') + self.players.extend(self.spectators) + self.spectators = [] + for bot in [p for p in self.players if p.is_bot]: + bot.game = None + self.players = [p for p in self.players if not p.is_bot] + print(self.players) + self.started = False + self.is_handling_death = False + self.waiting_for = 0 + self.incremental_turn = 0 + self.turn = 0 + self.pending_winners = [] + for p in self.players: + p.reset() + p.notify_self() + eventlet.sleep(0.5) + self.notify_room() + def notify_room(self, sid=None): if len([p for p in self.players if p.character == None]) != 0 or sid: self.sio.emit('room', room=self.name if not sid else sid, data={ @@ -549,25 +569,6 @@ class Game: corpse.notify_self() self.next_turn() - def reset(self): - print('resetting lobby') - self.players.extend(self.spectators) - self.spectators = [] - for bot in [p for p in self.players if p.is_bot]: - bot.game = None - self.players = [p for p in self.players if not p.is_bot] - print(self.players) - self.started = False - self.is_handling_death = False - self.waiting_for = 0 - self.incremental_turn = 0 - self.turn = 0 - self.pending_winners = [] - for p in self.players: - p.reset() - p.notify_self() - eventlet.sleep(0.5) - self.notify_room() def check_event(self, ev): if self.deck == None or len(self.deck.event_cards) == 0: return False diff --git a/backend/bang/players.py b/backend/bang/players.py index 00906ad..114c844 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -28,44 +28,9 @@ class Player: self.name = name self.sid = sid self.sio = sio - self.hand: cs.Card = [] - self.equipment: cs.Card = [] - self.role: r.Role = None - self.character: chars.Character = None - self.real_character: chars.Character = None - self.lives = 0 - self.max_lives = 0 - self.game: g = None - self.is_my_turn = False - self.is_waiting_for_action = True - self.has_played_bang = False - self.pending_action: PendingAction = None - self.available_characters = [] - self.was_shot = False - self.on_pick_cb = None - self.on_failed_response_cb = None - self.event_type: str = None - self.expected_response = [] - self.attacker: Player = None - self.target_p: str = None - self.is_drawing = False - self.can_play_vendetta = True - self.is_giving_life = False - self.is_using_checchino = False - self.choose_text = 'choose_card_to_get' - self.using_rimbalzo = 0 # 0 no, 1 scegli giocatore, 2 scegli carta - self.can_play_ranch = True - self.is_playing_ranch = False - self.mancato_needed = 0 - self.molly_discarded_cards = 0 self.is_bot = bot - self.bang_used = 0 - self.special_use_count = 0 - self.is_dead = False - self.death_turn = 0 - self.is_ghost = False - self.not_chosen_character = None - self.noStar = False + self.game: g = None + self.reset() def reset(self): self.hand: cs.Card = [] @@ -92,6 +57,7 @@ class Player: self.target_p: str = None self.is_drawing = False self.special_use_count = 0 + self.committed_suit_manette = None self.not_chosen_character = None try: del self.win_status @@ -103,6 +69,11 @@ class Player: self.is_ghost = False self.death_turn = 0 self.noStar = False + self.can_play_vendetta = True + self.is_giving_life = False + self.choose_text = 'choose_card_to_get' + self.using_rimbalzo = 0 # 0 no, 1 scegli giocatore, 2 scegli carta + self.bang_used = 0 def join_game(self, game): self.game = game @@ -248,10 +219,11 @@ 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 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.Indiani) or isinstance(c, cs.Gatling) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives and not self.game.check_event(ceh.IlReverendo))) + non_blocked_cards = [card for card in self.hand if (self.game.check_event(ceh.Manette) and card.suit == self.committed_suit_manette)] + equippables = [c for c in non_blocked_cards 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 non_blocked_cards if (isinstance(c, cs.WellsFargo) or isinstance(c, cs.Indiani) or isinstance(c, cs.Gatling) or isinstance(c, cs.Diligenza) or isinstance(c, cs.Emporio) or (isinstance(c, cs.Birra) and self.lives < self.max_lives and not self.game.check_event(ceh.IlReverendo)) or (c.need_with and len(self.hand) > 1 and not c.need_target and not (isinstance(c, csd.Whisky) and self.lives == self.max_lives))) and not (not c.can_be_used_now and self.game.check_event(ce.IlGiudice))] - 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 ( + need_target = [c for c in non_blocked_cards if c.need_target and c.can_be_used_now and not (c.need_with and len(self.hand) < 2) and not ( (self.game.check_event(ceh.Sermone) or self.has_played_bang and not (any([isinstance(c, cs.Volcanic) for c in self.equipment]) and type(c) == type(cs.Bang) ) 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] @@ -261,7 +233,9 @@ class Player: return elif len(misc) > 0: for c in misc: - if self.play_card(self.hand.index(c)): + if c.need_with and self.play_card(self.hand.index(c), _with=sample([j for j in range(len(self.hand)) if j != self.hand.index(c)], 1)[0]): + return + elif self.play_card(self.hand.index(c)): return elif len(need_target) > 0: for c in need_target: @@ -458,9 +432,21 @@ class Player: self.hand.append(self.game.deck.draw()) if self.game.check_event(ceh.Sete): return self.notify_self() - if self.game.check_event(ceh.IlTreno) or (self.is_ghost and self.game.check_event(ceh.CittaFantasma)): - self.hand.append(self.game.deck.draw()) - self.notify_self() + if self.game.check_event(ceh.IlTreno) or (self.is_ghost and self.game.check_event(ceh.CittaFantasma)): + self.hand.append(self.game.deck.draw()) + self.manette() + self.notify_self() + + def manette(self): + if self.game.check_event(ceh.Manette): + self.choose_text = 'choose_manette' + self.available_cards = [{ + 'name': '', + 'icon': '♦♣♥♠'[s], + 'alt_text': '', + 'noDesc': True + } for s in [0,1,2,3]] + self.pending_action = PendingAction.CHOOSE def pick(self): if self.pending_action != PendingAction.PICK: @@ -547,7 +533,7 @@ class Player: withCard = self.hand.pop(_with) if hand_index > _with else self.hand.pop(_with - 1) print(self.name, 'is playing ', card, ' against:', against, ' with:', _with) did_play_card = False - event_blocks_card = (self.game.check_event(ce.IlGiudice) and (card.is_equipment or (card.usable_next_turn and not card.can_be_used_now))) or (self.game.check_event(ce.Lazo) and card.usable_next_turn and card.can_be_used_now) + event_blocks_card = (self.game.check_event(ce.IlGiudice) and (card.is_equipment or (card.usable_next_turn and not card.can_be_used_now))) or (self.game.check_event(ce.Lazo) and card.usable_next_turn and card.can_be_used_now) or (self.game.check_event(ceh.Manette) and card.suit != self.committed_suit_manette and not (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.check_suit(self.game, [cs.Suit.DIAMONDS])) and not event_blocks_card: if against == self.name and not isinstance(card, csd.Tequila): did_play_card = False @@ -609,6 +595,11 @@ class Player: self.lives = 2 self.sio.emit('chat_message', room=self.game.name, data=f'_choose_character|{self.name}|{self.character.name}') self.play_turn(again = True) + elif self.game.check_event(ceh.Manette) and self.choose_text == 'choose_manette': + self.committed_suit_manette = cs.Suit(card_index) + self.sio.emit('chat_message', room=self.game.name, data=f'_choose_manette|{self.name}|{"♦♣♥♠"[card_index]}') + self.pending_action = PendingAction.PLAY + 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']) @@ -694,6 +685,7 @@ class Player: self.game.deck.put_on_top(self.available_cards.pop()) self.is_drawing = False self.pending_action = PendingAction.PLAY + self.manette() self.notify_self() elif self.is_drawing and self.character.check(self.game, chd.PatBrennan): self.is_drawing = False @@ -703,6 +695,7 @@ class Player: self.available_cards = [] self.game.get_player_named(self.pat_target).notify_self() self.pending_action = PendingAction.PLAY + self.manette() self.notify_self() else: # emporio self.game.respond_emporio(self, card_index) @@ -1023,6 +1016,7 @@ class Player: self.game.deck.scrap(self.hand.pop(), True) for i in range(len(self.equipment)): self.game.deck.scrap(self.equipment.pop(), True) + self.committed_suit_manette = None self.pending_action = PendingAction.WAIT self.notify_self() self.game.next_turn() diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 908258d..305afdc 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -108,9 +108,10 @@ export default { } }, mounted() { - if (localStorage.getItem('lang')) + if (localStorage.getItem('lang')) { this.$i18n.locale = localStorage.getItem('lang'); document.documentElement.lang = this.$i18n.locale; + } this.detectColorScheme() }, created() { diff --git a/frontend/src/components/Help.vue b/frontend/src/components/Help.vue index 8ed959e..13d9032 100644 --- a/frontend/src/components/Help.vue +++ b/frontend/src/components/Help.vue @@ -75,6 +75,24 @@ +

{{$t('help.highnooncards')}}

+
+
+ +
+

{{$t(`cards.${c.name}.desc`)}}

+
+
+
+

{{$t('help.foccards')}}

+
+
+ +
+

{{$t(`cards.${c.name}.desc`)}}

+
+
+