def apply_action(self): src, tgt = self.source, self.target g = Game.getgame() src.tags['suika_target'].append(tgt) if g.process_action(Pindian(src, tgt)): g.process_action(LaunchCard(src, [src], HeavyDrinkerWine(src), bypass_check=True)) g.process_action(LaunchCard(tgt, [tgt], HeavyDrinkerWine(src), bypass_check=True)) else: src.tags['suika_failed'] = src.tags['turn_count'] return True
def is_valid(self): src = self.source card = self.associated_card.associated_cards[0] if card.is_card(AttackCard) and src.tags['vitality'] < 1: if not AttackCardVitalityHandler.is_disabled(src): return False if card.usage != 'launch': return False victim = self.target tgts = self.target_list[1:] lc = LaunchCard(victim, tgts, card) return lc.can_fire()
def is_valid(self): src = self.source card = self.associated_card.associated_cards[0] if card.is_card(AttackCard) and src.tags["vitality"] < 1: if not AttackCardVitalityHandler.is_disabled(src): return False if card.usage != "launch": return False victim = self.target tgts = self.target_list[1:] lc = LaunchCard(victim, tgts, card) return lc.can_fire()
def handle(self, evt_type, act): if evt_type == 'action_before' and isinstance(act, BaseAttack): if hasattr(act, 'roukanken_tag'): return act src = act.source tgt = act.target g = Game.getgame() # if tgt is g.current_player: return act if not tgt.has_skill(Reversal): return act if not user_input([tgt], ChooseOptionInputlet(self, (False, True))): return act def nhand(p): return len(p.cards) + len(p.showncards) g.process_action(DrawCards(tgt, 1)) if nhand(tgt) > nhand(src): g.process_action(LaunchCard(src, [tgt], ReversalDuel(src))) act.cancelled = True return act
def handle(self, evt_type, act): if evt_type == 'action_shootdown' and isinstance(act, ActionStageLaunchCard): src = act.source if not src.has_skill(Discarder): return act g = Game.getgame() if src is not g.current_player: return act self.card = c = act.card if not c.is_card(PhysicalCard): return act if not c.is_card(AttackCard): raise DiscarderAttackOnly dist = LaunchCard.calc_distance(src, Discarder(src)) dist.pop(src, '') nearest = max(min(dist.values()), 0) avail = {p for p in dist if dist[p] <= nearest} if not set(act.target_list) <= avail: raise DiscarderDistanceLimit elif evt_type == 'action_after' and isinstance(act, PlayerTurn): tgt = act.target if tgt.has_skill(Discarder): tgt.skills.remove(Discarder) tgt.tags['reisen_discarder'] = False # for tag return act
def handle(self, evt_type, act): if evt_type == 'action_after' and isinstance(act, PlayerDeath): src = act.source if not src or not src.has_skill(S****t): return act dist = LaunchCard.calc_distance(src, AttackCard()) candidates = [k for k, v in dist.items() if v <= 0 and k is not src] if not candidates: return act pl = user_choose_players(self, src, candidates) if pl: Game.getgame().process_action(SadistAction(src, pl[0])) elif evt_type == 'action_before' and isinstance(act, Damage): src = act.source tgt = act.target if not src or src is tgt: return act if not src.has_skill(S****t): return act if tgt.life == 1: act.amount += 1 return act
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 handle(self, evt_type, act): if evt_type == 'action_after' and isinstance(act, PlayerDeath): src = act.source if not src or not src.has_skill(S****t): return act dist = LaunchCard.calc_distance(src, AttackCard()) candidates = [ k for k, v in dist.items() if v <= 0 and k is not src ] if not candidates: return act pl = user_choose_players(self, src, candidates) if pl: Game.getgame().process_action(SadistAction(src, pl[0])) elif evt_type == 'action_before' and isinstance(act, Damage): src = act.source tgt = act.target if not src or src is tgt: return act if not src.has_skill(S****t): return act if tgt.life == 1: act.amount += 1 return act
def handle(self, evt_type, act): if evt_type == 'action_shootdown' and isinstance( act, ActionStageLaunchCard): src = act.source if not src.has_skill(Discarder): return act g = Game.getgame() if src is not g.current_player: return act self.card = c = act.card if not c.is_card(AttackCard): if c.is_card(PhysicalCard) or 'treat_as' in c.category: raise DiscarderAttackOnly else: return act dist = LaunchCard.calc_distance(src, Discarder(src)) dist.pop(src, '') nearest = max(min(dist.values()), 0) avail = {p for p in dist if dist[p] <= nearest} if not set(act.target_list) <= avail: raise DiscarderDistanceLimit elif evt_type == 'action_after' and isinstance(act, PlayerTurn): tgt = act.target if tgt.has_skill(Discarder): tgt.skills.remove(Discarder) tgt.tags['reisen_discarder'] = False # for tag return act
def handle(self, evt_type, arg): if evt_type == 'character_debut': old, new = arg if not new.has_skill(AssaultKOF): return arg g = Game.getgame() op = g.get_opponent(new) lc = LaunchCard(new, [op], AssaultAttack(new)) if not lc.can_fire(): return arg if user_input([new], ChooseOptionInputlet(self, (False, True))): g.process_action(lc) return arg
def resp(evt_type, act): if evt_type == 'action_before' and isinstance(act, Demolition): g.pause(1.5) dialog(Cirno, u'哈哈,早知道你会用这一招,怎能让你轻易得逞!', 17) g.process_action( LaunchCard(cirno, [cirno], cirnoreject, Reject(cirno, act))) elif evt_type == 'action_before' and isinstance( act, Reject) and act.associated_card is cirnoreject: g.pause(1.5) dialog(Meirin, u'这又是怎么回事……好像|G城管执法|r并没有起作用?', 38) dialog(Sakuya, u'咦,这笨蛋居然知道用|G好人卡|r啊……', 19) dialog(Cirno, u'什么笨蛋,老娘是天才,天~才~', 18) text = (u'|G好人卡|r的效果是|R抵消符卡效果|r,也就是说,你的|G城管执法|r的效果被无效化了。\n' u'(在PC版中鼠标移动到卡牌/人物上,或者手机版中长按卡牌/人物头像,就会弹出说明,很有用的)') dialog(Sakuya, text, 20) dialog(Sakuya, u'但是,|G好人卡|r的“无效符卡”的效果,本身也是符卡效果,是可以被|G好人卡|r抵消的!', 21) meirinreject = g.deck.inject(RejectCard, Card.CLUB, 4) g.process_action(DrawCards(meirin, 1)) while not act.cancelled: dialog(Meirin, u'我知道了,我也用|G好人卡|r去抵消她的|G好人卡|r效果就好了!', 39) rej = RejectHandler() rej.target_act = act with InputTransaction('AskForRejectAction', [meirin]) as trans: p, rst = ask_for_action(rej, [meirin], ('cards', 'showncards'), [], trans=trans) if not p: continue cards, _ = rst assert cards[0] is meirinreject g.process_action( LaunchCard(meirin, [cirno], meirinreject, Reject(meirin, act))) return act
def apply_action(self): src = self.source tags = src.tags tgt, victim = self.target_list tags['incite_tag'] = tags['turn_count'] g = Game.getgame() if g.process_action(Pindian(src, tgt)): g.process_action(LaunchCard(tgt, [victim], InciteAttack(tgt))) else: if user_input([tgt], ChooseOptionInputlet(self, (False, True))): g.process_action(LaunchCard(tgt, [src], InciteFailAttack(tgt))) else: g.process_action(InciteSilentFailAction(src, tgt)) return True
def is_valid(self): src = self.source tags = src.tags if tags['turn_count'] <= tags['incite_tag']: return False tgt, victim = self.target_list Pindian(src, tgt).action_shootdown_exception() return LaunchCard(tgt, [victim], InciteAttack(tgt)).can_fire()
def apply_action(self): src, tgt, c = self.source, self.target, self.card g = Game.getgame() g.process_action(Reforge(src, src, c)) g.process_action( LaunchCard(src, [tgt], XianshizhanAttackCard(src), bypass_check=True)) return True
def is_valid(self): tags = self.source.tags if tags['turn_count'] <= tags['darkness_tag']: return False attacker, victim = self.target_list if not LaunchCard(attacker, [victim], AttackCard()).can_fire(): return False return True
def apply_action(self): g = Game.getgame() src = self.source pl = [p for p in g.players if not p.dead] attacker, victim = user_choose_players(self, src, pl) or (None, None) if attacker is None: return False self.target_list = attacker, victim g.process_action(LaunchCard(src, [attacker, victim], LittleLegionDollControlCard(attacker))) return True
def fatetell_action(self, ft): act = self.act src = self.source g = Game.getgame() if ft.succeeded: # rej = spellcard.LaunchReject(src, act, SaigyouBranchSkill(src)) g.process_action( LaunchCard(src, [act.target], MaidenCostume(src), spellcard.Reject(src, act))) return True else: return False
def apply_action(self): g = Game.getgame() src = self.source pl = [p for p in g.players if not p.dead and p is not src] if not pl: return False victim, = user_choose_players(self, src, pl) or (None,) if victim is None: return False lc = LaunchCard(src, [victim], LittleLegionAttackCard(src), bypass_check=True) g.process_action(lc) return True
def apply_action(self): attacker, victim = self.target_list src = self.source g = Game.getgame() tags = self.source.tags tags['darkness_tag'] = tags['turn_count'] cards = user_choose_cards(self, attacker, ('cards', 'showncards')) if cards: c = cards[0] g.process_action(LaunchCard(attacker, [victim], c)) else: g.process_action(Damage(src, attacker, 1)) return True
def apply_action(self): tl = self.target_list assert len(tl) == 2 src = self.source attacker, victim = tl cards = user_choose_cards(self, attacker, ['cards', 'showncards']) g = Game.getgame() if cards: g.players.reveal(cards) g.process_action(LaunchCard(attacker, [victim], cards[0])) else: l = [e for e in attacker.equips if e.equipment_category == 'weapon'] migrate_cards(l, src.cards) return True
def is_valid(self): if self.target.dead: return False assert len(self.target_list) == 2 attacker, victim = self.target_list if not any(e.equipment_category == 'weapon' for e in attacker.equips): return False from .definition import AttackCard if not LaunchCard(attacker, [victim], AttackCard()).can_fire(): return False return True
def apply_action(self): src, tgt = self.source, self.target g = Game.getgame() choice = user_input([tgt], ChooseOptionInputlet(self, ('duel', 'attack'))) if choice == 'duel': cls = KanakoFaithDuel elif choice == 'attack': cls = KanakoFaithAttack else: cls = KanakoFaithAttack g.process_action(LaunchCard(tgt, [src], cls(tgt), bypass_check=True)) return True
def handle(self, evt_type, act): if evt_type == 'action_after' and isinstance(act, Damage): src = act.source tgt = act.target if not (src and src.has_skill(FerryFee)): return act if not (tgt.cards or tgt.showncards or tgt.equips): return act dist = LaunchCard.calc_distance(src, FerryFee(src)) if not dist.get(tgt, 10000) <= 0: return act if user_input([src], ChooseOptionInputlet(self, (False, True))): catnames = ('cards', 'showncards', 'equips') card = user_input([src], ChoosePeerCardInputlet(self, tgt, catnames)) card = card or random_choose_card([tgt.cards, tgt.showncards, tgt.equips]) if not card: return act g = Game.getgame() g.process_action(FerryFeeEffect(src, tgt, card)) return act
def handle(self, evt_type, act): if evt_type == 'action_shootdown' and isinstance(act, LaunchCard): if act.bypass_check: return act c = act.card if not c.is_card(AttackCard): return act src, tgt = act.source, act.target if not src.tags['scarlet_mist'] == 'nerf': return act dist = LaunchCard.calc_raw_distance(src, DummyCard()) if dist[tgt] > 1: raise ScarletMistAttackLimit elif evt_type == 'post_calcdistance': src, c, dist = act if not c.is_card(AttackCard): return act if src.tags['scarlet_mist'] != 'buff': return act for k in dist: dist[k] = 0 elif evt_type == 'action_after' and isinstance(act, Damage): src = act.source if not (src and src.tags['scarlet_mist'] == 'buff'): return act if src.life >= src.maxlife: return act g = Game.getgame() pact = g.action_stack[-1] if not isinstance(pact, Attack): return act if not pact.associated_card: return act g.process_action(Heal(src, src, act.amount)) elif evt_type == 'action_apply' and isinstance(act, PrepareStage): tgt = act.target if not tgt.has_skill(ScarletMist): return act if not tgt.tags['scarlet_mist']: return act g = Game.getgame() g.process_action(ScarletMistEndAction(None, None)) 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 handle(self, evt_type, act): if evt_type == 'action_before' and isinstance(act, SpellCardAction): if act.cancelled: return act # some other thing have done the job if act.non_responsive: return act g = Game.getgame() has_reject = False while g.SERVER_SIDE: # from thb.characters.baseclasses import Character # from thb.characters.reimu import SpiritualAttack # for p in g.players: # if isinstance(p, Character) and p.has_skill(SpiritualAttack): # has_reject = True # break # if has_reject: break from thb.cards.definition import RejectCard for c in flatten([[p.cards, p.showncards] for p in g.players]): if isinstance(c, RejectCard): has_reject = True break break has_reject = sync_primitive(has_reject, g.players) if not has_reject: return act self.target_act = act pl = BatchList(p for p in g.players if not p.dead) with InputTransaction('AskForRejectAction', pl) as trans: p, rst = ask_for_action(self, pl, ('cards', 'showncards'), [], trans=trans) if not p: return act cards, _ = rst assert cards and self.cond(cards) g.process_action( LaunchCard(p, [act.target], cards[0], Reject(p, act))) return act
def handle(self, evt_type, act): if evt_type != 'action_after': return act if not isinstance(act, LaunchCard): return act g = Game.getgame() card = act.card if not card: return act if 'basic' not in card.category: return act if card.color != Card.RED: return act if card.is_card(VirtualCard): rawcards = VirtualCard.unwrap([card]) else: rawcards = [card] if not all(c.resides_in is None or c.resides_in.type == 'droppedcard' for c in rawcards): return act tgt = act.source self.target = tgt # for ui if tgt.dead: return act for p in g.players: if p.dead or p is tgt: continue if not p.has_skill(ImperishableNight): continue if p is g.current_player: continue if not user_input([p], ChooseOptionInputlet(self, (False, True))): continue cards = user_choose_cards(self, p, ('cards', 'showncards', 'equips')) if cards: g.players.reveal(cards) skill = skill_wrap(p, [ImperishableNight], cards, {}) assert skill_check(skill) # should not fail g.deck.register_vcard(skill) rst = g.process_action(LaunchCard(p, [tgt], skill)) assert rst return act
def apply_action(self): src = self.source tgt = 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]) if not c: return False src.reveal(c) migrate_cards([c], src.cards) src.tags['borrow_tag'] = src.tags['turn_count'] if user_input([tgt], ChooseOptionInputlet(self, (False, True))): g.process_action( LaunchCard(tgt, [src], Daze(tgt), bypass_check=True)) return True
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 handle(self, evt_type, act): if evt_type == 'action_after' and isinstance(act, Damage): src = act.source tgt = act.target if not (src and src.has_skill(FerryFee)): return act if not (tgt.cards or tgt.showncards or tgt.equips): return act dist = LaunchCard.calc_distance(src, FerryFee(src)) if not dist.get(tgt, 10000) <= 0: return act if user_input([src], ChooseOptionInputlet(self, (False, True))): catnames = ('cards', 'showncards', 'equips') card = user_input([src], ChoosePeerCardInputlet(self, tgt, catnames)) card = card or random_choose_card( [tgt.cards, tgt.showncards, tgt.equips]) if not card: return act g = Game.getgame() g.process_action(FerryFeeEffect(src, tgt, card)) return act
def handle(self, evt_type, act): if evt_type == 'action_apply' and isinstance(act, ActionStage): g = Game.getgame() for p in g.players: if p.dead: continue if not p.has_skill(Sentry): continue tgt = act.target if p is tgt: continue self.target = tgt # for ui dist = LaunchCard.calc_distance(p, AttackCard()) if dist.get(tgt, 1) > 0: continue if not user_input([p], ChooseOptionInputlet(self, (False, True))): continue g.process_action(SentryAction(p, tgt)) return act
def handle(self, evt_type, act): if evt_type == 'action_after' and isinstance(act, Fatetell): tgt = act.target if act.card.color != Card.RED: return act g = Game.getgame() if not act.card.detached: return act g = Game.getgame() pl = [p for p in g.players if p.has_skill(ScarletPerception) and not p.dead] assert len(pl) <= 1 if pl: p = pl[0] dist = LaunchCard.calc_distance(p, ScarletPerception(p)) if dist.get(tgt, 1) <= 0: g.process_action(ScarletPerceptionAction(p, tgt, act.card)) return act
def apply_action(self): g = Game.getgame() card = self.associated_card.associated_cards[0] src = self.source victim = self.target tgts = self.target_list[1:] g.players.reveal(card) # card.move_to(victim.cards) # HACK: Silently, no events # migrate_cards([self.associated_card], victim.cards, unwrap=migrate_cards.SINGLE_LAYER) if card.is_card(AttackCard): src.tags['vitality'] -= 1 # XXX: Use card owned by other lc = LaunchCard(victim, tgts, card) g = Game.getgame() g.process_action(lc) return True
def handle(self, evt_type, arg): if self.processing: return arg elif evt_type == 'calcdistance': src, c, dist = arg if not src.has_skill(Telegnosis): return arg if not c.is_card(AttackCard): return arg try: self.processing = True for p in dist: if p is src: continue d = LaunchCard.calc_distance(p, AttackCard()) if d[src] <= 0: dist[p] = 0 finally: self.processing = False return arg
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 handle(self, evt_type, act): if evt_type != 'action_before': return act if not isinstance(act, DropCards): return act g = Game.getgame() pact = g.action_stack[-1] if not isinstance(pact, Demolition): return act if not pact.source.has_skill(Envy): return act src = pact.source tgt = pact.target self.card = card = pact.card assert len(act.cards) == 1 assert card is act.cards[0] if card.resides_in is None: return act if card.resides_in.type not in ('cards', 'showncards', 'equips'): return act assert tgt is card.resides_in.owner if src.dead: return act if card.suit != Card.DIAMOND: return act dist = LaunchCard.calc_distance(src, EnvyRecycle()) if not dist[tgt] <= 0: return act g.emit_event('ui_show_disputed', [card]) if not user_input([src], ChooseOptionInputlet(self, (False, True))): return act act.__class__ = classmix(EnvyRecycleAction, act.__class__) return act
def __init__(self, source, target, card, cause): LaunchCard.__init__(self, source, [target], card, bypass_check=True) self.cause = cause # for ui
def target(g, p, tl): l = g.players.rotate_to(p) del l[0] dists = LaunchCard.calc_raw_distance(p, AttackCard()) return ([t for t in l if not t.dead and dists[t] <= 1], True)