diff --git a/core/src/Brewing.cpp b/core/src/Brewing.cpp new file mode 100644 index 0000000..3a9a38a --- /dev/null +++ b/core/src/Brewing.cpp @@ -0,0 +1,154 @@ +#include "vf/Brewing.h" + +#include +#include + +namespace vf { + +namespace { + +using Ingredient = BrewRecipe::Ingredient; + +struct PotionProfile { + EffectKind kind = EffectKind::Count; + int baseTicks = 0; + int extendedTicks = 0; // zero: redstone does nothing + int upgradedTicks = 0; // zero: glowstone does nothing + int upgradedLevel = 1; +}; + +const PotionProfile& profileFor(PotionKind kind) { + static const PotionProfile profiles[] = { + {EffectKind::Count, 0, 0, 0, 1}, // Water + {EffectKind::Count, 0, 0, 0, 1}, // Mundane + {EffectKind::Count, 0, 0, 0, 1}, // Thick + {EffectKind::Count, 0, 0, 0, 1}, // Awkward + {EffectKind::InstantHealth, 1, 0, 1, 2}, // Healing + {EffectKind::InstantDamage, 1, 0, 1, 2}, // Harming + {EffectKind::Regeneration, 900, 1800, 440, 2}, // Regeneration + {EffectKind::Poison, 900, 1800, 432, 2}, // Poison + {EffectKind::Speed, 3600, 9600, 1800, 2}, // Swiftness + {EffectKind::Slowness, 1800, 4800, 400, 4}, // Slowness + {EffectKind::JumpBoost, 3600, 9600, 1800, 2}, // Leaping + {EffectKind::Strength, 3600, 9600, 1800, 2}, // Strength + {EffectKind::Weakness, 1800, 4800, 0, 1}, // Weakness + {EffectKind::FireResistance, 3600, 9600, 0, 1}, // FireResistance + {EffectKind::WaterBreathing, 3600, 9600, 0, 1}, // WaterBreathing + {EffectKind::NightVision, 3600, 9600, 0, 1}, // NightVision + {EffectKind::Invisibility, 3600, 9600, 0, 1}, // Invisibility + }; + static_assert(sizeof(profiles) / sizeof(profiles[0]) == + static_cast(PotionKind::Count), + "potion profile table must cover every PotionKind"); + return profiles[static_cast(kind)]; +} + +bool applyModifier(PotionItem& potion, Ingredient ingredient) { + const PotionProfile& profile = profileFor(potion.kind); + switch (ingredient) { + case Ingredient::Glowstone: + if (profile.upgradedTicks == 0 || potion.upgraded) return false; + potion.upgraded = true; + potion.extended = false; + return true; + case Ingredient::Redstone: + if (profile.extendedTicks == 0 || potion.extended) return false; + potion.extended = true; + potion.upgraded = false; + return true; + case Ingredient::Gunpowder: + if (potion.form == PotionItem::Form::Splash) return false; + potion.form = PotionItem::Form::Splash; + return true; + default: + return false; + } +} + +} // namespace + +const std::vector& brewRecipes() { + static const std::vector recipes = { + {PotionKind::Water, Ingredient::NetherWart, PotionKind::Awkward}, + {PotionKind::Water, Ingredient::Glowstone, PotionKind::Thick}, + {PotionKind::Water, Ingredient::Redstone, PotionKind::Mundane}, + {PotionKind::Water, Ingredient::FermentedSpiderEye, PotionKind::Weakness}, + + {PotionKind::Awkward, Ingredient::Sugar, PotionKind::Swiftness}, + {PotionKind::Awkward, Ingredient::GlisteringMelon, PotionKind::Healing}, + {PotionKind::Awkward, Ingredient::SpiderEye, PotionKind::Poison}, + {PotionKind::Awkward, Ingredient::BlazePowder, PotionKind::Strength}, + {PotionKind::Awkward, Ingredient::MagmaCream, PotionKind::FireResistance}, + {PotionKind::Awkward, Ingredient::PufferFish, PotionKind::WaterBreathing}, + {PotionKind::Awkward, Ingredient::GoldenCarrot, PotionKind::NightVision}, + {PotionKind::Awkward, Ingredient::GhastTear, PotionKind::Regeneration}, + {PotionKind::Awkward, Ingredient::RabbitFoot, PotionKind::Leaping}, + + {PotionKind::NightVision, Ingredient::FermentedSpiderEye, PotionKind::Invisibility}, + {PotionKind::Healing, Ingredient::FermentedSpiderEye, PotionKind::Harming}, + {PotionKind::Poison, Ingredient::FermentedSpiderEye, PotionKind::Harming}, + {PotionKind::Swiftness, Ingredient::FermentedSpiderEye, PotionKind::Slowness}, + {PotionKind::Leaping, Ingredient::FermentedSpiderEye, PotionKind::Slowness}, + {PotionKind::Strength, Ingredient::FermentedSpiderEye, PotionKind::Weakness}, + }; + return recipes; +} + +PotionItem brewResult(const PotionItem& base, Ingredient ingredient, bool& changed) { + PotionItem brewed = base; + changed = false; + if (ingredient == Ingredient::None) return brewed; + + for (const BrewRecipe& recipe : brewRecipes()) { + if (recipe.input != base.kind || recipe.ingredient != ingredient) continue; + brewed.kind = recipe.output; + brewed.upgraded = false; + brewed.extended = false; + changed = true; + return brewed; + } + changed = applyModifier(brewed, ingredient); + return brewed; +} + +bool setBottle(BrewingStandState& stand, int slot, const PotionItem& potion) { + if (slot < 0 || slot >= brewingBottleSlots) return false; + BrewingSlot& bottle = stand.bottles[static_cast(slot)]; + if (bottle.occupied) return false; + bottle.potion = potion; + bottle.occupied = true; + stand.progressTicks = 0; + return true; +} + +PotionItem takeBottle(BrewingStandState& stand, int slot, bool& taken) { + taken = false; + if (slot < 0 || slot >= brewingBottleSlots) return {}; + BrewingSlot& bottle = stand.bottles[static_cast(slot)]; + if (!bottle.occupied) return {}; + PotionItem removed = bottle.potion; + bottle = BrewingSlot{}; + taken = true; + stand.progressTicks = 0; + return removed; +} + +bool setIngredient(BrewingStandState& stand, Ingredient ingredient, int count) { + if (ingredient == Ingredient::None || count <= 0) return false; + if (stand.ingredientCount > 0 && stand.ingredient != ingredient) return false; + if (stand.ingredient == ingredient) { + stand.ingredientCount += count; + return true; + } + stand.ingredient = ingredient; + stand.ingredientCount = count; + stand.progressTicks = 0; + return true; +} + +bool addFuel(BrewingStandState& stand, int blazePowderCount) { + if (blazePowderCount <= 0) return false; + stand.fuel += blazePowderCount * brewsPerBlazePowder; + return true; +} +