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; } }
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); }
// 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); }
// 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); }
// 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(); } }
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; } }
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)); }
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); } } }
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); }