/// <summary> /// Activates the specified ability of the specified card. /// </summary> /// <param name="player">The owner player of the card that is activating the effect.</param> /// <param name="card">The card that is activating the effect.</param> /// <param name="abilityIndex">The index of the ability to activate.</param> /// <param name="targetInfo">The optional target information.</param> public void ActivateAbility(PlayerInfo player, RuntimeCard card, int abilityIndex, List <int> targetInfo = null) { var libraryCard = gameState.config.GetCard(card.cardId); var activatedAbilities = libraryCard.abilities.FindAll(x => x is ActivatedAbility); var activatedAbility = activatedAbilities[abilityIndex] as ActivatedAbility; if (activatedAbility.effect is PlayerEffect && AreTargetsAvailable(activatedAbility.effect, card, activatedAbility.target)) { var targets = GetPlayerTargets(player, activatedAbility.target, targetInfo); foreach (var t in targets) { (activatedAbility.effect as PlayerEffect).Resolve(gameState, t); } } else if (activatedAbility.effect is CardEffect && AreTargetsAvailable(activatedAbility.effect, card, activatedAbility.target)) { var cardEffect = activatedAbility.effect as CardEffect; var targets = GetCardTargets(player, card, activatedAbility.target, cardEffect.gameZoneId, cardEffect.cardTypeId, targetInfo); foreach (var t in targets) { (activatedAbility.effect as CardEffect).Resolve(gameState, t); } } else if (activatedAbility.effect is MoveCardEffect && AreTargetsAvailable(activatedAbility.effect, card, activatedAbility.target)) { var moveCardEffect = activatedAbility.effect as MoveCardEffect; var targets = GetCardTargets(player, card, activatedAbility.target, moveCardEffect.originGameZoneId, moveCardEffect.cardTypeId, targetInfo); foreach (var t in targets) { (activatedAbility.effect as MoveCardEffect).Resolve(gameState, t); } } }
public override void Resolve(GameState state, RuntimeCard card) { var originZone = state.config.gameZones.Find(x => x.id == originGameZoneId); var destinationZone = state.config.gameZones.Find(x => x.id == destinationGameZoneId); state.effectSolver.MoveCard(card.ownerPlayer.netId, card, originZone.name, destinationZone.name); }
public void FightCreature(RuntimeCard attackingCard, RuntimeCard attackedCard) { effectSolver.FightCreature(netId, attackingCard, attackedCard); var msg = new FightCreatureMessage(); msg.attackingPlayerNetId = netId; msg.attackingCardInstanceId = attackingCard.instanceId; msg.attackedCardInstanceId = attackedCard.instanceId; client.Send(NetworkProtocol.FightCreature, msg); }
/// <summary> /// Resolves the combat between the specified creatures. /// </summary> /// <param name="attackingPlayerNetId">The network identifier of the attacking player.</param> /// <param name="attackingCreature">The attacking creature.</param> /// <param name="attackedCreature">The attacked creature.</param> public void FightCreature(NetworkInstanceId attackingPlayerNetId, RuntimeCard attackingCreature, RuntimeCard attackedCreature) { var attackingPlayer = gameState.players.Find(x => x.netId == attackingPlayerNetId); var attackedPlayer = gameState.players.Find(x => x.netId != attackingPlayerNetId); if (attackingPlayer != null && attackedPlayer != null) { attackedCreature.namedStats["Life"].baseValue -= attackingCreature.namedStats["Attack"].effectiveValue; attackingCreature.namedStats["Life"].baseValue -= attackedCreature.namedStats["Attack"].effectiveValue; } }
/// <summary> /// Sets the triggers of the specified card. /// </summary> /// <param name="card">The card to set.</param> public void SetTriggers(RuntimeCard card) { foreach (var stat in card.stats) { stat.Value.onValueChanged += (oldValue, newValue) => { TriggerEffect <OnCardStatIncreasedTrigger>(card.ownerPlayer, card, x => { return(x.IsTrue(stat.Value, newValue, oldValue)); }); TriggerEffect <OnCardStatDecreasedTrigger>(card.ownerPlayer, card, x => { return(x.IsTrue(stat.Value, newValue, oldValue)); }); TriggerEffect <OnCardStatReachedValueTrigger>(card.ownerPlayer, card, x => { return(x.IsTrue(stat.Value, newValue, oldValue)); }); }; } }
/// <summary> /// Adds a card to this zone. /// </summary> /// <param name="card">The card to add.</param> public void AddCard(RuntimeCard card) { if (cards.Count < maxCards && !cards.Contains(card)) { cards.Add(card); _numCards += 1; if (onZoneChanged != null) { onZoneChanged(numCards); } if (onCardAdded != null) { onCardAdded(card); } } }
/// <summary> /// Removes a card from this zone. /// </summary> /// <param name="card">The card to remove.</param> public void RemoveCard(RuntimeCard card) { if (cards.Contains(card)) { cards.Remove(card); _numCards -= 1; if (onZoneChanged != null) { onZoneChanged(numCards); } if (onCardRemoved != null) { onCardRemoved(card); } } }
/// <summary> /// Sets the destroy conditions of the specified card. /// </summary> /// <param name="card">The card to set.</param> public void SetDestroyConditions(RuntimeCard card) { var cardType = card.cardType; foreach (var condition in cardType.destroyConditions) { if (condition is StatDestroyCardCondition) { var statCondition = condition as StatDestroyCardCondition; card.stats[statCondition.statId].onValueChanged += (oldValue, newValue) => { if (statCondition.IsTrue(card)) { MoveCard(card.ownerPlayer.netId, card, "Board", "Graveyard"); } }; } } }
/// <summary> /// Returns true if there are any targets available for this effect and false otherwise. /// </summary> /// <param name="state">The game's state.</param> /// <param name="sourceCard">The card containing the effect.</param> /// <param name="target">The target type of the effect.</param> /// <returns>True if there are any targets available for this effect; false otherwise.</returns> public override bool AreTargetsAvailable(GameState state, RuntimeCard sourceCard, Target target) { var players = new List <PlayerInfo>(); switch (target.GetTarget()) { case EffectTarget.Player: players.Add(sourceCard.ownerPlayer); break; case EffectTarget.Opponent: var opponent = state.players.Find(x => x != sourceCard.ownerPlayer); players.Add(opponent); break; case EffectTarget.TargetPlayer: case EffectTarget.RandomPlayer: case EffectTarget.AllPlayers: players.AddRange(state.players); break; default: break; } players.RemoveAll(x => { var conditionsFullfilled = true; var playerTarget = target as PlayerTargetBase; foreach (var condition in playerTarget.conditions) { if (!condition.IsTrue(x)) { conditionsFullfilled = false; break; } } return(!conditionsFullfilled); }); return(players.Count > 0); }
/// <summary> /// Triggers the triggered effects of the specified card. /// </summary> /// <typeparam name="T">The type of the trigger.</typeparam> /// <param name="player">The owner player of the card that is triggering the effect.</param> /// <param name="card">The card that is triggering the effect.</param> /// <param name="predicate">The predicate that needs to be satisfied in order to trigger the effect.</param> /// <param name="targetInfo">The optional target information.</param> public void TriggerEffect <T>(PlayerInfo player, RuntimeCard card, Predicate <T> predicate, List <int> targetInfo = null) where T : Trigger { var libraryCard = gameState.config.GetCard(card.cardId); var triggeredAbilities = libraryCard.abilities.FindAll(x => x is TriggeredAbility); foreach (var ability in triggeredAbilities) { var triggeredAbility = ability as TriggeredAbility; var trigger = triggeredAbility.trigger as T; if (trigger != null && predicate(trigger) == true) { if (triggeredAbility.effect is PlayerEffect && AreTargetsAvailable(triggeredAbility.effect, card, triggeredAbility.target)) { var targets = GetPlayerTargets(player, triggeredAbility.target, targetInfo); foreach (var t in targets) { (triggeredAbility.effect as PlayerEffect).Resolve(gameState, t); } } else if (triggeredAbility.effect is CardEffect && AreTargetsAvailable(triggeredAbility.effect, card, triggeredAbility.target)) { var cardEffect = triggeredAbility.effect as CardEffect; var targets = GetCardTargets(player, card, triggeredAbility.target, cardEffect.gameZoneId, cardEffect.cardTypeId, targetInfo); foreach (var t in targets) { (triggeredAbility.effect as CardEffect).Resolve(gameState, t); } } else if (triggeredAbility.effect is MoveCardEffect && AreTargetsAvailable(triggeredAbility.effect, card, triggeredAbility.target)) { var moveCardEffect = triggeredAbility.effect as MoveCardEffect; var targets = GetCardTargets(player, card, triggeredAbility.target, moveCardEffect.originGameZoneId, moveCardEffect.cardTypeId, targetInfo); foreach (var t in targets) { (triggeredAbility.effect as MoveCardEffect).Resolve(gameState, t); } } } } }
public static NetCard GetNetCard(RuntimeCard card) { var netCard = new NetCard(); netCard.cardId = card.cardId; netCard.instanceId = card.instanceId; var netStats = new List <NetStat>(card.stats.Count); foreach (var stat in card.stats) { netStats.Add(GetNetStat(stat.Value)); } netCard.stats = netStats.ToArray(); var netKeywords = new List <NetKeyword>(card.keywords.Count); foreach (var keyword in card.keywords) { netKeywords.Add(GetNetKeyword(keyword)); } netCard.keywords = netKeywords.ToArray(); return(netCard); }
/// <summary> /// Moves the specified card from the specified origin zone to the specified destination zone. /// </summary> /// <param name="playerNetId">The network identifier of the card's owner player.</param> /// <param name="card">The card to move.</param> /// <param name="originZone">The origin zone.</param> /// <param name="destinationZone">The destination zone.</param> /// <param name="targetInfo">The optional target information.</param> public void MoveCard(NetworkInstanceId playerNetId, RuntimeCard card, string originZone, string destinationZone, List <int> targetInfo = null) { var player = gameState.players.Find(x => x.netId == playerNetId); if (player != null) { player.namedZones[originZone].RemoveCard(card); player.namedZones[destinationZone].AddCard(card); TriggerEffect <OnCardLeftZoneTrigger>(player, card, x => { return(x.IsTrue(gameState, originZone)); }, targetInfo); TriggerEffect <OnCardEnteredZoneTrigger>(player, card, x => { return(x.IsTrue(gameState, destinationZone)); }, targetInfo); var libraryCard = gameState.config.GetCard(card.cardId); var cardType = gameState.config.cardTypes.Find(x => x.id == libraryCard.cardTypeId); if (cardType.moveAfterTriggeringEffect) { var finalDestinationZone = gameState.config.gameZones.Find(x => x.id == cardType.zoneId); // We do not use the MoveCards function here, because we do not want to trigger any effects // (which would cause an infinite recursion). player.namedZones[destinationZone].RemoveCard(card); player.namedZones[finalDestinationZone.name].AddCard(card); } } }
public static RuntimeCard GetRuntimeCard(NetCard netCard) { var runtimeCard = new RuntimeCard(); runtimeCard.cardId = netCard.cardId; runtimeCard.instanceId = netCard.instanceId; foreach (var stat in netCard.stats) { var runtimeStat = GetRuntimeStat(stat); runtimeCard.stats[stat.statId] = runtimeStat; var libraryCard = GameManager.Instance.config.GetCard(netCard.cardId); var statName = libraryCard.stats.Find(x => x.statId == stat.statId).name; runtimeCard.namedStats[statName] = runtimeStat; } var keywords = new List <RuntimeKeyword>(); foreach (var keyword in netCard.keywords) { keywords.Add(GetRuntimeKeyword(keyword)); } runtimeCard.keywords = keywords; return(runtimeCard); }
public void PlaySpellCard(RuntimeCard card, List <int> targetInfo = null) { var libraryCard = GameManager.Instance.config.GetCard(card.cardId); var cost = libraryCard.costs.Find(x => x is PayResourceCost); if (cost != null) { var payResourceCost = cost as PayResourceCost; var manaCost = payResourceCost.value; playerInfo.stats[payResourceCost.statId].baseValue -= manaCost; } var msg = new MoveCardMessage(); msg.playerNetId = netId; msg.cardInstanceId = card.instanceId; msg.originZoneId = playerInfo.namedZones["Hand"].zoneId; msg.destinationZoneId = playerInfo.namedZones["Board"].zoneId; if (targetInfo != null) { msg.targetInfo = targetInfo.ToArray(); } client.Send(NetworkProtocol.MoveCard, msg); }
/// <summary> /// Returns true if there are any targets available for this effect and false otherwise. /// </summary> /// <param name="state">The game's state.</param> /// <param name="sourceCard">The card containing the effect.</param> /// <param name="target">The target type of the effect.</param> /// <returns>True if there are any targets available for this effect; false otherwise.</returns> public override bool AreTargetsAvailable(GameState state, RuntimeCard sourceCard, Target target) { var cards = new List <RuntimeCard>(); switch (target.GetTarget()) { case EffectTarget.ThisCard: cards.Add(sourceCard); break; case EffectTarget.PlayerCard: case EffectTarget.AllPlayerCards: case EffectTarget.RandomPlayerCard: { foreach (var card in state.currentPlayer.zones[gameZoneId].cards) { cards.Add(card); } break; } case EffectTarget.OpponentCard: case EffectTarget.AllOpponentCards: case EffectTarget.RandomOpponentCard: { foreach (var card in state.currentOpponent.zones[gameZoneId].cards) { cards.Add(card); } break; } case EffectTarget.TargetCard: case EffectTarget.AllCards: case EffectTarget.RandomCard: { foreach (var card in state.currentPlayer.zones[gameZoneId].cards) { cards.Add(card); } foreach (var card in state.currentOpponent.zones[gameZoneId].cards) { cards.Add(card); } break; } case EffectTarget.PlayerOrPlayerCreature: case EffectTarget.OpponentOrOpponentCreature: case EffectTarget.AnyPlayerOrCreature: return(true); default: return(false); } cards.RemoveAll(x => x.cardType.id != cardTypeId); cards.RemoveAll(x => { var conditionsFullfilled = true; var cardTarget = target as CardTargetBase; foreach (var condition in cardTarget.conditions) { if (!condition.IsTrue(x)) { conditionsFullfilled = false; break; } } return(!conditionsFullfilled); }); return(cards.Count > 0); }
/// <summary> /// Resolves this effect on the specified card. /// </summary> /// <param name="state">The game's state.</param> /// <param name="player">The card on which to resolve this effect.</param> public virtual void Resolve(GameState state, RuntimeCard card) { }
/// <summary> /// Returns true if there are any targets available for this effect and false otherwise. /// </summary> /// <param name="state">The game's state.</param> /// <param name="sourceCard">The card containing the effect.</param> /// <param name="target">The target type of the effect.</param> /// <returns>True if there are any targets available for this effect; false otherwise.</returns> public virtual bool AreTargetsAvailable(GameState state, RuntimeCard sourceCard, Target target) { return(true); }
protected virtual void OnRegisterPlayer(NetworkMessage netMsg) { var msg = netMsg.ReadMessage <RegisterPlayerMessage>(); Assert.IsNotNull(msg); // If this player is already registered, ignore this message. var player = server.gameState.players.Find(x => x.netId == msg.netId); if (player != null) { return; } // Create a new player info for the registered player. player = new PlayerInfo(); player.id = server.gameState.players.Count; player.connectionId = netMsg.conn.connectionId; player.netId = msg.netId; player.nickname = msg.name; player.isConnected = true; player.isHuman = msg.isHuman; var gameConfig = GameManager.Instance.config; // Set the player stats based on the generic player definition. foreach (var stat in gameConfig.playerStats) { var statCopy = new Stat(); statCopy.name = stat.name; statCopy.statId = stat.id; statCopy.originalValue = stat.originalValue; statCopy.baseValue = stat.baseValue; statCopy.minValue = stat.minValue; statCopy.maxValue = stat.maxValue; player.stats[stat.id] = statCopy; player.namedStats[stat.name] = statCopy; } // Set the player zones based on the generic zone definitions. var personalZones = gameConfig.gameZones.FindAll(x => x.owner != ZoneOwner.Shared); foreach (var zone in personalZones) { var zoneCopy = new RuntimeZone(); zoneCopy.name = zone.name; zoneCopy.zoneId = zone.id; if (zone.hasMaxSize) { zoneCopy.maxCards = zone.maxSize; } else { zoneCopy.maxCards = int.MaxValue; } player.zones[zone.id] = zoneCopy; player.namedZones[zone.name] = zoneCopy; } foreach (var condition in gameConfig.properties.endGameConditions) { if (condition is PlayerStatEndGameCondition) { var playerStatCondition = condition as PlayerStatEndGameCondition; player.stats[playerStatCondition.statId].onValueChanged += (oldValue, newValue) => { if (playerStatCondition.IsTrue(player)) { server.EndGame(player, playerStatCondition.type); } }; } else if (condition is CardsInZoneEndGameCondition) { var cardsCondition = condition as CardsInZoneEndGameCondition; player.zones[cardsCondition.zoneId].onZoneChanged += value => { if (cardsCondition.IsTrue(player)) { server.EndGame(player, cardsCondition.type); } }; } } // Add the default deck. var deckZoneId = gameConfig.gameZones.Find(x => x.name == "Deck").id; var deck = player.zones[deckZoneId]; foreach (var id in msg.deck) { var card = new RuntimeCard(); card.cardId = id; card.instanceId = player.currentCardInstanceId++; card.ownerPlayer = player; // Copy stats. var libraryCard = gameConfig.GetCard(id); foreach (var stat in libraryCard.stats) { var statCopy = new Stat(); statCopy.statId = stat.statId; statCopy.name = stat.name; statCopy.originalValue = stat.originalValue; statCopy.baseValue = stat.baseValue; statCopy.minValue = stat.minValue; statCopy.maxValue = stat.maxValue; card.stats[stat.statId] = statCopy; card.namedStats[stat.name] = statCopy; } // Copy keywords. foreach (var keyword in libraryCard.keywords) { var keywordCopy = new RuntimeKeyword(); keywordCopy.keywordId = keyword.keywordId; keywordCopy.valueId = keyword.valueId; card.keywords.Add(keywordCopy); } deck.cards.Add(card); } // Add the new player to the server's list of players. server.gameState.players.Add(player); Logger.Log("Player with id " + player.id + " has joined the game."); // When the appropriate number of players is registered, the game can start. if (server.gameState.players.Count == 2) { server.StartGame(); } }
/// <summary> /// Returns true if there are any targets available for the specified effect and false otherwise. /// </summary> /// <param name="effect">The effect.</param> /// <param name="sourceCard">The card originating the effect.</param> /// <param name="target">The target.</param> /// <returns>True if there are any targets available for the specified effect; false otherwise.</returns> public bool AreTargetsAvailable(Effect effect, RuntimeCard sourceCard, Target target) { return(effect.AreTargetsAvailable(gameState, sourceCard, target)); }
/// <summary> /// Returns the actual card targets of the specified target. /// </summary> /// <param name="player">The current player.</param> /// <param name="sourceCard">The current card.</param> /// <param name="abilityTarget">The target.</param> /// <param name="gameZoneId">The game zone identifier.</param> /// <param name="cardTypeId">The card type.</param> /// <param name="targetInfo">The target information.</param> /// <returns>The actual card targets of the specified target.</returns> public List <RuntimeCard> GetCardTargets(PlayerInfo player, RuntimeCard sourceCard, Target abilityTarget, int gameZoneId, int cardTypeId, List <int> targetInfo) { var cardTargets = new List <RuntimeCard>(); var opponent = gameState.players.Find(x => x != player); var target = abilityTarget.GetTarget(); var effectZone = gameZoneId; var effectCardType = cardTypeId; var zoneId = (targetInfo != null && targetInfo.Count > 0) ? targetInfo[0] : effectZone; switch (target) { case EffectTarget.ThisCard: cardTargets.Add(sourceCard); break; case EffectTarget.PlayerCard: { var card = player.GetCard(targetInfo[1], zoneId); cardTargets.Add(card); } break; case EffectTarget.OpponentCard: { var card = opponent.GetCard(targetInfo[1], zoneId); cardTargets.Add(card); } break; case EffectTarget.TargetCard: { var card = player.GetCard(targetInfo[1], zoneId); if (card == null) { card = opponent.GetCard(targetInfo[1], zoneId); } cardTargets.Add(card); } break; case EffectTarget.RandomPlayerCard: { cardTargets.AddRange(player.zones[zoneId].cards); cardTargets.RemoveAll(x => x.cardType.id != effectCardType); var card = cardTargets[GetRandomNumber(cardTargets.Count)]; cardTargets.RemoveAll(x => x != card); } break; case EffectTarget.RandomOpponentCard: { cardTargets.AddRange(opponent.zones[zoneId].cards); cardTargets.RemoveAll(x => x.cardType.id != effectCardType); var card = cardTargets[GetRandomNumber(cardTargets.Count)]; cardTargets.RemoveAll(x => x != card); } break; case EffectTarget.RandomCard: { cardTargets.AddRange(player.zones[zoneId].cards); cardTargets.AddRange(opponent.zones[zoneId].cards); cardTargets.RemoveAll(x => x.cardType.id != effectCardType); var card = cardTargets[GetRandomNumber(cardTargets.Count)]; cardTargets.RemoveAll(x => x != card); } break; case EffectTarget.AllPlayerCards: cardTargets.AddRange(player.zones[zoneId].cards); cardTargets.RemoveAll(x => x.cardType.id != effectCardType); break; case EffectTarget.AllOpponentCards: cardTargets.AddRange(opponent.zones[zoneId].cards); cardTargets.RemoveAll(x => x.cardType.id != effectCardType); break; case EffectTarget.AllCards: cardTargets.AddRange(player.zones[zoneId].cards); cardTargets.AddRange(opponent.zones[zoneId].cards); cardTargets.RemoveAll(x => x.cardType.id != effectCardType); break; default: break; } cardTargets.RemoveAll(x => { var conditionsFullfilled = true; var cardTarget = abilityTarget as CardTargetBase; foreach (var condition in cardTarget.conditions) { if (!condition.IsTrue(x)) { conditionsFullfilled = false; break; } } return(!conditionsFullfilled); }); return(cardTargets); }