Coverage for thb/characters/yugi.py : 39%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2from __future__ import annotations
4# -- stdlib --
5from typing import TYPE_CHECKING, cast
7# -- third party --
8# -- own --
9from thb.actions import Damage, DropCards, FatetellAction, LaunchCard, random_choose_card
10from thb.cards.base import Card, Skill, VirtualCard
11from thb.cards.classes import AttackCard, BaseAttack, InevitableAttack, RedUFOSkill, TreatAs, t_None
12from thb.characters.base import Character, register_character_to
13from thb.inputlets import ChooseOptionInputlet, ChoosePeerCardInputlet
14from thb.mode import THBEventHandler, THBAction
15from utils.misc import classmix
17# -- typing --
18if TYPE_CHECKING:
19 from thb.thbkof import THBattleKOF # noqa: F401
22# -- code --
23class Assault(RedUFOSkill):
24 skill_category = ['character', 'passive', 'compulsory']
25 increment = 1
28class AssaultKOF(Skill):
29 associated_action = None
30 skill_category = ['character', 'passive']
31 target = t_None()
34class AssaultAttack(TreatAs, VirtualCard):
35 treat_as = AttackCard
38class AssaultKOFHandler(THBEventHandler):
39 interested = ['character_debut']
40 game: THBattleKOF
42 def handle(self, evt_type, arg):
43 if evt_type == 'character_debut':
44 old, new = arg
45 if not new.has_skill(AssaultKOF):
46 return arg
48 g = self.game
49 op = g.get_opponent(new)
50 lc = LaunchCard(new, [op], AssaultAttack(new))
51 if not lc.can_fire():
52 return arg
54 if g.user_input([new], ChooseOptionInputlet(self, (False, True))):
55 g.process_action(lc)
57 return arg
60class FreakingPower(Skill):
61 associated_action = None
62 skill_category = ['character', 'passive']
63 target = t_None()
66class FreakingPowerAction(FatetellAction):
67 def __init__(self, atkact):
68 self.atkact = atkact
69 self.source = atkact.source
70 self.target = atkact.target
71 self.fatetell_target = atkact.source
73 def fatetell_action(self, ft):
74 act = self.atkact
75 if ft.succeeded:
76 act.__class__ = classmix(InevitableAttack, act.__class__)
77 else:
78 act._['freaking_power'] = True
80 return True
82 @staticmethod
83 def fatetell_cond(c):
84 return c.color == Card.RED
87class FreakingPowerHandler(THBEventHandler):
88 interested = ['action_after', 'action_before']
89 execute_before = ['AyaRoundfanHandler']
91 def handle(self, evt_type, act):
92 if evt_type == 'action_before' and isinstance(act, BaseAttack) and not act._['freaking_power']:
93 src = act.source
94 g = self.game
95 if not src.has_skill(FreakingPower): return act
96 if not g.user_input([src], ChooseOptionInputlet(self, (False, True))):
97 return act
98 tgt = act.target
99 g.process_action(FreakingPowerAction(act))
101 elif evt_type == 'action_after' and isinstance(act, Damage):
102 g = self.game
104 if act.cancelled: return act
106 pact = cast(THBAction, g.action_stack[-1])
107 if not pact._['freaking_power']:
108 return act
110 src, tgt = pact.source, act.target
111 if tgt.dead: return act
113 if not (tgt.cards or tgt.showncards or tgt.equips):
114 return act
116 catnames = ('cards', 'showncards', 'equips')
117 card = g.user_input([src], ChoosePeerCardInputlet(self, tgt, catnames))
118 card = card or random_choose_card(g, [tgt.cards, tgt.showncards, tgt.equips])
119 if card:
120 g.players.exclude(tgt).reveal(card)
121 g.process_action(DropCards(src, tgt, [card]))
123 return act
126@register_character_to('common', '-kof')
127class Yugi(Character):
128 skills = [Assault, FreakingPower]
129 eventhandlers = [FreakingPowerHandler]
130 maxlife = 4
133@register_character_to('kof')
134class YugiKOF(Character):
135 skills = [AssaultKOF, FreakingPower]
136 eventhandlers = [AssaultKOFHandler, FreakingPowerHandler]
137 maxlife = 4