def handle(self, evt_type, act): if evt_type == 'action_after' and isinstance(act, Damage): src = act.source if not src: return act if not src.has_skill(IbukiGourdSkill): return act g = Game.getgame() ttags(src)['ibukigourd_did_damage'] = True elif evt_type == 'action_apply' and isinstance(act, FinalizeStage): tgt = act.target if not tgt.has_skill(IbukiGourdSkill): return act g = Game.getgame() if ttags(tgt)['ibukigourd_did_damage']: return act g.process_action(basic.Wine(tgt, tgt)) elif evt_type == 'card_migration': from .definition import IbukiGourdCard act, cl, _from, to, _ = arg = act if not any(c.is_card(IbukiGourdCard) for c in cl): return arg if to.type != 'equips': return arg tgt = to.owner g = Game.getgame() g.process_action(basic.Wine(tgt, tgt)) return arg return act
def sound_effect(act): tgt = act.target if ttags(tgt)['__icewing_se']: return None ttags(tgt)['__icewing_se'] = True return 'thb-cv-card_icewing'
def handle(self, evt_type, act): if evt_type == 'action_after' and isinstance(act, Damage): src = act.source if not src: return act if not src.has_skill(DestructionImpulse): return act g = Game.getgame() ttags(src)['destruction_tag'] = True elif evt_type == 'action_after' and isinstance(act, PlayerTurn): tgt = act.target if not tgt.has_skill(DestructionImpulse): return act g = Game.getgame() if ttags(tgt)['destruction_tag']: return act dist = LaunchCard.calc_distance(tgt, DestructionImpulse(tgt)) dist.pop(tgt, '') for k in dist: dist[k] = max(dist[k], 0) nearest = min(dist.values()) candidates = [p for p, d in dist.items() if d == nearest] candidates = [p for p in g.players if p in candidates] # order matters if len(candidates) > 1: pl = user_choose_players(self, tgt, candidates) p = pl[0] if pl else candidates[0] else: p = candidates[0] g.process_action(DestructionImpulseAction(tgt, p)) return act
def clickable(game): me = game.me if not (my_turn() and (me.cards or me.showncards)): return False if ttags(me)["ran_eikof_tag"]: return False if not ttags(me)["ran_eikof_card"]: return False return True
def handle(self, evt_type, act): if evt_type == 'action_after' and isinstance(act, ActionStageLaunchCard): c = act.card if c.is_card(Craftsman): src = act.source ttags(src)['craftsman'] = True elif evt_type == 'action_shootdown': if not isinstance(act, ActionStageLaunchCard): return act c = act.card if not c.is_card(Craftsman): return act if ttags(act.source)['craftsman']: raise ActionLimitExceeded return act
def apply_action(self): tgt = self.target g = Game.getgame() g.process_action(DrawCards(tgt, 1)) ttags(tgt)['miracle_times'] += 1 if ttags(tgt)['miracle_times'] == 3: candidates = [p for p in g.players if not p.dead and p.life < p.maxlife] if candidates: beneficiery, = user_choose_players(self, tgt, candidates) or (None,) if beneficiery: g.process_action(MiracleHeal(tgt, beneficiery)) return True
def is_valid(self): tgt = self.target g = Game.getgame() cl = self.associated_card.associated_cards n = len([p for p in g.players if not p.dead]) / 2 if not 0 < len(cl) <= n: return False return not ttags(tgt)['qiliao']
def clickable(game): me = game.me if ttags(me)['bakadesu']: return False return my_turn()
def handle(self, evt_type, act): if evt_type == 'action_before' and hasattr(act, 'associated_card'): g = Game.getgame() lc = g.action_stack[-1] for lc in reversed(g.action_stack): if isinstance(lc, (LaunchCard, LaunchFatetellCard)) and lc.card_action is act: break else: return act me = g.current_player if not me or not me.has_skill(Tianyi): return act while True: if isinstance(act, SpellCardAction): break if isinstance(act, ForEach) and issubclass(act.action_cls, SpellCardAction): break # Another HACK return act if ttags(me)['mima_tianyi']: return act if not user_input([me], ChooseOptionInputlet(self, (False, True))): return act g.process_action(TianyiAction(me, lc)) return act
def is_action_valid(g, cl, tl): cards = cl[0].associated_cards expected = ttags(g.me)['miracle_times'] + 1 if len(cards) != expected: return (False, u'奇迹:请选择%d张牌!' % expected) return (True, u'奇迹是存在的!')
def clickable(g): if not my_turn(): return False if ttags(g.me)['qiliao']: return False return True
def sound_effect(act): if not isinstance(act, actions.ActionStageLaunchCard): return 'thb-cv-card_attack1' current = G().current_player if act.source is not current: return 'thb-cv-card_attack1' ttags(current)['__attack_graze_count'] += 1 return [ 'thb-cv-card_attack1', 'thb-cv-card_attack2', 'thb-cv-card_attack3', 'thb-cv-card_attack4', ][ttags(current)['__attack_graze_count'] % 4 - 1]
def clickable(game): me = game.me if not my_turn(): return False if ttags(me)['assisted_attack_disable']: return False return True
def clickable(game): me = game.me if ttags(me)['find']: return False if my_turn() and (me.cards or me.showncards or me.equips): return True return False
def apply_action(self): g = Game.getgame() cards = self.associated_card.associated_cards n = len(cards) # card will be dropped at LaunchCard # g.process_action(DropCards(tgt, tgt, cards)) tgt = self.target g.process_action(DrawCards(tgt, n)) ttags(tgt)['find'] = True return True
def handle(self, evt_type, act): if evt_type == 'action_apply' and isinstance(act, ActionStageLaunchCard): if not act.card.is_card(VirtualCard): src = act.source if not src.has_skill(ExtremeIntelligenceKOF): return act c = act.card if 'instant_spellcard' not in c.category: return act ttags(src)['ran_eikof_card'] = c.__class__ elif act.card.is_card(ExtremeIntelligenceKOF): src = act.source ttags(src)['ran_eikof_tag'] = True elif evt_type == 'action_shootdown' and isinstance(act, ActionStageLaunchCard) and act.card.is_card(ExtremeIntelligenceKOF): src = act.source tt = ttags(src) if tt['ran_eikof_tag'] or not tt['ran_eikof_card']: raise ActionLimitExceeded return act
def clickable(g): try: me = g.me if not me.cards and not me.showncards: return False if ttags(me)['craftsman'] and g.current_player is me: return False return True except (IndexError, AttributeError): return False
def handle(self, evt_type, act): if evt_type == 'action_before' and isinstance(act, ActionStageLaunchCard): src, tgt = act.source, act.target if not src or not tgt: return act ttags(src)['solid_shield_launch_count'] += 1 if ttags(src)['solid_shield_launch_count'] != 1: return act if src is tgt: return act c = act.card if not (c.is_card(AttackCard) or 'instant_spellcard' in c.category): return act g = Game.getgame() for p in g.players.rotate_to(src): if p is src: continue if p is tgt: continue if not p.has_skill(SolidShield): continue dist = LaunchCard.calc_distance(p, SolidShield(p)) if dist[tgt] > 0: continue cond = c.is_card(AttackCard) or 'instant_spellcard' in c.category cond = cond and (c.is_card(DollControlCard) or len(act.target_list) == 1) # HACK HERE! if not cond: return act if user_input([p], ChooseOptionInputlet(self, (False, True))): g.process_action(SolidShieldAction(p, src, act)) break return act
def apply_action(self): src, tgt = self.source, self.target ttags(src)['dismantle'] = True g = Game.getgame() c = user_input([src], ChoosePeerCardInputlet(self, tgt, ('equips', ))) c = c or random_choose_card([tgt.equips]) if not c: return False g.process_action(Reforge(src, tgt, c)) g.process_action(DrawCards(tgt, 1)) return True
def apply_action(self): src, tgt = self.source, self.target g = Game.getgame() pl = [p for p in g.players if not p.dead and p is not src] p, rst = ask_for_action(self, pl, ('cards', 'showncards'), [], timeout=6) if not p: ttags(src)['assisted_attack_disable'] = True return False (c,), _ = rst g.process_action(ActionStageLaunchCard(src, [tgt], AssistedAttackCard.wrap([c], src))) return True
def handle(self, evt_type, act): if evt_type == 'action_apply' and isinstance(act, Damage): if not act.source: return act src, tgt = act.source, act.target g = Game.getgame() if src is not g.current_player: return act if src is tgt: return act ttags(src)['did_damage'] = True elif evt_type == 'action_after' and isinstance(act, Damage): if not act.source: return act src, tgt = act.source, act.target g = Game.getgame() cur = g.current_player if not cur: return act if not tgt.has_skill(ReimuExterminate): return act if cur.dead: return act if cur is tgt: return act g.process_action(ReimuExterminateAction(tgt, g.current_player, 'damage')) elif evt_type == 'action_apply' and isinstance(act, FinalizeStage): tgt = act.target if not ttags(tgt)['did_damage']: return act if tgt.dead: return act g = Game.getgame() for actor in g.players.rotate_to(g.current_player): if tgt is actor: continue if not actor.has_skill(ReimuExterminate): continue g.process_action(ReimuExterminateAction(actor, tgt, 'finalize')) return act
def handle(self, evt_type, act): if evt_type == 'action_before' and isinstance(act, FinalizeStage): tgt = act.target if not tgt.has_skill(KanakoFaithKOF): return act g = Game.getgame() op = g.get_opponent(tgt) if tgt.life > op.life or ttags(tgt)['kanako_faith_kof']: n = tgt.life - (len(tgt.cards) + len(tgt.showncards)) if n > 0: g.process_action(KanakoFaithKOFAction(tgt, n)) elif evt_type == 'action_apply' and isinstance(act, Damage): src, tgt = act.source, act.target g = Game.getgame() if src and src.has_skill(KanakoFaithKOF) and tgt is g.get_opponent(src): ttags(src)['kanako_faith_kof'] = True return act
def apply_action(self): src, tgt = self.source, self.target ttags(src)['bakadesu'] = True cl = user_choose_cards(self, tgt, ('cards', 'showncards')) g = Game.getgame() if cl: g.process_action(LaunchCard(tgt, [src], cl[0])) else: c = user_input([src], ChoosePeerCardInputlet(self, tgt, ('cards', 'showncards', 'equips'))) c = c or random_choose_card([tgt.cards, tgt.showncards, tgt.equips]) c and g.process_action(CirnoDropCards(src, tgt, [c])) return True
def is_valid(self): try: p = self.target if ttags(p)['find']: return False g = Game.getgame() cards = self.associated_card.associated_cards if not 0 < len(cards) <= len([i for i in g.players if not i.dead]): return False return True except AttributeError: # well, some cards are skill? return False
def apply_action(self): src = self.source tl = self.target_list g = Game.getgame() for p in tl: g.process_action(SanaeFaithCollectCardAction(src, p)) g.deck.shuffle(src.cards) for p in tl: g.process_action(SanaeFaithReturnCardAction(src, p)) ttags(src)['faith'] = True return True
def apply_action(self): tgt = self.target ttags(tgt)['qiliao'] = True g = Game.getgame() cl = getattr(tgt, 'meirin_qiliao', None) if cl is None: cl = CardList(tgt, 'meirin_qiliao') tgt.meirin_qiliao = cl tgt.showncardlists.append(cl) migrate_cards([self.associated_card], cl, unwrap=True) g.deck.shuffle(cl) return True
def apply_action(self): src, tgt = self.source, self.target ttags(src)['bakadesu'] = True cl = user_choose_cards(self, tgt, ('cards', 'showncards')) g = Game.getgame() if cl: g.process_action(LaunchCard(tgt, [src], cl[0])) else: c = user_input([src], ChoosePeerCardInputlet( self, tgt, ('cards', 'showncards', 'equips'))) c = c or random_choose_card( [tgt.cards, tgt.showncards, tgt.equips]) c and g.process_action(CirnoDropCards(src, tgt, [c])) return True
def apply_action(self): src, tgt = self.source, self.target g = Game.getgame() pl = [p for p in g.players if not p.dead and p is not src] p, rst = ask_for_action(self, pl, ('cards', 'showncards'), [], timeout=6) if not p: ttags(src)['assisted_attack_disable'] = True return False (c, ), _ = rst g.process_action( ActionStageLaunchCard(src, [tgt], AssistedAttackCard.wrap([c], src))) return True
def handle(self, evt_type, act): if evt_type == 'action_apply' and isinstance(act, FinalizeStage): g = Game.getgame() src = act.target if not src.has_skill(GuidedDeath) or src.dead: return act p = ttags(src)['guided_death_active_use'] if p: g.process_action(Heal(p, p, 1)) else: tl = [p for p in g.players.rotate_to(src) if p.life == 1 and p is not src] if not tl: return act g.process_action(GuidedDeathEffect(src, tl)) return act
def apply_action(self): src, tgt = self.source, self.target g = Game.getgame() c = user_input([src], ChoosePeerCardInputlet( self, tgt, ['cards', 'showncards', 'equips'])) c = c or random_choose_card([tgt.cards, tgt.showncards, tgt.equips]) g.players.reveal(c) g.process_action(DropCards(src, tgt, [c])) if tgt.dead: return False action = 'draw' if tgt.life < tgt.maxlife: action = user_input( [tgt], ChooseOptionInputlet(self, ('heal', 'draw'))) or 'draw' if action == 'heal': g.process_action(EirinHeal(src, tgt)) else: g.deck.getcards(3) g.deck.cards.rotate(3) cl = g.deck.getcards(3) g.process_action(ShowCards(tgt, cl)) drop = [c for c in cl if 'basic' in c.category] get = [c for c in cl if c not in drop] if get: migrate_cards(get, tgt.cards) if drop: migrate_cards(drop, g.deck.droppedcards) ttags(src)['sky_silk'] = True return True
def apply_action(self): src, lc = self.source, self.action assert isinstance(lc, (LaunchCard, LaunchFatetellCard)) lc.card_action.cancelled = True ttags(src)['mima_tianyi'] = True if isinstance(lc, LaunchCard): # HACK! RejectCard has no target, but not implemented this way. if lc.force_action and isinstance(lc.force_action, Reject): return True lst = lc.target_list[:] elif isinstance(lc, LaunchFatetellCard): lst = [lc.target] else: assert False, 'WTF?!' g = Game.getgame() for p in lst: g.process_action(LaunchCard(src, [p], TianyiAttack(src), bypass_check=True)) return True
def is_valid(self): src, tgt = self.source, self.target return (tgt.cards or tgt.showncards or tgt.equips) and not ttags(src)['sky_silk']
def is_valid(self): tgt = self.target return not ttags(tgt)['teach_used']
def is_valid(self): src, tgt = self.source, self.target act = ActionStageLaunchCard(src, [tgt], AttackCard()) disabled = ttags(src)['assisted_attack_disable'] return not disabled and act.can_fire()
def apply_action(self): g = Game.getgame() src, tgt = self.source, self.target ttags(src)['mind_read'] = True return g.process_action(MindReadEffect(src, tgt))
def is_valid(self): src = self.source return not ttags(src)['teach_used']
def clickable(g): return my_turn() and not ttags(g.me)['teach_used']
def clickable(g): return my_turn() and not ttags(g.me)['faith']
def clickable(game): me = game.me return my_turn() and not ttags(me)['mind_read']
def clickable(game): me = game.me if not my_turn() or actions.ttags(me)['sky_silk']: return False return True
def is_valid(self): src = self.source return not ttags(src)['faith']
def is_valid(self): tgt = self.target return len(self.associated_card.associated_cards ) == ttags(tgt)['miracle_times'] + 1
def is_valid(self): return not ttags(self.source)['dismantle'] and bool(self.target.equips)
def clickable(g): if ttags(g.me)['dismantle']: return False return my_turn()
def __init__(self, player): Skill.__init__(self, player) self.treat_as = ttags(player).get('ran_eikof_card') or DummyCard
def apply_action(self): tgt = self.target ttags(tgt)['flan_cs'] = True tgt.tags['flan_targets'] = [] return True
def is_valid(self): tgt = self.target return len(self.associated_card.associated_cards) == ttags(tgt)['miracle_times'] + 1
def in_critical_strike(self, p): return (ttags(p)['flan_cs'] and Game.getgame().current_player is p and p.has_skill(CriticalStrike))
def is_valid(self): src, tgt = self.source, self.target return not ttags(src)['mind_read'] and bool(tgt.cards)
def is_valid(self): src, tgt = self.source, self.target if not LaunchCard(tgt, [src], AttackCard()).can_fire(): return False return not ttags(src)['bakadesu']