Coverage for thb/characters/nitori.py : 89%
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 --
5# -- third party --
6# -- own --
7from thb.actions import ActionLimitExceeded, DrawCards, LaunchCard, PlayerTurn, Reforge, UserAction
8from thb.actions import random_choose_card, ttags
9from thb.cards.base import PhysicalCard, Skill, TreatAs, t_OtherOne
10from thb.cards.definition import AttackCard
11from thb.characters.base import Character, register_character_to
12from thb.inputlets import ChoosePeerCardInputlet
13from thb.mode import THBEventHandler
16# -- code --
17class DismantleAction(UserAction):
18 def apply_action(self):
19 src, tgt = self.source, self.target
20 ttags(src)['dismantle'] = True
22 g = self.game
23 c = g.user_input([src], ChoosePeerCardInputlet(self, tgt, ('equips', )))
24 c = c or random_choose_card(g, [tgt.equips])
25 if not c: return False 25 ↛ exitline 25 didn't return from function 'apply_action', because the return on line 25 wasn't executed
27 g.process_action(Reforge(src, tgt, c))
28 g.process_action(DrawCards(tgt, 1))
30 return True
32 def is_valid(self):
33 return not ttags(self.source)['dismantle'] and bool(self.target.equips)
36class Dismantle(Skill):
37 associated_action = DismantleAction
38 skill_category = ['character', 'active']
39 target = t_OtherOne()
41 def check(self):
42 return not self.associated_cards
45class Craftsman(TreatAs, Skill):
46 skill_category = ['character', 'active']
48 @property
49 def treat_as(self):
50 params = getattr(self, 'action_params', {})
51 return PhysicalCard.classes.get(params.get('treat_as'), AttackCard)
53 def check(self):
54 cl = self.associated_cards
55 p = self.character
57 if 'basic' not in self.treat_as.category: 57 ↛ 58line 57 didn't jump to line 58, because the condition on line 57 was never true
58 return False
60 if not cl or set(cl) != (set(p.cards) | set(p.showncards)):
61 return False
63 return True
65 @classmethod
66 def list_treat_as(cls):
67 return [c() for c in PhysicalCard.classes.values() if 'basic' in c.category]
70class CraftsmanHandler(THBEventHandler):
71 interested = ['action_after', 'action_shootdown']
73 def handle(self, evt_type, act):
74 if evt_type == 'action_after' and isinstance(act, LaunchCard):
75 c = act.card
76 if c.is_card(Craftsman):
77 src = act.source
78 ttags(src)['craftsman'] = True
80 elif evt_type == 'action_shootdown':
81 if not isinstance(act, LaunchCard): return act
82 c = act.card
83 if not c.is_card(Craftsman): return act
84 g = self.game
85 try:
86 current = PlayerTurn.get_current(g).target
87 except IndexError:
88 return act
90 if ttags(act.source)['craftsman'] and current is act.source: 90 ↛ 91line 90 didn't jump to line 91, because the condition on line 90 was never true
91 raise ActionLimitExceeded
93 return act
96@register_character_to('common', '-kof')
97class Nitori(Character):
98 skills = [Dismantle, Craftsman]
99 eventhandlers = [CraftsmanHandler]
100 maxlife = 3