mirror of
https://github.com/solero/houdini.git
synced 2024-11-25 15:07:24 +00:00
Card Jitsu game handlers
This commit is contained in:
parent
2d9b73e54b
commit
a00d287d14
@ -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),
|
||||||
|
@ -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):
|
||||||
|
@ -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'
|
||||||
|
@ -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}')
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user