Hide keyboard shortcuts

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 

3 

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 

15 

16 

17# -- code -- 

18class EirinHeal(Heal): 

19 pass 

20 

21 

22class SkySilkAction(UserAction): 

23 def apply_action(self): 

24 src, tgt = self.source, self.target 

25 g = self.game 

26 

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) 

30 

31 g.process_action(DropCards(src, tgt, [c])) 

32 if tgt.dead: return False 

33 

34 action = 'draw' 

35 if tgt.life < tgt.maxlife: 

36 action = g.user_input([tgt], ChooseOptionInputlet(self, ('heal', 'draw'))) or 'draw' 

37 

38 if action == 'heal': 

39 g.process_action(EirinHeal(src, tgt)) 

40 else: 

41 g.deck.getcards(3) 

42 g.deck.cards.rotate(3) 

43 cl = g.deck.getcards(3) 

44 g.process_action(ShowCards(tgt, cl)) 

45 

46 drop = [c for c in cl if 'basic' in c.category] 

47 get = [c for c in cl if c not in drop] 

48 

49 if get: 

50 migrate_cards(get, tgt.cards) 

51 

52 if drop: 

53 migrate_cards(drop, g.deck.droppedcards) 

54 

55 ttags(src)['sky_silk'] = True 

56 return True 

57 

58 def is_valid(self): 

59 src, tgt = self.source, self.target 

60 return (tgt.cards or tgt.showncards or tgt.equips) and not ttags(src)['sky_silk'] 

61 

62 

63class SkySilk(Skill): 

64 associated_action = SkySilkAction 

65 skill_category = ('character', 'active') 

66 target = t_One() 

67 usage = 'drop' 

68 

69 def check(self): 

70 cl = self.associated_cards 

71 return bool(not cl) 

72 

73 

74class LunaStringPlaceCard(GenericAction): 

75 def __init__(self, target, card): 

76 self.source = self.target = target 

77 self.card = card 

78 

79 def apply_action(self): 

80 g = self.game 

81 tgt = self.target 

82 direction = g.user_input([tgt], ChooseOptionInputlet(self, ('front', 'back'))) 

83 sk = self.card 

84 assert sk.is_card(LunaString) 

85 c = sk.associated_cards[0] 

86 sk.associated_cards[:] = [] 

87 sk.cost_detached = True 

88 self.direction = direction # for ui 

89 migrate_cards([c], g.deck.cards, unwrap=True, direction=direction) 

90 return True 

91 

92 

93class LunaStringLaunchCardHandler(EventHandler): 

94 interested = ('action_before',) 

95 execute_before = ('SolidShieldHandler',) 

96 

97 def handle(self, evt_type, act): 

98 if evt_type == 'action_before': 98 ↛ 126line 98 didn't jump to line 126, because the condition on line 98 was never false

99 if not isinstance(act, LaunchCard): 

100 return act 

101 

102 c = act.card 

103 

104 def walk(c): 

105 if c.is_card(LunaString): 

106 return c 

107 

108 if c.is_card(PhysicalCard) or c.is_card(HiddenCard): 

109 return None 

110 

111 assert isinstance(c, VirtualCard) 

112 

113 for c1 in c.associated_cards: 

114 r = walk(c1) 

115 if r: 115 ↛ 116line 115 didn't jump to line 116, because the condition on line 115 was never true

116 return r 

117 

118 return None 

119 

120 c = walk(c) 

121 

122 if c: 

123 g = self.game 

124 g.process_action(LunaStringPlaceCard(c.character, c)) 

125 

126 return act 

127 

128 

129class LunaString(TreatAs, Skill): 

130 treat_as = AttackCard 

131 

132 skill_category = ('character', 'active') 

133 no_reveal = True 

134 use_action = LunaStringPlaceCard # UseCard hook 

135 

136 color = Card.NOTSET 

137 suit = Card.NOTSET 

138 number = 0 

139 

140 cost_detached = False 

141 

142 def check(self): 

143 if self.cost_detached: 143 ↛ 144line 143 didn't jump to line 144, because the condition on line 143 was never true

144 return True 

145 

146 cl = self.associated_cards 

147 if not len(cl) == 1: 

148 return False 

149 

150 c = cl[0] 

151 

152 if not (c.is_card(PhysicalCard) or c.is_card(HiddenCard)): # HiddenCard for other viewpoints 152 ↛ 153line 152 didn't jump to line 153, because the condition on line 152 was never true

153 return False 

154 

155 return c.resides_in.type in ('cards', 'showncards') 

156 

157 

158@register_character_to('common', '-kof') 

159class Eirin(Character): 

160 skills = [SkySilk, LunaString] 

161 eventhandlers = [LunaStringLaunchCardHandler] 

162 maxlife = 3