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),
(995, 'Water', FALSE, 80, NULL, TRUE, FALSE, FALSE, 34),
(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),
(324, 'Dojo Exterior Solo', 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)
p.waddle = None
async def send_xt(self, *data):
for penguin in self.penguins:
async def send_xt(self, *data, f=None):
for penguin in filter(f, self.penguins):
await penguin.send_xt(*data)
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"))
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):
__tablename__ = 'card_starter_deck'

View File

@ -5,9 +5,9 @@ from dataclasses import dataclass
from houdini import handlers
from houdini.data.room import RoomWaddle
from houdini.handlers import XTPacket
from houdini.handlers.games.ninja.card import CardJitsuLogic
from houdini.handlers.games.ninja.fire import CardJitsuFireLogic
from houdini.handlers.games.ninja.water import CardJitsuWaterLogic
from houdini.handlers.games.ninja.card import SenseiLogic, CardJitsuLogic, CardJitsuMatLogic
from houdini.handlers.games.ninja.fire import FireSenseiLogic, CardJitsuFireLogic
from houdini.handlers.games.ninja.water import WaterSenseiLogic, CardJitsuWaterLogic
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)
def card_match(waddle_room_id, waddle_game):
def card_match(waddle_game):
async def match(matched):
nicknames = [f'{mm.penguin.safe_name}|{mm.penguin.color}' for mm in matched]
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.room = waddle_room
rw.logic = waddle_game
waddle_room.waddles[rw.id] = rw
for mm in matched:
@ -103,9 +105,9 @@ def card_match(waddle_room_id, waddle_game):
return match
card_matched = card_match(CardJitsuLogic.room_id, 'card')
card_fire_matched = card_match(CardJitsuFireLogic.room_id, 'fire')
card_water_matched = card_match(CardJitsuWaterLogic.room_id, 'water')
card_matched = card_match(CardJitsuLogic)
card_fire_matched = card_match(CardJitsuFireLogic)
card_water_matched = card_match(CardJitsuWaterLogic)
@handlers.boot
@ -142,11 +144,23 @@ async def handle_join_water_match_making(p):
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.player_in_room(MatchMaking.SenseiRoom)
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.room = waddle_room
rw.logic = SenseiLogic
waddle_room.waddles[rw.id] = rw
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.player_in_room(MatchMaking.SenseiFireRoom)
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.room = waddle_room
rw.logic = FireSenseiLogic
waddle_room.waddles[rw.id] = rw
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.player_in_room(MatchMaking.SenseiWaterRoom)
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.room = waddle_room
rw.logic = WaterSenseiLogic
waddle_room.waddles[rw.id] = rw
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 math
import random
from collections import Counter
from dataclasses import dataclass
from typing import Dict, List, Union
from houdini import IWaddle
from houdini import IWaddle, handlers
from houdini.data.ninja import Card
from houdini.handlers import XTPacket
from houdini.penguin import Penguin
@ -13,34 +17,47 @@ class Played:
card: Card
player: int
opponent: int
value: int
element: str
@dataclass
class Ninja:
penguin: Penguin
deck: Dict[int, Card]
deck: Dict[int, Played]
bank: Dict[str, List[Played]]
chosen: Union[Played, None]
class CardJitsuLogic(IWaddle):
room_id = 998
rule_set = {'f': 's', 'w': 'f', 's': 'w'}
discard_elements = {4: 's', 5: 'w', 6: 'f'}
discard_colors = {7: 'r', 8: 'b', 9: 'g', 10: 'y', 11: 'o', 12: 'p'}
replacements = {16: ['w', 'f'], 17: ['s', 'w'], 18: ['f', 's']}
rank_speed = 1
RuleSet = {'f': 's', 'w': 'f', 's': 'w'}
DiscardElements = {4: 's', 5: 'w', 6: 'f'}
DiscardColors = {7: 'r', 8: 'b', 9: 'g', 10: 'y', 11: 'o', 12: 'p'}
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):
super().__init__(waddle)
self.ninjas = [
Ninja(
penguin=p,
deck={},
bank={'f': [], 'w': [], 's': []},
chosen=None
) for p in waddle.penguins]
self.ninjas = [Ninja(
penguin=p,
deck={},
bank={'f': [], 'w': [], 's': []},
chosen=None
) for p in waddle.penguins]
self.card_id = 1
self.powers = {}
@ -64,29 +81,28 @@ class CardJitsuLogic(IWaddle):
return False, -1
def has_cards_to_play(self, seat_id):
power_limiters = {13: 's', 14: 'f', 15: 'w'}
for power_id, element in power_limiters.items():
for power_id, element in CardJitsuLogic.PowerLimiters.items():
if power_id in self.powers:
power_card = self.powers[power_id]
if power_card.opponent == seat_id:
opponent_deck = self.ninjas[power_card.opponent].deck
for card_id, card in opponent_deck.items():
if card.element != element:
if card.card.element != element:
return True
return False
return True
def discard_opponent_card(self, power_id, opponent_seat_id):
opponent_cards = self.ninjas[opponent_seat_id].bank
if power_id in self.discard_elements:
element_to_discard = self.discard_elements[power_id]
if power_id in self.DiscardElements:
element_to_discard = self.DiscardElements[power_id]
if len(opponent_cards[element_to_discard]) > 0:
card_to_discard = self.ninjas[opponent_seat_id].bank[element_to_discard][-1]
self.discards.append(card_to_discard.id)
del self.ninjas[opponent_seat_id].bank[element_to_discard][-1]
return True
if power_id in self.discard_colors:
color_to_discard = self.discard_colors[power_id]
if power_id in self.DiscardColors:
color_to_discard = self.DiscardColors[power_id]
for element, cards in opponent_cards.items():
for index, card in enumerate(cards):
if card.card.color == color_to_discard:
@ -98,76 +114,81 @@ class CardJitsuLogic(IWaddle):
def adjust_card_values(self, first_card, second_card):
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:
first_card.card.value = 1
second_card.card.value = 1
if power_card.card.power_id == 1 and first_card.element == second_card.element:
swap_value = first_card.value
first_card.value = second_card.value
second_card.value = swap_value
if power_card.card.power_id == 2:
if power_card.player == 0:
first_card.card.value += 2
first_card.value += 2
else:
second_card.card.value += 2
second_card.value += 2
if power_card.card.power_id == 3:
if power_card.player == 0:
second_card.card.value -= 2
second_card.value -= 2
else:
first_card.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)
first_card.value -= 2
def on_played_effects(self, first_card, second_card):
for ninja_seat_id, ninja in enumerate(self.ninjas):
played_card = ninja.chosen
power_id = played_card.card.power_id
if not power_id:
continue
opponent_seat_id = 1 if ninja_seat_id == 0 else 0
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}
on_played = power_id in CardJitsuLogic.OnPlayed
current_round = power_id in CardJitsuLogic.CurrentRound
next_round = not current_round
if on_played and next_round:
self.powers[power_id] = played_card
if on_scored and ninja_seat_id == winner_seat_id:
if on_played:
if next_round:
self.powers[power_id] = played_card
if current_round:
self.discard_opponent_card(power_id, opponent_seat_id)
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.replace_cards(power_id, first_card, second_card)
self.ninjas[0].chosen = None
self.ninjas[1].chosen = None
def on_scored_effects(self, first_card, second_card):
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
@classmethod
def replace_opponent_card(cls, power_id, first_card, second_card, seat_id):
for replace_power_id, replacement in cls.replacements.items():
if power_id == replace_power_id:
original, replace = replacement
if seat_id == 1 and first_card.card.element == original:
first_card.card.element = replace
if seat_id == 0 and second_card.card.element == original:
second_card.card.element = replace
def replace_cards(cls, power_id, first_card, second_card):
original, replace = cls.Replacements[power_id]
if first_card.element == original:
first_card.element = replace
if second_card.element == original:
second_card.element = replace
@classmethod
def get_winner_seat_id(cls, first_card, second_card):
if first_card.card.element != second_card.card.element:
return 0 if cls.rule_set[first_card.card.element] == second_card.card.element else 1
elif first_card.card.value > second_card.card.value:
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.card.value > first_card.card.value:
elif second_card.value > first_card.value:
return 1
return -1
class CardJitsuMatLogic(CardJitsuLogic):
rank_speed = 0.5
RankSpeed = 0.5
class SenseiLogic(CardJitsuLogic):
@ -175,27 +196,341 @@ class SenseiLogic(CardJitsuLogic):
def __init__(self, waddle):
super().__init__(waddle)
self.ninja = Ninja(
penguin=waddle.penguins[0],
deck={},
bank={'f': [], 'w': [], 's': []},
chosen=None
)
self.ninjas.insert(0, Ninja(
penguin=waddle.penguins[0],
deck={},
bank={'f': [], 'w': [], 's': []},
chosen=None
))
self.sensei_move = {}
self.colors = []
def get_win_card(self, card):
self.colors = [] if len(self.colors) >= 6 else self.colors
for card_check in self.ninja.penguin.server.cards.values():
if self.beats_card(card_check, card) and card_check.color not in self.colors:
for card_check in self.penguins[0].server.cards.values():
if card_check.color not in self.colors and self.beats_card(card_check, card):
self.colors.append(card_check.color)
return card_check
@classmethod
def beats_card(cls, card_check, card_play):
if card_check.card.element != card_play.card.element:
return True if cls.rule_set[card_check.card.element] == card_play.card.element else False
elif card_check.card.value > card_play.card.value:
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 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.games.four import ConnectFourLogic
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.water import CardJitsuWaterLogic, WaterSenseiLogic
from houdini.handlers.games.sled import SledRacingLogic
@ -29,7 +29,8 @@ TableLogicMapping = {
WaddleLogicMapping = {
'sled': SledRacingLogic,
'card': CardJitsuLogic,
'card': CardJitsuMatLogic,
'match': CardJitsuLogic,
'sensei': SenseiLogic,
'water': CardJitsuWaterLogic,