Coverage for thb/characters/eirin.py : 92%
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 game.base import EventHandler
8from thb.actions import DropCards, GenericAction, LaunchCard, ShowCards, UserAction, migrate_cards
9from thb.actions import random_choose_card, ttags
10from thb.cards.base import Card, HiddenCard, PhysicalCard, Skill, TreatAs, VirtualCard, t_One
11from thb.cards.basic import Heal
12from thb.cards.definition import AttackCard
13from thb.characters.base import Character, register_character_to
14from thb.inputlets import ChooseOptionInputlet, ChoosePeerCardInputlet
17# -- code --
18class EirinHeal(Heal):
19 pass
22class SkySilkAction(UserAction):
23 def apply_action(self):
24 src, tgt = self.source, self.target
25 g = self.game
27 c = g.user_input([src], ChoosePeerCardInputlet(self, tgt, ['cards', 'showncards', 'equips']))
28 c = c or random_choose_card(g, [tgt.cards, tgt.showncards, tgt.equips])
29 g.players.reveal(c)
31 g.process_action(DropCards(src, tgt, [c]))
33 action = 'draw'
34 if tgt.life < tgt.maxlife:
35 action = g.user_input([tgt], ChooseOptionInputlet(self, ('heal', 'draw'))) or 'draw'
37 if action == 'heal': 37 ↛ 38line 37 didn't jump to line 38, because the condition on line 37 was never true
38 g.process_action(EirinHeal(src, tgt))
39 else:
40 g.deck.getcards(3)
41 g.deck.cards.rotate(3)
42 cl = g.deck.getcards(3)
43 g.process_action(ShowCards(tgt, cl))
45 drop = [c for c in cl if 'basic' in c.category]
46 get = [c for c in cl if c not in drop]
48 if get: 48 ↛ 51line 48 didn't jump to line 51, because the condition on line 48 was never false
49 migrate_cards(get, tgt.cards)
51 if drop: 51 ↛ 54line 51 didn't jump to line 54, because the condition on line 51 was never false
52 migrate_cards(drop, g.deck.droppedcards)
54 ttags(src)['sky_silk'] = True
55 return True
57 def is_valid(self):
58 src, tgt = self.source, self.target
59 return (tgt.cards or tgt.showncards or tgt.equips) and not ttags(src)['sky_silk']
62class SkySilk(Skill):
63 associated_action = SkySilkAction
64 skill_category = ('character', 'active')
65 target = t_One()
66 usage = 'drop'
68 def check(self):
69 cl = self.associated_cards
70 return bool(not cl)
73class LunaStringPlaceCard(GenericAction):
74 def __init__(self, target, card):
75 self.source = self.target = target
76 self.card = card
78 def apply_action(self):
79 g = self.game
80 tgt = self.target
81 direction = g.user_input([tgt], ChooseOptionInputlet(self, ('front', 'back')))
82 sk = self.card
83 assert sk.is_card(LunaString)
84 c = sk.associated_cards[0]
85 sk.associated_cards[:] = []
86 sk.cost_detached = True
87 self.direction = direction # for ui
88 migrate_cards([c], g.deck.cards, unwrap=True, direction=direction)
89 return True
92class LunaStringLaunchCardHandler(EventHandler):
93 interested = ('action_before',)
94 execute_before = ('SolidShieldHandler',)
96 def handle(self, evt_type, act):
97 if evt_type == 'action_before': 97 ↛ 125line 97 didn't jump to line 125, because the condition on line 97 was never false
98 if not isinstance(act, LaunchCard):
99 return act
101 c = act.card
103 def walk(c):
104 if c.is_card(LunaString):
105 return c
107 if c.is_card(PhysicalCard) or c.is_card(HiddenCard):
108 return None
110 assert isinstance(c, VirtualCard)
112 for c1 in c.associated_cards:
113 r = walk(c1)
114 if r: 114 ↛ 115line 114 didn't jump to line 115, because the condition on line 114 was never true
115 return r
117 return None
119 c = walk(c)
121 if c:
122 g = self.game
123 g.process_action(LunaStringPlaceCard(c.character, c))
125 return act
128class LunaString(TreatAs, Skill):
129 treat_as = AttackCard
131 skill_category = ('character', 'active')
132 no_reveal = True
133 use_action = LunaStringPlaceCard # UseCard hook
135 color = Card.NOTSET
136 suit = Card.NOTSET
137 number = 0
139 cost_detached = False
141 def check(self):
142 if self.cost_detached: 142 ↛ 143line 142 didn't jump to line 143, because the condition on line 142 was never true
143 return True
145 cl = self.associated_cards
146 if not len(cl) == 1:
147 return False
149 c = cl[0]
151 if not (c.is_card(PhysicalCard) or c.is_card(HiddenCard)): # HiddenCard for other viewpoints 151 ↛ 152line 151 didn't jump to line 152, because the condition on line 151 was never true
152 return False
154 return c.resides_in.type in ('cards', 'showncards')
157@register_character_to('common', '-kof')
158class Eirin(Character):
159 skills = [SkySilk, LunaString]
160 eventhandlers = [LunaStringLaunchCardHandler]
161 maxlife = 3