diff --git a/houdini/handlers/games/ninja/water.py b/houdini/handlers/games/ninja/water.py index b6da198..184259a 100644 --- a/houdini/handlers/games/ninja/water.py +++ b/houdini/handlers/games/ninja/water.py @@ -1,691 +1,447 @@ -# Created by Allinol, Dote & DiamondFire. +import itertools +import math +import random +import asyncio +from collections import Counter +from dataclasses import dataclass +from typing import Dict, 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 -from dataclasses import dataclass, field -from typing import List, Union -from random import choice, shuffle, sample, randint -from collections import deque -from concurrent.futures import ProcessPoolExecutor -import asyncio -import numpy as np -import math +from houdini.penguin import Penguin -executor = ProcessPoolExecutor() +# made by diamondfern only desmondflame not anybody else... does not condone suicide. (you'll see) - -class WaterCard: - __slots__ = ("id", "card", "index", "element", "value") - - def __init__(self, card, index): - self.card = card - print(card) - self.id = self.card.id - self.element = self.card.element - self.value = self.card.value - self.index = index - - def __str__(self): - return f"{self.id}-{self.index}" - -class Cells: - __slots__ = ("id", "type", "value", "penguin") - - def __init__(self, cell_id, _type, value): - self.id = cell_id - self.type = _type if value != 0 else 3 - self.value = min(value, 20) if self.type != 3 else 0 - self.penguin = None - - def penguin_jump(self, ninja): - self.type = 3 - self.penguin = ninja - ninja.cell = self - - def update_value(self, dv): - self.value = max(0, min(self.value + dv, 20)) - if self.value == 0: - self.type = 3 - - def can_jump(self): - return self.type != 4 and self.penguin is None - - def __str__(self): - return f"{self.id}-{self.type}-{self.value}" - - @dataclass -class Rows: - n_col: int - index: int - empty: bool = False - cells: List[Cells] = field(default_factory=list) - - def __post_init__(self): - self.cell_generator() - - def __getitem__(self, i): - return self.cells[i] - - def cell_generator(self): - self.cells = [Cells( - cell_id = int("{}{}".format(self.index, i)), - _type = randint(0, 2) if not self.empty else 3, - value = randint(1, 20/2)) for i in range(self.n_col)] - - def __str__(self): - return ",".join(map(str, self.cells)) - -@dataclass -class WaterNinja: - penguin: penguin - ready: bool - seat_id: int - cell: Union[Cells, None] - deck: List[Card] = field(default_factory=list) - chosen: Union[Card, None] = None - cards: dict = field(default_factory=dict) - slipped: int = 0 - jumps: int = 0 - position: int = 0 - winner: bool = False - joined: bool = False - - def __hash__(self): - return self.penguin +class Played: + id: int + card: Card + value: int + element: str + discard: bool + +@dataclass +class Tile: + id: int + element: int # 0: fire 1: water 2: snow 3: none + value: int + seat: int + +@dataclass +class Ninja: + Sensei: bool + penguin: Penguin + deck: Dict[int, Played] + chosen: Union[Played, None] + synced: bool + x: int + y: int + stonesCleared: int + edgeCount: int + tile: Union[Tile, None] - class CardJitsuWaterLogic(IWaddle): + room_id = 995 - rule_set = {'f' : 1, 'w' : 2, 's' : 3} - timer_task = None - started = False - Sensei = False - card_amount = 7 - AVAILABLE_CARDS = {*range(1,114), *range(201, 261), *range(301, 428), *range(501, 596)} - ItemAwards = [6026, 4121, 2025, 1087, 3032] - StampAwards = {2: 278, 4: 282} + tile_iterator = card_iterator = 0 + tick = 60 + cardTimer = rowTimer = startTimer = None + isReady = False + RuleSet = {'f': 's', 'w': 'f', 's': 'w'} + RuleSetValues = {'f': 0, 'w': 1, 's': 2, 'n': 3} + RuleSetInvValues = {v: k for k, v in RuleSetValues.items()} + + RankSpeed = 1.0 + + StampGroupId = 34 + def __init__(self, waddle): super().__init__(waddle) - self.timer = 60 - self.in_battle = False - self.rows = 0 self.columns = 5 if len(waddle.penguins) <= 2 else 7 - self.ninjas = [WaterNinja( - penguin=p, - ready=False, - cell=None, - seat_id=seat_id - ) for seat_id, p in enumerate(waddle.penguins)] - - - async def initiate_player_cards(self): - for ninja in self.ninjas: - index = ninja.seat_id + x_vals = [1, 3, 5] if len(waddle.penguins) <= 3 else [1, 2, 4, 5] - ninja.cards = self.generate_card(ninja) - ninja.deck = deque([WaterCard( - card=next(ninja.cards), - index=i) - for i in range(self.card_amount)]) - - await self.send_zm_client(ninja, "ci", '|'.join(map(str, ninja.deck))) - - async def game_over(self, ninja_dead = None): - if ninja_dead is not None: - await end_game_stamps(ninja_dead) - if ninja_dead in self.ninjas: - self.ninjas.remove(ninja_dead) - if len(self.ninjas) < 1: - await self.game_over() + self.ninjas = {i: Ninja( + penguin=waddle.penguins[i], + Sensei=False, + deck={}, + chosen=None, + tile=None, + synced=False, + stonesCleared=0, + edgeCount=0, + x=x_vals[i], + y=6 + ) for i in range(len(waddle.penguins))} + + self.board = [] + for i in range(self.columns): + self.board.append([Tile( + id=(_ + self.tile_iterator), + element=random.randint((3 if _ < 2 else 0), (3 if _ < 2 else 2)), + value=random.randint((0 if _ < 2 else 1), (0 if _ < 2 else 8)), + seat=-1 + ) for _ in range(8)]) + self.tile_iterator += 8 + + for player in self.ninjas.values(): + deck = Counter((card.card_id for card in player.penguin.cards.values() for _ in range(card.quantity + card.member_quantity))) + deal = random.sample(list((deck)), 5) + for card_id in deal: + card = player.penguin.server.cards[card_id] + player.deck[self.card_iterator] = Played( + id=self.card_iterator, + card=card, + value=card.value, + element=card.element, + discard=False) + self.card_iterator += 1 + + for seat, player in self.ninjas.items(): + self.board[player.x][1].seat = seat + player.tile = self.board[player.x][1] + + self.startTimer = asyncio.create_task(self.tickCallback()) + + async def handle_drown(self, winner_id): + self.rowTimer.cancel() + self.cardTimer.cancel() + self.senseiontousTimer.cancel() + await super().send_xt('zm', 'gw&' + str(winner_id) + '&0&00&false') + rank = 2 + for row in self.board: + for i in range(len(row)-1, -1, -1): + curr_tile = row[i] + if curr_tile.seat >= 0 and curr_tile.seat != winner_id: + await super().send_xt('zm', 'pd&' + str(curr_tile.seat) + '&' + str(rank) + '&00&false') + rank += 1 + + async def remove_penguin(self, p, isQuit=True): + if p.waddle is None or p.waddle.room_id != self.room_id: return + seat_id = self.get_seat_id(p) + player = self.ninjas[seat_id] - if self.velocity_loop is not None: - self.velocity_loop.cancel() + player.tile.seat = -1 - self.started = False - players = self.ninjas - position = len(players) - for p in players: - if not p.winner: - progress, rank = await water_ninja_progress(p.penguin, p.position) - await self.send_zm('pd', p.seat_id, position, f'{int(progress)}{rank}', 'false') + del self.ninjas[seat_id] + await super().remove_penguin(p) + + if all([player.synced for player in self.ninjas.values()]): + self.isReady = True + if len(self.ninjas) < 1: + if self.rowTimer is not None: + self.rowTimer.cancel() + if self.cardTimer is not None: + self.cardTimer.cancel() + + await self.ninja_stamps_earned(p) + + async def tickCallback(self): + try: + while True: + await asyncio.sleep(1) + self.tick -= 1 + for player in self.ninjas.values(): + await player.penguin.send_xt('zm', 'tt&' + str(self.tick)) - def get_playable_cells(self, ninja): - cell = ninja.cell - row, col = cell.id//10, cell.id%10 + if self.isReady: + self.tick = 4 + self.isReady = False + + if self.tick < 0: + await super().send_xt('zm', 'pi&' + self.get_player_init_string()) + self.startTimer = None + self.cardTimer = asyncio.create_task(self.cardCallback()) + self.rowTimer = asyncio.create_task(self.rowCallback()) + sensei = self.ninjas[1] + if sensei.Sensei: + self.senseiontousTimer = asyncio.create_task(self.find_sensei_path()) + break + except asyncio.CancelledError: + pass - return self.get_nearby_cells(row, col) - - async def cycle_row(self): - loop = asyncio.get_running_loop() - async def edge_users_slip(row): - players_in_row = [self.rows_by_id[row][i].penguin for i in range(self.columns) if self.rows_by_id[row][i].penguin is not None] if row in self.rows_by_id else [] - position = len(self.ninjas) - return await self.send_zm(":".join(map(lambda p: 'pk&{}&{}&00&false'.format(p.seat_id, position), players_in_row))) - - dropped, drop_row = self.row_generator() - if dropped: - - players_in_row = [drop_row[i].penguin for i in range(self.columns) if drop_row[i].penguin is not None] - print('lazy penguins', players_in_row) - position = len(self.ninjas) - loop = asyncio.get_running_loop() - await edge_users_slip(drop_row.index+1) - [(await self.send_zm_client(p, 'gf'), await self.game_over(p)) for p in players_in_row] - - await self.send_zm("br", self.board_array[-1]) - - def get_cell(self, y, x): - return self.board_array[y][x] - - def get_nearby_cells(self, row, col): - if row not in self.rows_by_id: - return set() - - row_ref = self.rows_by_id[row] - playable_cells = set() - - for i in range(max(0, col-1), min(self.columns, col+2)): - if row+1 in self.rows_by_id: - playable_cells.add(self.rows_by_id[row+1][i]) - - if row-1 in self.rows_by_id: - playable_cells.add(self.rows_by_id[row-1][i]) - - if i != col: - playable_cells.add(self.rows_by_id[row][i]) - - return list(playable_cells) - - - def generate_card(self, ninja): - cards = list(filter(lambda x: x.card_id in self.AVAILABLE_CARDS, list(ninja.penguin.cards.values()))) - i = 0 - while True: - i += 1 - yield ninja.penguin.server.cards[choice(cards).card_id] + async def cardCallback(self): + try: + self.tick = 0 + while True: + await asyncio.sleep(2) + self.tick += 1 + for player in self.ninjas.values(): + if self.tick >= 3: + player.deck.pop(min(player.deck.keys()), None) + deck = Counter((card.card_id for card in player.penguin.cards.values() for _ in range(card.quantity + card.member_quantity))) + dealt = Counter((played.card.id for played in player.deck.values() if played is not player.chosen)) + difference = (list((deck - dealt).elements())) + random.shuffle(difference) + card_id = random.choice(difference) + card = player.penguin.server.cards[card_id] + player.deck[self.card_iterator] = Played( + id=self.card_iterator, + card=card, + value=card.value, + element=card.element, + discard=False) + await player.penguin.send_xt('zm', 'ca&' + str(card_id) + '-' + str(self.card_iterator)) + self.card_iterator += 1 + except asyncio.CancelledError: + pass - async def tick_timer(self): - await self.send_zm("tt", self.timer) - self.timer -= 1 - - - if self.timer < 1 or all(map(lambda ninja: ninja.ready, self.ninjas)): - self.timer_task.cancel() + async def rowCallback(self): + try: + while True: + await asyncio.sleep(3) + if len(self.board[0]) >= 10: + for i in range(self.columns): + tile = self.board[i][0] + if tile.seat != -1: # someones in it! + self.ninjas[tile.seat].edgeCount += 1 + + await asyncio.sleep(2) - if all(map(lambda ninja: ninja.ready, self.ninjas)): - self.in_battle = True - await self.player_initiate() - self.velocity_loop = asyncio.create_task(set_interval(1,self.set_velocity)) - - elif self.timer < 1: - await self.send_zm("ge") - await self.game_over() + board_row = '' + for i in range(self.columns): + self.board[i].append(Tile( + id=self.tile_iterator, + element=random.randint(0, 2), + value=random.randint(1, 8), + seat=-1 + )) + board_row += f'{self.board[i][-1].id}-{self.board[i][-1].element}-0{self.board[i][-1].value},' + self.tile_iterator += 1 + await super().send_xt('zm', 'br&' + board_row[:-1]) - async def card_selected(self, ninja, card): - card_id = int(card) - card = self.get_player_card(ninja, card_id) - if card is None: - return await self.send_zm_client(ninja, 'cp') - - print(card) - ninja.chosen = card - await self.send_zm_client(ninja, 'cp', card) - return - - def get_player_card(self, ninja, card_index): - return next(card for card in ninja.deck if card.index == card_index) - - - async def initiate_vector(self): - self.board_array = deque() - self.rows_by_id = {} - self.cards_by_id = {} - - self.rows = 0 - - [self.row_generator(empty=True) for i in range(2)] - [self.row_generator() for i in range(6)] - - await self.initiate_velocity() - await self.send_zm("bi", self.columns, self.serialize_board()) - [self.get_cell(1, i*2).penguin_jump(self.ninjas[i]) for i in range(len(self.ninjas))] - - - async def initiate_velocity(self): - self.board_velocity_delta = 200.0 - self.board_velocity = 3000.0 - self.board_velocity_delta - self.board_velocity_slope = 0.5 - self.card_velocity = np.array((60000.0, 0.0)) - self.card_position = 0 - - self.board_position = 278 - self.row_destroy_time = -1 - - await self.send_zm("bv", self.board_velocity / self.board_velocity_slope, self.board_velocity) - await self.send_zm("cv", *self.card_velocity) + if len(self.board[0]) >= 10: + for i in range(self.columns): + tile = self.board[i].pop(0) + if tile.seat != -1: # someones in it! + await self.ninjas[tile.seat].penguin.add_stamp(self.ninjas[tile.seat].penguin.server.stamps[274], notify=True) + await super().send_xt('zm', 'pk&' + str(tile.seat) + '&' + str(len(self.ninjas)) + '&00&false') + await self.remove_penguin(self.ninjas[tile.seat].penguin, False) + # ^ & dead place & amulet state , rank awarded & is sensei + except asyncio.CancelledError: + pass - async def player_initiate(self): - pi_data = [] - available_pos = range(self.columns) - - for ninja in self.ninjas: - cellId = int(ninja.cell.id) - row, col = 6, cellId%10 - - pi_data.append("|".join([str(ninja.seat_id), ninja.penguin.safe_name, str(ninja.penguin.color), "{},{}".format(col, row)])) - - await self.send_zm("pi", *pi_data) + async def ninja_stamps_earned(self, p): + game_stamps = [stamp for stamp in p.server.stamps.values() if stamp.group_id == p.room.stamp_group] + collected_stamps = [stamp for stamp in game_stamps if stamp.id in p.stamps] + total_collected_stamps = len(collected_stamps) + total_game_stamps = len(game_stamps) + collected_stamps_string = '|'.join(str(stamp.id) for stamp in collected_stamps) + await p.send_xt('cjsi', collected_stamps_string, total_collected_stamps, total_game_stamps) - - - def row_generator(self, empty = False): - if len(self.board_array) > 9: - pop_row = self.board_array.popleft() - if pop_row.index in self.rows_by_id: - del self.rows_by_id[pop_row.index] - - return True, pop_row - - self.rows += 1 - row = Rows( - n_col=self.columns, - index=self.rows, - empty=empty) - - self.board_array.append(row) - self.rows_by_id[row.index] = row - - return False, None - - async def send_zm(self, *args): - await super().send_xt("zm", "&".join(map(str, args))) - - async def send_zm_client(self, ninja, *args): - await ninja.penguin.send_xt("zm", "&".join(map(str, args))) - - def update_velocity_vector(self, vel, f=50): - vel = np.array(vel) - - a = np.linalg.norm(vel) / 1000.0 - b = 1000.0 / f - vel *= a / vel.max() - b = np.linalg.norm(vel) / b - vel *= b / vel.max() - - return vel - - async def set_velocity(self): - - self.board_velocity += self.board_velocity_delta - self.card_velocity[0] += self.board_velocity_delta / 2.0 - velocity_vector = (self.board_velocity / self.board_velocity_slope, self.board_velocity) - loop = asyncio.get_running_loop() - - ''' - R: y = 0.5x + 186 - T: y = -2x + 1226 - int: (416, 394) => R(9) - time = (Y - y) / updateF * 0.05 - ''' - updateFreq = (await loop.run_in_executor(executor, self.update_velocity_vector, velocity_vector))[1] - pos_delta = 394 - self.board_position + def get_seat_id(self, p): + for seat, player in self.ninjas.items(): + if player.penguin is p: + return seat + return -1 - if pos_delta <= 0: - await self.cycle_row() - self.board_position = 278 - - updateCardFreq = (await loop.run_in_executor(executor, self.update_velocity_vector, self.card_velocity))[0] - cardPos_delta = 128 - self.card_position - if cardPos_delta <= 0: - await self.cycle_card() - self.card_position = 0 - - self.board_position += updateFreq * 100 - self.card_position += updateCardFreq * 100 - - await self.send_zm("bv", *velocity_vector) - await self.send_zm("cv", *self.card_velocity) - - async def cycle_card(self): - for ninja in self.ninjas: - if ninja.deck is None: - continue - self.card_amount += 1 - card = WaterCard( - card=next(ninja.cards), - index=self.card_amount) - - if len(ninja.deck) > 9: - pop_card = ninja.deck.popleft() - - if ninja.chosen is not None and \ - pop_card.index == ninja.chosen.index: - - ninja.chosen = None - - ninja.deck.append(card) - await self.send_zm_client(ninja, 'ca', card) - - - - def serialize_board(self): - return '|'.join(map(str, self.board_array)) - - def get_ninja_by_penguin(self, penguin): - return next(ninja for ninja in self.ninjas if ninja.penguin == penguin) - + def is_winning_row(self, tile_id): + for i in range(self.columns): + if self.board[i][-3].id == tile_id: + return True + return False + def get_tile(self, tile_id, withCoordinates=False): + for i in range(self.columns): + for j in range(len(self.board[i])): + if self.board[i][j].id == tile_id: + return (self.board[i][j], i, j) if withCoordinates else self.board[i][j] + return None + + def find_neighbors(self, x, y): + return [[self.board[i][j] if i >= 0 and i < len(self.board) and j >= 0 and j < len(self.board[0]) else None + for j in range(y-1-1, y+1)] + for i in range(x-1-1, x+1)] + + def get_player_init_string(self): + sensei = self.ninjas[1] + ninja = self.ninjas[0] + if sensei.Sensei: + return f'0|{ninja.penguin.safe_name}|{ninja.penguin.color}|{ninja.x},{ninja.y}&1|Sensei|14|{sensei.x},{sensei.y}' + else: + return '&'.join([f'{seat}|{player.penguin.safe_name}|{player.penguin.color}|{player.x},{player.y}' for seat, player in self.ninjas.items()]) + + def fizzle_test(self, tile_element, card_element): + #return True if tile_element in self.RuleSet and (self.RuleSet[tile_element] == card_element or tile_element != card_element) else False + if tile_element in self.RuleSet: + if self.RuleSet[tile_element] == card_element: + return True + return False + + def kills_element(self, tile_element, card_element): + return True if tile_element in self.RuleSet and self.RuleSet[card_element] == tile_element else False class WaterMatLogic(CardJitsuWaterLogic): - RankSpeed = 0.5 - + RankSpeed = 0.0 # Practice class WaterSenseiLogic(CardJitsuWaterLogic): + RankSpeed = 0.0 def __init__(self, waddle): super().__init__(waddle) - sensei = WaterNinja( - penguin=waddle.penguins[0], - joined=True, - ready=True, - cell=None, - seat_id=1 - ) - self.ninjas.append(sensei) - - async def player_initiate(self): - available_pos = range(self.columns) - - ninja = self.ninjas[0] - sensei = self.ninjas[1] - cellId = int(ninja.cell.id) - sensei_cellId = int(sensei.cell.id) - row, player_col, sensei_col = 6, cellId%10, sensei_cellId%10 - pi_data = f'{ninja.seat_id}|{ninja.penguin.safe_name}|{ninja.penguin.color}|{player_col},{row}&{sensei.seat_id}|Sensei|14|{sensei_col},{row}' - await self.send_zm_client(ninja, "pi", pi_data) - - async def initiate_player_cards(self): - ninja = self.ninjas[0] - ninja.cards = self.generate_card(ninja) - ninja.deck = deque([WaterCard( - card=next(ninja.cards), - index=i) - for i in range(self.card_amount)]) - - await self.send_zm_client(ninja, "ci", '|'.join(map(str, ninja.deck))) - - - async def game_over(self, ninja_dead = None): - if ninja_dead is not None: - if ninja_dead in self.ninjas: - self.ninjas.remove(ninja_dead) - if len(self.ninjas) <= 1: - await self.game_over() + self.ninjas[1] = Ninja(Sensei=True,penguin=waddle.penguins[0],deck={},chosen=None,tile=self.board[3][1],synced=True,stonesCleared=0,edgeCount=0,x=3,y=6) + self.board[3][1].seat = 1 - return - - if self.velocity_loop is not None: - self.sensei_loop.cancel() - self.velocity_loop.cancel() - - self.started = False - players = self.ninjas - position = len(players) - for p in players: - await end_game_stamps(p) - if not p.winner: - await self.send_zm('pd', p.seat_id, position, '00', 'false') + self.isReady = True - async def tick_timer(self): - await self.send_zm("tt", self.timer) - self.timer -= 1 - - - if self.timer < 1 or all(map(lambda ninja: ninja.ready, self.ninjas)): - self.timer_task.cancel() - - if all(map(lambda ninja: ninja.ready, self.ninjas)): - self.in_battle = True - await self.player_initiate() - self.velocity_loop = asyncio.create_task(set_interval(1,self.set_velocity)) + async def find_sensei_path(self): + try: + while True: ninja = self.ninjas[0] - if ninja.penguin.water_ninja_rank < 4: - self.sensei_loop = asyncio.create_task(set_interval(1.7,self.sensei_ai)) + if ninja.penguin.water_ninja_rank >=4: + await asyncio.sleep(4) + if ninja.penguin.water_ninja_rank <=3: + await asyncio.sleep(2) + sensei = self.ninjas[1] + board = self.board + currentRow = sensei.x + currentCell = sensei.y + #print(board) + tile = self.find_neighbors(currentRow,currentCell)[0][2] + possibleOptions = 3 if currentCell != 6 else 2 + optionTried = 1 + SenseiLocation = f"{sensei.x},{sensei.y}" + elementIndex = 2 + newRow = currentRow + 1 + if sensei.stonesCleared == 0: + newRow = 2 + options={1:currentCell - 1 if currentCell != 0 else currentCell, 2:currentCell, 3:currentCell + 1} + newCell = options.get(optionTried) + if not newCell: + locationFound=True + newcellrow = f"{newCell},{newRow}" + if SenseiLocation != newcellrow: + newCellInfo = self.find_neighbors(newCell,newRow)[0][2] + if newCellInfo is None: + newCellInfo = self.find_neighbors(newCell,newRow)[0][2] + print(f"new retard: {newCellInfo}") + switcher={0:1, 1:2, 2:3} + elementIndex = switcher.get(int(newCellInfo.element),3) + tile.value = 0 + tile.element = 3 + if elementIndex != 3: + await self.send_xt('zm', 'pt&1&' + str(elementIndex) + '-' + str(newCellInfo.id) + '&' + + str(newCellInfo.id) + '-' + str(newCellInfo.element) + '-P0') + await self.send_xt('zm', 'pm&1-' + str(newCellInfo.id)) + sensei.x = newCell + sensei.y = newRow + sensei.stonesCleared += 1 + if self.is_winning_row(newCellInfo.id): + self.handle_drown(1) else: - self.sensei_loop = asyncio.create_task(set_interval(3.5,self.sensei_ai)) - - elif self.timer < 1: - await self.send_zm("ge") - await self.game_over() + print("Sensei tried to jump on the player, trying a different cell.") + optionTried += 1 + except asyncio.CancelledError: + pass - - async def sensei_ai(self): - sensei = self.ninjas[1] - row, cell = sensei.cell.id//10, sensei.cell.id % 10 - available_cells = self.get_playable_cells(sensei) - available_cells_by_id = {i.id: i for i in available_cells} - sensei_move = [i for i in available_cells_by_id.values() if i.id//10 > row] - - print("sensei's shit", repr(sensei_move)) - sensei_move = choice(sensei_move) - possible_cards = [1,2,0,3] - card = possible_cards[sensei_move.type] - sensei_move.update_value(sensei_move.value * -1) - row, cell = sensei_move.id//10, sensei_move.id % 10 - cells = [i for i in self.get_nearby_cells(row, cell)[:6] if i.can_jump() and i.id != sensei.cell.id] - for i in cells: - i.type = sensei_move.type if i.type == 3 else i.type - i.update_value(i.value * -1) - cells.insert(0, sensei_move) - sensei.cell.penguin = None - sensei.cell = None - sensei_move.penguin_jump(sensei) - await self.send_zm('pt', sensei.seat_id, '{}-{}'.format(card-1, sensei_move.id), '|'.join(map(str, cells))) - await self.send_zm('pm', f'{sensei.seat_id}-{sensei_move.id}') - row = sensei_move.id // 10 - last_row = self.board_array[-1] - if last_row.index - 2 == row: - await self.send_zm("gw", sensei.seat_id, 0, 00, 'false') - sensei.winner = True - self.started = False - return await self.game_over() - - - async def cycle_card(self): - ninja = self.ninjas[0] - - self.card_amount += 1 - card = WaterCard( - card=next(ninja.cards), - index=self.card_amount) - - if len(ninja.deck) > 9: - pop_card = ninja.deck.popleft() - - if ninja.chosen is not None and \ - pop_card.index == ninja.chosen.index: - - ninja.chosen = None - - ninja.deck.append(card) - await self.send_zm_client(ninja, 'ca', card) - -@handlers.handler(XTPacket('gz', ext='z')) -@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic) -async def handle_get_game(p): - seat_id = p.waddle.get_seat_id(p) - ninja = p.waddle.get_ninja_by_penguin(p) - await p.send_xt('gz') - await p.send_xt('jz') - await p.waddle.send_zm_client(ninja, "po", seat_id) - ninja.joined = True - if all(map(lambda ninja: ninja.joined, p.waddle.ninjas)): - await p.waddle.initiate_vector() - await p.waddle.initiate_player_cards() +### SENSEI SH#T ### @handlers.handler(XTPacket('gz', ext='z')) @handlers.waddle(WaterSenseiLogic) async def handle_get_sensei_game(p): seat_id = p.waddle.get_seat_id(p) - ninja = p.waddle.get_ninja_by_penguin(p) await p.send_xt('gz') await p.send_xt('jz') - await p.waddle.send_zm_client(ninja, "po", seat_id) - await p.waddle.initiate_vector() - await p.waddle.initiate_player_cards() - - -async def set_interval(timeout, stuff): - while True: - await asyncio.sleep(timeout) - await stuff() - -async def end_game_stamps(ninja): - if ninja.jumps >= 4: - await ninja.penguin.add_stamp(ninja.penguin.server.stamps[288]) - if ninja.position == 1: - await ninja.penguin.update(water_matches_won=ninja.penguin.water_matches_won + 1).apply() - await ninja.penguin.add_stamp(ninja.penguin.server.stamps[270]) - if ninja.penguin.water_matches_won >= 100: - await ninja.penguin.add_stamp(ninja.penguin.server.stamps[276]) - if ninja.slipped >= 2: - await ninja.penguin.add_stamp(ninja.penguin.server.stamps[286]) - if type(ninja.penguin.waddle) == WaterSenseiLogic: - await ninja.penguin.add_stamp(ninja.penguin.server.stamps[284]) - - -async def water_ninja_progress(p, position): - position = len(p.waddle.penguins) if position <=0 else position - if p.water_ninja_rank < 4: - rankup = await water_ninja_rank_up(p) - speed = p.waddle.RankSpeed - points = math.floor((25 / (p.water_ninja_rank+1) / position) * speed) - await p.update(water_ninja_progress=p.water_ninja_progress+points).apply() - return rankup, p.water_ninja_rank - elif p.water_ninja_rank == 4 and position == 1: - await p.update(water_ninja_progress=100).apply() - return False, p.water_ninja_rank - -async def water_ninja_rank_up(p, ranks=1): - if p.water_ninja_rank + ranks > len(CardJitsuWaterLogic.ItemAwards): - return False - for rank in range(p.water_ninja_rank, p.water_ninja_rank+ranks): - await p.add_inventory(p.server.items[CardJitsuWaterLogic.ItemAwards[rank]], notify=False) - if rank in CardJitsuWaterLogic.StampAwards: - await p.add_stamp(p.server.stamps[CardJitsuWaterLogic.StampAwards[rank]]) - await p.update( - water_ninja_rank=p.water_ninja_rank + ranks, - water_ninja_progress=p.water_ninja_progress % 100 - ).apply() - return True - -@handlers.handler(XTPacket('zm', ext='z'), match=['103']) -@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic, WaterSenseiLogic) -async def handle_start_game(p): - ninja = p.waddle.get_ninja_by_penguin(p) - ninja.ready = True - if not p.waddle.timer_task: - p.waddle.timer_task = asyncio.create_task(set_interval(1, p.waddle.tick_timer)) + board_str = '|'.join(','.join([f'{p.waddle.board[col][row].id}-{p.waddle.board[col][row].element}-0{p.waddle.board[col][row].value}' for col in range(5)]) for row in range(8)) + await p.send_xt('zm', 'gi&250:bi&' + str(p.waddle.columns) + '&' + board_str + ':ci&' + '|'.join([f'{card.card.id}-{card.id}' for card in p.waddle.ninjas[seat_id].deck.values()]) + ':po&' + str(seat_id) + ':cv&64000.0&0.0:bv&7571.428571428572&3714.285714285714:tt&' + str(p.waddle.tick)) +### REGULAR SH#T @handlers.handler(XTPacket('zm', ext='z'), match=['110']) -@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic, WaterSenseiLogic) -async def handle_choose_card(p, *, card_id: int): - print(f"Player Card Data{card_id}") - ninja = p.waddle.get_ninja_by_penguin(p) - await p.waddle.card_selected(ninja, card_id) +@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic) +async def handle_player_card_select(p, action: str, card_id: int): + seat_id = p.waddle.get_seat_id(p) + if card_id in p.waddle.ninjas[seat_id].deck: + p.waddle.ninjas[seat_id].chosen = p.waddle.ninjas[seat_id].deck[card_id] +@handlers.handler(XTPacket('zm', ext='z'), match=['103']) +@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic) +async def handle_game_start(p, action: str): + seat_id = p.waddle.get_seat_id(p) + p.waddle.ninjas[seat_id].synced = True + if all([player.synced for player in p.waddle.ninjas.values()]): + p.waddle.isReady = True @handlers.handler(XTPacket('zm', ext='z'), match=['120']) -@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic, WaterSenseiLogic) -async def handle_player_move(p, action: str, cell_id: int): - ninja = p.waddle.get_ninja_by_penguin(p) - available_cells = p.waddle.get_playable_cells(ninja) - available_cells_by_id = {i.id: i for i in available_cells} +@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic) +async def handle_player_move(p, action: str, tile_id: int): + seat_id = p.waddle.get_seat_id(p) + tile = p.waddle.get_tile(tile_id) + if tile is not None and tile.value <= 0 and tile.seat == -1: + ninja_obj = p.waddle.ninjas[seat_id] + ninja_obj.tile.seat = -1 + tile.seat = seat_id + ninja_obj.tile = tile + await p.waddle.send_xt('zm', 'pm&' + str(seat_id) + '-' + str(tile.id)) - if cell_id not in available_cells_by_id: - print(cell_id, available_cells_by_id.keys(), ninja.cell.id) - return await p.waddle.send_zm_client(ninja, 'pf', '{}-{}'.format(ninja.seat_id, cell_id), 'lmao') + if p.waddle.is_winning_row(tile_id): + await p.waddle.handle_drown(seat_id) + await p.add_stamp(p.server.stamps[270], notify=True) + if ninja_obj.stonesCleared >= 28: + await p.add_stamp(p.server.stamps[288], notify=True) + if ninja_obj.edgeCount >= 2: + await p.add_stamp(p.server.stamps[286], notify=True) + await p.update(water_matches_won=p.water_matches_won+1).apply() + if p.water_matches_won == 100: + await p.add_stamp(p.server.stamps[276], notify=True) - cell = available_cells_by_id[cell_id] - - if cell.type != 3 or cell.penguin is not None: - return await p.waddle.send_zm_client(ninja, 'pf', '{}-{}'.format(ninja.seat_id, cell_id), 'not empty?') - - ninja.cell.penguin = None - ninja.cell = None - cell.penguin_jump(ninja) - - await p.waddle.send_zm('pm', '{}-{}'.format(ninja.seat_id, cell.id)) - - last_row = p.waddle.board_array[-1] - row = cell.id // 10 - if last_row.index - 2 == row: - - print("ROWS:",last_row.index, row) - ninja.position = 1 - progress, rank = await water_ninja_progress(ninja.penguin, ninja.position) - print("Penguin Progress", progress, rank) - await p.waddle.send_zm("gw", ninja.seat_id, 1, '{}{}'.format(int(progress), rank), 'false') - ninja.winner = True - p.waddle.started = False - return await p.waddle.game_over() - - - -@handlers.handler(XTPacket('lz', ext='z')) -@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic, WaterSenseiLogic) -async def handle_leave_match(p): - p.waddle.started = False - @handlers.handler(XTPacket('zm', ext='z'), match=['121']) -@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic, WaterSenseiLogic) -async def handle_throw_card(p, *, cell_id: int): - ninja = p.waddle.get_ninja_by_penguin(p) - available_cells = p.waddle.get_playable_cells(ninja) - available_cells_by_id = {i.id: i for i in available_cells} - - if cell_id not in available_cells_by_id: - print(cell_id, available_cells_by_id.keys(), ninja.cell.id) +@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic) +async def handle_player_throw(p, action: str, tile_id: int): + seat_id = p.waddle.get_seat_id(p) + tile, x, y = p.waddle.get_tile(tile_id, True) + ninja_obj = p.waddle.ninjas[seat_id] + if ninja_obj.chosen is not None and tile is not None: + card = ninja_obj.chosen + card_element = card.element + if (p.waddle.fizzle_test(p.waddle.RuleSetInvValues[tile.element], card.element)): + await p.send_xt('zm', 'pf&' + str(tile.element) + '-' + str(tile_id)) + return - return await p.waddle.send_zm_client(ninja, 'pf', '{}-{}'.format(ninja.seat_id, cell_id)) + affected_tiles = [tile] + if card.value >= 9: # power card + surronding_tiles = p.waddle.find_neighbors(x, y) + for cols in surronding_tiles: + for curr_tile in cols: + if curr_tile is not None and (not p.waddle.fizzle_test(p.waddle.RuleSetInvValues[curr_tile.element], card.element)): + if (p.waddle.kills_element(p.waddle.RuleSetInvValues[curr_tile.element], card.element)): + curr_tile.value -= card.value // 3 + elif curr_tile.element != 3: + curr_tile.value += card.value // 3 + affected_tiles.append(curr_tile) - cell = available_cells_by_id[cell_id] - if (ninja.chosen is None) or not cell.can_jump(): - print(ninja.chosen, cell.can_jump()) - return await p.waddle.send_zm_client(ninja, 'pf', '{}-{}'.format(ninja.seat_id, cell_id)) + if curr_tile.value <= 0: + curr_tile.value = 0 + curr_tile.element = 3 + ninja_obj.stonesCleared += 1 + if (p.waddle.kills_element(p.waddle.RuleSetInvValues[tile.element], card.element)): + tile.value -= card.value + if card.value >= 9: # power card + tile.value = 0 # need to clear surrondings as well + #elif card.value >= 6: + # tile.value = 0 if tile.value <= 6 else (tile.value - random.randint(3,4)) + #else: + # tile.value = 0 if tile.value <= 3 else (tile.value - random.randint(3,4)) - card = ninja.chosen - won = ((3 + p.waddle.rule_set[card.element] - (cell.type+1)) % 3 - 1) if cell.type != 3 else -1 + # need more stuff + if tile.value <= 0: + tile.value = 0 + tile.element = 3 + ninja_obj.stonesCleared += 1 + elif tile.element != 3: + tile.value += card.value - print("CJ WIN:", card.element, cell.type, won) + ninja_obj.chosen = None + await p.waddle.send_xt('zm', 'pt&' + str(seat_id) + '&' + str(p.waddle.RuleSetValues[card_element]) + '-' + str(tile_id) + '&' + '|'.join([f'{t.id}-{t.element}-{t.value}' for t in affected_tiles])) - if won > 0: - return await p.waddle.send_zm_client(ninja, 'pf', '{}-{}'.format(ninja.seat_id, cell_id)) - - ninja.chosen = None - - value_del = card.value * (-1 if won != -1 else 1) - cell.update_value(value_del) - if cell.type == 3 and cell.value > 0: - cell.type = p.waddle.rule_set[card.element]-1 - ninja.jumps += 1 - - print("ValDel:", value_del, cell.value) - - row, col = cell.id//10, cell.id%10 - cells = [i for i in p.waddle.get_nearby_cells(row, col)[:6] if i.can_jump() and i.id != ninja.cell.id] - for i in cells: - cell_win = ((3 + p.waddle.rule_set[card.element] - (i.type+1)) % 3 - 1) if i.type != 3 else -1 - if cell_win < 1 and card.value >= 9: - i.type = cell.type if i.type == 3 else i.type - i.update_value(card.value * (-1 if cell_win == -1 else 1) if cell.type == p.waddle.rule_set[card.element] else 0) - - cells.insert(0, cell) - - await p.waddle.send_zm('pt', ninja.seat_id, '{}-{}'.format(p.waddle.rule_set[card.element]-1, cell.id), '|'.join(map(str, cells))) +@handlers.handler(XTPacket('gz', ext='z')) +@handlers.waddle(CardJitsuWaterLogic, WaterMatLogic) +async def handle_get_game(p): + seat_id = p.waddle.get_seat_id(p) + await p.send_xt('gz') + await p.send_xt('jz') + board_str = '|'.join(','.join([f'{p.waddle.board[col][row].id}-{p.waddle.board[col][row].element}-0{p.waddle.board[col][row].value}' for col in range(5)]) for row in range(8)) + await p.send_xt('zm', 'gi&250:bi&' + str(p.waddle.columns) + '&' + board_str + ':ci&' + '|'.join([f'{card.card.id}-{card.id}' for card in p.waddle.ninjas[seat_id].deck.values()]) + ':po&' + str(seat_id) + ':cv&64000.0&0.0:bv&7571.428571428572&3714.285714285714:tt&' + str(p.waddle.tick)) + # gi&250:bi + # will have to edit cols ^ its 5 bi&