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

2 

3# -- stdlib -- 

4# -- third party -- 

5# -- own -- 

6from thb.actions import Damage, DrawCards, DropCards, GenericAction, LaunchCard, MaxLifeChange 

7from thb.actions import PlayerTurn, UserAction, migrate_cards, random_choose_card 

8from thb.cards.base import Skill 

9from thb.cards.classes import t_None, t_OtherOne 

10from thb.characters.base import Character, register_character_to 

11from thb.inputlets import ChooseOptionInputlet, ChoosePeerCardInputlet 

12from thb.mode import THBEventHandler 

13 

14 

15# -- code -- 

16class RiversideAction(UserAction): 

17 def apply_action(self): 

18 g = self.game 

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

20 src.tags['riverside_tag'] = src.tags['turn_count'] 

21 tgt.tags['riverside_target'] = g.turn_count 

22 minhp = min([p.life for p in g.players if not p.dead]) 

23 if tgt.life == minhp: 

24 has_card = tgt.cards or tgt.showncards or tgt.equips 

25 if has_card and g.user_input([src], ChooseOptionInputlet(self, ('drop', 'draw'))) == 'drop': 

26 self.action = 'drop' 

27 catnames = ('cards', 'showncards', 'equips') 

28 card = g.user_input([src], ChoosePeerCardInputlet(self, tgt, catnames)) 

29 card = card or random_choose_card(g, [tgt.cards, tgt.showncards, tgt.equips]) 

30 g.players.reveal(card) 

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

32 else: 

33 self.action = 'draw' 

34 g.process_action(DrawCards(src, 1)) 

35 

36 return True 

37 

38 def is_valid(self): 

39 src = self.source 

40 # Fire with Exinwan -> dead -> skills cleared -> assertion fail 

41 # assert src.has_skill(Riverside) 

42 return not src.tags['riverside_tag'] >= src.tags['turn_count'] 

43 

44 

45class RiversideHandler(THBEventHandler): 

46 interested = ['calcdistance'] 

47 

48 def handle(self, evt_type, arg): 

49 if evt_type == 'calcdistance': 49 ↛ 59line 49 didn't jump to line 59, because the condition on line 49 was never false

50 src, card, dist = arg 

51 if not src.has_skill(Riverside): 

52 return arg 

53 

54 turn_count = self.game.turn_count 

55 for p in dist: 

56 if p.tags.get('riverside_target') == turn_count: 

57 dist[p] -= 10000 

58 

59 return arg 

60 

61 

62class Riverside(Skill): 

63 associated_action = RiversideAction 

64 skill_category = ['character', 'active'] 

65 target = t_OtherOne() 

66 usage = 'drop' 

67 

68 def check(self): 

69 cl = self.associated_cards 

70 if len(cl) != 1: return False 

71 return cl[0].resides_in.type in ('cards', 'showncards', 'equips') 

72 

73 

74class ReturningAwake(GenericAction): 

75 def apply_action(self): 

76 g = self.game 

77 tgt = self.target 

78 tgt.skills.remove(Returning) 

79 tgt.skills.append(FerryFee) 

80 g.process_action(MaxLifeChange(tgt, tgt, -1)) 

81 

82 return True 

83 

84 

85class ReturningHandler(THBEventHandler): 

86 interested = ['action_before'] 

87 

88 def handle(self, evt_type, act): 

89 if evt_type == 'action_before' and isinstance(act, PlayerTurn): 

90 tgt = act.target 

91 if not tgt.has_skill(Returning): return act 

92 g = self.game 

93 ncards = len(tgt.cards) + len(tgt.showncards) 

94 if tgt.life <= 2 and tgt.life < ncards: 

95 g.process_action(ReturningAwake(tgt, tgt)) 

96 

97 return act 

98 

99 

100class Returning(Skill): 

101 associated_action = None 

102 skill_category = ['character', 'passive', 'awake'] 

103 target = t_None() 

104 

105 

106class FerryFee(Skill): 

107 associated_action = None 

108 skill_category = ['character', 'passive'] 

109 target = t_None() 

110 distance = 1 

111 

112 

113class FerryFeeEffect(UserAction): 

114 def __init__(self, source, target, card): 

115 self.source = source 

116 self.target = target 

117 self.card = card 

118 

119 def apply_action(self): 

120 src = self.source 

121 card = self.card 

122 src.reveal(card) 

123 migrate_cards([card], src.cards, unwrap=True) 

124 return True 

125 

126 

127class FerryFeeHandler(THBEventHandler): 

128 interested = ['action_after'] 

129 

130 def handle(self, evt_type, act): 

131 if evt_type == 'action_after' and isinstance(act, Damage): 

132 src = act.source 

133 tgt = act.target 

134 if not (src and src.has_skill(FerryFee)): return act 

135 if not (tgt.cards or tgt.showncards or tgt.equips): return act 

136 g = self.game 

137 dist = LaunchCard.calc_distance(g, src, FerryFee(src)) 

138 if not dist.get(tgt, 10000) <= 0: return act 

139 if g.user_input([src], ChooseOptionInputlet(self, (False, True))): 

140 g = self.game 

141 catnames = ('cards', 'showncards', 'equips') 

142 card = g.user_input([src], ChoosePeerCardInputlet(self, tgt, catnames)) 

143 card = card or random_choose_card(g, [tgt.cards, tgt.showncards, tgt.equips]) 

144 if not card: return act 144 ↛ exitline 144 didn't return from function 'handle', because the return on line 144 wasn't executed

145 g.process_action(FerryFeeEffect(src, tgt, card)) 

146 

147 return act 

148 

149 

150@register_character_to('common') 

151class Komachi(Character): 

152 skills = [Riverside, Returning] 

153 eventhandlers = [RiversideHandler, ReturningHandler, FerryFeeHandler] 

154 maxlife = 4