public static CardTags GetCardTags(CardDescription cardDesc) { CardTags tags = GetCardTagsFromCardType(cardDesc.cardType); tags |= GetCardTagsFromManaCost(cardDesc.manaCost); switch (cardDesc.cardType) { case CardType.CREATURE: CreatureCardDescription creatureDesc = cardDesc as CreatureCardDescription; tags |= GetCardTagsFromCreatureType(creatureDesc.creatureType); foreach (KeywordAttribute keywords in creatureDesc.GetAttributes()) { tags |= GetCardTagsFromKeywordAttributes(keywords); } break; case CardType.SPELL: case CardType.TRAP: foreach (CardEffectDescription effect in cardDesc.cardEffects) { if (effect.GetAlignment() == Alignment.POSITIVE) { tags |= GetCardTagsFromTargetType(effect.targettingType); } } break; } return(tags); }
static private CardDescription GenerateCreatureCard(System.Random random, IHistogram model, ImageGlossary images, CreatureModelIndex creatureModels, NameModel nameModel, CardGenerationFlags flags) { CreatureCardDescription card = ScriptableObject.CreateInstance(typeof(CreatureCardDescription)) as CreatureCardDescription; card.creatureType = ProceduralUtils.GetRandomValue <CreatureType>(random, model); if ((flags & CardGenerationFlags.HUMAN) == CardGenerationFlags.HUMAN) { card.creatureType = CreatureType.HUMAN; } else if ((flags & CardGenerationFlags.GOBLIN) == CardGenerationFlags.GOBLIN) { card.creatureType = CreatureType.GOBLIN; } else if ((flags & CardGenerationFlags.FAERIE) == CardGenerationFlags.FAERIE) { card.creatureType = CreatureType.FAERIE; } MultiCardHistogram combinedModel = ScriptableObject.CreateInstance(typeof(MultiCardHistogram)) as MultiCardHistogram; combinedModel.Init(new IHistogram[] { model, creatureModels.GetModel(card.creatureType) }); card.manaCost = (int)ProceduralUtils.GetRandomValue <ManaCost>(random, model); // Potentially generate a stronger body, but with a drawback double bodyManaCost = GetCreatureBodyBudget(creatureModels.GetBodyLambda(card.creatureType), random.Next(), card.manaCost + 1); int maxStats = PowerBudget.StatBudget(bodyManaCost); // Decide on stats card.health = GetHealth(random, creatureModels.GetStatProbability(card.creatureType, (int)Math.Round(bodyManaCost, MidpointRounding.AwayFromZero)), maxStats); card.attack = maxStats - card.health; // Decide on power budget double powerBudget = PowerBudget.ManaPowerBudgets[card.manaCost]; double powerMargin = PowerBudget.ManaPowerMargin[card.manaCost]; double powerLimit = PowerBudget.ManaPowerLimit[card.manaCost]; card.cardName = "A creature card"; //card.name += "(" + powerBudget.ToString() + ")"; // Decide on keyword attributes int maxKeywords = 3; for (int i = 0; i < maxKeywords; i++) { double keywordPowerLimit = powerLimit - card.PowerLevel(); if (keywordPowerLimit < 0) { keywordPowerLimit = 0; } KeywordAttribute keyword = ProceduralUtils.GetRandomValue(random, combinedModel, ProceduralUtils.GetKeywordsWithinBudget(keywordPowerLimit, card.attack, card.health)); if (keyword == KeywordAttribute.NONE) { break; } card.AddAttribute(keyword); } // Decide on effects GenerateCardEffects(random, combinedModel, creatureModels, card, powerBudget, powerMargin, powerLimit); // Revise the mana cost based on what effects we actually did generate int revisedMana = PowerBudget.PowerLevelToMana(card.PowerLevel()); if (revisedMana != card.manaCost) { Debug.Log("Had to revise the mana cost from " + card.manaCost.ToString() + " to " + revisedMana.ToString()); card.manaCost = revisedMana; } card.image = ProceduralUtils.GetRandomTexture(random, images.GetCreatureImages(card.creatureType)); CardTags tags = CardTagging.GetCardTags(card); card.cardName = nameModel.GenerateName(random, tags); return(card); }
public static double GetTriggerModifier(TriggerCondition trigger, CardDescription card) { switch (trigger) { // Can happen repeatedly and can make decisions very difficult for opponent case TriggerCondition.ON_CREATURE_DIES: return((card is CreatureCardDescription) ? 2.5 : 1.0); // Should occur very frequently, and creature entering is very hard for opponent to play around // Entering is more threatening than dying case TriggerCondition.ON_CREATURE_ENTER: return((card is CreatureCardDescription) ? 3 : 1.0); // Worse than on enter, on self enter is like a spell so its the baseline for an effects strength case TriggerCondition.ON_SELF_DIES: return(0.9); // Very good on bodies with good offensive keywords case TriggerCondition.ON_SELF_DAMAGE_DEALT_TO_PLAYER: { CreatureCardDescription creatureCard = card as CreatureCardDescription; // Base is worse than a mostly guarenteed trigger like on dies // Gets better the easier it is to inflict player damage // Much weaker with a 0 power creature, because you require another card or effect to help double multiplier = (creatureCard.attack == 0) ? 0.25 : 0.5; if (creatureCard.HasKeywordAttribute(KeywordAttribute.EVASION)) { // Evasion is the strongest offensive keyword multiplier += (creatureCard.attack == 0) ? 0.5 : 1; } if (creatureCard.HasKeywordAttribute(KeywordAttribute.PIERCING)) { // Piercing depends on how good the body is, for now we'll say the average blocker has 4 toughness, // So you get the max effectiveness from piercing at 5 attack multiplier += 0.5 * Math.Min(5, creatureCard.attack) / 5; } if (creatureCard.HasKeywordAttribute(KeywordAttribute.FAST_STRIKE)) { // Fast strike is less appealing to block with high power, like piercing but will not get damage through // a blocker only deter opponent from blocking so cap is smaller multiplier += 0.25 * Math.Min(5, creatureCard.attack) / 5; } if (creatureCard.HasKeywordAttribute(KeywordAttribute.EAGER)) { // With eager the player can likely guarentee the effect at least once if (creatureCard.attack > 0) { multiplier += 0.5; } } return(multiplier); } // Good with high health, also good with untouchable because the common way to beat it is through combat case TriggerCondition.ON_SELF_DAMAGE_TAKEN: { CreatureCardDescription creatureCard = card as CreatureCardDescription; // Assume average damage will come in 3s, but cap how strong the card effect multiplier is double multiplier = Math.Max(3.0, creatureCard.health / 3.0); if (!creatureCard.HasKeywordAttribute(KeywordAttribute.UNTOUCHABLE)) { multiplier *= 0.75; } return(multiplier); } } return(1.0); }