public static CardInstance FindIdenticalCardInSource(IList <CardInstance> source, CardInstance card, IList <CardInstance> exclusions = null, bool failureOkay = false) { if (exclusions == null) { exclusions = new List <CardInstance>(); } CardInstance res = null; var cs = card.ToString(); foreach (var c in source) { if (!exclusions.Contains(c) && c.ToString() == cs) { return(c); } } if (res == null) { if (failureOkay) { return(null); } throw new Exception("No card."); } return(res); }
public void Exhaust(CardInstance ci, EffectSet ef) { ci.OtherAction(Action.Exhaust, ef); //this has to somehow hook into relics that care about exhaust, and also player / monster statuses which care too. ExhaustCard?.Invoke(ef); ExhaustPile.Add(ci); }
/// <summary> /// after block is accounted. /// bool represents if they are still alive. /// For use by essence of steel status too. /// </summary> public bool ApplyDamage(int amount, EffectSet ef, CardInstance ci, List <string> history) { HP -= amount; //this is for any damage type. TakeDamage?.Invoke(ef, amount, ci); history.Add($"{Name} took {amount} dmg"); return(true); }
internal void BeforePlayingCard(CardInstance ci) { ///Todo this will be a problem with playing cards that have just been created. if (!Hand.Contains(ci)) { throw new Exception("playing card you don't have"); } Hand.Remove(ci); }
internal CardInstance Copy() { var ci = new CardInstance(Card, UpgradeCount); ci.PerTurnOverrideEnergyCost = PerTurnOverrideEnergyCost; ci.PerFightOverrideEnergyCost = PerFightOverrideEnergyCost; ci.OverrideExhaust = OverrideExhaust; return(ci); }
public void ExhaustFromHand(CardInstance ci, EffectSet ef, List <string> h) { if (ci == null) { return; } Hand.Remove(ci); Exhaust(ci, ef); h.Add($"Exhausted {ci}"); }
public override List <int> GetKeys(Deck d, CardInstance ci) { var res = new List <int>(); for (var ii = 0; ii < d.GetDrawPile.Count + 1; ii++) { res.Add(ii); } return(res); }
internal override void Play(EffectSet ef, Player player, IEnemy enemy, int upgradeCount, IList <CardInstance> targets = null, Deck deck = null, long?key = null) { var dmg = upgradeCount == 0 ? 21 : 28; ef.EnemyEffect.SetInitialDamage(dmg); ef.DeckEffect.Add((Deck d, List <string> h) => { var burn = new CardInstance(new Burn(), 0); d.AddToDiscardPile(burn); h.Add("Added burn to discard pile"); }); }
internal override void Play(EffectSet ef, Player player, IEnemy enemy, int upgradeCount, IList <CardInstance> targets = null, Deck deck = null, long?key = null) { var dmg = upgradeCount == 0 ? 7 : 10; ef.DeckEffect.Add((Deck d, List <string> h) => { var dazed = new CardInstance(new Dazed(), 0); var position = d.AddToRandomSpotInDrawPile(dazed, key); h.Add($"Reckless charge added dazed to draw position {position}"); }); ef.EnemyEffect.SetInitialDamage(dmg); }
internal override void Play(EffectSet ef, Player player, IEnemy enemy, int upgradeCount, IList <CardInstance> targets = null, Deck deck = null, long?key = null) { var dmg = upgradeCount == 0 ? 6 : 8; ef.EnemyEffect.SetInitialDamage(dmg); ef.DeckEffect.Add((Deck d, List <string> h) => { var copy = new CardInstance(this, upgradeCount); d.AddToDiscardPile(copy); h.Add("Duplicated Anger into discard pile"); }); }
/// <summary> /// add to hand if hand isn't too bigyet. /// </summary> private void TryAddToHand(CardInstance ci, EffectSet ef) { if (Hand.Count < 10) { Hand.Add(ci); DrawCard?.Invoke(ci, ef); } else { DiscardPile.Add(ci); } }
public static List <CardInstance> GetRandomCards(int ccount) { var ac = AllCards.Cards.Keys.ToList(); var cards = new List <CardInstance>(); for (var ii = 0; ii < ccount; ii++) { var card = AllCards.Cards[ac[Rnd.Next(ac.Count)]]; var ci = new CardInstance(card, Rnd.Next(2) == 1 ? 1 : 0); cards.Add(ci); } return(cards); }
public static CardInstance GetCi(string name) { var x = SplitCardName(name); var card = AllCards.Cards[x.Item1]; if (card == null) { throw new Exception("Missing card."); } var ci = new CardInstance(card, x.Item2); return(ci); }
/// <summary> /// Returns position key. /// </summary> internal long AddToRandomSpotInDrawPile(CardInstance ci, long?key = null) { long position; if (key == null) { position = Rnd.Next(DrawPile.Count + 1); } else { position = key.Value; } DrawPile.Insert((int)position, ci); return(position); }
/// <summary> /// Todo: Why do I manually use the components of the monster move ef rather than just using /// applyEffectSet? /// </summary> /// <param name="cardInstance"></param> /// <param name="history"></param> public void _Attack(CardInstance cardInstance, List <string> history) { var enemy = _Enemies[0]; var player = _Player; var ef = new EffectSet(); cardInstance.Play(ef, _Player, _Enemies[0]); _Player.NotifyAttacked(ef); foreach (var si in enemy.StatusInstances) { var statusIsTargeted = false; si.Apply(cardInstance.Card, ef.EnemyEffect, ef.PlayerEffect, statusIsTargeted, false); } foreach (var si in player.StatusInstances) { var statusIsTargeted = true; si.Apply(cardInstance.Card, ef.EnemyEffect, ef.PlayerEffect, statusIsTargeted, false); } //this won't be right for Torii for example. foreach (var relic in _Player.Relics) { relic.CardPlayed(cardInstance.Card, ef, player: _Player, enemy: _Enemies[0]); } GainBlock(_Player, ef.PlayerEffect, history); GainBlock(_Enemies[0], ef.EnemyEffect, history); ReceiveDamage(_Enemies[0], ef.EnemyEffect, ef, history, cardInstance); ReceiveDamage(_Player, ef.PlayerEffect, ef, history, cardInstance); ApplyStatus(_Player, ef.PlayerEffect.Status, history); ApplyStatus(_Enemies[0], ef.EnemyEffect.Status, history); //enemy dying of flame barrier status while killing the player, still results in a loss for the player. if (_Player.HP <= 0) { history.Add("Player Died from enemy attack"); Died(_Player, history); return; } if (_Enemies[0].HP <= 0) { history.Add("Enemy Died on his turn"); Died(_Enemies[0], history); } }
internal override void Play(EffectSet ef, Player player, IEnemy enemy, int upgradeCount, IList <CardInstance> targets = null, Deck deck = null, long?key = null) { //I need some way to: // * make sure the childnode from playing this ends up in the random list (not choices) // * distinguish between those random entries. ef.DeckEffect.Add((Deck d, List <string> h) => { var newCi = new CardInstance(new Wound(), 0); var position = d.AddToRandomSpotInDrawPile(newCi, key); h.Add($"Wound added to draw pile position:{position}"); }); var dmg = upgradeCount == 0 ? 12 : 17; ef.EnemyEffect.SetInitialDamage(dmg); ef.HadRandomness = true; ef.Key = key ?? 0; }
public static IList <CardInstance> GetCis(params string[] names) { var cis = new List <CardInstance>(); foreach (var name in names) { var x = SplitCardName(name); var card = AllCards.Cards[x.Item1]; if (card == null) { throw new Exception("Missing card."); } var ci = new CardInstance(card, x.Item2); cis.Add(ci); } return(cis); }
internal void EvolveCardDrawnEvent(CardInstance ci, EffectSet ef) { var si = Entity.StatusInstances.SingleOrDefault(el => el.Status.StatusType == StatusType.EvolveStatus); if (si == null) { return; } if (ci.Card.CardType == CardType.Curse || ci.Card.CardType == CardType.Status) { var newEf = new EffectSet(); newEf.DeckEffect.Add((Deck d, List <string> h) => { var drawn = d.DrawToHand(null, si.Intensity, true, null, newEf, h); h.Add($"{ci} Caused card draw: {string.Join(',', drawn)}"); }); ef.AddNextEf(newEf); } }
internal void AfterPlayingCard(CardInstance ci, EffectSet ef, List <string> history) { if (ci.Card.CardType == CardType.Power) { //card just disappears. } else { ci.LeavingHand(ef); if (ci.Exhausts()) { Exhaust(ci, ef); history.Add($"Exhausted {ci}"); } else { PutIntoDiscardAfterApplyingEffectSet = ci; } } }
/// <summary> /// When we generate an action, we check to see if it's already a duplicate (in randoms or choices). This is how we compare them. /// </summary> public bool IsEqual(FightAction other) { if (FightActionType != other.FightActionType) { return(false); } if (CardInstance?.ToString() != other.CardInstance?.ToString()) { return(false); } if (Potion?.Name != other.Potion?.Name) { return(false); } if (Target?.Name != other.Target?.Name) { return(false); } if (CardTargets != null && other.CardTargets == null) { return(false); } if (CardTargets == null && other.CardTargets != null) { return(false); } if (!Helpers.CompareHands(CardTargets, other.CardTargets, out var msg2)) { return(false); } //if (Key != other.Key) return false; //we do not compare key here because this is at the "choice" stage. if (Random != other.Random) { return(false); } return(true); }
public virtual List <int> GetKeys(Deck d, CardInstance ci) { throw new System.Exception("Can't call this upon non-random marked card."); }
internal void MoveFromDiscardToDraw(CardInstance headbuttTarget) { DiscardPile.Remove(headbuttTarget); DrawPile.Add(headbuttTarget); }
internal void AddToDiscardPile(CardInstance newCi) { //assuming we want to interleave it. DiscardPile.Add(newCi); }
/// <summary> /// an action in a fight is one of: /// * player play card /// * player drink pot /// * player end turn /// /// * enemy play card (enemyAttack) /// * enemy buff (or do nothing) /// * enemy playerStatusATtack /// </summary> public FightAction(FightActionEnum fightActionType, CardInstance card = null, IList <CardInstance> cardTargets = null, Potion potion = null, IEntity target = null, List <string> history = null, long?key = null, List <long> keys = null, bool hadRandomEffects = false, bool playable = true) { CardTargets = cardTargets; FightActionType = fightActionType; Potion = potion?.Copy(); CardInstance = card?.Copy(); Target = target; History = history; Keys = keys; Key = key; Random = hadRandomEffects; // For console view, whether it can actually be chosen/played. Playable = playable; switch (fightActionType) { case FightActionEnum.Potion: if (hadRandomEffects != potion.Random) { throw new Exception("Enemy moves always random."); } break; case FightActionEnum.PlayCard: if (hadRandomEffects && !card.Card.RandomEffects) { throw new Exception("Unexpected"); } //had => rE but RE !=> had since not every randomizable effect card will actually have an effect every time. break; case FightActionEnum.EndTurn: case FightActionEnum.StartTurnEffect: case FightActionEnum.EndTurnEffect: case FightActionEnum.EndTurnDeckEffect: case FightActionEnum.EndTurnOtherEffect: case FightActionEnum.StartFightEffect: case FightActionEnum.EndFightEffect: case FightActionEnum.EnemyDied: case FightActionEnum.EndEnemyTurn: case FightActionEnum.WonFight: case FightActionEnum.LostFight: case FightActionEnum.TooLong: case FightActionEnum.NotInitialized: case FightActionEnum.StartTurn: if (hadRandomEffects) { throw new Exception($"{fightActionType} is not random since deck was already shuffled."); } break; case FightActionEnum.StartFight: if (!hadRandomEffects) { throw new Exception($"StartFight should be random."); } break; case FightActionEnum.EnemyMove: if (!hadRandomEffects) { throw new Exception("Enemy moves always random."); } //I need a key to disambiguate the same actions. //i.e. if a monster has two choices that would be key 0 and key 1. //harder is to find a way to handle draws. ideally it'd be hand.GetHash() break; } Validate(); }
public static CardInstance Copy(CardInstance ci) { var newCi = new CardInstance(ci.Card, ci.UpgradeCount); return(newCi); }
internal bool DiscardPileContains(CardInstance headbuttTarget) { return(DiscardPile.Contains(headbuttTarget)); }
public void PlayCard(CardInstance ci, List <CardInstance> cardTargets = null, bool forceExhaust = false, bool newCard = false, IList <CardInstance> source = null) { var action = new FightAction(FightActionEnum.PlayCard, card: ci, cardTargets: cardTargets, hadRandomEffects: ci.Card.RandomEffects); PlayCard(action, forceExhaust: forceExhaust, newCard: newCard, source: source); }
private void ApplyEffectSet(EffectSet ef, Player player, IEnemy enemy, List <string> history, Potion potion = null, CardInstance ci = null, bool subEffectSet = false) { //TODO not clear if this order is the most sensible really or not. //complex effects like afterImage + playing defend with neg dex. //What happens if a deckeffect has further effects like exhausting a card, and the player has a status that triggers on this? //TODO this is complicated. Evolve actually adds new deckeffects in the deckeffect evaluation. foreach (var f in ef.DeckEffect) { f.Invoke(_Deck, history); } GainBlock(player, ef.PlayerEffect, history); ReceiveDamage(enemy, ef.EnemyEffect, ef, history, ci); GainBlock(enemy, ef.EnemyEffect, history); ReceiveDamage(player, ef.PlayerEffect, ef, history, ci); ApplyStatus(player, ef.PlayerEffect.Status, history); ApplyStatus(enemy, ef.EnemyEffect.Status, history); if (ef.PlayerEnergy != 0) { _Player.Energy += ef.PlayerEnergy; history.Add($"Gained ${ef.PlayerEnergy} to {_Player.Energy}"); } ef.FightEffect.ForEach(fe => fe.Action.Invoke(this, _Deck, history)); foreach (var en in _Enemies) { if (!en.Dead) { if (en.HP <= 0) { history.Add($"{en.Name} Died at {en.HP} HP"); Died(en, history); } } } if (_Player.HP <= 0) { if (!_Player.Dead) { history.Add("Player Died"); Died(_Player, history); } } if (!subEffectSet) { while (ef.NextEffectSet.Count > 0) { var next = ef.NextEffectSet.First(); ef.NextEffectSet.RemoveAt(0); ApplyEffectSet(next, player, enemy, history, potion, ci); } } }
private void ReceiveDamage(IEntity entity, IndividualEffect ie, EffectSet ef, List <string> history, CardInstance ci) { if (ie.GetInitialDamage() == null && ie.DamageAdjustments?.Count > 0) { throw new Exception("should not happen"); //Vuln will only add a progression if initialdamage != null } //We don't actually want to if (ie.GetInitialDamage() != null) { var val = ie.GetInitialDamage().Select(el => (double)el); foreach (var prog in ie.DamageAdjustments.OrderBy(el => el.Order)) { val = prog.Fun(val.ToList()); } var usingVal = val.Select(el => (int)Math.Floor(el)); history.Add($"{entity.Name} got attacked for {string.Join(',', usingVal)}"); foreach (var el in usingVal) { var elCopy = el; if (elCopy > 0) { //handle block here. if (entity.Block > 0) { if (elCopy > entity.Block) { elCopy = elCopy - entity.Block; history.Add($"{entity.Name} blocked {entity.Block}"); entity.Block = 0; } else { entity.Block -= el; history.Add($"{entity.Name} blocked {el}"); elCopy = 0; } } if (elCopy > 0) { entity.ApplyDamage(elCopy, ef, ci, history); } } } //history.Add($"{entity.Details()}"); } }