feat: add refreshOffers and takeOffer to Enchant
This commit is contained in:
1 parent
c3794851a2
commit
6a21f1d332
1 file changed
+110
@@ -298,3 +298,113 @@ EnchantSet rollEnchantments(Enchantment::Target target, int enchantability, int
|
||||
float spread = 1.0f + (unitFloat(rng) + unitFloat(rng) - 1.0f) * 0.15f;
|
||||
modified = std::max(1, static_cast<int>(std::lround(static_cast<float>(modified) * spread)));
|
||||
|
||||
std::vector<Enchantment> candidates;
|
||||
for (int slot = 0; slot < 3; ++slot) {
|
||||
candidates.clear();
|
||||
int totalWeight = 0;
|
||||
for (int k = 0; k < static_cast<int>(EnchantKind::Count); ++k) {
|
||||
EnchantKind kind = static_cast<EnchantKind>(k);
|
||||
if (!enchantApplies(kind, target)) continue;
|
||||
if (chosen.levelOf(kind) > 0 || chosen.conflictsWith(kind)) continue;
|
||||
for (int level = maxEnchantLevel(kind); level >= 1; --level) {
|
||||
if (modified < enchantMinCost(kind, level)) continue;
|
||||
if (modified > enchantMaxCost(kind, level)) continue;
|
||||
candidates.push_back({kind, level});
|
||||
totalWeight += enchantWeight(kind);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (candidates.empty()) break;
|
||||
int pick = rollBelow(rng, totalWeight);
|
||||
Enchantment picked = candidates.back();
|
||||
for (const Enchantment& candidate : candidates) {
|
||||
pick -= enchantWeight(candidate.kind);
|
||||
if (pick < 0) {
|
||||
picked = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
chosen.entries.push_back(picked);
|
||||
if (slot == 2) break;
|
||||
modified = modified * 4 / 5;
|
||||
if (rollBelow(rng, 50) > modified) break;
|
||||
}
|
||||
return chosen;
|
||||
}
|
||||
|
||||
void refreshOffers(EnchantTableState& state) {
|
||||
uint32_t rng = state.seed != 0 ? state.seed : 0x9e3779b9u;
|
||||
int shelves = std::min(std::max(state.bookshelves, 0), maxBookshelfPower);
|
||||
int base = 1 + rollBelow(rng, 8) + shelves / 2 + rollBelow(rng, shelves + 1);
|
||||
|
||||
int slotLevels[3] = {
|
||||
std::max(base / 3, 1),
|
||||
(base * 2) / 3 + 1,
|
||||
std::max(base, shelves * 2),
|
||||
};
|
||||
|
||||
for (int slot = 0; slot < 3; ++slot) {
|
||||
EnchantOffer offer;
|
||||
offer.lapisCost = slot + 1;
|
||||
offer.requiredLevels = slotLevels[slot];
|
||||
uint32_t slotRng = rng ^ (0x85ebca6bu * static_cast<uint32_t>(slot + 1));
|
||||
offer.enchants = rollEnchantments(state.target, state.enchantability, slotLevels[slot],
|
||||
slotRng);
|
||||
if (offer.enchants.empty()) offer.requiredLevels = 0;
|
||||
state.offers[static_cast<std::size_t>(slot)] = offer;
|
||||
}
|
||||
}
|
||||
|
||||
EnchantOffer takeOffer(EnchantTableState& state, int slot, int playerLevels, int lapisCount) {
|
||||
if (slot < 0 || slot > 2) return {};
|
||||
const EnchantOffer& offer = state.offers[static_cast<std::size_t>(slot)];
|
||||
if (!offer.valid()) return {};
|
||||
if (playerLevels < offer.requiredLevels || lapisCount < offer.lapisCost) return {};
|
||||
|
||||
EnchantOffer granted = offer;
|
||||
state.seed = state.seed * 1664525u + 1013904223u + static_cast<uint32_t>(slot);
|
||||
refreshOffers(state);
|
||||
return granted;
|
||||
}
|
||||
|
||||
int anvilRepairCost(int priorWork) {
|
||||
int clamped = std::min(std::max(priorWork, 0), 30);
|
||||
return (1 << clamped) - 1;
|
||||
}
|
||||
|
||||
EnchantOffer anvilCombine(const EnchantSet& target, int targetPriorWork, const EnchantSet& sacrifice,
|
||||
int sacrificePriorWork) {
|
||||
EnchantOffer merged;
|
||||
merged.enchants = target;
|
||||
merged.priorWork = std::max(targetPriorWork, sacrificePriorWork) + 1;
|
||||
|
||||
int cost = anvilRepairCost(targetPriorWork) + anvilRepairCost(sacrificePriorWork);
|
||||
for (const Enchantment& incoming : sacrifice.entries) {
|
||||
int existing = merged.enchants.levelOf(incoming.kind);
|
||||
if (existing == 0) {
|
||||
if (merged.enchants.conflictsWith(incoming.kind)) {
|
||||
cost += 1;
|
||||
continue;
|
||||
}
|
||||
merged.enchants.entries.push_back(incoming);
|
||||
cost += anvilCostMultiplier(incoming.kind) * incoming.level;
|
||||
continue;
|
||||
}
|
||||
int newLevel = existing;
|
||||
if (incoming.level > existing) {
|
||||
newLevel = incoming.level;
|
||||
} else if (incoming.level == existing) {
|
||||
newLevel = std::min(existing + 1, maxEnchantLevel(incoming.kind));
|
||||
}
|
||||
for (Enchantment& entry : merged.enchants.entries) {
|
||||
if (entry.kind == incoming.kind) entry.level = newLevel;
|
||||
}
|
||||
cost += anvilCostMultiplier(incoming.kind) * newLevel;
|
||||
}
|
||||
|
||||
merged.requiredLevels = cost;
|
||||
merged.tooExpensive = cost >= anvilTooExpensiveCost;
|
||||
return merged;
|
||||
}
|
||||
|
||||
} // namespace vf
|
||||
Reference in new issue
Block a user