feat: add blazePowderForBrews and catalogBrewStep to PotionCatalog

This commit is contained in:
dualfroz committed 2026-09-08 20:19:08 +02:00
1 parent f13622eaef
commit 395ba54d52
1 file changed
+153
+153
View File
@@ -155,3 +155,156 @@ int PotionCatalog::variantTicks(const PotionItem& potion) const {
if (!row.carriesEffect()) return 0; if (!row.carriesEffect()) return 0;
if (row.instant) return 1; if (row.instant) return 1;
int ticks = row.normalTicks;
if (potion.upgraded && row.acceptsGlowstone()) {
ticks = row.upgradedTicks;
} else if (potion.extended && row.acceptsRedstone()) {
ticks = row.extendedTicks;
}
if (potion.form == PotionItem::Form::Splash) {
return static_cast<int>(std::floor(static_cast<float>(ticks) * splashDurationScale));
}
if (potion.form == PotionItem::Form::Lingering) {
return static_cast<int>(std::floor(static_cast<float>(ticks) * lingeringDoseScale));
}
return ticks;
}
int PotionCatalog::cloudTicks(const PotionItem& potion) const {
if (potion.form != PotionItem::Form::Lingering) return 0;
if (!entry(potion.kind).carriesEffect()) return 0;
return lingeringCloudTicks;
}
const PotionCatalog& potionCatalog() {
static const PotionCatalog catalog;
return catalog;
}
int blazePowderForBrews(int brewCount) {
if (brewCount <= 0) return 0;
return (brewCount + brewsPerBlazePowder - 1) / brewsPerBlazePowder;
}
PotionItem catalogBrewStep(const PotionItem& base, Ingredient ingredient, bool& changed) {
changed = false;
if (base.form == PotionItem::Form::Lingering) return base;
if (ingredient == Ingredient::DragonBreath) {
if (base.form != PotionItem::Form::Splash) return base;
PotionItem lingering = base;
lingering.form = PotionItem::Form::Lingering;
changed = true;
return lingering;
}
return brewResult(base, ingredient, changed);
}
int BrewGraph::stateCount() { return potionKindCount * potionFormCount * potionModifierCount; }
int BrewGraph::stateIndex(const PotionItem& potion) {
int kind = static_cast<int>(potion.kind);
int form = static_cast<int>(potion.form);
return (kind * potionFormCount + form) * potionModifierCount + modifierIndex(potion);
}
PotionItem BrewGraph::stateAt(int index) {
PotionItem potion;
int modifier = index % potionModifierCount;
int rest = index / potionModifierCount;
potion.form = static_cast<PotionItem::Form>(rest % potionFormCount);
potion.kind = static_cast<PotionKind>(rest / potionFormCount);
potion.upgraded = modifier == 1;
potion.extended = modifier == 2;
return potion;
}
BrewGraph::BrewGraph(const PotionCatalog& source) : catalog(&source), nodes(stateCount()) {
int start = stateIndex(PotionItem{});
nodes[static_cast<std::size_t>(start)].depth = 0;
std::deque<int> frontier;
frontier.push_back(start);
while (!frontier.empty()) {
int current = frontier.front();
frontier.pop_front();
PotionItem bottle = stateAt(current);
for (int step = 1; step < static_cast<int>(Ingredient::Count); ++step) {
Ingredient ingredient = static_cast<Ingredient>(step);
bool changed = false;
PotionItem brewed = catalogBrewStep(bottle, ingredient, changed);
if (!changed) continue;
int next = stateIndex(brewed);
Node& node = nodes[static_cast<std::size_t>(next)];
if (node.depth >= 0) continue;
node.depth = nodes[static_cast<std::size_t>(current)].depth + 1;
node.previous = current;
node.via = ingredient;
frontier.push_back(next);
}
}
}
int BrewGraph::depthOf(const PotionItem& potion) const {
return nodes[static_cast<std::size_t>(stateIndex(potion))].depth;
}
bool BrewGraph::reachable(const PotionItem& potion) const { return depthOf(potion) >= 0; }
BrewPath BrewGraph::shortestPath(const PotionItem& target) const {
BrewPath path;
path.target = target;
int index = stateIndex(target);
if (nodes[static_cast<std::size_t>(index)].depth < 0) return path;
path.reachable = true;
while (nodes[static_cast<std::size_t>(index)].previous >= 0) {
const Node& node = nodes[static_cast<std::size_t>(index)];
path.steps.push_back(node.via);
if (node.via == Ingredient::BlazePowder) ++path.blazePowderIngredient;
index = node.previous;
}
std::reverse(path.steps.begin(), path.steps.end());
path.blazePowderFuel = blazePowderForBrews(path.stepCount());
path.totalTicks = path.stepCount() * brewDurationTicks;
return path;
}
BrewPath BrewGraph::shortestPath(PotionKind kind) const {
PotionItem bottle;
bottle.kind = kind;
return shortestPath(bottle);
}
int BrewGraph::reachableStateCount() const {
int total = 0;
for (const Node& node : nodes) {
if (node.depth >= 0) ++total;
}
return total;
}
std::vector<PotionItem> BrewGraph::statesAtDepth(int steps) const {
std::vector<PotionItem> found;
for (int index = 0; index < stateCount(); ++index) {
if (nodes[static_cast<std::size_t>(index)].depth != steps) continue;
found.push_back(stateAt(index));
}
return found;
}
std::vector<BrewPath> BrewGraph::drinkablePaths() const {
std::vector<BrewPath> paths;
for (const PotionEntry& row : catalog->entries()) paths.push_back(shortestPath(row.kind));
return paths;
}
const BrewGraph& brewGraph() {
static const BrewGraph graph(potionCatalog());
return graph;
}
} // namespace vf