diff --git a/backend/bang/expansions/dodge_city/cards.py b/backend/bang/expansions/dodge_city/cards.py index ecc0b68..b62c0d2 100644 --- a/backend/bang/expansions/dodge_city/cards.py +++ b/backend/bang/expansions/dodge_city/cards.py @@ -75,12 +75,19 @@ class Rissa(CatBalou): def play_card(self, player, against, _with): if _with != None: - players_with_cards = [p.name for p in player.game.players if p != player and (len(p.hand)+len(p.equipment)) > 0] - if len(players_with_cards) == 0: + if len([p for p in player.game.players if p != player and (len(p.hand)+len(p.equipment)) > 0]) == 0: return False + #se sono qui vuol dire che ci sono giocatori con carte in mano oltre a me + player.rissa_targets = [] + target = player.game.get_player_named(player.name, next=True) + while target != player: + if len(target.hand) + len(target.equipment) > 0: + player.rissa_targets.append(target) + target = player.game.get_player_named(target.name, next=True) player.game.deck.scrap(_with) player.event_type = 'rissa' - super().play_card(player, against=players_with_cards[0]) + print(f'rissa targets: {player.rissa_targets}') + super().play_card(player, against=player.rissa_targets.pop(0).name) player.sio.emit('chat_message', room=player.game.name, data=f'_play_card|{player.name}|{self.name}') return True return False diff --git a/backend/bang/game.py b/backend/bang/game.py index ad5dd2a..152ff6d 100644 --- a/backend/bang/game.py +++ b/backend/bang/game.py @@ -81,12 +81,12 @@ class Game: eventlet.sleep(0.5) self.notify_room() - def replay(self, log): + def replay(self, log, speed=1.0, fast_forward = -1): from tests.dummy_socket import DummySocket self.players = [] self.is_hidden = True self.is_replay = True - self.replay_speed = 1 + self.replay_speed = speed for i in range(len(log)-1): print('replay:', i, 'of', len(log)-3, '->', log[i]) if (log[i] == "@@@"): @@ -116,7 +116,10 @@ class Game: player.end_turn() if cmd[1] == 'play_card': data = json.loads(cmd[2]) - player.play_card(data['index'], data['against'], data['with']) + if len(data) != 0: + player.play_card(data['index'], data['against'], data['with']) + else: + player.special(data) #TODO: remove this, is only for the typo in the log if cmd[1] == 'respond': player.respond(int(cmd[2])) if cmd[1] == 'choose': @@ -131,6 +134,9 @@ class Game: player.buy_gold_rush_card(int(cmd[2])) # if cmd[1] == 'chat_message': # chat_message(None, cmd[2], player) + if i == fast_forward: + self.replay_speed = 1.0 + eventlet.sleep(max(self.replay_speed, 0.1)) eventlet.sleep(6) if self.is_replay: @@ -390,7 +396,9 @@ class Game: {'name':nextPlayer.name,'cards': self.available_cards}, default=lambda o: o.__dict__)) nextPlayer.notify_self() - def get_player_named(self, name:str): + def get_player_named(self, name:str, next=False): + if next: + return self.players[(self.players_map[name]+1) % len(self.players)] return self.players[self.players_map[name]] def responders_did_respond_resume_turn(self, did_lose=False): diff --git a/backend/bang/players.py b/backend/bang/players.py index d5e413f..fe45fa9 100644 --- a/backend/bang/players.py +++ b/backend/bang/players.py @@ -61,6 +61,7 @@ class Player: self.target_p: str = None self.is_drawing = False self.special_use_count = 0 + self.rissa_targets = [] self.committed_suit_manette = None self.not_chosen_character = None try: @@ -207,6 +208,7 @@ class Player: ser.pop('on_pick_cb') ser.pop('on_failed_response_cb') ser.pop('attacker') + ser.pop('rissa_targets') if self.attacker: ser['attacker'] = self.attacker.name ser['sight'] = self.get_sight() @@ -657,7 +659,7 @@ class Player: def choose(self, card_index): if self.pending_action != PendingAction.CHOOSE: return - if self.target_p and self.target_p != '': # panico, cat balou + if self.target_p and self.target_p != '': # panico, cat balou, rissa target = self.game.get_player_named(self.target_p) card = None if (target.name == self.name): @@ -672,15 +674,14 @@ class Player: self.hand.append(card) else: self.game.deck.scrap(card, True) - if self.event_type != 'rissa' or (self.event_type == 'rissa' and (len([p.name for p in self.game.get_alive_players() if p != self and (len(p.hand)+len(p.equipment)) > 0]) == 0 or self.target_p == [p.name for p in self.game.get_alive_players() if p != self and (len(p.hand)+len(p.equipment)) > 0][-1])): + if self.event_type != 'rissa' or len(self.rissa_targets) == 0: self.event_type = '' self.target_p = '' self.choose_action = '' self.pending_action = PendingAction.PLAY else: - self.target_p = self.game.players[(self.game.players_map[self.target_p]+1)%len(self.game.players)].name - 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)%len(self.game.players)].name + self.target_p = self.rissa_targets.pop(0).name + print(f'rissa targets: {self.rissa_targets}') self.notify_self() elif self.choose_text == 'choose_ricercato': player = self.game.get_player_named(self.available_cards[card_index]['name']) diff --git a/backend/server.py b/backend/server.py index 0908df2..c9fbe64 100644 --- a/backend/server.py +++ b/backend/server.py @@ -331,7 +331,7 @@ def scrap(sid, card_index): @sio.event def special(sid, data): ses: Player = sio.get_session(sid) - ses.game.rpc_log.append(f'{ses.name};play_card;{json.dumps(data)}') + ses.game.rpc_log.append(f'{ses.name};special;{json.dumps(data)}') ses.special(data) @sio.event @@ -368,12 +368,16 @@ def chat_message(sid, msg, pl=None): return if '/replay' in msg and not '/replayspeed' in msg: _cmd = msg.split() - if len(_cmd) == 2: + if len(_cmd) >= 2: replay_id = _cmd[1] response = requests.get(f"https://www.toptal.com/developers/hastebin/raw/{replay_id}") log = response.text.splitlines() ses.game.spectators.append(ses) - ses.game.replay(log) + if len(_cmd) == 2: + ses.game.replay(log) + if len(_cmd) == 3: + line = int(_cmd[2]) + ses.game.replay(log, speed=0.1, fast_forward=line) return if '/replayspeed' in msg: _cmd = msg.split() diff --git a/frontend/package.json b/frontend/package.json index d1de466..faf14c8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,14 +8,14 @@ "lint": "vue-cli-service lint" }, "dependencies": { - "caniuse-lite": "^1.0.30001320", + "caniuse-lite": "^1.0.30001322", "core-js": "^3.16.2", "pretty-checkbox-vue": "^1.1.9", "register-service-worker": "^1.7.2", "socket.io-client": "^4.4.1", "vue": "^2.6.14", "vue-clipboard2": "^0.3.3", - "vue-i18n": "^8.27.0", + "vue-i18n": "^8.27.1", "vue-router": "^3.5.3", "vue-socket.io": "^3.0.10" }, diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 6ad06fe..c0079af 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2244,10 +2244,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001286, caniuse-lite@^1.0.30001320: - version "1.0.30001320" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz#8397391bec389b8ccce328636499b7284ee13285" - integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001286, caniuse-lite@^1.0.30001322: + version "1.0.30001322" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001322.tgz#2e4c09d11e1e8f852767dab287069a8d0c29d623" + integrity sha512-neRmrmIrCGuMnxGSoh+x7zYtQFFgnSY2jaomjU56sCkTA6JINqQrxutF459JpWcWRajvoyn95sOXq4Pqrnyjew== case-sensitive-paths-webpack-plugin@^2.3.0: version "2.4.0" @@ -7807,10 +7807,10 @@ vue-hot-reload-api@^2.3.0: version "2.3.4" resolved "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz" -vue-i18n@^8.27.0: - version "8.27.0" - resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.27.0.tgz#3e3b3ed2c107ccbd7f20dbdd7a96763a9990253e" - integrity sha512-SX35iJHL5PJ4Gfh0Mo/q0shyHiI2V6Zkh51c+k8E9O1RKv5BQyYrCxRzpvPrsIOJEnLaeiovet3dsUB0e/kDzw== +vue-i18n@^8.27.1: + version "8.27.1" + resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.27.1.tgz#fe660f6c14793ae404d6a715875d772594a3324f" + integrity sha512-lWrGm4F25qReJ7XxSnFVb2h3PfW54ldnM4C+YLBGGJ75+Myt/kj4hHSTKqsyDLamvNYpvINMicSOdW+7yuqgIQ== "vue-loader-v16@npm:vue-loader@^16.1.0": version "16.8.3"