public async Task <bool> tryUse(THHGame game, Card card, int position, params Card[] targets) { if (!card.isUsable(game, this, out _)) { return(false); } card.setUsed(true); await setGem(game, gem - card.getCost()); await game.triggers.doEvent(new UseEventArg() { player = this, card = card, position = position, targets = targets }, async arg => { THHPlayer player = arg.player; card = arg.card; targets = arg.targets; game.logger.log(arg.player + "使用" + arg.card + (targets.Length > 0 ? ",目标:" + string.Join <Card>(",", targets) : null)); if (arg.card.define is ServantCardDefine || (card.define is GeneratedCardDefine && (card.define as GeneratedCardDefine).type == CardDefineType.SERVANT)) { //随从卡,将卡置入战场 await tryPutIntoField(game, arg.player.hand, arg.card, arg.position); IEffect effect = arg.card.define.getEffectOn <ActiveEventArg>(game.triggers); if (effect != null) { ActiveEventArg active = new ActiveEventArg(player, card, targets); await game.triggers.doEvent(active, activeLogic); async Task activeLogic(ActiveEventArg eventArg) { await effect.execute(game, player, card, new object[] { eventArg }, targets); } } //IEffect effect = arg.card.define.getEffectOn<BattleCryEventArg>(game.triggers); //if (effect != null) //{ // await game.triggers.doEvent(new BattleCryEventArg() { player = arg.player, card = arg.card, effect = effect, targets = arg.targets }, arg2 => // { // return arg2.effect.execute(game, arg2.player, arg2.card, new object[] { arg2 }, arg2.targets); // }); //} } else if (card.define is SkillCardDefine) { IEffect effect = arg.card.define.getEffectOn <ActiveEventArg>(game.triggers); await effect.execute(game, arg.player, arg.card, new object[] { new ActiveEventArg(player, card, targets) }, arg.targets); } else if (card.define is SpellCardDefine || (card.define is GeneratedCardDefine && (card.define as GeneratedCardDefine).type == CardDefineType.SPELL)) { //法术卡,释放效果然后丢进墓地 player.hand.remove(game, card); IEffect effect = arg.card.define.getEffectOn <ActiveEventArg>(game.triggers); await effect.execute(game, player, card, new object[] { new ActiveEventArg(player, card, targets) }, targets); player.grave.add(game, card); } }); await game.updateDeath(); return(true); }
async Task turnStart(THHPlayer player) { if (cts == null || cts.IsCancellationRequested) { return; } await triggers.doEvent(new TurnStartEventArg() { player = player }, async arg => { logger.log("Debug", arg.player + "的回合开始"); //玩家的最大能量加1但是不超过10,充满玩家的能量。 await arg.player.setMaxGem(this, arg.player.maxGem + 1); await arg.player.setGem(this, arg.player.maxGem); //抽一张牌 await arg.player.draw(this); //重置技能 player.skill.setUsed(false); //使随从可以攻击 foreach (Card card in player.field) { card.setReady(true); card.setAttackTimes(0); } }); }
/// <summary> /// 这个角色能否对目标进行攻击? /// </summary> /// <param name="card"></param> /// <param name="game"></param> /// <param name="player"></param> /// <param name="target"></param> /// <returns></returns> public static bool isAttackable(this Card card, THHGame game, THHPlayer player, Card target, out string tip) { if (target == player.master || player.field.Contains(target)) { tip = "你不能攻击友方角色"; return(false); } if (target.getCurrentLife(game) <= 0) { tip = "目标随从已经死亡"; return(false); } if (game.getOpponent(player).field.Any(c => c.isTaunt(game)) && !target.isTaunt(game)) { tip = "你必须先攻击具有嘲讽的随从"; return(false); } if (card.isRush(game) && !card.isReady(game) && game.players.Any(p => p.master == target) && !card.isCharge(game)) { tip = "具有突袭的随从在没有准备好的情况下不能攻击敌方英雄";//除非你具有冲锋 return(false); } if (target.isStealth(game)) { tip = "无法攻击潜行的目标"; return(false); } tip = null; return(true); }
async Task turnStart(THHPlayer player) { if (!isRunning) { return; } await triggers.doEvent(new TurnStartEventArg() { player = player }, async arg => { logger.log("Debug", arg.player + "的回合开始"); //玩家的最大能量加1但是不超过10,充满玩家的能量。 await arg.player.setMaxGem(this, arg.player.maxGem + 1); await arg.player.setGem(this, arg.player.maxGem); //抽一张牌 await arg.player.draw(this); //重置技能 player.skill.setUsed(false); //使随从可以攻击 foreach (Card card in player.field) { card.setReady(true); card.setAttackTimes(0); } }); //倒计时75秒 turnTimer = time.startTimer(option.timeoutForTurn); turnTimer.onExpired += onTurnTimeout; }
public static async Task <bool> tryAttack(this Card card, THHGame game, THHPlayer player, Card target) { if (!card.canAttack(game, player)) { game.logger.log(card + "无法进行攻击"); return(false); } if (!card.isAttackable(game, player, target, out var reason)) { game.logger.log(card + "无法攻击" + target + ",因为" + reason); return(false); } await game.triggers.doEvent(new AttackEventArg() { card = card, target = target }, async arg => { game.logger.log(arg.card + "攻击" + arg.target); arg.card.setAttackTimes(arg.card.getAttackTimes() + 1); if (arg.card.getAttack() > 0) { await arg.target.damage(game, arg.card.getAttack()); } if (arg.target.getAttack() > 0) { await arg.card.damage(game, arg.target.getAttack()); } }); await game.updateDeath(); return(true); }
private async Task gameflow() { await init(); Dictionary <int, IResponse> initReplaceResponses = await answers.askAll(sortedPlayers.Select(p => p.id).ToArray(), new InitReplaceRequest() { }, option.timeoutForInitReplace); foreach (var result in initReplaceResponses) { THHPlayer player = getPlayer(result.Key); await player.initReplace(this, getCards((result.Value as InitReplaceResponse).cardsId)); } await start(); currentPlayer = sortedPlayers[0]; for (int i = 0; i < 100; i++) { await turnStart(currentPlayer); await turnLoop(currentPlayer); await turnEnd(currentPlayer); currentPlayer = getPlayerForNextTurn(currentPlayer); } await gameEnd(new THHPlayer[0]); }
public async Task turnEnd(THHPlayer player) { if (!isRunning) { return; } await triggers.doEvent(new TurnEndEventArg() { player = player }, arg => { logger.log("Debug", currentPlayer + "回合结束"); foreach (Card servant in arg.player.field) { if (servant.isFreeze(this)) { servant.setAttackTimes(servant.getAttackTimes(this) + 1); if (servant.getMaxAttackTimes() - servant.getAttackTimes(this) >= 0) { logger.log("被冻结的随从解除冰冻"); servant.setFreeze(false); } } } answers.cancel(answers.getRequests(player.id)); return(Task.CompletedTask); }); time.cancel(turnTimer); turnTimer = null; }
async Task turnLoop(THHPlayer player) { if (cts == null || cts.IsCancellationRequested) { return; } for (int i = 0; i < 100; i++) { if (cts == null || cts.IsCancellationRequested) { return; } switch (await answers.ask(player.id, new FreeActRequest(), option.timeout)) { case UseResponse use: Card card = getCard(use.cardId); Card[] targets = getCards(use.targetsId); if (!await player.tryUse(this, card, use.position, targets)) { logger.log("Warning", "使用" + card + "失败"); } break; case AttackResponse attack: card = getCard(attack.cardId); Card target = getCard(attack.targetId); await card.tryAttack(this, target); break; case TurnEndResponse _: return; } } }
public async Task <bool> createToken(THHGame game, CardDefine define, int position) { if (game == null) { throw new ArgumentNullException(nameof(game)); } if (define == null) { throw new ArgumentNullException(nameof(define)); } if (field.count >= field.maxCount) { return(false); } await game.triggers.doEvent(new CreateTokenEventArg() { player = this, define = define, position = position }, async arg => { THHPlayer player = arg.player; define = arg.define; position = arg.position; if (field.count >= field.maxCount) { return; } game.logger.log(player + "召唤" + define.GetType().Name + "位于" + position); arg.card = game.createCard(define); await tryPutIntoField(game, null, arg.card, position); }); return(true); }
public Task draw(THHGame game, Card card) { if (!deck.Contains(card)) { return(Task.CompletedTask); } if (hand.count >= hand.maxCount) { return(game.triggers.doEvent(new BurnEventArg() { player = this, card = card }, arg => { card = arg.card; arg.player.deck.moveTo(game, card, arg.player.grave, arg.player.grave.count); game.logger.log(arg.player + "的手牌已经满了," + card + "被送入墓地"); return Task.CompletedTask; })); } else { return(game.triggers.doEvent(new DrawEventArg() { player = this, card = card }, async arg => { THHPlayer player = arg.player; card = arg.card; if (card.define is SpellCardDefine spell && card.getProp <bool>(game, Keyword.AUTOCAST)) { await player.deck.moveTo(game, card, player.warp); await card.activeEffect(game, player, new Card[0]); await player.warp.moveTo(game, card, player.grave); }
public static bool isUsable(this Card card, THHGame game, THHPlayer player, out string info) { if (game.currentPlayer != player)//不是你的回合 { info = "这不是你的回合"; return(false); } if (card.define is ServantCardDefine servant) { if (player.gem < card.getCost())//费用不够 { info = "你没有足够的法力值"; return(false); } if (player.field.count >= player.field.maxCount) { info = "你无法将更多的随从置入战场"; return(false); } } else if (card.define is SpellCardDefine spell) { if (player.gem < card.getCost()) { info = "你没有足够的法力值"; return(false); } } else if (card.define is SkillCardDefine skill) { if (card.isUsed())//已经用过了 { info = "你已经使用过技能了"; return(false); } if (player.gem < card.getCost())//费用不够 { info = "你没有足够的法力值"; return(false); } if (card.define.getEffectOn <THHPlayer.ActiveEventArg>(game.triggers) is IEffect effect && !effect.checkCondition(game, null, card, new object[] { new THHPlayer.ActiveEventArg(player, card, new object[0]) })) { info = "技能不可用"; return(false); } } else { info = "这是一张未知的卡牌"; return(false);//不知道是什么卡 } info = null; return(true); }
/// <summary> /// /// </summary> /// <param name="id"></param> /// <param name="name"></param> /// <param name="master"></param> /// <param name="deck">注意,牌库的第一张是牌库的底端</param> /// <returns></returns> public THHPlayer createPlayer(int id, string name, MasterCardDefine master, IEnumerable <CardDefine> deck) { if (players.Any(p => p.id == id)) { throw new ArgumentException("已经存在ID为" + id + "的玩家"); } THHPlayer player = new THHPlayer(this, id, name, master, deck); addPlayer(player); return(player); }
internal async Task init() { if (!isRunning) { return; } await triggers.doEvent(new InitEventArg(), arg => { //决定玩家行动顺序 if (option.sortedPlayers == null || option.sortedPlayers.Length != players.Length) { if (option.sortedPlayers != null && option.sortedPlayers.Length != players.Length) { logger?.log("Warning", "游戏参数玩家行动顺序长度与实际数量不匹配"); } List <THHPlayer> remainedList = new List <THHPlayer>(players); THHPlayer[] sortedPlayers = new THHPlayer[remainedList.Count]; for (int i = 0; i < sortedPlayers.Length; i++) { int index = randomInt(0, remainedList.Count - 1); sortedPlayers[i] = remainedList[index]; remainedList.RemoveAt(index); } this.sortedPlayers = sortedPlayers; } else { this.sortedPlayers = option.sortedPlayers.Select(id => players.FirstOrDefault(p => p.id == id)).ToArray(); } //创建主人公和技能卡 Card[] masterCards = sortedPlayers.Select(p => { return(p.master); }).ToArray(); foreach (Card card in masterCards) { card.setCurrentLife(30); } //洗牌,然后抽初始卡牌 for (int i = 0; i < sortedPlayers.Length; i++) { if (option.shuffle) { sortedPlayers[i].deck.shuffle(this); } int count = i == 0 ? 3 : 4; var cards = sortedPlayers[i].deck[sortedPlayers[i].deck.count - count, sortedPlayers[i].deck.count - 1].Reverse(); sortedPlayers[i].deck.moveTo(this, cards, sortedPlayers[i].init, 0); } logger.log("Debug", "游戏初始化,玩家行动顺序:" + string.Join("、", sortedPlayers.Select(p => p.ToString())) + "," + "初始卡牌:" + string.Join(";", sortedPlayers.Select(p => string.Join("、", p.init.Select(c => c.ToString()))))); return(Task.CompletedTask); }); }
public static async Task activeEffect(this Card card, THHGame game, THHPlayer player, Card[] targets) { ITriggerEffect triggerEffect = card.define.getEffectOn <THHPlayer.ActiveEventArg>(game.triggers); if (triggerEffect != null) { await triggerEffect.execute(game, card, new object[] { new THHPlayer.ActiveEventArg(player, card, targets) }, targets); } IActiveEffect activeEffect = card.define.getActiveEffect(); if (activeEffect != null) { await activeEffect.execute(game, card, new object[] { new THHPlayer.ActiveEventArg(player, card, targets) }, targets); } }
public async Task turnEnd(THHPlayer player) { if (cts == null || cts.IsCancellationRequested) { return; } await triggers.doEvent(new TurnEndEventArg() { player = player }, arg => { logger.log("Debug", currentPlayer + "回合结束"); return(Task.CompletedTask); }); }
/// <summary> /// 获取下一个行动的玩家。 /// </summary> /// <param name="lastPlayer"></param> /// <returns></returns> public THHPlayer getPlayerForNextTurn(THHPlayer lastPlayer) { int index = Array.IndexOf(sortedPlayers, lastPlayer); if (index < 0) { throw new IndexOutOfRangeException(lastPlayer + "不在玩家行动队列中"); } index++; if (index >= sortedPlayers.Length) { index = 0; } return(sortedPlayers[index]); }
/// <summary> /// 这个角色能否对目标进行攻击? /// </summary> /// <param name="card"></param> /// <param name="game"></param> /// <param name="player"></param> /// <param name="target"></param> /// <returns></returns> public static bool isAttackable(this Card card, THHGame game, THHPlayer player, Card target, out string tip) { if (target == player.master || player.field.Contains(target)) { tip = "你不能攻击友方角色"; return(false); } if (game.getOpponent(player).field.Any(c => c.isTaunt()) && !target.isTaunt()) { tip = "你必须先攻击具有嘲讽的随从"; return(false); } tip = null; return(true); }
async Task turnLoop(THHPlayer player) { if (!isRunning) { return; } for (int i = 0; i < 100; i++) { if (!isRunning) { return; } if (turnTimer == null)//超时,结束回合 { return; } IResponse response = await answers.ask(player.id, new FreeActRequest(), option.timeoutForTurn * 2); switch (response) { case UseResponse use: Card card = getCard(use.cardId); Card[] targets = getCards(use.targetsId); if (!await player.tryUse(this, card, use.position, targets)) { logger.log("Warning", "使用" + card + "失败"); } break; case AttackResponse attack: card = getCard(attack.cardId); Card target = getCard(attack.targetId); await card.tryAttack(this, player, target); break; case TurnEndResponse _: return; case SurrenderResponse _: await this.surrender(player); return; } } }
public async Task turnEnd(THHPlayer player) { if (!isRunning) { return; } await triggers.doEvent(new TurnEndEventArg() { player = player }, arg => { logger.log("Debug", currentPlayer + "回合结束"); return(Task.CompletedTask); }); time.cancel(turnTimer); turnTimer = null; }
public async Task <bool> tryPutIntoField(THHGame game, Pile from, Card card, int position) { if (field.count >= field.maxCount)//没位置了 { return(false); } await game.triggers.doEvent(new MoveEventArg() { player = this, from = from, card = card, position = position }, logic); Task logic(MoveEventArg arg) { THHPlayer player = arg.player; from = arg.from; card = arg.card; position = arg.position; if (from != null) { game.logger.log(arg.player + "将" + arg.card + "从" + arg.from + "置入战场,位于" + arg.position); } else { game.logger.log(arg.player + "将" + arg.card + "置入战场,位于" + arg.position); } if (from != null) { from.moveTo(game, arg.card, arg.player.field, arg.position); } else { player.field.insert(game, card, position); } if (card.define is ServantCardDefine servant) { card.setCurrentLife(servant.life); card.setReady(false); } return(Task.CompletedTask); } return(true); }
/// <summary> /// 这个角色能否进行攻击? /// </summary> /// <param name="card"></param> /// <returns></returns> public static bool canAttack(this Card card, THHGame game, THHPlayer player) { if (card.getAttack() <= 0)//没有攻击力 { return(false); } if (!card.isReady() &&//还没准备好 !card.isCharge() &&//且没有冲锋 !(card.isRush() && game.getOpponent(player).field.Any(c => card.isAttackable(game, player, c, out _))) //且并非有突袭且有可以攻击的敌方随从 ) { return(false); } if (card.getAttackTimes() >= card.getMaxAttackTimes())//已经攻击过了 { return(false); } return(true); }
public static async Task die(this IEnumerable <Card> cards, THHGame game, Dictionary <Card, DeathEventArg.Info> infoDic) { List <THHPlayer> remainPlayerList = new List <THHPlayer>(game.players); await game.triggers.doEvent(new DeathEventArg() { infoDic = infoDic }, arg => { infoDic = arg.infoDic; foreach (var pair in infoDic) { Card card = pair.Key; if (!game.players.Any(p => p.field.Contains(card) || p.master == card)) { continue; } THHPlayer player = game.players.FirstOrDefault(p => p.master == card); if (player != null) { remainPlayerList.Remove(player); game.logger.log(player + "失败"); } else { pair.Value.player.field.moveTo(game, card, pair.Value.player.grave); game.logger.log(card + "阵亡"); } } return(Task.CompletedTask); }); if (remainPlayerList.Count != game.players.Length) { if (remainPlayerList.Count > 0) { await game.gameEnd(remainPlayerList.ToArray()); } else { await game.gameEnd(new THHPlayer[0]); } } }
private async Task gameflow(Action onInited = null) { await init(); Task <Dictionary <int, IResponse> > task = answers.askAll(sortedPlayers.Select(p => p.id).ToArray(), new InitReplaceRequest() { }, option.timeoutForInitReplace); onInited?.Invoke(); Dictionary <int, IResponse> initReplaceResponses = await task; if (!isRunning) { return; } foreach (var result in initReplaceResponses) { THHPlayer player = getPlayer(result.Key); if (result.Value is InitReplaceResponse initReplace) { await player.initReplace(this, getCards(initReplace.cardsId)); } else if (result.Value is SurrenderResponse surrender) { await this.surrender(player); } } await start(); currentPlayer = sortedPlayers[0]; for (int i = 0; i < 100; i++) { await turnStart(currentPlayer); await turnLoop(currentPlayer); await turnEnd(currentPlayer); currentPlayer = getPlayerForNextTurn(currentPlayer); } await gameEnd(new THHPlayer[0]); }
public async Task leave(THHPlayer player) { await player.master.die(this); }
internal Task surrender(THHPlayer player) { logger.log(player + "投降"); return(player.master.die(this)); }
public static async Task <bool> tryAttack(this Card card, THHGame game, THHPlayer player, Card target) { if (!card.canAttack(game)) { game.logger.log(card + "无法进行攻击"); return(false); } if (!card.isAttackable(game, player, target, out var reason)) { game.logger.log(card + "无法攻击" + target + ",因为" + reason); return(false); } await game.triggers.doEvent(new AttackEventArg() { card = card, target = target }, async arg => { game.logger.log(arg.card + "攻击" + arg.target); arg.card.setAttackTimes(arg.card.getAttackTimes() + 1); if (arg.card.getAttack() > 0) { await arg.target.damage(game, arg.card, arg.card.getAttack()); } if (arg.target.getAttack() > 0) { await arg.card.damage(game, arg.target, arg.target.getAttack()); } if (arg.card.isDrain()) { await player.master.heal(game, arg.card.getAttack()); } if (arg.target.isDrain()) { await(arg.target.owner as THHPlayer).master.heal(game, arg.target.getAttack()); } if (arg.card.isPoisonous() && arg.target.owner != null) { DamageEventArg damage = game.triggers.getRecordedEvents().LastOrDefault(e => e is THHCard.DamageEventArg) as THHCard.DamageEventArg; //剧毒角色造成伤害后,对方死亡 if (damage.value > 0) { await arg.target.die(game, new DeathEventArg.Info() { card = target, player = (THHPlayer)arg.target.owner, position = player.field.indexOf(card) }); } } if (arg.target.isPoisonous() && arg.card != player.master) { DamageEventArg damage = game.triggers.getRecordedEvents().LastOrDefault(e => e is THHCard.DamageEventArg) as THHCard.DamageEventArg; if (damage.value > 0) { await arg.card.die(game, new DeathEventArg.Info() { card = card, player = player, position = player.field.indexOf(card) }); } } }); await game.updateDeath(); return(true); }
/// <summary> /// 获取玩家的对手。 /// </summary> /// <param name="player"></param> /// <returns></returns> public THHPlayer getOpponent(THHPlayer player) { return(players.FirstOrDefault(p => p != player)); }
public Card[] getAllEnemies(THHPlayer player) { THHPlayer opponent = getOpponent(player); return(opponent.field.Concat(new Card[] { opponent.master }).ToArray()); }
public ActiveEventArg(THHPlayer player, Card card, object[] targets) { this.player = player; this.card = card; this.targets = targets; }