mirror of
				https://github.com/solero/houdini.git
				synced 2025-11-04 06:31:54 +00:00 
			
		
		
		
	Card Jitsu Fire handlers
This commit is contained in:
		@@ -1,15 +1,651 @@
 | 
			
		||||
from houdini import IWaddle
 | 
			
		||||
import asyncio
 | 
			
		||||
import itertools
 | 
			
		||||
import math
 | 
			
		||||
import random
 | 
			
		||||
from collections import Counter
 | 
			
		||||
from dataclasses import dataclass, field
 | 
			
		||||
from typing import List, Union
 | 
			
		||||
 | 
			
		||||
from houdini import IWaddle, handlers
 | 
			
		||||
from houdini.data.ninja import Card
 | 
			
		||||
from houdini.handlers import XTPacket
 | 
			
		||||
from houdini.handlers.games.ninja.card import ninja_stamps_earned
 | 
			
		||||
from houdini.penguin import Penguin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@dataclass
 | 
			
		||||
class FireNinja:
 | 
			
		||||
    penguin: Penguin
 | 
			
		||||
    seat_id: int
 | 
			
		||||
    deck: List[Card] = field(default_factory=list)
 | 
			
		||||
    chosen: Union[int, None] = None
 | 
			
		||||
    energy: int = 6
 | 
			
		||||
    energy_won: int = 0
 | 
			
		||||
    state: int = 0
 | 
			
		||||
    ready: bool = False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CardJitsuFireLogic(IWaddle):
 | 
			
		||||
 | 
			
		||||
    room_id = 997
 | 
			
		||||
 | 
			
		||||
    Board = ['b', 's', 'w', 'f', 'c',
 | 
			
		||||
             's', 'f', 'w', 'b', 's',
 | 
			
		||||
             'w', 'f', 'c', 'w', 's', 'f']
 | 
			
		||||
    RuleSet = {'f': 's', 'w': 'f', 's': 'w'}
 | 
			
		||||
    DefaultTiles = [0, 8, 4, 12]
 | 
			
		||||
    AutoBattleTimeout = 22
 | 
			
		||||
 | 
			
		||||
    ItemAwards = [6025, 4120, 2013, 1086, 3032]
 | 
			
		||||
    StampAwards = {2: 256, 4: 262}
 | 
			
		||||
 | 
			
		||||
    RankSpeed = 1
 | 
			
		||||
 | 
			
		||||
    def __init__(self, waddle):
 | 
			
		||||
        super().__init__(waddle)
 | 
			
		||||
 | 
			
		||||
        self.ninjas = [FireNinja(
 | 
			
		||||
            penguin=p,
 | 
			
		||||
            seat_id=seat_id
 | 
			
		||||
        ) for seat_id, p in enumerate(waddle.penguins)]
 | 
			
		||||
        self.battle_ninjas = []
 | 
			
		||||
 | 
			
		||||
        self.podium = [0]*self.seats
 | 
			
		||||
        self.finish_position = self.seats
 | 
			
		||||
 | 
			
		||||
        self.tile_ids = CardJitsuFireLogic.DefaultTiles[:self.seats].copy()
 | 
			
		||||
 | 
			
		||||
        self.current_player = None
 | 
			
		||||
        self.ninja_circle = itertools.cycle(self.ninjas)
 | 
			
		||||
 | 
			
		||||
        self.spin_amount = 0
 | 
			
		||||
        self.move_clockwise = 0
 | 
			
		||||
        self.move_anticlockwise = 0
 | 
			
		||||
        self.tab_id = None
 | 
			
		||||
 | 
			
		||||
        self.current_battle_state = 0
 | 
			
		||||
        self.current_battle_element = 0
 | 
			
		||||
        self.current_battle_type = 'bt'
 | 
			
		||||
 | 
			
		||||
        self.choose_card_timeout = None
 | 
			
		||||
        self.choose_board_timeout = None
 | 
			
		||||
 | 
			
		||||
        self.next()
 | 
			
		||||
        self.deal()
 | 
			
		||||
        self.spin()
 | 
			
		||||
        self.set_choose_board_timeout()
 | 
			
		||||
 | 
			
		||||
    def next(self):
 | 
			
		||||
        self.current_player = next(self.ninja_circle)
 | 
			
		||||
        while self.current_player not in self.ninjas:
 | 
			
		||||
            self.current_player = next(self.ninja_circle)
 | 
			
		||||
 | 
			
		||||
    def deal(self):
 | 
			
		||||
        for ninja in self.ninjas:
 | 
			
		||||
            penguin = ninja.penguin
 | 
			
		||||
            deck = Counter(penguin.server.cards[card.card_id]
 | 
			
		||||
                           for card in penguin.cards.values()
 | 
			
		||||
                           for _ in range(card.quantity + card.member_quantity))
 | 
			
		||||
            dealt = Counter(ninja.deck)
 | 
			
		||||
            can_deal = list((deck - dealt).elements())
 | 
			
		||||
 | 
			
		||||
            if ninja.chosen is None:
 | 
			
		||||
                ninja.deck = random.sample(can_deal, 5)
 | 
			
		||||
            else:
 | 
			
		||||
                ninja.deck[ninja.chosen] = random.choice(can_deal)
 | 
			
		||||
 | 
			
		||||
    def spin(self):
 | 
			
		||||
        self.tab_id = None
 | 
			
		||||
        self.spin_amount = random.randrange(1, 7)
 | 
			
		||||
 | 
			
		||||
        player_position = self.tile_ids[self.current_player.seat_id]
 | 
			
		||||
        self.move_clockwise = (player_position + self.spin_amount) % 16
 | 
			
		||||
        self.move_anticlockwise = (player_position - self.spin_amount) % 16
 | 
			
		||||
 | 
			
		||||
    def set_choose_board_timeout(self):
 | 
			
		||||
        loop = asyncio.get_running_loop()
 | 
			
		||||
        self.choose_board_timeout = loop.call_later(
 | 
			
		||||
            CardJitsuFireLogic.AutoBattleTimeout,
 | 
			
		||||
            lambda: asyncio.ensure_future(self.auto_choose_board())
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def set_choose_card_timeout(self):
 | 
			
		||||
        loop = asyncio.get_running_loop()
 | 
			
		||||
        self.choose_card_timeout = loop.call_later(
 | 
			
		||||
            CardJitsuFireLogic.AutoBattleTimeout,
 | 
			
		||||
            lambda: asyncio.ensure_future(self.auto_choose_card())
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    async def auto_choose_board(self):
 | 
			
		||||
        self.tab_id = 1
 | 
			
		||||
        await self.current_player.penguin.send_xt('zm', 'tb')
 | 
			
		||||
        move = self.move_anticlockwise if random.randint(0, 1) else self.move_clockwise
 | 
			
		||||
        await self.choose_board(move, is_auto_play=True)
 | 
			
		||||
 | 
			
		||||
    async def auto_choose_card(self):
 | 
			
		||||
        for ninja in self.battle_ninjas:
 | 
			
		||||
            if ninja.chosen is None:
 | 
			
		||||
                playable_cards = self.get_playable_cards(ninja)
 | 
			
		||||
                await self.choose_card(ninja, random.choice(playable_cards))
 | 
			
		||||
 | 
			
		||||
    def get_ninja_by_seat_id(self, seat_id):
 | 
			
		||||
        return next(ninja for ninja in self.ninjas if ninja.seat_id == seat_id)
 | 
			
		||||
 | 
			
		||||
    def get_ninja_by_penguin(self, penguin):
 | 
			
		||||
        return next(ninja for ninja in self.ninjas if ninja.penguin == penguin)
 | 
			
		||||
 | 
			
		||||
    def get_ninjas_by_tile_id(self, tile_id):
 | 
			
		||||
        return [ninja for ninja in self.ninjas if self.tile_ids[ninja.seat_id] == tile_id]
 | 
			
		||||
 | 
			
		||||
    def is_card_playable(self, ninja, card_id):
 | 
			
		||||
        if self.current_battle_type == 'bt':
 | 
			
		||||
            if ninja.deck[card_id].element == self.current_battle_element:
 | 
			
		||||
                return True
 | 
			
		||||
            return all(card.element != self.current_battle_element for card in ninja.deck)
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def get_playable_cards(self, ninja):
 | 
			
		||||
        return [card_id for card_id in range(len(ninja.deck)) if self.is_card_playable(ninja, card_id)]
 | 
			
		||||
 | 
			
		||||
    def resolve_battle(self):
 | 
			
		||||
        if self.current_battle_type == 'be':
 | 
			
		||||
            first_ninja, second_ninja = self.battle_ninjas[:2]
 | 
			
		||||
            first_card = first_ninja.deck[first_ninja.chosen]
 | 
			
		||||
            second_card = second_ninja.deck[second_ninja.chosen]
 | 
			
		||||
 | 
			
		||||
            battle_result = CardJitsuFireLogic.get_battle_result(first_card, second_card)
 | 
			
		||||
 | 
			
		||||
            if battle_result == 0:
 | 
			
		||||
                first_ninja.state, second_ninja.state = (4, 1)
 | 
			
		||||
                first_ninja.energy += 1
 | 
			
		||||
                second_ninja.energy -= 1
 | 
			
		||||
                first_ninja.energy_won += 1
 | 
			
		||||
            elif battle_result == 1:
 | 
			
		||||
                first_ninja.state, second_ninja.state = (1, 4)
 | 
			
		||||
                first_ninja.energy -= 1
 | 
			
		||||
                second_ninja.energy += 1
 | 
			
		||||
                second_ninja.energy_won += 1
 | 
			
		||||
            else:
 | 
			
		||||
                first_ninja.state, second_ninja.state = (2, 2)
 | 
			
		||||
 | 
			
		||||
            self.current_battle_element = first_card.element if battle_result == 0 else second_card.element
 | 
			
		||||
        elif self.current_battle_type == 'bt':
 | 
			
		||||
            battle_card_values = [n.deck[n.chosen].value
 | 
			
		||||
                                  if n.deck[n.chosen].element == self.current_battle_element
 | 
			
		||||
                                  else 0 for n in self.battle_ninjas]
 | 
			
		||||
            highest_battle_card = max(battle_card_values)
 | 
			
		||||
            is_battle_tie = battle_card_values.count(highest_battle_card) >= 2
 | 
			
		||||
            for ninja in self.battle_ninjas:
 | 
			
		||||
                card = ninja.deck[ninja.chosen]
 | 
			
		||||
                if card.element != self.current_battle_element:
 | 
			
		||||
                    ninja.state = 1
 | 
			
		||||
                    ninja.energy -= 1
 | 
			
		||||
                elif is_battle_tie and card.value == highest_battle_card:
 | 
			
		||||
                    ninja.state = 2
 | 
			
		||||
                elif card.value == highest_battle_card:
 | 
			
		||||
                    ninja.state = 3
 | 
			
		||||
                else:
 | 
			
		||||
                    ninja.state = 1
 | 
			
		||||
                    ninja.energy -= 1
 | 
			
		||||
 | 
			
		||||
    async def click_spinner(self, tab_id):
 | 
			
		||||
        if self.current_battle_state == 0 and self.tab_id is None and 0 <= tab_id <= 6:
 | 
			
		||||
            self.tab_id = tab_id
 | 
			
		||||
            await self.send_xt('zm', 'is', self.current_player.seat_id, tab_id)
 | 
			
		||||
 | 
			
		||||
    async def ready_ninja(self, ninja):
 | 
			
		||||
        if self.current_battle_state == 0:
 | 
			
		||||
            ninja.ready = True
 | 
			
		||||
 | 
			
		||||
            if all(n.ready for n in self.ninjas):
 | 
			
		||||
                self.next()
 | 
			
		||||
                self.spin()
 | 
			
		||||
                self.deal()
 | 
			
		||||
 | 
			
		||||
                for n in self.ninjas:
 | 
			
		||||
                    n.chosen = None
 | 
			
		||||
                    n.ready = False
 | 
			
		||||
 | 
			
		||||
                    deck = ','.join(str(card.id) for card in n.deck)
 | 
			
		||||
                    spin = f'{self.spin_amount},{self.move_clockwise},{self.move_anticlockwise}'
 | 
			
		||||
 | 
			
		||||
                    await n.penguin.send_xt('zm', 'nt', self.current_player.seat_id, spin, deck)
 | 
			
		||||
 | 
			
		||||
                self.set_choose_board_timeout()
 | 
			
		||||
 | 
			
		||||
    async def choose_board(self, tile_id, is_auto_play=False):
 | 
			
		||||
        if self.current_battle_state == 0 and tile_id == self.move_clockwise or tile_id == self.move_anticlockwise:
 | 
			
		||||
            if not is_auto_play or self.current_battle_state == 0:
 | 
			
		||||
                self.tile_ids[self.current_player.seat_id] = tile_id
 | 
			
		||||
                tile_ids = ','.join(map(str, self.tile_ids))
 | 
			
		||||
 | 
			
		||||
                element = CardJitsuFireLogic.Board[tile_id]
 | 
			
		||||
 | 
			
		||||
                await self.send_xt('zm', 'ub', self.current_player.seat_id, tile_ids, self.tab_id)
 | 
			
		||||
 | 
			
		||||
                self.current_battle_type = 'bt'
 | 
			
		||||
                self.battle_ninjas = self.ninjas
 | 
			
		||||
            else:
 | 
			
		||||
                tile_id = self.tile_ids[self.current_player.seat_id]
 | 
			
		||||
                element = CardJitsuFireLogic.Board[tile_id]
 | 
			
		||||
 | 
			
		||||
            ninjas_on_tile = self.get_ninjas_by_tile_id(tile_id)
 | 
			
		||||
 | 
			
		||||
            if len(ninjas_on_tile) > 1:
 | 
			
		||||
                self.current_battle_state = 2
 | 
			
		||||
                self.current_battle_element = element
 | 
			
		||||
 | 
			
		||||
                if is_auto_play:
 | 
			
		||||
                    ninjas_on_tile.remove(self.current_player)
 | 
			
		||||
                    opponent = random.choice(ninjas_on_tile)
 | 
			
		||||
                    await self.choose_opponent(opponent.seat_id)
 | 
			
		||||
                else:
 | 
			
		||||
                    if len(ninjas_on_tile) > 2:
 | 
			
		||||
                        battle_seat_ids = ','.join(str(ninja.seat_id) for ninja in ninjas_on_tile)
 | 
			
		||||
                        await self.send_xt('zm', 'co', 0, battle_seat_ids)
 | 
			
		||||
                    else:
 | 
			
		||||
                        opponent = next(n for n in ninjas_on_tile if n != self.current_player)
 | 
			
		||||
                        await self.choose_opponent(opponent.seat_id)
 | 
			
		||||
            elif element in CardJitsuFireLogic.Board[1:4]:
 | 
			
		||||
                battle_seat_ids = ','.join(str(ninja.seat_id) for ninja in self.ninjas)
 | 
			
		||||
                self.current_battle_element = element
 | 
			
		||||
                self.current_battle_state = 3
 | 
			
		||||
 | 
			
		||||
                await self.send_xt('zm', 'sb', self.current_battle_type, battle_seat_ids, element)
 | 
			
		||||
 | 
			
		||||
                self.choose_board_timeout.cancel()
 | 
			
		||||
                self.set_choose_card_timeout()
 | 
			
		||||
            elif element == 'c':
 | 
			
		||||
                if is_auto_play:
 | 
			
		||||
                    battle_seat_ids = ','.join(str(ninja.seat_id) for ninja in self.ninjas)
 | 
			
		||||
                    self.current_battle_element = random.choice(CardJitsuFireLogic.Board[1:4])
 | 
			
		||||
                    self.current_battle_state = 3
 | 
			
		||||
 | 
			
		||||
                    await self.send_xt('zm', 'sb', self.current_battle_type, battle_seat_ids,
 | 
			
		||||
                                       self.current_battle_element)
 | 
			
		||||
 | 
			
		||||
                    self.choose_board_timeout.cancel()
 | 
			
		||||
                    self.set_choose_card_timeout()
 | 
			
		||||
                else:
 | 
			
		||||
                    self.current_battle_state = 1
 | 
			
		||||
                    await self.send_xt('zm', 'ct')
 | 
			
		||||
            elif element == 'b':
 | 
			
		||||
                self.current_battle_element = element
 | 
			
		||||
                self.current_battle_state = 2
 | 
			
		||||
 | 
			
		||||
                if is_auto_play:
 | 
			
		||||
                    opponent = next(n for n in self.ninjas if n != self.current_player)
 | 
			
		||||
                    await self.choose_opponent(opponent.seat_id)
 | 
			
		||||
                else:
 | 
			
		||||
                    if len(self.ninjas) > 2:
 | 
			
		||||
                        battle_seat_ids = ','.join(str(ninja.seat_id) for ninja in self.ninjas)
 | 
			
		||||
 | 
			
		||||
                        await self.send_xt('zm', 'co', 0, battle_seat_ids)
 | 
			
		||||
                    else:
 | 
			
		||||
                        opponent = next(n for n in self.ninjas if n != self.current_player)
 | 
			
		||||
                        await self.choose_opponent(opponent.seat_id)
 | 
			
		||||
 | 
			
		||||
    async def choose_card(self, ninja, card_id):
 | 
			
		||||
        if ninja.chosen is None and self.is_card_playable(ninja, card_id):
 | 
			
		||||
            ninja.chosen = card_id
 | 
			
		||||
 | 
			
		||||
            await self.send_xt('zm', 'ic', ninja.seat_id, f=lambda p: p != ninja.penguin)
 | 
			
		||||
 | 
			
		||||
            if all(n.chosen is not None for n in self.battle_ninjas):
 | 
			
		||||
                self.choose_card_timeout.cancel()
 | 
			
		||||
                self.resolve_battle()
 | 
			
		||||
 | 
			
		||||
                for n in self.ninjas:
 | 
			
		||||
                    if n.energy == 0:
 | 
			
		||||
                        self.podium[n.seat_id] = self.finish_position
 | 
			
		||||
                        self.finish_position -= 1
 | 
			
		||||
 | 
			
		||||
                if self.finish_position == 1:
 | 
			
		||||
                    winner_seat_id = self.podium.index(0)
 | 
			
		||||
                    self.podium[winner_seat_id] = 1
 | 
			
		||||
 | 
			
		||||
                battle_seat_ids = ','.join(str(n.seat_id) for n in self.battle_ninjas)
 | 
			
		||||
                battle_card_ids = ','.join(str(n.deck[n.chosen].id) for n in self.battle_ninjas)
 | 
			
		||||
                battle_energy = ','.join(str(n.energy) for n in self.battle_ninjas)
 | 
			
		||||
                battle_states = ','.join(str(n.state) for n in self.battle_ninjas)
 | 
			
		||||
                finish_positions = ','.join(str(position) for position in self.podium)
 | 
			
		||||
                battle = f'{self.current_battle_type},{self.current_battle_element}'
 | 
			
		||||
 | 
			
		||||
                for n in self.ninjas.copy():
 | 
			
		||||
                    deck = ','.join(str(card.id) for card in n.deck)
 | 
			
		||||
 | 
			
		||||
                    await n.penguin.send_xt(
 | 
			
		||||
                        'zm', 'rb',
 | 
			
		||||
                        battle_seat_ids,
 | 
			
		||||
                        battle_card_ids,
 | 
			
		||||
                        battle_energy,
 | 
			
		||||
                        battle_states,
 | 
			
		||||
                        battle,
 | 
			
		||||
                        deck,
 | 
			
		||||
                        finish_positions
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    if n.energy == 0 or self.finish_position == 1:
 | 
			
		||||
                        player_finish_position = self.podium[n.seat_id]
 | 
			
		||||
 | 
			
		||||
                        await end_game_stamps(n, player_finish_position)
 | 
			
		||||
                        await fire_ninja_progress(n.penguin, self.podium[n.seat_id])
 | 
			
		||||
 | 
			
		||||
                        finish_positions = ','.join(str(max(position, 1)) for position in self.podium)
 | 
			
		||||
                        await n.penguin.send_xt('zm', 'zo', finish_positions)
 | 
			
		||||
                        await self.remove_penguin(n.penguin, quit_early=False)
 | 
			
		||||
 | 
			
		||||
                self.current_battle_state = 0
 | 
			
		||||
 | 
			
		||||
    async def choose_opponent(self, seat_id):
 | 
			
		||||
        if self.current_battle_state == 2 and seat_id != self.current_player.seat_id:
 | 
			
		||||
            opponent = self.get_ninja_by_seat_id(seat_id)
 | 
			
		||||
            self.battle_ninjas = [self.current_player, opponent]
 | 
			
		||||
 | 
			
		||||
            self.current_battle_type = 'be'
 | 
			
		||||
            self.current_battle_state = 3
 | 
			
		||||
 | 
			
		||||
            battle_seat_ids = ','.join(str(ninja.seat_id) for ninja in self.battle_ninjas)
 | 
			
		||||
            await self.send_xt('zm', 'sb', self.current_battle_type, battle_seat_ids, self.current_battle_element)
 | 
			
		||||
 | 
			
		||||
            self.choose_board_timeout.cancel()
 | 
			
		||||
            self.set_choose_card_timeout()
 | 
			
		||||
 | 
			
		||||
    async def choose_trump(self, element):
 | 
			
		||||
        if self.current_battle_state == 1 and element in CardJitsuFireLogic.Board[1:4]:
 | 
			
		||||
            self.current_battle_element = element
 | 
			
		||||
            self.current_battle_state = 3
 | 
			
		||||
 | 
			
		||||
            battle_seat_ids = ','.join(str(ninja.seat_id) for ninja in self.ninjas)
 | 
			
		||||
            await self.send_xt('zm', 'sb', self.current_battle_type, battle_seat_ids, self.current_battle_element)
 | 
			
		||||
 | 
			
		||||
            self.choose_board_timeout.cancel()
 | 
			
		||||
            self.set_choose_card_timeout()
 | 
			
		||||
 | 
			
		||||
    async def remove_penguin(self, p, quit_early=True):
 | 
			
		||||
        await super().remove_penguin(p)
 | 
			
		||||
        ninja = self.get_ninja_by_penguin(p)
 | 
			
		||||
        self.ninjas.remove(ninja)
 | 
			
		||||
 | 
			
		||||
        if quit_early:
 | 
			
		||||
            self.podium[ninja.seat_id] = self.finish_position
 | 
			
		||||
            self.finish_position -= 1
 | 
			
		||||
            await self.send_xt('zm', 'cz', ninja.seat_id)
 | 
			
		||||
 | 
			
		||||
            if len(self.ninjas) == 1:
 | 
			
		||||
                opponent = next(n for n in self.ninjas if n != ninja)
 | 
			
		||||
                await opponent.penguin.send_xt('cz')
 | 
			
		||||
 | 
			
		||||
                await self.remove_penguin(opponent.penguin)
 | 
			
		||||
            elif len(self.ninjas) >= 2:
 | 
			
		||||
                if ninja == self.current_player and 0 <= self.current_battle_state <= 2:
 | 
			
		||||
                    self.choose_board_timeout.cancel()
 | 
			
		||||
                    await self.auto_choose_board()
 | 
			
		||||
                elif ninja.chosen is None and self.current_battle_state == 3:
 | 
			
		||||
                    playable_cards = self.get_playable_cards(ninja)
 | 
			
		||||
                    await self.choose_card(ninja, random.choice(playable_cards))
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_battle_result(cls, first_card, second_card):
 | 
			
		||||
        if first_card.element != second_card.element:
 | 
			
		||||
            return 0 if cls.RuleSet[first_card.element] == second_card.element else 1
 | 
			
		||||
        elif first_card.value > second_card.value:
 | 
			
		||||
            return 0
 | 
			
		||||
        elif second_card.value > first_card.value:
 | 
			
		||||
            return 1
 | 
			
		||||
        return -1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FireMatLogic(CardJitsuFireLogic):
 | 
			
		||||
 | 
			
		||||
    RankSpeed = 0.5
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FireSenseiLogic(CardJitsuFireLogic):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, waddle):
 | 
			
		||||
        super().__init__(waddle)
 | 
			
		||||
 | 
			
		||||
        sensei = FireNinja(
 | 
			
		||||
            penguin=waddle.penguins[0],
 | 
			
		||||
            seat_id=1
 | 
			
		||||
        )
 | 
			
		||||
        self.ninjas.append(sensei)
 | 
			
		||||
        self.tile_ids.append(CardJitsuFireLogic.DefaultTiles[1])
 | 
			
		||||
 | 
			
		||||
    async def auto_choose_card(self):
 | 
			
		||||
        ninja = self.ninjas[0]
 | 
			
		||||
        playable_cards = self.get_playable_cards(ninja)
 | 
			
		||||
        await self.choose_card(ninja, random.choice(playable_cards))
 | 
			
		||||
 | 
			
		||||
    async def ready_ninja(self, ninja):
 | 
			
		||||
        if self.current_battle_state == 0:
 | 
			
		||||
            self.next()
 | 
			
		||||
            self.spin()
 | 
			
		||||
            self.deal()
 | 
			
		||||
 | 
			
		||||
            ninja.chosen = None
 | 
			
		||||
 | 
			
		||||
            deck = ','.join(str(card.id) for card in ninja.deck)
 | 
			
		||||
            spin = f'{self.spin_amount},{self.move_clockwise},{self.move_anticlockwise}'
 | 
			
		||||
 | 
			
		||||
            await ninja.penguin.send_xt('zm', 'nt', self.current_player.seat_id, spin, deck)
 | 
			
		||||
 | 
			
		||||
            if self.current_player == ninja:
 | 
			
		||||
                self.set_choose_board_timeout()
 | 
			
		||||
            else:
 | 
			
		||||
                await self.auto_choose_board()
 | 
			
		||||
 | 
			
		||||
    async def choose_card(self, ninja, card_id):
 | 
			
		||||
        if ninja.chosen is None and self.is_card_playable(ninja, card_id):
 | 
			
		||||
            self.choose_card_timeout.cancel()
 | 
			
		||||
 | 
			
		||||
            sensei = self.ninjas[1]
 | 
			
		||||
            ninja.chosen = card_id
 | 
			
		||||
            card = ninja.deck[ninja.chosen]
 | 
			
		||||
 | 
			
		||||
            can_beat_sensei = ninja.penguin.fire_ninja_rank >= 4
 | 
			
		||||
            sensei_card = random.choice(list(ninja.penguin.server.cards.values())) \
 | 
			
		||||
                if can_beat_sensei else self.get_win_card(card)
 | 
			
		||||
            sensei.chosen = 0
 | 
			
		||||
            sensei.deck = [sensei_card]
 | 
			
		||||
 | 
			
		||||
            await ninja.penguin.send_xt('zm', 'ic', 1)
 | 
			
		||||
 | 
			
		||||
            self.resolve_battle()
 | 
			
		||||
 | 
			
		||||
            if ninja.energy == 0:
 | 
			
		||||
                self.podium = [2, 1]
 | 
			
		||||
            if sensei.energy == 0:
 | 
			
		||||
                self.podium = [1, 2]
 | 
			
		||||
 | 
			
		||||
            battle_seat_ids = ','.join(str(n.seat_id) for n in self.battle_ninjas)
 | 
			
		||||
            battle_card_ids = ','.join(str(n.deck[n.chosen].id) for n in self.battle_ninjas)
 | 
			
		||||
            battle_energy = ','.join(str(n.energy) for n in self.battle_ninjas)
 | 
			
		||||
            battle_states = ','.join(str(n.state) for n in self.battle_ninjas)
 | 
			
		||||
            finish_positions = ','.join(str(position) for position in self.podium)
 | 
			
		||||
            deck = ','.join(str(card.id) for card in ninja.deck)
 | 
			
		||||
            battle = f'{self.current_battle_type},{self.current_battle_element}'
 | 
			
		||||
 | 
			
		||||
            await ninja.penguin.send_xt(
 | 
			
		||||
                'zm', 'rb',
 | 
			
		||||
                battle_seat_ids,
 | 
			
		||||
                battle_card_ids,
 | 
			
		||||
                battle_energy,
 | 
			
		||||
                battle_states,
 | 
			
		||||
                battle,
 | 
			
		||||
                deck,
 | 
			
		||||
                finish_positions
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            player_finish_position = self.podium[ninja.seat_id]
 | 
			
		||||
            if player_finish_position > 0:
 | 
			
		||||
                await end_game_stamps(ninja, player_finish_position)
 | 
			
		||||
                await fire_ninja_progress(ninja.penguin, player_finish_position)
 | 
			
		||||
 | 
			
		||||
                await ninja.penguin.send_xt('zm', 'zo', finish_positions)
 | 
			
		||||
                await self.remove_penguin(ninja.penguin, quit_early=False)
 | 
			
		||||
 | 
			
		||||
            self.current_battle_state = 0
 | 
			
		||||
 | 
			
		||||
    def get_win_card(self, card):
 | 
			
		||||
        cards_to_pick = self.penguins[0].server.cards
 | 
			
		||||
        cards_iter = cards_to_pick.values()
 | 
			
		||||
        cards_end_to_end = itertools.chain(cards_iter, cards_iter)
 | 
			
		||||
        start_position = random.randint(0, len(cards_to_pick))
 | 
			
		||||
        cards_random_start = itertools.islice(cards_end_to_end, start_position, start_position+len(cards_to_pick))
 | 
			
		||||
 | 
			
		||||
        if self.current_battle_type == 'bt':
 | 
			
		||||
            return next(card_check for card_check in cards_random_start
 | 
			
		||||
                        if card_check.element == self.current_battle_element
 | 
			
		||||
                        and card_check.value >= card.value)
 | 
			
		||||
        elif self.current_battle_type == 'be':
 | 
			
		||||
            return next(card_check for card_check in cards_random_start
 | 
			
		||||
                        if FireSenseiLogic.beats_card(card_check, card))
 | 
			
		||||
 | 
			
		||||
    async def remove_penguin(self, p, quit_early=True):
 | 
			
		||||
        ninja = self.get_ninja_by_penguin(p)
 | 
			
		||||
        await super().remove_penguin(p, False)
 | 
			
		||||
 | 
			
		||||
        if ninja == self.current_player and 0 <= self.current_battle_state <= 2:
 | 
			
		||||
            self.choose_board_timeout.cancel()
 | 
			
		||||
        elif ninja.chosen is None and self.current_battle_state == 3:
 | 
			
		||||
            self.choose_card_timeout.cancel()
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def beats_card(cls, card_check, card_play):
 | 
			
		||||
        if card_check.element != card_play.element:
 | 
			
		||||
            return True if cls.RuleSet[card_check.element] == card_play.element else False
 | 
			
		||||
        elif card_check.value > card_play.value:
 | 
			
		||||
            return True
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def fire_ninja_rank_up(p, ranks=1):
 | 
			
		||||
    if p.fire_ninja_rank + ranks > len(CardJitsuFireLogic.ItemAwards):
 | 
			
		||||
        return False
 | 
			
		||||
    for rank in range(p.fire_ninja_rank, p.fire_ninja_rank+ranks):
 | 
			
		||||
        await p.add_inventory(p.server.items[CardJitsuFireLogic.ItemAwards[rank]], notify=False)
 | 
			
		||||
        if rank in CardJitsuFireLogic.StampAwards:
 | 
			
		||||
            await p.add_stamp(p.server.stamps[CardJitsuFireLogic.StampAwards[rank]])
 | 
			
		||||
    await p.update(
 | 
			
		||||
        fire_ninja_rank=p.fire_ninja_rank + ranks,
 | 
			
		||||
        fire_ninja_progress=p.fire_ninja_progress % 100
 | 
			
		||||
    ).apply()
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def fire_ninja_progress(p, finish_position=1):
 | 
			
		||||
    if p.fire_ninja_rank < 4:
 | 
			
		||||
        speed = type(p.waddle).RankSpeed
 | 
			
		||||
        points = math.floor((25 / (p.fire_ninja_rank+1) / finish_position) * speed)
 | 
			
		||||
        await p.update(fire_ninja_progress=p.fire_ninja_progress+points).apply()
 | 
			
		||||
    elif p.fire_ninja_rank == 4 and finish_position == 1:
 | 
			
		||||
        await p.update(fire_ninja_progress=100).apply()
 | 
			
		||||
    if p.fire_ninja_progress >= 100:
 | 
			
		||||
        await fire_ninja_rank_up(p)
 | 
			
		||||
        await p.send_xt('zm', 'nr', 0, p.fire_ninja_rank)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def end_game_stamps(ninja, finish_position):
 | 
			
		||||
    if finish_position == 1:
 | 
			
		||||
        await ninja.penguin.update(fire_matches_won=ninja.penguin.fire_matches_won + 1).apply()
 | 
			
		||||
        if ninja.penguin.fire_matches_won >= 10:
 | 
			
		||||
            await ninja.penguin.add_stamp(ninja.penguin.server.stamps[252])
 | 
			
		||||
        if ninja.penguin.fire_matches_won >= 50:
 | 
			
		||||
            await ninja.penguin.add_stamp(ninja.penguin.server.stamps[268])
 | 
			
		||||
        if ninja.energy >= 6:
 | 
			
		||||
            await ninja.penguin.add_stamp(ninja.penguin.server.stamps[260])
 | 
			
		||||
 | 
			
		||||
    if ninja.energy_won >= 1:
 | 
			
		||||
        await ninja.penguin.add_stamp(ninja.penguin.server.stamps[254])
 | 
			
		||||
    if ninja.energy_won >= 3:
 | 
			
		||||
        await ninja.penguin.add_stamp(ninja.penguin.server.stamps[266])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@handlers.handler(XTPacket('gz', ext='z'))
 | 
			
		||||
@handlers.waddle(CardJitsuFireLogic, FireMatLogic)
 | 
			
		||||
async def handle_get_game(p):
 | 
			
		||||
    seat_id = p.waddle.get_seat_id(p)
 | 
			
		||||
    await p.send_xt('gz', p.waddle.seats, len(p.waddle.penguins))
 | 
			
		||||
    await p.send_xt('jz', seat_id)
 | 
			
		||||
 | 
			
		||||
    nicknames = ','.join(penguin.safe_name for penguin in p.waddle.penguins)
 | 
			
		||||
    colors = ','.join(str(penguin.color) for penguin in p.waddle.penguins)
 | 
			
		||||
    energy = ','.join(str(ninja.energy) for ninja in p.waddle.ninjas)
 | 
			
		||||
    tile_ids = ','.join(map(str, p.waddle.tile_ids))
 | 
			
		||||
    deck = ','.join(str(card.id) for card in p.waddle.ninjas[seat_id].deck)
 | 
			
		||||
    spin = f'{p.waddle.spin_amount},{p.waddle.move_clockwise},{p.waddle.move_anticlockwise}'
 | 
			
		||||
    ninja_ranks = ','.join(str(penguin.fire_ninja_rank) for penguin in p.waddle.penguins)
 | 
			
		||||
 | 
			
		||||
    await p.send_xt('sz', 0, nicknames, colors, energy, tile_ids, deck, spin, ninja_ranks)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@handlers.handler(XTPacket('gz', ext='z'))
 | 
			
		||||
@handlers.waddle(FireSenseiLogic)
 | 
			
		||||
async def handle_get_sensei_game(p):
 | 
			
		||||
    await p.send_xt('gz', p.waddle.seats, len(p.waddle.penguins))
 | 
			
		||||
    await p.send_xt('jz', 0)
 | 
			
		||||
 | 
			
		||||
    nicknames = f'{p.safe_name},Sensei'
 | 
			
		||||
    colors = f'{p.color},-1'
 | 
			
		||||
    energy = ','.join(str(ninja.energy) for ninja in p.waddle.ninjas)
 | 
			
		||||
    tile_ids = ','.join(map(str, p.waddle.tile_ids))
 | 
			
		||||
    deck = ','.join(str(card.id) for card in p.waddle.ninjas[0].deck)
 | 
			
		||||
    spin = f'{p.waddle.spin_amount},{p.waddle.move_clockwise},{p.waddle.move_anticlockwise}'
 | 
			
		||||
    ninja_ranks = ','.join(str(penguin.fire_ninja_rank) for penguin in p.waddle.penguins)
 | 
			
		||||
 | 
			
		||||
    await p.send_xt('sz', 0, nicknames, colors, energy, tile_ids, deck, spin, ninja_ranks)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@handlers.handler(XTPacket('zm', ext='z'), match=['is'])
 | 
			
		||||
@handlers.waddle(CardJitsuFireLogic, FireMatLogic, FireSenseiLogic)
 | 
			
		||||
async def handle_info_click_spinner(p, *, tab_id: int):
 | 
			
		||||
    seat_id = p.waddle.get_seat_id(p)
 | 
			
		||||
 | 
			
		||||
    if seat_id == p.waddle.current_player.seat_id:
 | 
			
		||||
        await p.waddle.click_spinner(tab_id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@handlers.handler(XTPacket('zm', ext='z'), match=['cb'])
 | 
			
		||||
@handlers.waddle(CardJitsuFireLogic, FireMatLogic, FireSenseiLogic)
 | 
			
		||||
async def handle_choose_board(p, *, tile_id: int):
 | 
			
		||||
    seat_id = p.waddle.get_seat_id(p)
 | 
			
		||||
    if seat_id == p.waddle.current_player.seat_id:
 | 
			
		||||
        await p.waddle.choose_board(tile_id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@handlers.handler(XTPacket('zm', ext='z'), match=['co'])
 | 
			
		||||
@handlers.waddle(CardJitsuFireLogic, FireMatLogic, FireSenseiLogic)
 | 
			
		||||
async def handle_choose_opponent(p, *, opponent_seat_id: int):
 | 
			
		||||
    seat_id = p.waddle.get_seat_id(p)
 | 
			
		||||
    if seat_id == p.waddle.current_player.seat_id:
 | 
			
		||||
        await p.waddle.choose_opponent(opponent_seat_id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@handlers.handler(XTPacket('zm', ext='z'), match=['ct'])
 | 
			
		||||
@handlers.waddle(CardJitsuFireLogic, FireMatLogic, FireSenseiLogic)
 | 
			
		||||
async def handle_choose_trump(p, *, element: str):
 | 
			
		||||
    seat_id = p.waddle.get_seat_id(p)
 | 
			
		||||
    if seat_id == p.waddle.current_player.seat_id:
 | 
			
		||||
        await p.waddle.choose_trump(element)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@handlers.handler(XTPacket('zm', ext='z'), match=['cc'])
 | 
			
		||||
@handlers.waddle(CardJitsuFireLogic, FireMatLogic, FireSenseiLogic)
 | 
			
		||||
async def handle_choose_card(p, *, card_id: int):
 | 
			
		||||
    ninja = p.waddle.get_ninja_by_penguin(p)
 | 
			
		||||
    await p.waddle.choose_card(ninja, card_id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@handlers.handler(XTPacket('zm', ext='z'), match=['ir'])
 | 
			
		||||
@handlers.waddle(CardJitsuFireLogic, FireMatLogic, FireSenseiLogic)
 | 
			
		||||
async def handle_info_ready_sync(p):
 | 
			
		||||
    ninja = p.waddle.get_ninja_by_penguin(p)
 | 
			
		||||
    await p.waddle.ready_ninja(ninja)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@handlers.handler(XTPacket('lz', ext='z'))
 | 
			
		||||
@handlers.player_in_room(CardJitsuFireLogic.room_id)
 | 
			
		||||
async def handle_leave_game(p):
 | 
			
		||||
    await ninja_stamps_earned(p)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user