Card Jitsu game handlers

This commit is contained in:
Ben 2020-04-02 23:04:10 +01:00
parent 2d9b73e54b
commit a00d287d14
6 changed files with 446 additions and 89 deletions

View File

@ -9835,7 +9835,7 @@ INSERT INTO room (id, name, member, max_users, required_item, game, blackhole, s
(994, 'igloo_card', FALSE, 80, NULL, TRUE, FALSE, FALSE, NULL), (994, 'igloo_card', FALSE, 80, NULL, TRUE, FALSE, FALSE, NULL),
(995, 'Water', FALSE, 80, NULL, TRUE, FALSE, FALSE, 34), (995, 'Water', FALSE, 80, NULL, TRUE, FALSE, FALSE, 34),
(997, 'Fire', FALSE, 80, NULL, TRUE, FALSE, FALSE, 32), (997, 'Fire', FALSE, 80, NULL, TRUE, FALSE, FALSE, 32),
(998, 'Card Jitsu', FALSE, 0, NULL, TRUE, FALSE, FALSE, 38), (998, 'Card Jitsu', FALSE, 80, NULL, TRUE, FALSE, FALSE, 38),
(999, 'Sled Race', TRUE, 80, NULL, TRUE, FALSE, FALSE, NULL), (999, 'Sled Race', TRUE, 80, NULL, TRUE, FALSE, FALSE, NULL),
(324, 'Dojo Exterior Solo', FALSE, 80, NULL, FALSE, FALSE, FALSE, NULL), (324, 'Dojo Exterior Solo', FALSE, 80, NULL, FALSE, FALSE, FALSE, NULL),
(326, 'Dojo Snow', FALSE, 80, NULL, FALSE, FALSE, FALSE, NULL), (326, 'Dojo Snow', FALSE, 80, NULL, FALSE, FALSE, FALSE, NULL),

View File

@ -78,8 +78,8 @@ class IWaddle(ABC):
self.penguins.remove(p) self.penguins.remove(p)
p.waddle = None p.waddle = None
async def send_xt(self, *data): async def send_xt(self, *data, f=None):
for penguin in self.penguins: for penguin in filter(f, self.penguins):
await penguin.send_xt(*data) await penguin.send_xt(*data)
def get_seat_id(self, p): def get_seat_id(self, p):

View File

@ -13,6 +13,9 @@ class Card(db.Model):
value = db.Column(db.SmallInteger, nullable=False, server_default=db.text("2")) value = db.Column(db.SmallInteger, nullable=False, server_default=db.text("2"))
description = db.Column(db.String(255), nullable=False, server_default=db.text("''::character varying")) description = db.Column(db.String(255), nullable=False, server_default=db.text("''::character varying"))
def get_string(self):
return f'{self.id}|{self.element}|{self.value}|{self.color}|{self.power_id}'
class CardStarterDeck(db.Model): class CardStarterDeck(db.Model):
__tablename__ = 'card_starter_deck' __tablename__ = 'card_starter_deck'

View File

@ -5,9 +5,9 @@ from dataclasses import dataclass
from houdini import handlers from houdini import handlers
from houdini.data.room import RoomWaddle from houdini.data.room import RoomWaddle
from houdini.handlers import XTPacket from houdini.handlers import XTPacket
from houdini.handlers.games.ninja.card import CardJitsuLogic from houdini.handlers.games.ninja.card import SenseiLogic, CardJitsuLogic, CardJitsuMatLogic
from houdini.handlers.games.ninja.fire import CardJitsuFireLogic from houdini.handlers.games.ninja.fire import FireSenseiLogic, CardJitsuFireLogic
from houdini.handlers.games.ninja.water import CardJitsuWaterLogic from houdini.handlers.games.ninja.water import WaterSenseiLogic, CardJitsuWaterLogic
from houdini.penguin import Penguin from houdini.penguin import Penguin
@ -89,13 +89,15 @@ async def card_color_tick(matched):
await mm.penguin.send_xt('tmm', len(matched), mm.tick, *nicknames) await mm.penguin.send_xt('tmm', len(matched), mm.tick, *nicknames)
def card_match(waddle_room_id, waddle_game): def card_match(waddle_game):
async def match(matched): async def match(matched):
nicknames = [f'{mm.penguin.safe_name}|{mm.penguin.color}' for mm in matched] nicknames = [f'{mm.penguin.safe_name}|{mm.penguin.color}' for mm in matched]
host = matched[0].penguin host = matched[0].penguin
waddle_room = host.server.rooms[waddle_room_id] waddle_room = host.server.rooms[waddle_game.room_id]
rw = RoomWaddle(id=host.id, room_id=waddle_room.id, seats=len(matched), game=waddle_game, temporary=True) rw = RoomWaddle(id=host.id, room_id=waddle_room.id, seats=len(matched), game=waddle_game, temporary=True)
rw.room = waddle_room
rw.logic = waddle_game
waddle_room.waddles[rw.id] = rw waddle_room.waddles[rw.id] = rw
for mm in matched: for mm in matched:
@ -103,9 +105,9 @@ def card_match(waddle_room_id, waddle_game):
return match return match
card_matched = card_match(CardJitsuLogic.room_id, 'card') card_matched = card_match(CardJitsuLogic)
card_fire_matched = card_match(CardJitsuFireLogic.room_id, 'fire') card_fire_matched = card_match(CardJitsuFireLogic)
card_water_matched = card_match(CardJitsuWaterLogic.room_id, 'water') card_water_matched = card_match(CardJitsuWaterLogic)
@handlers.boot @handlers.boot
@ -142,11 +144,23 @@ async def handle_join_water_match_making(p):
await p.send_xt('jmm', p.safe_name) await p.send_xt('jmm', p.safe_name)
@handlers.handler(XTPacket('gwcj', ext='z'))
async def handle_get_card_jitsu_mat(p, waddle_id: int):
waddle_id = max(200, min(300, waddle_id))
if p.room.igloo and waddle_id not in p.room.waddles:
rw = RoomWaddle(id=waddle_id, room_id=p.room.id, seats=2, game='card', temporary=True)
rw.room = p.room
rw.logic = CardJitsuMatLogic
p.room.waddles[rw.id] = rw
@handlers.handler(XTPacket('jsen', ext='z')) @handlers.handler(XTPacket('jsen', ext='z'))
@handlers.player_in_room(MatchMaking.SenseiRoom) @handlers.player_in_room(MatchMaking.SenseiRoom)
async def handle_join_sensei_match(p): async def handle_join_sensei_match(p):
waddle_room = p.server.rooms[CardJitsuLogic.room_id] waddle_room = p.server.rooms[SenseiLogic.room_id]
rw = RoomWaddle(id=p.id, room_id=waddle_room.id, seats=1, game='sensei', temporary=True) rw = RoomWaddle(id=p.id, room_id=waddle_room.id, seats=1, game='sensei', temporary=True)
rw.room = waddle_room
rw.logic = SenseiLogic
waddle_room.waddles[rw.id] = rw waddle_room.waddles[rw.id] = rw
await p.send_xt('scard', waddle_room.id, rw.id, 1, 0, f'{p.safe_name}|{p.color}') await p.send_xt('scard', waddle_room.id, rw.id, 1, 0, f'{p.safe_name}|{p.color}')
@ -155,8 +169,10 @@ async def handle_join_sensei_match(p):
@handlers.handler(XTPacket('jsen', ext='z')) @handlers.handler(XTPacket('jsen', ext='z'))
@handlers.player_in_room(MatchMaking.SenseiFireRoom) @handlers.player_in_room(MatchMaking.SenseiFireRoom)
async def handle_join_fire_sensei_match(p): async def handle_join_fire_sensei_match(p):
waddle_room = p.server.rooms[CardJitsuFireLogic.room_id] waddle_room = p.server.rooms[FireSenseiLogic.room_id]
rw = RoomWaddle(id=p.id, room_id=waddle_room.id, seats=1, game='firesensei', temporary=True) rw = RoomWaddle(id=p.id, room_id=waddle_room.id, seats=1, game='firesensei', temporary=True)
rw.room = waddle_room
rw.logic = FireSenseiLogic
waddle_room.waddles[rw.id] = rw waddle_room.waddles[rw.id] = rw
await p.send_xt('scard', waddle_room.id, rw.id, 1, 0, f'{p.safe_name}|{p.color}') await p.send_xt('scard', waddle_room.id, rw.id, 1, 0, f'{p.safe_name}|{p.color}')
@ -165,8 +181,10 @@ async def handle_join_fire_sensei_match(p):
@handlers.handler(XTPacket('jsen', ext='z')) @handlers.handler(XTPacket('jsen', ext='z'))
@handlers.player_in_room(MatchMaking.SenseiWaterRoom) @handlers.player_in_room(MatchMaking.SenseiWaterRoom)
async def handle_join_water_sensei_match(p): async def handle_join_water_sensei_match(p):
waddle_room = p.server.rooms[CardJitsuWaterLogic.room_id] waddle_room = p.server.rooms[WaterSenseiLogic.room_id]
rw = RoomWaddle(id=p.id, room_id=waddle_room.id, seats=1, game='watersensei', temporary=True) rw = RoomWaddle(id=p.id, room_id=waddle_room.id, seats=1, game='watersensei', temporary=True)
rw.room = waddle_room
rw.logic = WaterSenseiLogic
waddle_room.waddles[rw.id] = rw waddle_room.waddles[rw.id] = rw
await p.send_xt('scard', waddle_room.id, rw.id, 1, 0, f'{p.safe_name}|{p.color}') await p.send_xt('scard', waddle_room.id, rw.id, 1, 0, f'{p.safe_name}|{p.color}')

View File

@ -1,9 +1,13 @@
import itertools import itertools
import math
import random
from collections import Counter
from dataclasses import dataclass from dataclasses import dataclass
from typing import Dict, List, Union from typing import Dict, List, Union
from houdini import IWaddle from houdini import IWaddle, handlers
from houdini.data.ninja import Card from houdini.data.ninja import Card
from houdini.handlers import XTPacket
from houdini.penguin import Penguin from houdini.penguin import Penguin
@ -13,29 +17,42 @@ class Played:
card: Card card: Card
player: int player: int
opponent: int opponent: int
value: int
element: str
@dataclass @dataclass
class Ninja: class Ninja:
penguin: Penguin penguin: Penguin
deck: Dict[int, Card] deck: Dict[int, Played]
bank: Dict[str, List[Played]] bank: Dict[str, List[Played]]
chosen: Union[Played, None] chosen: Union[Played, None]
class CardJitsuLogic(IWaddle): class CardJitsuLogic(IWaddle):
room_id = 998 room_id = 998
rule_set = {'f': 's', 'w': 'f', 's': 'w'}
discard_elements = {4: 's', 5: 'w', 6: 'f'} RuleSet = {'f': 's', 'w': 'f', 's': 'w'}
discard_colors = {7: 'r', 8: 'b', 9: 'g', 10: 'y', 11: 'o', 12: 'p'} DiscardElements = {4: 's', 5: 'w', 6: 'f'}
replacements = {16: ['w', 'f'], 17: ['s', 'w'], 18: ['f', 's']} DiscardColors = {7: 'r', 8: 'b', 9: 'g', 10: 'y', 11: 'o', 12: 'p'}
rank_speed = 1 Replacements = {16: ['w', 'f'], 17: ['s', 'w'], 18: ['f', 's']}
PowerLimiters = {13: 's', 14: 'f', 15: 'w'}
OnPlayed = {1, 16, 17, 18}
CurrentRound = {4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 17, 18}
AffectsOwnPlayer = {2}
ItemAwards = [4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 104]
PostcardAwards = {0: 177, 4: 178, 8: 179}
StampAwards = {0: 230, 4: 232, 8: 234, 9: 236}
StampGroupId = 38
RankSpeed = 1
def __init__(self, waddle): def __init__(self, waddle):
super().__init__(waddle) super().__init__(waddle)
self.ninjas = [ self.ninjas = [Ninja(
Ninja(
penguin=p, penguin=p,
deck={}, deck={},
bank={'f': [], 'w': [], 's': []}, bank={'f': [], 'w': [], 's': []},
@ -64,29 +81,28 @@ class CardJitsuLogic(IWaddle):
return False, -1 return False, -1
def has_cards_to_play(self, seat_id): def has_cards_to_play(self, seat_id):
power_limiters = {13: 's', 14: 'f', 15: 'w'} for power_id, element in CardJitsuLogic.PowerLimiters.items():
for power_id, element in power_limiters.items():
if power_id in self.powers: if power_id in self.powers:
power_card = self.powers[power_id] power_card = self.powers[power_id]
if power_card.opponent == seat_id: if power_card.opponent == seat_id:
opponent_deck = self.ninjas[power_card.opponent].deck opponent_deck = self.ninjas[power_card.opponent].deck
for card_id, card in opponent_deck.items(): for card_id, card in opponent_deck.items():
if card.element != element: if card.card.element != element:
return True return True
return False return False
return True return True
def discard_opponent_card(self, power_id, opponent_seat_id): def discard_opponent_card(self, power_id, opponent_seat_id):
opponent_cards = self.ninjas[opponent_seat_id].bank opponent_cards = self.ninjas[opponent_seat_id].bank
if power_id in self.discard_elements: if power_id in self.DiscardElements:
element_to_discard = self.discard_elements[power_id] element_to_discard = self.DiscardElements[power_id]
if len(opponent_cards[element_to_discard]) > 0: if len(opponent_cards[element_to_discard]) > 0:
card_to_discard = self.ninjas[opponent_seat_id].bank[element_to_discard][-1] card_to_discard = self.ninjas[opponent_seat_id].bank[element_to_discard][-1]
self.discards.append(card_to_discard.id) self.discards.append(card_to_discard.id)
del self.ninjas[opponent_seat_id].bank[element_to_discard][-1] del self.ninjas[opponent_seat_id].bank[element_to_discard][-1]
return True return True
if power_id in self.discard_colors: if power_id in self.DiscardColors:
color_to_discard = self.discard_colors[power_id] color_to_discard = self.DiscardColors[power_id]
for element, cards in opponent_cards.items(): for element, cards in opponent_cards.items():
for index, card in enumerate(cards): for index, card in enumerate(cards):
if card.card.color == color_to_discard: if card.card.color == color_to_discard:
@ -98,76 +114,81 @@ class CardJitsuLogic(IWaddle):
def adjust_card_values(self, first_card, second_card): def adjust_card_values(self, first_card, second_card):
for power_id, power_card in self.powers.items(): for power_id, power_card in self.powers.items():
if power_card.card.power_id == 1 and first_card.card.element == second_card.card.element: if power_card.card.power_id == 1 and first_card.element == second_card.element:
first_card.card.value = 1 swap_value = first_card.value
second_card.card.value = 1 first_card.value = second_card.value
second_card.value = swap_value
if power_card.card.power_id == 2: if power_card.card.power_id == 2:
if power_card.player == 0: if power_card.player == 0:
first_card.card.value += 2 first_card.value += 2
else: else:
second_card.card.value += 2 second_card.value += 2
if power_card.card.power_id == 3: if power_card.card.power_id == 3:
if power_card.player == 0: if power_card.player == 0:
second_card.card.value -= 2 second_card.value -= 2
else: else:
first_card.card.value -= 2 first_card.value -= 2
def get_round_winner(self):
first_card, second_card = self.ninjas[0].chosen, self.ninjas[1].chosen
winner_seat_id = self.get_winner_seat_id(first_card, second_card)
self.adjust_card_values(first_card, second_card)
def on_played_effects(self, first_card, second_card):
for ninja_seat_id, ninja in enumerate(self.ninjas): for ninja_seat_id, ninja in enumerate(self.ninjas):
played_card = ninja.chosen played_card = ninja.chosen
power_id = played_card.card.power_id power_id = played_card.card.power_id
if not power_id: if not power_id:
continue continue
on_played = power_id in CardJitsuLogic.OnPlayed
opponent_seat_id = 1 if ninja_seat_id == 0 else 0 current_round = power_id in CardJitsuLogic.CurrentRound
on_played = power_id in {1, 16, 17, 18}
on_scored = not on_played
current_round = power_id in {4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 17, 18}
next_round = not current_round next_round = not current_round
if on_played:
if on_played and next_round:
self.powers[power_id] = played_card
if on_scored and ninja_seat_id == winner_seat_id:
if next_round: if next_round:
self.powers[power_id] = played_card self.powers[power_id] = played_card
if current_round: if current_round:
self.discard_opponent_card(power_id, opponent_seat_id) self.replace_cards(power_id, first_card, second_card)
if on_played and current_round:
self.replace_opponent_card(power_id, first_card, second_card, played_card.player)
winner_seat_id = self.get_winner_seat_id(first_card, second_card)
self.ninjas[0].chosen = None def on_scored_effects(self, first_card, second_card):
self.ninjas[1].chosen = None winner_seat_id = self.get_winner_seat_id(first_card, second_card)
for ninja_seat_id, ninja in enumerate(self.ninjas):
power_id = ninja.chosen.card.power_id
if power_id:
opponent_seat_id = (ninja_seat_id + 1) % 2
on_scored = power_id not in CardJitsuLogic.OnPlayed
current_round = power_id in CardJitsuLogic.CurrentRound
next_round = not current_round
if on_scored and ninja_seat_id == winner_seat_id:
if next_round:
self.powers[power_id] = ninja.chosen
if current_round:
self.discard_opponent_card(power_id, opponent_seat_id)
def get_round_winner(self):
first_card, second_card = self.ninjas[0].chosen, self.ninjas[1].chosen
self.adjust_card_values(first_card, second_card)
self.powers = {}
self.on_played_effects(first_card, second_card)
self.on_scored_effects(first_card, second_card)
winner_seat_id = self.get_winner_seat_id(first_card, second_card)
return winner_seat_id return winner_seat_id
@classmethod @classmethod
def replace_opponent_card(cls, power_id, first_card, second_card, seat_id): def replace_cards(cls, power_id, first_card, second_card):
for replace_power_id, replacement in cls.replacements.items(): original, replace = cls.Replacements[power_id]
if power_id == replace_power_id: if first_card.element == original:
original, replace = replacement first_card.element = replace
if seat_id == 1 and first_card.card.element == original: if second_card.element == original:
first_card.card.element = replace second_card.element = replace
if seat_id == 0 and second_card.card.element == original:
second_card.card.element = replace
@classmethod @classmethod
def get_winner_seat_id(cls, first_card, second_card): def get_winner_seat_id(cls, first_card, second_card):
if first_card.card.element != second_card.card.element: if first_card.element != second_card.element:
return 0 if cls.rule_set[first_card.card.element] == second_card.card.element else 1 return 0 if cls.RuleSet[first_card.element] == second_card.element else 1
elif first_card.card.value > second_card.card.value: elif first_card.value > second_card.value:
return 0 return 0
elif second_card.card.value > first_card.card.value: elif second_card.value > first_card.value:
return 1 return 1
return -1 return -1
class CardJitsuMatLogic(CardJitsuLogic): class CardJitsuMatLogic(CardJitsuLogic):
rank_speed = 0.5 RankSpeed = 0.5
class SenseiLogic(CardJitsuLogic): class SenseiLogic(CardJitsuLogic):
@ -175,27 +196,341 @@ class SenseiLogic(CardJitsuLogic):
def __init__(self, waddle): def __init__(self, waddle):
super().__init__(waddle) super().__init__(waddle)
self.ninja = Ninja( self.ninjas.insert(0, Ninja(
penguin=waddle.penguins[0], penguin=waddle.penguins[0],
deck={}, deck={},
bank={'f': [], 'w': [], 's': []}, bank={'f': [], 'w': [], 's': []},
chosen=None chosen=None
) ))
self.sensei_move = {} self.sensei_move = {}
self.colors = [] self.colors = []
def get_win_card(self, card): def get_win_card(self, card):
self.colors = [] if len(self.colors) >= 6 else self.colors self.colors = [] if len(self.colors) >= 6 else self.colors
for card_check in self.ninja.penguin.server.cards.values(): for card_check in self.penguins[0].server.cards.values():
if self.beats_card(card_check, card) and card_check.color not in self.colors: if card_check.color not in self.colors and self.beats_card(card_check, card):
self.colors.append(card_check.color) self.colors.append(card_check.color)
return card_check return card_check
@classmethod @classmethod
def beats_card(cls, card_check, card_play): def beats_card(cls, card_check, card_play):
if card_check.card.element != card_play.card.element: if card_check.element != card_play.element:
return True if cls.rule_set[card_check.card.element] == card_play.card.element else False return True if cls.RuleSet[card_check.element] == card_play.element else False
elif card_check.card.value > card_play.card.value: elif card_check.value > card_play.value:
return True return True
return False return False
async def ninja_rank_up(p, ranks=1):
if p.ninja_rank + ranks > len(CardJitsuLogic.ItemAwards):
return False
for rank in range(p.ninja_rank, p.ninja_rank+ranks):
await p.add_inventory(p.server.items[CardJitsuLogic.ItemAwards[rank]], notify=False)
if rank in CardJitsuLogic.PostcardAwards:
await p.add_inbox(p.server.postcards[CardJitsuLogic.PostcardAwards[rank]])
if rank in CardJitsuLogic.StampAwards:
await p.add_stamp(p.server.stamps[CardJitsuLogic.StampAwards[rank]])
await p.update(ninja_rank=p.ninja_rank + ranks, ninja_progress=0).apply()
return True
async def ninja_progress(p, won=False):
if p.ninja_rank == 0:
await p.update(ninja_progress=100).apply()
elif p.ninja_rank < 9:
speed = type(p.waddle).RankSpeed
if not won:
speed *= 0.5
points = math.floor((100 / p.ninja_rank) * speed)
await p.update(ninja_progress=p.ninja_progress+points).apply()
if p.ninja_progress >= 100:
await ninja_rank_up(p)
await p.send_xt('cza', p.ninja_rank)
async def ninja_stamps_earned(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)
async def ninja_win(winner, loser):
await ninja_progress(winner.penguin, won=True)
await ninja_progress(loser.penguin, won=False)
await ninja_stamps_earned(winner.penguin)
await ninja_stamps_earned(loser.penguin)
await winner.penguin.waddle.remove_penguin(winner.penguin)
await loser.penguin.waddle.remove_penguin(loser.penguin)
@handlers.handler(XTPacket('gz', ext='z'))
@handlers.waddle(CardJitsuLogic, CardJitsuMatLogic)
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, p.safe_name, p.color, p.ninja_rank)
@handlers.handler(XTPacket('uz', ext='z'))
@handlers.waddle(CardJitsuLogic, CardJitsuMatLogic)
async def handle_update_game(p):
players = [f'{seat_id}|{player.safe_name}|{player.color}|{player.ninja_rank}'
for seat_id, player in enumerate(p.waddle.penguins)]
await p.send_xt('uz', *players)
await p.send_xt('sz')
@handlers.handler(XTPacket('lz', ext='z'))
@handlers.waddle(CardJitsuLogic, CardJitsuMatLogic, SenseiLogic)
async def handle_leave_game(p):
seat_id = p.waddle.get_seat_id(p)
await p.waddle.send_xt('cz', p.safe_name, f=lambda penguin: penguin is not p)
await p.waddle.send_xt('lz', seat_id, f=lambda penguin: penguin is not p)
await p.waddle.remove_penguin(p)
@handlers.handler(XTPacket('zm', ext='z'), match=['deal'])
@handlers.waddle(CardJitsuLogic, CardJitsuMatLogic)
async def handle_send_deal(p, action: str):
seat_id = p.waddle.get_seat_id(p)
opponent_seat_id = (seat_id + 1) % 2
me = p.waddle.ninjas[seat_id]
deck = Counter((card.card_id for card in p.cards.values() for _ in range(card.quantity + card.member_quantity)))
dealt = Counter((played.card.id for played in me.deck.values()))
undealt = random.sample(list((deck - dealt).elements()), 5 - len(me.deck))
strings = []
for card_id in undealt:
card = p.server.cards[card_id]
me.deck[p.waddle.card_id] = Played(
id=p.waddle.card_id,
card=card,
player=seat_id,
opponent=opponent_seat_id,
value=card.value,
element=card.element
)
strings.append(f'{p.waddle.card_id}|{card.get_string()}')
p.waddle.card_id += 1
await p.waddle.send_xt('zm', action, seat_id, *strings)
@handlers.handler(XTPacket('zm', ext='z'), match=['pick'])
@handlers.waddle(CardJitsuLogic, CardJitsuMatLogic)
async def handle_send_pick(p, action: str, card_id: int):
seat_id = p.waddle.get_seat_id(p)
opponent_seat_id = (seat_id + 1) % 2
me = p.waddle.ninjas[seat_id]
opponent = p.waddle.ninjas[opponent_seat_id]
if card_id not in me.deck or me.chosen is not None:
return
me.chosen = me.deck[card_id]
del me.deck[card_id]
await p.waddle.send_xt('zm', action, seat_id, card_id)
if me.chosen and opponent.chosen:
winner_seat_id = p.waddle.get_round_winner()
if me.chosen.card.id == 256 or opponent.chosen.card.id == 256:
stamp = p.server.stamps[246]
await me.penguin.add_stamp(stamp, notify=True)
await opponent.penguin.add_stamp(stamp, notify=True)
if me.chosen.card.power_id and me.chosen.card.power_id in CardJitsuLogic.OnPlayed:
await p.waddle.send_xt('zm', 'power', seat_id, opponent_seat_id, me.chosen.card.power_id)
if opponent.chosen.card.power_id and opponent.chosen.card.power_id in CardJitsuLogic.OnPlayed:
await p.waddle.send_xt('zm', 'power', opponent_seat_id, seat_id, opponent.chosen.card.power_id)
if winner_seat_id != -1:
loser_seat_id = (winner_seat_id + 1) % 2
winner = p.waddle.ninjas[winner_seat_id]
loser = p.waddle.ninjas[loser_seat_id]
winning_card = winner.chosen
winner.bank[winning_card.card.element].append(winning_card)
if winning_card.card.power_id and winning_card.card.power_id not in CardJitsuLogic.OnPlayed:
affects_own_player = winning_card.card.power_id in CardJitsuLogic.AffectsOwnPlayer
sender, recipient = (winner_seat_id, winner_seat_id) if affects_own_player else (winner_seat_id, loser_seat_id)
await p.waddle.send_xt('zm', 'power', sender, recipient, winning_card.card.power_id, *p.waddle.discards)
p.waddle.discards = []
winning_cards, win_method = p.waddle.get_winning_cards(winner_seat_id)
if winning_cards:
await p.waddle.send_xt('czo', 0, winner_seat_id, *(card.id for card in winning_cards))
stamp = p.server.stamps[[244, 242][win_method]]
await winner.penguin.add_stamp(stamp, notify=True)
if all(not cards for cards in loser.bank.values()):
stamp = p.server.stamps[238]
await winner.penguin.add_stamp(stamp, notify=True)
if sum(1 for cards in winner.bank.values() for _ in cards) >= 9:
stamp = p.server.stamps[248]
await winner.penguin.add_stamp(stamp, notify=True)
await winner.penguin.update(ninja_matches_won=winner.penguin.ninja_matches_won+1).apply()
if winner.penguin.ninja_matches_won == 25:
stamp = p.server.stamps[240]
await winner.penguin.add_stamp(stamp, notify=True)
await ninja_win(winner, loser)
else:
for seat_id, ninja in enumerate(p.waddle.ninjas):
if not p.waddle.has_cards_to_play(seat_id):
winner_seat_id = (seat_id + 1) % 2
winner = p.waddle.ninjas[winner_seat_id]
loser = p.waddle.ninjas[seat_id]
await p.waddle.send_xt('czo', 0, winner_seat_id)
await ninja_win(winner, loser)
await me.penguin.send_xt('zm', 'judge', winner_seat_id)
await opponent.penguin.send_xt('zm', 'judge', winner_seat_id)
me.chosen = None
opponent.chosen = None
@handlers.handler(XTPacket('gz', ext='z'))
@handlers.waddle(SenseiLogic)
async def handle_get_sensei_game(p):
await p.send_xt('gz', 2, 2)
await p.send_xt('jz', 1, p.safe_name, p.color, p.ninja_rank)
@handlers.handler(XTPacket('uz', ext='z'))
@handlers.waddle(SenseiLogic)
async def handle_update_sensei_game(p):
await p.send_xt('uz', '0|Sensei|14|10', f'1|{p.safe_name}|{p.color}|{p.ninja_rank}')
await p.send_xt('sz')
@handlers.handler(XTPacket('zm', ext='z'), match=['deal'])
@handlers.waddle(SenseiLogic)
async def handle_send_sensei_deal(p, action: str):
can_beat_sensei = p.ninja_rank > len(CardJitsuLogic.ItemAwards) - 1
sensei, me = p.waddle.ninjas
deck = Counter((card.card_id for card in p.cards.values() if
can_beat_sensei or p.server.cards[card.card_id].power_id == 0
for _ in range(card.quantity + card.member_quantity)))
dealt = Counter((played.card.id for played in me.deck.values()))
undealt = random.sample(list((deck - dealt).elements()), 5 - len(me.deck))
strings = []
sensei_strings = []
for card_id in undealt:
card = p.server.cards[card_id]
me.deck[p.waddle.card_id] = Played(
id=p.waddle.card_id,
card=card,
player=1,
opponent=0,
value=card.value,
element=card.element
)
strings.append(f'{p.waddle.card_id}|{card.get_string()}')
p.waddle.card_id += 1
sensei_card = random.choice(list(p.server.cards.values())) if can_beat_sensei else p.waddle.get_win_card(card)
sensei.deck[p.waddle.card_id] = Played(
id=p.waddle.card_id,
card=sensei_card,
player=0,
opponent=1,
value=sensei_card.value,
element=sensei_card.element
)
sensei_strings.append(f'{p.waddle.card_id}|{sensei_card.get_string()}')
p.waddle.sensei_move[p.waddle.card_id - 1] = p.waddle.card_id
p.waddle.card_id += 1
await p.waddle.send_xt('zm', action, 0, *sensei_strings)
await p.waddle.send_xt('zm', action, 1, *strings)
@handlers.handler(XTPacket('zm', ext='z'), match=['pick'])
@handlers.waddle(SenseiLogic)
async def handle_send_sensei_pick(p, action: str, card_id: int):
sensei, me = p.waddle.ninjas
if card_id not in me.deck or me.chosen is not None:
return
me.chosen = me.deck[card_id]
sensei.chosen = sensei.deck[p.waddle.sensei_move[card_id]]
del me.deck[card_id]
del sensei.deck[p.waddle.sensei_move[card_id]]
del p.waddle.sensei_move[card_id]
await p.send_xt('zm', action, 0, sensei.chosen.id)
await p.send_xt('zm', action, 1, me.chosen.id)
winner_seat_id = p.waddle.get_round_winner()
if me.chosen.card.id == 256 or sensei.chosen.card.id == 256:
stamp = p.server.stamps[246]
await p.add_stamp(stamp, notify=True)
if me.chosen.card.power_id and me.chosen.card.power_id in CardJitsuLogic.OnPlayed:
await p.send_xt('zm', 'power', 1, 0, me.chosen.card.power_id)
if sensei.chosen.card.power_id and sensei.chosen.card.power_id in CardJitsuLogic.OnPlayed:
await p.send_xt('zm', 'power', 0, 1, sensei.chosen.card.power_id)
if winner_seat_id != -1:
loser_seat_id = (winner_seat_id + 1) % 2
winner = sensei if winner_seat_id == 0 else me
winning_card = sensei.chosen if winner_seat_id == 0 else me.chosen
winner.bank[winning_card.card.element].append(winning_card)
if winning_card.card.power_id and winning_card.card.power_id not in CardJitsuLogic.OnPlayed:
affects_own_player = winning_card.card.power_id in CardJitsuLogic.AffectsOwnPlayer
sender, recipient = (winner_seat_id, winner_seat_id) if affects_own_player else (winner_seat_id, loser_seat_id)
await p.send_xt('zm', 'power', sender, recipient, winning_card.card.power_id, *p.waddle.discards)
p.waddle.discards = []
winning_cards, win_method = p.waddle.get_winning_cards(winner_seat_id)
if winning_cards:
await p.waddle.send_xt('czo', 0, winner_seat_id, *(card.id for card in winning_cards))
if winner == me:
stamp = p.server.stamps[[244, 242][win_method]]
await p.add_stamp(stamp, notify=True)
if all(not cards for cards in sensei.bank.values()):
stamp = p.server.stamps[238]
await p.add_stamp(stamp, notify=True)
if sum(1 for cards in me.bank.values() for _ in cards) >= 9:
stamp = p.server.stamps[248]
await p.add_stamp(stamp, notify=True)
await p.update(ninja_matches_won=p.ninja_matches_won + 1).apply()
if p.ninja_matches_won == 25:
stamp = p.server.stamps[240]
await p.add_stamp(stamp, notify=True)
await ninja_stamps_earned(p)
can_rank_up = await ninja_rank_up(p)
if can_rank_up:
await p.send_xt('cza', p.ninja_rank)
else:
for seat_id, ninja in enumerate(p.waddle.ninjas):
if not p.waddle.has_cards_to_play(seat_id):
winner_seat_id = (seat_id + 1) % 2
winner = p.waddle.ninjas[winner_seat_id]
if winner == me:
can_rank_up = await ninja_rank_up(p)
if can_rank_up:
await p.send_xt('cza', p.ninja_rank)
await p.waddle.send_xt('czo', 0, winner_seat_id)
await ninja_stamps_earned(p)
await p.send_xt('zm', 'judge', winner_seat_id)
me.chosen = None
sensei.chosen = None

View File

@ -13,7 +13,7 @@ from houdini.data.room import PenguinBackyardRoom, PenguinIglooRoom, Room, RoomC
from houdini.handlers import XTPacket from houdini.handlers import XTPacket
from houdini.handlers.games.four import ConnectFourLogic from houdini.handlers.games.four import ConnectFourLogic
from houdini.handlers.games.mancala import MancalaLogic from houdini.handlers.games.mancala import MancalaLogic
from houdini.handlers.games.ninja.card import CardJitsuLogic, SenseiLogic from houdini.handlers.games.ninja.card import CardJitsuLogic, CardJitsuMatLogic, SenseiLogic
from houdini.handlers.games.ninja.fire import CardJitsuFireLogic, FireSenseiLogic from houdini.handlers.games.ninja.fire import CardJitsuFireLogic, FireSenseiLogic
from houdini.handlers.games.ninja.water import CardJitsuWaterLogic, WaterSenseiLogic from houdini.handlers.games.ninja.water import CardJitsuWaterLogic, WaterSenseiLogic
from houdini.handlers.games.sled import SledRacingLogic from houdini.handlers.games.sled import SledRacingLogic
@ -29,7 +29,8 @@ TableLogicMapping = {
WaddleLogicMapping = { WaddleLogicMapping = {
'sled': SledRacingLogic, 'sled': SledRacingLogic,
'card': CardJitsuLogic, 'card': CardJitsuMatLogic,
'match': CardJitsuLogic,
'sensei': SenseiLogic, 'sensei': SenseiLogic,
'water': CardJitsuWaterLogic, 'water': CardJitsuWaterLogic,