Beispiel #1
0
        public void Validate()
        {
            int statBudget = PowerBudget.StatBudget(mana);

            while (statModels.Count > statBudget)
            {
                statModels.RemoveAt(statModels.Count - 1);
            }
            while (statModels.Count < statBudget)
            {
                int i = statModels.Count;

                statModels.Add(new StatModelEntry());
                statModels[i].value  = 1;
                statModels[i].health = i + 1;
                statModels[i].mana   = mana;
            }

            int total = 0;

            foreach (StatModelEntry statModel in statModels)
            {
                total += statModel.value;
            }

            foreach (StatModelEntry statModel in statModels)
            {
                statModel.total = total;
            }
        }
Beispiel #2
0
    static private CardDescription GenerateTrapCard(System.Random random, IHistogram model, ImageGlossary images, CreatureModelIndex creatureModels, NameModel nameModel, CardGenerationFlags flags)
    {
        CardDescription card = ScriptableObject.CreateInstance(typeof(CardDescription)) as CardDescription;

        card.cardType = CardType.TRAP;
        card.manaCost = (int)ProceduralUtils.GetRandomValue <ManaCost>(random, model);

        double powerBudget = PowerBudget.ManaPowerBudgets[card.manaCost];
        double powerMargin = PowerBudget.ManaPowerMargin[card.manaCost];
        double powerLimit  = PowerBudget.ManaPowerLimit[card.manaCost];

        card.cardName = "A trap card";
        //card.name += "(" + powerBudget.ToString() + ")";

        GenerateCardEffects(random, model, 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.GetTrapImages());

        CardTags tags = CardTagging.GetCardTags(card);

        card.cardName = nameModel.GenerateName(random, tags);

        return(card);
    }
Beispiel #3
0
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown("space"))
        {
            if (desc == null)
            {
                ICardGenerator cardGenerator = new ProceduralCardGenerator(model, images, creatureModels, nameModel);

                if (providedSeed == 0)
                {
                    generatedSeed = Random.Range(0, 10000);
                }
                else
                {
                    generatedSeed = providedSeed;
                }
                instance = new CardInstance(cardGenerator.GenerateCard(generatedSeed, flags));
            }
            else
            {
                display.SetCard(new CardInstance(desc));
            }
            display.SetCard(instance);
        }
        else if (Input.GetKeyDown("q"))
        {
            if (instance != null)
            {
                double power = instance.baseCard.PowerLevel();
                double mana  = PowerBudget.PowerLevelToMana(power);
            }
        }
    }
    public override IEffectDescription Generate()
    {
        AuraModifierEffectDescription desc = new AuraModifierEffectDescription(effectType, modifierType);

        double durationMod = PowerBudget.GetDurationTypeModifier(DurationType.AURA);

        modifierGenerator.SetupParameters(random, model, minAllocatedBudget / durationMod, maxAllocatedBudget / durationMod);
        desc.modifierDescription = modifierGenerator.Generate();

        return(desc);
    }
    public override double PowerLevel()
    {
        double powerLevel = base.PowerLevel();

        foreach (KeywordAttribute keyword in attributes)
        {
            powerLevel += PowerBudget.GetKeywordCost(keyword, attack, health);
        }
        powerLevel += PowerBudget.StatsToPowerBudget(attack + health);
        return(powerLevel);
    }
Beispiel #6
0
    // Keywords have varying evaluations depending on the budget
    static public SortedSet <KeywordAttribute> GetKeywordsWithinBudget(double maxBudget, int atk, int hp)
    {
        SortedSet <KeywordAttribute> ret = new SortedSet <KeywordAttribute>();

        foreach (KeywordAttribute keyword in Enum.GetValues(typeof(KeywordAttribute)))
        {
            if (PowerBudget.GetKeywordCost(keyword, atk, hp) <= maxBudget)
            {
                ret.Add(keyword);
            }
        }

        return(ret);
    }
Beispiel #7
0
    // Draw the property inside the given rect
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        if (property != null)
        {
            // Using BeginProperty / EndProperty on the parent property means that
            // prefab override logic works on the entire property.
            EditorGUI.BeginProperty(position, label, property);

            // Draw label
            position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

            // Don't make child fields be indented
            var indent = EditorGUI.indentLevel;
            EditorGUI.indentLevel = 0;

            // Calculate rects
            var rect1 = new Rect(position.x, position.y, 50, position.height);
            var rect2 = new Rect(position.x + 55, position.y, 50, position.height);
            var rect3 = new Rect(position.x + 110, position.y, 200, position.height);
            var rect4 = new Rect(position.x + 315, position.y, 50, position.height);
            var rect5 = new Rect(position.x + 370, position.y, position.width - 370, position.height);


            SerializedProperty health = property.FindPropertyRelative("health");
            SerializedProperty mana   = property.FindPropertyRelative("mana");
            SerializedProperty value  = property.FindPropertyRelative("value");
            SerializedProperty total  = property.FindPropertyRelative("total");

            // Draw fields - pass GUIContent.none to each so they are drawn without labels
            EditorGUI.LabelField(rect1, "Atk: " + (PowerBudget.StatBudget(mana.intValue) - health.intValue).ToString());
            EditorGUI.LabelField(rect2, "Hp: " + health.intValue.ToString());

            EditorGUI.PropertyField(rect3, value, GUIContent.none, true);

            float percent = 0;
            if (total.intValue > 0)
            {
                percent = (value.intValue / (float)total.intValue);
            }
            string percentText = (percent * 100).ToString("0.00") + "%";

            EditorGUI.LabelField(rect4, percentText);
            EditorGUI.ProgressBar(rect5, percent, "");

            // Set indent back to what it was
            EditorGUI.indentLevel = indent;

            EditorGUI.EndProperty();
        }
    }
Beispiel #8
0
        public StatProbability(int manaCost)
        {
            statModels = new List <StatModelEntry>();
            mana       = manaCost;

            int statBudget = PowerBudget.StatBudget(mana);

            for (int i = 0; i < statBudget; i++)
            {
                statModels.Add(new StatModelEntry());
                statModels[i].value  = 1;
                statModels[i].health = i + 1;
                statModels[i].total  = statBudget;
                statModels[i].mana   = mana;
            }
        }
Beispiel #9
0
    public virtual double PowerLevel()
    {
        double power = 0;

        foreach (CardEffectDescription effect in cardEffects)
        {
            if (effect.GetAlignment() != Alignment.NEGATIVE)
            {
                power += effect.PowerLevel() * PowerBudget.GetTriggerModifier(effect.triggerCondition, this);
            }
            else
            {
                power -= effect.PowerLevel() * PowerBudget.DOWNSIDE_WEIGHT * PowerBudget.GetTriggerModifier(effect.triggerCondition, this);
            }
        }
        return(power);
    }
    public override IEffectDescription Generate()
    {
        GiveModifierEffectDescription desc = new GiveModifierEffectDescription(effectType, modifierType);

        desc.durationType = (random.NextDouble() > 0.5) ? DurationType.END_OF_TURN : DurationType.FOREVER;

        if (effectType == EffectType.GIVE_MANA_COST_TAX)
        {
            // Taxing effects for your turn only won't really work
            desc.durationType = DurationType.FOREVER;
        }

        double durationMod = PowerBudget.GetDurationTypeModifier(desc.durationType);

        modifierGenerator.SetupParameters(random, model, minAllocatedBudget / durationMod, maxAllocatedBudget / durationMod);
        desc.modifierDescription = modifierGenerator.Generate();

        return(desc);
    }
 public override double GetMinCost()
 {
     return(modifierGenerator.GetMinCost() * PowerBudget.GetDurationTypeModifier(DurationType.AURA));
 }
Beispiel #12
0
    static private void GenerateCardEffects(System.Random random, IHistogram model, CreatureModelIndex creatureModels, CardDescription cardDesc, double powerBudget, double powerMargin, double powerLimit)
    {
        // A trap card only has one trigger condition
        if (cardDesc.cardType == CardType.TRAP)
        {
            ProceduralUtils.GetRandomValue(random, model, CardEnums.GetValidFlags <TriggerCondition>(CardType.TRAP));
        }

        int effectCount = 0;

        List <TriggerCondition> triggerBlacklist = new List <TriggerCondition>();

        while ((cardDesc.PowerLevel() + PowerBudget.FLAT_EFFECT_COST) < powerBudget && effectCount < EffectConstants.MAX_CARD_EFFECTS)
        {
            // Generate effects
            CardEffectDescription cardEffect = new CardEffectDescription();

            // Create effects with a power level ranging between using max limit of budget, or uniformly distributing the min budget
            double maxAllowableBudget = powerLimit - cardDesc.PowerLevel() - PowerBudget.FLAT_EFFECT_COST;
            double minAllowableBudget = (powerBudget - cardDesc.PowerLevel() - PowerBudget.FLAT_EFFECT_COST) / (EffectConstants.MAX_CARD_EFFECTS - effectCount);

            if (cardDesc.cardType == CardType.SPELL || (cardDesc.cardType == CardType.TRAP && effectCount > 0))
            {
                // After the first condition of a trap or after casting a spell all further effects of
                // the card should just resolve so trigger cond is NONE
                cardEffect.triggerCondition = TriggerCondition.NONE;

                // If NONE has been blacklisted that means that there are no candidates for the remaining budget
                if (triggerBlacklist.Contains(TriggerCondition.NONE))
                {
                    //Debug.Log("No effects are valid for budget " + maxAllowableBudget);

                    break;
                }
            }
            else
            {
                if (ProceduralUtils.FlagsExist(triggerBlacklist, CardEnums.GetValidFlags <TriggerCondition>(cardDesc.cardType)))
                {
                    cardEffect.triggerCondition = ProceduralUtils.GetRandomValueExcluding(random, model, triggerBlacklist, CardEnums.GetValidFlags <TriggerCondition>(cardDesc.cardType));
                }
                else
                {
                    // No triggers available mean each trigger type has been blacklisted

                    //Debug.Log("No effects are valid for budget " + maxAllowableBudget);

                    break;
                }
            }

            double triggerBudgetModifier = PowerBudget.GetTriggerModifier(cardEffect.triggerCondition, cardDesc);
            maxAllowableBudget /= triggerBudgetModifier;
            minAllowableBudget /= triggerBudgetModifier;

            SortedSet <EffectType> candidatesWithinBudget = ProceduralUtils.GetEffectsWithinBudget(maxAllowableBudget);
            if (candidatesWithinBudget.Count == 0)
            {
                triggerBlacklist.Add(cardEffect.triggerCondition);

                Debug.Log("No effects are valid for budget " + maxAllowableBudget);
                continue;
            }

            bool validEffect = false;

            SortedSet <EffectType> effectCandidates = new SortedSet <EffectType>(CardEnums.GetValidFlags <EffectType>(cardEffect.triggerCondition).Intersect(candidatesWithinBudget));
            effectCandidates.Remove(EffectType.NONE);

            while (!validEffect && effectCandidates.Count > 0)
            {
                EffectType effectType = ProceduralUtils.GetRandomValueExcluding(random, model, new EffectType[] { EffectType.NONE }, effectCandidates);
                // This means that there isn't an effect that meets this condition
                if (effectType == EffectType.NONE)
                {
                    // Add to black list so we don't get multiple effects that trigger on same condition
                    if (cardEffect.triggerCondition != TriggerCondition.NONE)
                    {
                        triggerBlacklist.Add(cardEffect.triggerCondition);
                    }
                    break;
                }

                validEffect = GenerateCardEffect(random, model, creatureModels, cardEffect, effectType, minAllowableBudget, maxAllowableBudget, true);
            }

            // This means that there isn't an effect that meets this condition
            if (validEffect)
            {
                cardDesc.cardEffects.Add(cardEffect);
                effectCount++;
            }
            else
            {
                Debug.Log("No valid effect could be generated for trigger <" + cardEffect.triggerCondition.ToString() + "> with budget " + maxAllowableBudget);
            }

            // Add to black list so we don't get multiple effects that trigger on same condition
            if (cardEffect.triggerCondition != TriggerCondition.NONE)
            {
                triggerBlacklist.Add(cardEffect.triggerCondition);
            }
        }

        // Generate a draw back
        while (cardDesc.PowerLevel() > powerMargin)
        {
            // TODO: Drawback should be one of, additional cost, negative effect, or negative modification to existing effect
            // For now just add additional negative effect

            CardEffectDescription cardEffect = new CardEffectDescription();

            double maxAllowableBudget = (cardDesc.PowerLevel() - powerBudget - PowerBudget.FLAT_EFFECT_COST) / PowerBudget.DOWNSIDE_WEIGHT;
            double minAllowableBudget = (cardDesc.PowerLevel() - powerMargin - PowerBudget.FLAT_EFFECT_COST) / PowerBudget.DOWNSIDE_WEIGHT;

            if (cardDesc.cardType == CardType.SPELL || (cardDesc.cardType == CardType.TRAP && effectCount > 0))
            {
                // After the first condition of a trap or after casting a spell all further effects of
                // the card should just resolve so trigger cond is NONE
                cardEffect.triggerCondition = TriggerCondition.NONE;

                // If NONE has been blacklisted that means that there are no candidates for the remaining budget
                if (triggerBlacklist.Contains(TriggerCondition.NONE))
                {
                    Debug.Log("No effects are valid for budget " + maxAllowableBudget);

                    break;
                }
            }
            else
            {
                if (ProceduralUtils.FlagsExist(triggerBlacklist, CardEnums.GetValidFlags <TriggerCondition>(cardDesc.cardType)))
                {
                    cardEffect.triggerCondition = ProceduralUtils.GetRandomValueExcluding(random, model, triggerBlacklist, CardEnums.GetValidFlags <TriggerCondition>(cardDesc.cardType));
                }
                else
                {
                    // No triggers available mean each trigger type has been blacklisted

                    Debug.Log("No effects are valid for budget " + maxAllowableBudget);

                    break;
                }
            }

            double triggerBudgetModifier = PowerBudget.GetTriggerModifier(cardEffect.triggerCondition, cardDesc);
            maxAllowableBudget /= triggerBudgetModifier;
            minAllowableBudget /= triggerBudgetModifier;

            SortedSet <EffectType> candidatesWithinBudget = ProceduralUtils.GetEffectsWithinBudget(maxAllowableBudget);
            if (candidatesWithinBudget.Count == 0)
            {
                triggerBlacklist.Add(cardEffect.triggerCondition);

                Debug.Log("No effects are valid for budget " + maxAllowableBudget);
                continue;
            }

            bool validEffect = false;

            SortedSet <EffectType> effectCandidates = new SortedSet <EffectType>(CardEnums.GetValidFlags <EffectType>(cardEffect.triggerCondition).Intersect(candidatesWithinBudget));
            effectCandidates.Remove(EffectType.NONE);

            while (!validEffect && effectCandidates.Count > 0)
            {
                EffectType effectType = ProceduralUtils.GetRandomValueExcluding(random, model, new EffectType[] { EffectType.NONE }, effectCandidates);
                // This means that there isn't an effect that meets this condition
                if (effectType == EffectType.NONE)
                {
                    // Add to black list so we don't get multiple effects that trigger on same condition
                    if (cardEffect.triggerCondition != TriggerCondition.NONE)
                    {
                        triggerBlacklist.Add(cardEffect.triggerCondition);
                    }
                    break;
                }

                validEffect = GenerateCardEffect(random, model, creatureModels, cardEffect, effectType, minAllowableBudget, maxAllowableBudget, false);
            }

            // This means that there isn't an effect that meets this condition
            if (validEffect)
            {
                cardDesc.cardEffects.Add(cardEffect);
                break;
            }
            else
            {
                Debug.Log("No valid effect could be generated for trigger <" + cardEffect.triggerCondition.ToString() + "> with budget " + -maxAllowableBudget);
            }

            // Add to black list so we don't get multiple effects that trigger on same condition
            if (cardEffect.triggerCondition != TriggerCondition.NONE)
            {
                triggerBlacklist.Add(cardEffect.triggerCondition);
            }
        }
    }
Beispiel #13
0
    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);
    }