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 

33 action = 'draw' 

34 if tgt.life < tgt.maxlife: 

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

36 

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)) 

44 

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

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

47 

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) 

50 

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) 

53 

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

55 return True 

56 

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'] 

60 

61 

62class SkySilk(Skill): 

63 associated_action = SkySilkAction 

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

65 target = t_One() 

66 usage = 'drop' 

67 

68 def check(self): 

69 cl = self.associated_cards 

70 return bool(not cl) 

71 

72 

73class LunaStringPlaceCard(GenericAction): 

74 def __init__(self, target, card): 

75 self.source = self.target = target 

76 self.card = card 

77 

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 

90 

91 

92class LunaStringLaunchCardHandler(EventHandler): 

93 interested = ('action_before',) 

94 execute_before = ('SolidShieldHandler',) 

95 

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 

100 

101 c = act.card 

102 

103 def walk(c): 

104 if c.is_card(LunaString): 

105 return c 

106 

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

108 return None 

109 

110 assert isinstance(c, VirtualCard) 

111 

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 

116 

117 return None 

118 

119 c = walk(c) 

120 

121 if c: 

122 g = self.game 

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

124 

125 return act 

126 

127 

128class LunaString(TreatAs, Skill): 

129 treat_as = AttackCard 

130 

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

132 no_reveal = True 

133 use_action = LunaStringPlaceCard # UseCard hook 

134 

135 color = Card.NOTSET 

136 suit = Card.NOTSET 

137 number = 0 

138 

139 cost_detached = False 

140 

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 

144 

145 cl = self.associated_cards 

146 if not len(cl) == 1: 

147 return False 

148 

149 c = cl[0] 

150 

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 

153 

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

155 

156 

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

158class Eirin(Character): 

159 skills = [SkySilk, LunaString] 

160 eventhandlers = [LunaStringLaunchCardHandler] 

161 maxlife = 3