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 thb.actions import ActionLimitExceeded, ActionStageLaunchCard, Damage, DropCards, GenericAction 

8from thb.actions import PlayerTurn, PrepareStage, ttags, user_choose_cards 

9from thb.cards.base import DummyCard, Skill, VirtualCard, t_None 

10from thb.cards.classes import InstantSpellCardAction, Reject, SpellCardAction, TreatAs 

11from thb.characters.base import Character, register_character_to 

12from thb.inputlets import ChooseOptionInputlet, ProphetInputlet 

13from thb.mode import THBEventHandler 

14 

15 

16# -- code -- 

17class Prophet(Skill): 

18 associated_action = None 

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

20 target = t_None() 

21 

22 

23class ExtremeIntelligence(Skill): 

24 associated_action = None 

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

26 target = t_None() 

27 

28 

29class ProphetAction(GenericAction): 

30 def apply_action(self): 

31 tgt = self.target 

32 g = self.game 

33 n = min(len([p for p in g.players if not p.dead]), 5) 

34 cards = g.deck.getcards(n) 

35 

36 assert cards == g.deck.getcards(n) 

37 

38 tgt.reveal(cards) 

39 

40 upcards, downcards = g.user_input([tgt], ProphetInputlet(self, cards), timeout=45) or [list(range(n)), []] 

41 

42 deck = g.deck.cards 

43 for i, c in enumerate(downcards): 43 ↛ 44line 43 didn't jump to line 44, because the loop on line 43 never started

44 deck[i] = c 

45 deck.rotate(-len(downcards)) 

46 

47 for i, c in enumerate(upcards): 

48 deck[i] = c 

49 

50 assert g.deck.getcards(len(upcards)) == upcards 

51 

52 return True 

53 

54 

55class ProphetHandler(THBEventHandler): 

56 interested = ['action_apply'] 

57 

58 def handle(self, evt_type, act): 

59 if evt_type == 'action_apply' and isinstance(act, PrepareStage): 

60 tgt = act.target 

61 if not tgt.has_skill(Prophet): return act 

62 g = self.game 

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

64 return act 

65 

66 g.process_action(ProphetAction(tgt, tgt)) 

67 

68 return act 

69 

70 

71class ExtremeIntelligenceAction(GenericAction): 

72 card_usage = 'drop' 

73 

74 def __init__(self, source, target, act): 

75 self.source, self.target, self.action = \ 

76 source, act.target, act 

77 

78 def activate_action(self): 

79 p = self.source 

80 self.cards = cards = user_choose_cards(self, p, ('cards', 'showncards', 'equips')) 

81 if not cards: return False 

82 p.tags['ran_ei'] = p.tags['turn_count'] + 1 

83 return True 

84 

85 def apply_action(self): 

86 p = self.source 

87 cards = self.cards 

88 g = self.game 

89 g.process_action(DropCards(p, p, cards)) 

90 

91 act = self.action 

92 nact = act.__class__(source=p, target=act.target) 

93 try: 

94 nact.target_list = act.target_list 

95 except AttributeError: 

96 pass 

97 

98 try: 

99 # HACK: This is for actions triggered by ForEach action. 

100 # Well, actually it's for Harvest since only this 

101 # uses the attrib 

102 nact.parent_action = act.parent_action 

103 except AttributeError: 

104 pass 

105 

106 try: 

107 nact.associated_card = act.associated_card 

108 except AttributeError: 

109 pass 

110 

111 g.process_action(nact) 

112 return True 

113 

114 def cond(self, cl): 

115 return len(cl) == 1 and not cl[0].is_card(Skill) 

116 

117 

118class ExtremeIntelligenceHandler(THBEventHandler): 

119 interested = ['action_after', 'game_begin'] 

120 

121 def handle(self, evt_type, act): 

122 if evt_type == 'action_after' and isinstance(act, InstantSpellCardAction): 

123 if isinstance(act, Reject): return act 

124 g = self.game 

125 

126 tgt = PlayerTurn.get_current(g).target 

127 for p in g.players.exclude(tgt): 

128 if p.dead: 

129 continue 

130 

131 if not p.has_skill(ExtremeIntelligence): 

132 continue 

133 

134 if p.tags['ran_ei'] >= p.tags['turn_count'] + 1: 

135 continue 

136 

137 try: 

138 tl = act.target_list 

139 except AttributeError: 

140 tl = [act.target] 

141 

142 if any(t.dead for t in tl): 

143 return act 

144 

145 if not act.can_fire(): 

146 return act # act cannot fire again 

147 

148 nact = ExtremeIntelligenceAction(p, act.target, act) 

149 

150 if nact.activate_action(): 

151 g.process_action(nact) 

152 

153 elif evt_type == 'game_begin': 

154 g = self.game 

155 for p in g.players: 

156 if isinstance(p, Ran): 

157 p.tags['ran_ei'] = 0 # for ui 

158 

159 return act 

160 

161 

162class ExtremeIntelligenceKOF(TreatAs, Skill): 

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

164 

165 def __init__(self, player): 

166 Skill.__init__(self, player) 

167 self.treat_as = ttags(player).get('ran_eikof_card') or DummyCard 

168 

169 def check(self): 

170 cards = self.associated_cards 

171 if len(cards) != 1: return False 

172 c = cards[0] 

173 if c.resides_in is None: return False 173 ↛ exitline 173 didn't return from function 'check', because the return on line 173 wasn't executed

174 if c.resides_in.type not in ('cards', 'showncards'): return False 

175 return True 

176 

177 

178class ExtremeIntelligenceKOFHandler(THBEventHandler): 

179 interested = ['action_apply', 'action_shootdown'] 

180 

181 def handle(self, evt_type, act): 

182 if evt_type == 'action_apply' and isinstance(act, ActionStageLaunchCard): 

183 if not act.card.is_card(VirtualCard): 

184 src = act.source 

185 if not src.has_skill(ExtremeIntelligenceKOF): return act 

186 c = act.card 

187 if 'instant_spellcard' not in c.category: return act 

188 ttags(src)['ran_eikof_card'] = c.__class__ 

189 

190 elif act.card.is_card(ExtremeIntelligenceKOF): 

191 src = act.source 

192 ttags(src)['ran_eikof_tag'] = True 

193 

194 elif evt_type == 'action_shootdown' and isinstance(act, ActionStageLaunchCard) and act.card.is_card(ExtremeIntelligenceKOF): 

195 src = act.source 

196 tt = ttags(src) 

197 if tt['ran_eikof_tag'] or not tt['ran_eikof_card']: 

198 raise ActionLimitExceeded 

199 

200 return act 

201 

202 

203class NakedFox(Skill): 

204 associated_action = None 

205 skill_category = ['character', 'passive', 'compulsory'] 

206 target = t_None() 

207 

208 

209class NakedFoxAction(GenericAction): 

210 def __init__(self, dmg): 

211 self.source = self.target = dmg.target 

212 self.dmgact = dmg 

213 self.dmgamount = dmg.amount # for UI 

214 

215 def apply_action(self): 

216 self.dmgact.amount -= 1 

217 return True 

218 

219 

220class NakedFoxHandler(THBEventHandler): 

221 interested = ['action_before'] 

222 

223 def handle(self, evt_type, act): 

224 if evt_type == 'action_before' and isinstance(act, Damage): 

225 g = self.game 

226 tgt = act.target 

227 if not tgt.has_skill(NakedFox): return act 

228 pact = g.action_stack[-1] 

229 if not isinstance(pact, SpellCardAction): return act 

230 if tgt.cards or tgt.showncards: return act 

231 if act.amount < 1: return act 231 ↛ exitline 231 didn't return from function 'handle', because the return on line 231 wasn't executed

232 

233 g.process_action(NakedFoxAction(act)) 

234 return act 

235 

236 return act 

237 

238 

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

240class Ran(Character): 

241 skills = [Prophet, ExtremeIntelligence, NakedFox] 

242 eventhandlers = [ 

243 ProphetHandler, 

244 ExtremeIntelligenceHandler, 

245 NakedFoxHandler, 

246 ] 

247 maxlife = 3 

248 

249 

250@register_character_to('kof') 

251class RanKOF(Character): 

252 skills = [Prophet, ExtremeIntelligenceKOF, NakedFox] 

253 eventhandlers = [ 

254 ProphetHandler, 

255 ExtremeIntelligenceKOFHandler, 

256 NakedFoxHandler, 

257 ] 

258 maxlife = 3