def handle(self, evt_type, act): if evt_type == 'action_after' and isinstance(act, PrepareStage): src = act.target if not src.has_skill(LunaDial): return act PlayerTurn.get_current(src).pending_stages.insert(0, LunaDialActionStage) return act
def fatetell_action(self, ft): if ft.succeeded: turn = PlayerTurn.get_current(self.target) try: turn.pending_stages.remove(DrawCardStage) except Exception: pass return True return False
def apply_action(self): tgt = self.target ActionStage.force_break() turn = PlayerTurn.get_current(tgt) try: turn.pending_stages.remove(DropCardStage) turn.pending_stages.remove(FinalizeStage) except Exception: pass return True
def apply_action(self): src = self.source g = Game.getgame() g.process_action(DrawCards(src, 1)) turn = PlayerTurn.get_current(src) try: turn.pending_stages.remove(DropCardStage) except Exception: pass return True
def handle(self, evt_type, arg): if evt_type == 'card_migration': act, cards, _from, to, _ = arg if isinstance(act, (DistributeCards, DrawCardStage)): return arg if to is None or not to.owner: return arg if to.type not in ('cards', 'showncards', 'equips'): return arg if _from is not None and _from.owner is to.owner: return arg g = Game.getgame() a, b = g.players if not a.has_skill(SanaeFaithKOF): a, b = b, a if not a.has_skill(SanaeFaithKOF): return arg if b is not to.owner: return arg turn = PlayerTurn.get_current() if not turn: return arg stage = turn.current_stage if stage.target is not b or not isinstance(stage, ActionStage): return arg g = Game.getgame() g.process_action(SanaeFaithKOFDrawCards(a, 1)) return arg
def apply_action(self): g = Game.getgame() params = self.params from thb.cards import Deck g.stats = [] g.deck = Deck() g.ehclasses = [] if params['random_force']: seed = get_seed_for(g.players) random.Random(seed).shuffle(g.players) g.draw_extra_card = params['draw_extra_card'] f1 = BatchList() f2 = BatchList() g.forces = BatchList([f1, f2]) H, M = Identity.TYPE.HAKUREI, Identity.TYPE.MORIYA for p, id, f in zip(g.players, [H, H, M, M], [f1, f1, f2, f2]): p.identity = Identity() p.identity.type = id p.force = f f.append(p) pl = g.players for p in pl: g.process_action(RevealIdentity(p, pl)) roll_rst = roll(g, self.items) f1, f2 = partition(lambda p: p.force is roll_rst[0].force, roll_rst) final_order = [f1[0], f2[0], f2[1], f1[1]] g.players[:] = final_order g.emit_event('reseat', None) # ban / choose girls --> from . import characters chars = characters.get_characters('common', '2v2') seed = get_seed_for(g.players) random.Random(seed).shuffle(chars) # ANCHOR(test) testing = list(settings.TESTING_CHARACTERS) testing, chars = partition(lambda c: c.__name__ in testing, chars) chars.extend(testing) chars = chars[-20:] choices = [CharChoice(cls) for cls in chars] banned = set() mapping = {p: choices for p in g.players} with InputTransaction('BanGirl', g.players, mapping=mapping) as trans: for p in g.players: c = user_input([p], ChooseGirlInputlet(g, mapping), timeout=30, trans=trans) c = c or [_c for _c in choices if not _c.chosen][0] c.chosen = p banned.add(c.char_cls) trans.notify('girl_chosen', (p, c)) assert len(banned) == 4 g.stats.extend([{ 'event': 'ban', 'attributes': { 'gamemode': g.__class__.__name__, 'character': i.__name__ } } for i in banned]) chars = [_c for _c in chars if _c not in banned] g.random.shuffle(chars) if Game.CLIENT_SIDE: chars = [None] * len(chars) for p in g.players: p.choices = [CharChoice(cls) for cls in chars[-4:]] p.choices[-1].as_akari = True del chars[-4:] p.reveal(p.choices) g.pause(1) mapping = {p: p.choices for p in g.players} with InputTransaction('ChooseGirl', g.players, mapping=mapping) as trans: ilet = ChooseGirlInputlet(g, mapping) @ilet.with_post_process def process(p, c): c = c or p.choices[0] trans.notify('girl_chosen', (p, c)) return c rst = user_input(g.players, ilet, timeout=30, type='all', trans=trans) # reveal for p, c in rst.items(): c.as_akari = False g.players.reveal(c) g.set_character(p, c.char_cls) # ------- for p in g.players: log.info( u'>> Player: %s:%s %s', p.__class__.__name__, Identity.TYPE.rlookup(p.identity.type), p.account.username, ) # ------- g.emit_event('game_begin', g) for p in g.players: g.process_action(DistributeCards(p, amount=4)) for i, p in enumerate(cycle(pl)): if i >= 6000: break if not p.dead: g.emit_event('player_turn', p) try: g.process_action(PlayerTurn(p)) except InterruptActionFlow: pass return True
def apply_action(self): g = Game.getgame() from thb.characters.meirin import Meirin from thb.characters.cirno import Cirno from thb.characters.sakuya import Sakuya # ----- Init ----- from thb.cards import Deck g.deck = Deck() g.ehclasses = [] cirno, meirin = g.players for i, p in enumerate(g.players): p.identity = Identity() p.identity.type = Identity.TYPE.HIDDEN g.set_character(cirno, Cirno) g.set_character(meirin, Meirin) pl = g.players for p in pl: g.process_action(RevealIdentity(p, pl)) g.emit_event('game_begin', g) # ----- End Init ----- def dialog(character, dialog, voice): if voice is not None: voice = 'thb-cv-newbie-%s-%s' % (character.__name__.lower(), ('000' + str(voice))[-3:]) user_input([meirin], GalgameDialogInputlet(g, character, dialog, voice), timeout=60) def inject_eh(hook): eh = AdhocEventHandler() eh.handle = hook g.add_adhoc_event_handler(eh) return eh def remove_eh(eh): try: g.remove_adhoc_event_handler(eh) except: pass def fail(): dialog(Meirin, u'喂剧本不是这么写的啊,重来重来!', 1) cirno, meirin = g.players # update dialog(Meirin, u'一个pad,两个pad,三个pad……', 2) dialog(Sakuya, u'(唰', None) dialog(Meirin, u'啊,我头上的是……', 3) dialog(Sakuya, u'别做白日梦,起床了起床了。那边那个妖精可又来门口找麻烦了,为了你的晚餐考虑,还是去解决一下吧?', 1) dialog(Meirin, u'是是是……这都已经是第999次了吧,那家伙真是不知道什么叫做放弃吗……', 4) dialog(Cirno, u'俺又来啦,这次绝对要打赢你!赌上大酱的100场陪练!', 1) dialog(Meirin, u'前面998次你也都是这么说的……好了,废话少说,放马过来吧!', 5) dialog(Cirno, u'正合我意!', 2) g.current_player = cirno c = g.deck.inject(AttackCard, Card.SPADE, 1) g.process_action(DrawCards(cirno, 1)) dialog(Cirno, u'“吃我大弹幕啦!”', 3) g.process_action(LaunchCard(cirno, [meirin], c)) # 红美铃受到一点伤害 dialog(Meirin, u'呜哇!?', 6) dialog(Sakuya, u'怎么搞的,被一只妖精弄伤了?', 2) dialog(Meirin, u'不不不,那个咲夜你听我说,这是偷袭……', 7) dialog(Sakuya, u'嗯……明明游戏已经开始了,不打起十二分的精神迎战可是不行的啊。在玩thb的时候请注意队友的感受,不要挂机喔。', 3) dialog(Meirin, u'啥啊又在对着不存在的人说些莫名其妙的东西……', 8) dialog(Sakuya, u'嗯?', 4) dialog(Meirin, u'我可什么都没说!', 9) # 红美铃的回合【目的:使用基本牌(麻薯,弹幕)】 g.current_player = meirin c = g.deck.inject(HealCard, Card.HEART, 2) g.process_action(DrawCards(meirin, 1)) while c in meirin.cards: text = (u'总之,这里先回复……\n' u'(请使用麻薯)\n' u'(在PC版中鼠标移动到卡牌/人物上,或者手机版中长按卡牌/人物头像,就会弹出说明,很有用的)') dialog(Meirin, text, 10) g.process_action(ActionStage(meirin, one_shot=True)) atkcard = g.deck.inject(AttackCard, Card.SPADE, 3) g.process_action(DrawCards(meirin, 1)) while atkcard in meirin.cards: text = (u'好,状态全满!那边的妖精!吃我大弹幕啦!\n' u'(请首先点击弹幕,然后点击琪露诺,最后点击出牌)\n' u'(在PC版中鼠标移动到卡牌/人物上,或者手机版中长按卡牌/人物头像,就会弹出说明,很有用的)') dialog(Meirin, text, 11) g.process_action(ActionStage(meirin, one_shot=True)) dialog(Cirno, u'哎呀!?', 4) dialog(Sakuya, u'啊啦,干的不错。', 5) dialog(Meirin, u'那是自然啦,对付一些这样的妖精还是不在话下的……', 12) dialog(Cirno, u'喂!悄悄话说的也太大声了!!', 5) # 琪露诺的回合【目的:使用基本牌(擦弹)】【使用太极(1)】 g.current_player = cirno g.deck.inject(HealCard, Card.HEART, 4) g.process_action(DrawCards(cirno, 1)) while True: if meirin.life < meirin.maxlife: g.process_action( Heal(meirin, meirin, meirin.maxlife - meirin.life)) if meirin.cards: g.process_action(DropCards(meirin, meirin, meirin.cards)) atkcard = g.deck.inject(AttackCard, Card.SPADE, 5) g.process_action(DrawCards(cirno, 1)) graze = g.deck.inject(GrazeCard, Card.DIAMOND, 6) g.process_action(DrawCards(meirin, 1)) dialog(Cirno, u'这回就轮到我了!接招!超⑨武神霸斩!', 6) lc = LaunchCard(cirno, [meirin], atkcard) @inject_eh def resp(evt_type, act): if evt_type == 'choose_target' and act[0] is lc: g.pause(1) dialog(Meirin, u'来的正好!', 13) elif evt_type == 'action_after' and isinstance( act, LaunchGraze) and act.succeeded: g.pause(1) dialog(Cirno, u'我的计谋竟被……', 7) text = (u'还没完呐!\n' u'(使用技能,震飞琪露诺一张手牌)\n' u'(每一名角色都有自己独特的技能,灵活利用好这些技能是你取得胜利的关键所在)') dialog(Meirin, text, 14) return act g.process_action(lc) remove_eh(resp) if graze in meirin.cards or cirno.cards: fail() continue break dialog(Cirno, u'切,再让你嘚瑟一会儿,我还有自己的杀手锏呢……', 8) dialog(Meirin, u'在这种时候放空话可是谁都不会相信的啦。', 15) green = g.deck.inject(GreenUFOCard, Card.DIAMOND, 7) g.process_action(DrawCards(cirno, 1)) dialog(Cirno, u'总之不能再让你这么自在地用弹幕打到俺了……看我的杀手锏!', 9) g.process_action(LaunchCard(cirno, [cirno], green)) dialog(Meirin, u'咦……', 16) dialog(Sakuya, u'不会连这个你也不清楚吧。', 6) dialog( Meirin, u'我记得是记得啦,似乎是我现在够不到琪露诺了之类的而琪露诺可以够到我……吧?说回来,这样的解释似乎很不科学诶,为什么我够不到但是对方够得到我啊,这个|G绿色UFO|r到底是什么东西……', 17) dialog(Sakuya, u'……你只要好好打完这局就可以了,再问这么多为什么,我可不保证你的脑门上会多出什么奇怪的金属制品。', 7) dialog(Meirin, u'是!', 18) # 红美铃的回合【目的:使用延时符卡(冻青蛙),使用太极(2),使用红色UFO】' g.current_player = meirin frozen = g.deck.inject(FrozenFrogCard, Card.SPADE, 8) g.process_action(DrawCards(meirin, 1)) dialog(Meirin, u'咦,这张牌是……', 19) dialog( Sakuya, u'这是|G冻青蛙|r。\n(咳嗽了一声)|G冻青蛙|r是一种|R延时符卡|r,它和|G封魔阵|r一样在使用时并不会立即发生作用,只有轮到了那个角色的行动回合时,才会进行一次判定来执行该符卡的后续效果。', 8) dialog(Meirin, u'原来是这样……那就先贴到她脸上再说!', 20) g.process_action(ActionStage(meirin, one_shot=True)) dialog(Meirin, u'这是怎么回事…为什么不能使用…那就先来一发|G弹幕|r好了!', 21) atkcard = g.deck.inject(AttackCard, Card.SPADE, 9) g.process_action(DrawCards(meirin, 1)) g.process_action(ActionStage(meirin, one_shot=True)) dialog(Meirin, u'咲夜咲夜咲夜,我没法打她啊!', 22) dialog( Sakuya, u'……你忘了琪露诺的|G绿色UFO|r吗。现在从你这边看来和琪露诺的距离为2,也就是,赤手空拳的距离1是没有办法用|G弹幕|r打中她的。我记得鬼族有她们的方法,但是很显然你并不会。', 9) dialog(Meirin, u'好吧……所以?', 23) dialog(Sakuya, u'(掏出飞刀', None) dialog(Meirin, u'好啦好啦,我不问啦!', 24) red = g.deck.inject(RedUFOCard, Card.HEART, 10) g.process_action(DrawCards(meirin, 1)) while red in meirin.cards: text = (u'哈,我找到了这个!\n' u'(红色UFO可以拉近其他角色与你的距离,快装备上吧)') dialog(Meirin, text, 25) g.process_action(ActionStage(meirin, one_shot=True)) dialog(Sakuya, u'你这不是知道UFO的规则嘛。', 10) dialog(Meirin, u'只是想趁这次机会和咲夜多说说话啦,平时总是一副大忙人的样子来无影去无踪的……', 26) dialog(Sakuya, u'你以为奉承一下我就会给你涨工资吗。', 11) dialog(Meirin, u'啊哈,啊哈哈。', 27) g.pause(1) g.deck.inject(NazrinRodCard, Card.HEART, 11) graze = g.deck.inject(GrazeCard, Card.DIAMOND, 12) g.process_action(DrawCards(cirno, 2)) while True: if atkcard not in meirin.cards: atkcard = g.deck.inject(AttackCard, Card.SPADE, 9) g.process_action(DrawCards(meirin, 1)) if graze not in cirno.cards: graze = g.deck.inject(GrazeCard, Card.DIAMOND, 12) g.process_action(DrawCards(cirno, 1)) dialog(Cirno, u'喂,读条要过了你们在那儿干嘛呢,说好的弹幕呢!', 10) dialog(Meirin, u'我这辈子还没听过这么欠扁的要求!吃我一弹!', 28) @inject_eh def resp(evt_type, act): if evt_type == 'action_after' and isinstance( act, LaunchGraze) and act.target is cirno: g.pause(1) dialog(Cirno, u'你以为只有你会闪开吗!', 11) dialog(Meirin, u'确实谁都会闪啦,不过接下来的,可就不是谁都会的咯?', 29) return act g.process_action(ActionStage(meirin, one_shot=True)) remove_eh(resp) if atkcard in meirin.cards: continue if cirno.cards: fail() continue break g.pause(1) dialog(Cirno, u'呜哇你赖皮!', 12) dialog(Meirin, u'哪来的什么赖皮不赖皮,我有自己的能力,但是你也有啊。', 30) dialog(Cirno, u'可是我又不会用!你这不是赖皮是什么嘛!', 13) dialog(Meirin, u'……', None) dialog(Sakuya, u'……还是不要跟笨蛋说话的比较好,智商会下降的。', 12) while frozen in meirin.cards: dialog(Meirin, u'那么,把这张|G冻青蛙|r也贴上去吧!', 31) g.process_action(ActionStage(meirin)) g.current_player = cirno g.deck.inject(SinsackCard, Card.SPADE, 13) g.process_action(FatetellStage(cirno)) g.pause(2) dialog(Sakuya, u'所谓“笨蛋的运气总会很不错”吗。', 13) dialog(Cirno, u'哼,俺可是自带⑨翅膀的天才呀!', 14) dialog(Meirin, u'可惜依旧是笨蛋。', 32) shield = g.deck.inject(MomijiShieldCard, Card.SPADE, 1) g.process_action(DrawCards(cirno, 1)) dialog(Cirno, u'无路赛……我要出王牌啦!', 15) g.process_action(LaunchCard(cirno, [cirno], shield)) dialog(Meirin, u'这是……', 33) dialog(Cirno, u'这是我在妖怪之山的妖精那里【借】来的宝物,怎么样,接下来你就没办法用弹幕伤到俺了吧~', 16) dialog(Sakuya, u'只是黑色的弹幕无效而已。', 14) dialog(Meirin, u'对呀对呀。', 34) dialog(Sakuya, u'而且,只要拆掉的话不就好了吗。', 15) dialog(Meirin, u'对呀对……啥?', 35) dialog(Sakuya, u'真是的,你之前的998局到底是怎么赢的……', 16) # 红美铃的回合【目的:使用符卡(城管执法,好人卡)】 g.current_player = meirin demolition = g.deck.inject(DemolitionCard, Card.CLUB, 2) g.process_action(DrawCards(meirin, 1)) cirnoreject = g.deck.inject(RejectCard, Card.CLUB, 3) g.process_action(DrawCards(cirno, 1)) while demolition in meirin.cards: dialog(Meirin, u'咲夜咲夜!', 36) dialog(Sakuya, u'是啦,这就是我说的那张符卡了。和其他的|R非延时符卡|r使用方法都一样,属于发动之后就会立即生效的类型。', 17) dialog(Meirin, u'……不是很好理解诶。', 37) dialog(Sakuya, u'用用看就知道了。快去卸掉她的|G天狗盾|r吧。', 18) @inject_eh 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 g.process_action(ActionStage(meirin, one_shot=True)) remove_eh(resp) if shield in cirno.equips: dialog(Sakuya, u'喂,不是说要拆掉|G天狗盾|r吗,你明明装备着|G红色UFO|r的,她是在你的距离范围内的。', 22) dialog(Meirin, u'哎呀,手抖了的说……', 40) else: dialog(Cirno, u'呜哇你赔我的|G天狗盾|r!', 19) dialog(Meirin, u'怪我咯!?', 41) g.deck.inject(ExinwanCard, Card.CLUB, 3) g.process_action(DrawCards(meirin, 1)) dialog(Meirin, u'咦?咲夜,这张牌好奇怪……为什么是负面的效果?', 42) dialog( Sakuya, u'是|G恶心丸|r啊……你的运气不太好哦。不过尽管说是一张负面效果的牌,但是看发动条件的话,是可以恶心到别人的。情况允许的话就留在手里好了,直接吃掉肯定是不合算的。', 23) g.current_player = cirno demolition = g.deck.inject(DemolitionCard, Card.CLUB, 4) g.process_action(DrawCards(cirno, 1)) dialog(Cirno, u'可恶,你到底有没有认真的在打啊!看我双倍奉还!', 20) g.process_action(LaunchCard(cirno, [meirin], demolition)) dialog(Cirno, u'呜哇,这是什么!不要来找我!', 21) dialog(Meirin, u'哈哈,说好的双倍奉还呢?', 43) # 美铃的觉醒和主动技能 er = g.deck.inject(ElementalReactorCard, Card.DIAMOND, 5) atks = [g.deck.inject(AttackCard, Card.SPADE, i) for i in (6, 7, 8, 9)] g.process_action(DrawCards(cirno, 5)) dialog(Cirno, u'真是伤脑筋……看来我要拿出真正的实力来了!', 22) g.process_action(LaunchCard(cirno, [cirno], er)) dialog(Cirno, u'接招啦!!', 23) for c in atks[:-1]: g.pause(0.5) g.process_action(LaunchCard(cirno, [meirin], c)) dialog(Meirin, u'唔,不好,再这样下去就要撑不住了……', 44) wine = g.deck.inject(WineCard, Card.DIAMOND, 10) g.process_action(DrawCards(meirin, 1)) while wine in meirin.cards: dialog(Meirin, u'没办法,这瓶|G酒|r本来是想留着|R来一发2点伤害的弹幕|r用的,现在只能用来|R抵挡1点致命伤害|r了……', 45) g.process_action(ActionStage(meirin)) g.pause(0.5) g.process_action(LaunchCard(cirno, [meirin], atks[-1])) g.pause(0.5) dialog(Cirno, u'怎么样,老娘最强!', 24) dialog(Meirin, u'呼呼,撑过来了……', 46) dialog(Meirin, u'咲夜,这是怎么回事?|G弹幕|r不应该|R一回合只能使用一次|r吗?', 47) dialog( Sakuya, u'嗯……说的不错。|R一回合只能使用一次|r这个规则是没错啦,不过你看她的手上,是河童们研制的迷你|G八卦炉|r,只要装备上的话,一回合就可以使用任意次数的|G弹幕|r了。', 24) dialog(Meirin, u'你这家伙好像【借】来了不少东西嘛……不过笨蛋就是笨蛋,我怎么可能会输在笨蛋的手上!', 48) g.process_action(DummyPlayerTurn(meirin)) # awake! g.pause(2) dialog(Cirno, u'你怎么会突然多出来一个技能,这一点也不公平!', 25) dialog( Sakuya, u'“笨蛋就是笨蛋”这句话说的一点没错……你像这样打伤美铃,触发了美铃的|R觉醒技|r。|R觉醒技|r通常都是很厉害的技能,但是要满足一定条件以后才可以开始使用。据我所知,那个三途川的草鞋船夫也有类似的能力,而美铃的觉醒技,就是|G太极|r了。', 25) dialog(Cirno, u'啊,原来是这样……不不,才不是笨蛋,老娘最强!', 26) graze = g.deck.inject(GrazeCard, Card.DIAMOND, 11) g.process_action(DrawCards(meirin, 1)) while graze in meirin.cards: text = (u'现在说不是笨蛋是不是有点晚啊……见识一下吧,这来自古老东方的两仪|G太极|r之力!\n' u'(使用主动发动的技能:请点击技能按钮,然后选择擦弹,然后选择琪露诺,最后出牌)') dialog(Meirin, text, 49) g.process_action(ActionStage(meirin, one_shot=True)) dialog(Cirno, u'呜啊……', 27) dialog(Sakuya, u'我要回去做晚饭了。一会儿到了饭点你还没有解决掉这个妖精,我可不会给你留吃的。', 26) dialog(Meirin, u'喂咲夜你先等等……', 50) dialog(Sakuya, u'(The World', None) dialog(Meirin, u'……好吧。那边的妖精!', 51) dialog(Cirno, u'诶?', 28) dialog(Meirin, u'以晚饭之名!我要制裁你!', 52) dialog(Cirno, u'虽然不知道为什么突然燃起了斗志,不过……', 29) dialog(Cirno, u'来吧!老娘是不可能会输的!', 30) g.process_action(Heal(cirno, cirno, cirno.maxlife - cirno.life)) g.process_action(Heal(meirin, meirin, meirin.maxlife - meirin.life)) g.process_action(DrawCards(cirno, 4)) g.process_action(DrawCards(meirin, 4)) for i, idx in enumerate(cycle([1, 0])): p = g.players[idx] if i >= 6000: break try: g.emit_event('player_turn', p) g.process_action(PlayerTurn(p)) except InterruptActionFlow: pass return True
def apply_action(self): g = Game.getgame() from . import cards g.pick_history = [] g.deck = cards.Deck(cards.kof_card_definition) g.ehclasses = [] g.current_player = None for i, p in enumerate(g.players): p.identity = Identity() p.identity.type = (Identity.TYPE.HAKUREI, Identity.TYPE.MORIYA)[i % 2] # choose girls --> from thb.characters import get_characters chars = get_characters('common', 'kof') A, B = roll(g, self.items) order = [A, B, B, A, A, B, B, A, A, B] choices, imperial_choices = build_choices( g, self.items, candidates=chars, players=[A, B], num=10, akaris=4, shared=True, ) chosen = {A: [], B: []} with InputTransaction('ChooseGirl', g.players, mapping=choices) as trans: for p, c in imperial_choices: c.chosen = p chosen[p].append(c) trans.notify('girl_chosen', (p, c)) order.remove(p) for p in order: c = user_input([p], ChooseGirlInputlet(g, choices), 10, 'single', trans) c = c or first(choices[p], lambda c: not c.chosen) c.chosen = p chosen[p].append(c) trans.notify('girl_chosen', (p, c)) # reveal akaris for themselves for p in [A, B]: for c in chosen[p]: c.akari = False p.reveal(c) del c.chosen list_shuffle(chosen[A], A) list_shuffle(chosen[B], B) with InputTransaction('ChooseGirl', g.players, mapping=chosen) as trans: ilet = ChooseGirlInputlet(g, chosen) ilet.with_post_process(lambda p, rst: trans.notify('girl_chosen', (p, rst)) or rst) rst = user_input([A, B], ilet, type='all', trans=trans) def s(p): c = rst[p] or chosen[p][0] chosen[p].remove(c) p.choices = chosen[p] p.remaining = [2] p = g.next_character(p, c) return p A, B = s(A), s(B) order = [1, 0] if A is g.players[0] else [0, 1] for p in [A, B]: g.process_action(RevealIdentity(p, g.players)) g.emit_event('game_begin', g) g.process_action(DistributeCards(A, amount=4)) g.process_action(DistributeCards(B, amount=3)) for i in order: g.emit_event('character_debut', (None, g.players[i])) for i, idx in enumerate(cycle(order)): p = g.players[idx] if i >= 6000: break if p.dead: KOFCharacterSwitchHandler.do_switch_dead() p = g.players[idx] # player changed assert not p.dead try: g.emit_event('player_turn', p) g.process_action(PlayerTurn(p)) except InterruptActionFlow: pass
def apply_action(self): g = Game.getgame() params = self.params from thb.cards import Deck g.picks = [] g.deck = Deck() g.ehclasses = list(action_eventhandlers) + g.game_ehs.values() H, M = Identity.TYPE.HAKUREI, Identity.TYPE.MORIYA if params['random_seat']: # reseat seed = get_seed_for(g.players) random.Random(seed).shuffle(g.players) g.emit_event('reseat', None) L = [[H, H, M, M, H, M], [H, M, H, M, H, M]] rnd = random.Random(get_seed_for(g.players)) L = rnd.choice(L) * 2 s = rnd.randrange(0, 6) idlist = L[s:s + 6] del L, s, rnd else: idlist = [H, M, H, M, H, M] del H, M for p, identity in zip(g.players, idlist): p.identity = Identity() p.identity.type = identity g.process_action(RevealIdentity(p, g.players)) force_hakurei = BatchList() force_moriya = BatchList() force_hakurei.pool = [] force_moriya.pool = [] for p in g.players: if p.identity.type == Identity.TYPE.HAKUREI: force_hakurei.append(p) p.force = force_hakurei elif p.identity.type == Identity.TYPE.MORIYA: force_moriya.append(p) p.force = force_moriya g.forces = BatchList([force_hakurei, force_moriya]) roll_rst = roll(g, self.items) first = roll_rst[0] # choose girls --> from . import characters chars = characters.get_characters('common', 'faith') choices, _ = build_choices( g, self.items, candidates=chars, players=g.players, num=[4] * 6, akaris=[1] * 6, shared=False, ) rst = user_input(g.players, SortCharacterInputlet(g, choices, 2), timeout=30, type='all') for p in g.players: a, b = [choices[p][i] for i in rst[p][:2]] b.chosen = None p.force.reveal(b) g.switch_character(p, a) p.force.pool.append(b) for p in g.players: if p.player is first: first = p break pl = g.players first_index = pl.index(first) order = BatchList(range(len(pl))).rotate_to(first_index) for p in pl: g.process_action(RevealIdentity(p, pl)) g.emit_event('game_begin', g) for p in pl: g.process_action(DistributeCards(p, amount=4)) pl = g.players.rotate_to(first) rst = user_input(pl[1:], ChooseOptionInputlet(DeathHandler(), (False, True)), type='all') for p in pl[1:]: rst.get(p) and g.process_action(RedrawCards(p, p)) pl = g.players for i, idx in enumerate(cycle(order)): if i >= 6000: break p = pl[idx] if p.dead: continue g.emit_event('player_turn', p) try: g.process_action(PlayerTurn(p)) except InterruptActionFlow: pass return True
def apply_action(self): g = Game.getgame() params = self.params from thb.cards import Deck g.deck = Deck() g.ehclasses = [] if params['random_seat']: seed = get_seed_for(g.players) random.Random(seed).shuffle(g.players) g.emit_event('reseat', None) for i, p in enumerate(g.players): p.identity = Identity() p.identity.type = (Identity.TYPE.HAKUREI, Identity.TYPE.MORIYA)[i % 2] g.forces = forces = BatchList([BatchList(), BatchList()]) for i, p in enumerate(g.players): f = i % 2 p.force = f forces[f].append(p) pl = g.players for p in pl: g.process_action(RevealIdentity(p, pl)) from . import characters chars = characters.get_characters('common', '3v3') choices, imperial_choices = build_choices( g, self.items, candidates=chars, players=g.players, num=16, akaris=4, shared=True, ) roll_rst = roll(g, self.items) first = roll_rst[0] first_index = g.players.index(first) order_list = (0, 5, 3, 4, 2, 1) n = len(order_list) order = [g.players[(first_index + i) % n] for i in order_list] akaris = [] with InputTransaction('ChooseGirl', g.players, mapping=choices) as trans: chosen = set() for p, c in imperial_choices: chosen.add(p) c.chosen = p g.set_character(p, c.char_cls) trans.notify('girl_chosen', (p, c)) for p in order: if p in chosen: continue c = user_input([p], ChooseGirlInputlet(g, choices), timeout=30, trans=trans) c = c or [_c for _c in reversed(choices[p]) if not _c.chosen][0] c.chosen = p if c.akari: c.akari = False akaris.append((p, c)) else: g.set_character(p, c.char_cls) trans.notify('girl_chosen', (p, c)) # reveal akaris if akaris: g.players.reveal([i[1] for i in akaris]) for p, c in akaris: g.set_character(p, c.char_cls) # ------- for p in g.players: log.info( u'>> Player: %s:%s %s', p.__class__.__name__, Identity.TYPE.rlookup(p.identity.type), p.account.username, ) # ------- first = g.players[first_index] g.emit_event('game_begin', g) for p in g.players: g.process_action(DrawCards(p, amount=3 if p is first else 4)) pl = g.players.rotate_to(first) for i, p in enumerate(cycle(pl)): if i >= 6000: break if not p.dead: g.emit_event('player_turn', p) try: g.process_action(PlayerTurn(p)) except InterruptActionFlow: pass return True
def apply_action(self): g = Game.getgame() params = self.params from thb.cards import Deck g.deck = Deck() g.ehclasses = [] # arrange identities --> g.double_curtain = params['double_curtain'] mapping = { 'B': Identity.TYPE.BOSS, '!': Identity.TYPE.ATTACKER, '&': Identity.TYPE.ACCOMPLICE, '?': Identity.TYPE.CURTAIN, } if g.double_curtain: identities = 'B!!!&&??' else: identities = 'B!!!!&&?' pl = g.players[:] identities = [mapping[i] for i in identities] g.identities = identities[:] imperial_identities = ImperialIdentity.get_chosen(self.items, pl) for p, i in imperial_identities: pl.remove(p) identities.remove(i) g.random.shuffle(identities) if Game.CLIENT_SIDE: identities = [Identity.TYPE.HIDDEN for _ in identities] for p, i in imperial_identities + zip(pl, identities): p.identity = Identity() p.identity.type = i g.process_action(RevealIdentity(p, p)) del identities is_boss = sync_primitive( [p.identity.type == Identity.TYPE.BOSS for p in g.players], g.players) boss_idx = is_boss.index(True) boss = g.boss = g.players[boss_idx] boss.identity = Identity() boss.identity.type = Identity.TYPE.BOSS g.process_action(RevealIdentity(boss, g.players)) # choose girls init --> from .characters import get_characters pl = g.players.rotate_to(boss) choices, _ = build_choices( g, self.items, candidates=get_characters('common', 'id', 'id8', '-boss'), players=[boss], num=[5], akaris=[1], shared=False, ) choices[boss][:0] = [CharChoice(cls) for cls in get_characters('boss')] with InputTransaction('ChooseGirl', [boss], mapping=choices) as trans: c = user_input([boss], ChooseGirlInputlet(g, choices), 30, 'single', trans) c = c or choices[boss][-1] c.chosen = boss c.akari = False g.players.reveal(c) trans.notify('girl_chosen', (boss, c)) chars = get_characters('common', 'id', 'id8') try: chars.remove(c.char_cls) except: pass # mix it in advance # so the others could see it boss = g.switch_character(boss, c.char_cls) # boss's hp bonus if g.n_persons > 5: boss.maxlife += 1 boss.life = boss.maxlife # choose boss dedicated skill g.process_action(ChooseBossSkillAction(boss, boss)) # reseat seed = get_seed_for(g.players) random.Random(seed).shuffle(g.players) g.emit_event('reseat', None) # others choose girls pl = g.players.exclude(boss) choices, _ = build_choices( g, self.items, candidates=chars, players=pl, num=[4] * len(pl), akaris=[1] * len(pl), shared=False, ) with InputTransaction('ChooseGirl', pl, mapping=choices) as trans: ilet = ChooseGirlInputlet(g, choices) ilet.with_post_process( lambda p, rst: trans.notify('girl_chosen', (p, rst)) or rst) result = user_input(pl, ilet, type='all', trans=trans) # mix char class with player --> for p in pl: c = result[p] or choices[p][-1] c.akari = False g.players.reveal(c) p = g.switch_character(p, c.char_cls) # ------- for p in g.players: log.info( u'>> Player: %s:%s %s', p.__class__.__name__, Identity.TYPE.rlookup(p.identity.type), p.account.username, ) # ------- g.emit_event('game_begin', g) for p in g.players: g.process_action(DistributeCards(p, amount=4)) for i, p in enumerate(cycle(g.players.rotate_to(boss))): if i >= 6000: break if not p.dead: try: g.process_action(PlayerTurn(p)) except InterruptActionFlow: pass return True