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 DropCards, GenericAction, MaxLifeChange, PlayerTurn, random_choose_card 

7from thb.cards.base import DummyCard, Skill, t_None 

8from thb.cards.classes import AttackCard, BaseAttack, GrazeCard, LaunchGraze, TreatAs 

9from thb.characters.base import Character, register_character_to 

10from thb.inputlets import ChooseOptionInputlet, ChoosePeerCardInputlet 

11from thb.mode import THBEventHandler 

12 

13 

14# -- code -- 

15class LoongPunch(Skill): 

16 associated_action = None 

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

18 target = t_None() 

19 

20 

21class Taichi(TreatAs, Skill): 

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

23 

24 @property 

25 def treat_as(self): 

26 cl = self.associated_cards 

27 if not cl: return DummyCard 

28 c = cl[0] 

29 if c.is_card(GrazeCard): 

30 return AttackCard 

31 if c.is_card(AttackCard): 

32 return GrazeCard 

33 return DummyCard 

34 

35 def check(self): 

36 cl = self.associated_cards 

37 if not cl or len(cl) != 1: return False 

38 c = cl[0] 

39 if not (c.is_card(AttackCard) or c.is_card(GrazeCard)): return False 39 ↛ exitline 39 didn't return from function 'check', because the return on line 39 wasn't executed

40 return c.resides_in is not None and c.resides_in.type in ( 

41 'cards', 'showncards', 

42 ) 

43 

44 

45class RiverBehind(Skill): 

46 associated_action = None 

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

48 target = t_None() 

49 

50 

51class LoongPunchAction(GenericAction): 

52 def __init__(self, source, target, _type): 

53 self.source = source 

54 self.target = target 

55 self.type = _type 

56 

57 def apply_action(self): 

58 g = self.game 

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

60 c = g.user_input([src], ChoosePeerCardInputlet(self, tgt, ('cards', 'showncards'))) 

61 c = c or random_choose_card(g, [tgt.cards, tgt.showncards]) 

62 if not c: return False 

63 g.players.exclude(tgt).reveal(c) 

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

65 return True 

66 

67 

68class LoongPunchHandler(THBEventHandler): 

69 interested = ['action_after'] 

70 execute_after = ['DeathSickleHandler'] 

71 

72 def handle(self, evt_type, act): 

73 if evt_type == 'action_after' and isinstance(act, LaunchGraze): 

74 if not act.succeeded: return act 

75 g = self.game 

76 pact = g.action_stack[-1] 

77 if not isinstance(pact, BaseAttack): return act 77 ↛ exitline 77 didn't return from function 'handle', because the return on line 77 wasn't executed

78 self.do_effect(pact.source, pact.target, 'attack') 

79 self.do_effect(pact.target, pact.source, 'graze') 

80 

81 return act 

82 

83 def do_effect(self, src, tgt, _type): 

84 if not src.has_skill(LoongPunch): return 

85 if not (tgt.cards or tgt.showncards): return 85 ↛ exitline 85 didn't return from function 'do_effect', because the return on line 85 wasn't executed

86 g = self.game 

87 if not g.user_input([src], ChooseOptionInputlet(self, (False, True))): return 87 ↛ 89line 87 didn't jump to line 89, because the condition on line 87 was never false

88 

89 g.process_action(LoongPunchAction(src, tgt, _type)) 

90 

91 

92class RiverBehindAwake(GenericAction): 

93 def apply_action(self): 

94 tgt = self.target 

95 assert tgt.has_skill(RiverBehind) 

96 tgt.skills.remove(RiverBehind) 

97 tgt.skills.append(Taichi) 

98 g = self.game 

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

100 return True 

101 

102 

103class RiverBehindHandler(THBEventHandler): 

104 interested = ['action_apply'] 

105 

106 def handle(self, evt_type, act): 

107 if evt_type == 'action_apply' and isinstance(act, PlayerTurn): 

108 tgt = act.target 

109 if not tgt.has_skill(RiverBehind): return act 

110 g = self.game 

111 if tgt.life <= 2 and tgt.life <= min(p.life for p in g.players if not p.dead): 

112 g.process_action(RiverBehindAwake(tgt, tgt)) 

113 return act 

114 

115 

116@register_character_to('common') 

117class Meirin(Character): 

118 skills = [LoongPunch, RiverBehind] 

119 eventhandlers = [RiverBehindHandler, LoongPunchHandler] 

120 maxlife = 4