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 game.base import ActionShootdown 

7from thb.actions import ActionStageLaunchCard, Damage, LaunchCard, PlayerTurn, UserAction 

8from thb.cards.base import Skill 

9from thb.cards.classes import AttackCard, DuelCard, Heal, HealCard, PhysicalCard, t_None 

10from thb.characters.base import Character, register_character_to 

11from thb.inputlets import ChooseOptionInputlet 

12from thb.mode import THBEventHandler 

13 

14 

15# -- code -- 

16class Lunatic(Skill): 

17 associated_action = None 

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

19 target = t_None() 

20 

21 

22class Discarder(Skill): 

23 associated_action = None 

24 distance = 1 

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

26 target = t_None() 

27 

28 

29class MahjongDrug(Skill): 

30 associated_action = None 

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

32 target = t_None() 

33 

34 

35class LunaticAction(UserAction): 

36 def apply_action(self): 

37 self.target.skills.append(Discarder) 

38 self.target.tags['reisen_discarder'] = True # for tag 

39 return True 

40 

41 

42class LunaticHandler(THBEventHandler): 

43 interested = ['action_after'] 

44 

45 def handle(self, evt_type, act): 

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

47 src = act.source 

48 if not src: return act 

49 if not src.has_skill(Lunatic): return act 

50 

51 tgt = act.target 

52 if tgt.dead or tgt.has_skill(Discarder): return act 

53 

54 g = self.game 

55 for lc in reversed(g.action_stack): 55 ↛ 59line 55 didn't jump to line 59, because the loop on line 55 didn't complete

56 if isinstance(lc, LaunchCard): 

57 break 

58 else: 

59 return act 

60 

61 c = lc.card 

62 if not (c.is_card(AttackCard) or c.is_card(DuelCard)): 

63 return act 

64 

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

66 g.process_action(LunaticAction(src, tgt)) 

67 

68 return act 

69 

70 

71class DiscarderAttackOnly(ActionShootdown): 

72 pass 

73 

74 

75class DiscarderDistanceLimit(ActionShootdown): 

76 pass 

77 

78 

79class DiscarderHandler(THBEventHandler): 

80 interested = ['action_after', 'action_shootdown'] 

81 

82 def handle(self, evt_type, act): 

83 if evt_type == 'action_shootdown' and isinstance(act, ActionStageLaunchCard): 

84 src = act.source 

85 if not src.has_skill(Discarder): return act 

86 g = self.game 

87 current = PlayerTurn.get_current(g).target 

88 if src is not current: return act 88 ↛ exitline 88 didn't return from function 'handle', because the return on line 88 wasn't executed

89 

90 self.card = c = act.card 

91 if not c.is_card(AttackCard): 

92 if c.is_card(PhysicalCard) or 'treat_as' in c.category: 

93 raise DiscarderAttackOnly 

94 else: 

95 return act 

96 

97 dist = LaunchCard.calc_distance(g, src, Discarder(src)) 

98 dist.pop(src, '') 

99 nearest = max(min(dist.values()), 0) 

100 avail = {p for p in dist if dist[p] <= nearest} 

101 

102 if not set(act.target_list) <= avail: 

103 raise DiscarderDistanceLimit 

104 

105 elif evt_type == 'action_after' and isinstance(act, PlayerTurn): 

106 tgt = act.target 

107 if tgt.has_skill(Discarder): 

108 tgt.skills.remove(Discarder) 

109 tgt.tags['reisen_discarder'] = False # for tag 

110 

111 return act 

112 

113 

114class MahjongDrugAction(UserAction): 

115 def apply_action(self): 

116 self.target.tags['wine'] = True 

117 return True 

118 

119 def is_valid(self): 

120 return not self.target.dead 

121 

122 

123class MahjongDrugHandler(THBEventHandler): 

124 interested = ['action_after'] 

125 

126 def handle(self, evt_type, act): 

127 if evt_type == 'action_after' and isinstance(act, Heal): 

128 tgt = act.target 

129 if not tgt.has_skill(MahjongDrug): return act 

130 card = getattr(act, 'associated_card', None) 

131 if not card or not card.is_card(HealCard): return act 

132 

133 g = self.game 

134 if g.user_input([tgt], ChooseOptionInputlet(self, (False, True))): 

135 g.process_action(MahjongDrugAction(tgt, tgt)) 

136 

137 return act 

138 

139 

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

141class Reisen(Character): 

142 skills = [Lunatic, MahjongDrug] 

143 eventhandlers = [DiscarderHandler, LunaticHandler, MahjongDrugHandler] 

144 maxlife = 4 

145 

146 

147@register_character_to('kof') 

148class ReisenKOF(Character): 

149 skills = [Lunatic] 

150 eventhandlers = [DiscarderHandler, LunaticHandler] 

151 maxlife = 4