Various fixes to the enchanting and loot system

- enchanted loot generated by mapgen now uses PseudoRandom for randomness
- prevent fishing loot from generating loot 32767 times (!!!) when only 1 is needed
- bows and fishing rods obtained from the treasure section of fishing loot are now enchanted
- there is now a function to uniform enchant items other than books
This commit is contained in:
Elias Fleckenstein 2021-12-07 17:57:18 +01:00
parent b3958a956d
commit ec7e245b9d
No known key found for this signature in database
GPG Key ID: 06927A5199D6C9B2
7 changed files with 76 additions and 43 deletions

@ -58,26 +58,27 @@ function mcl_loot.get_loot(loot_definitions, pr)
end end
if item then if item then
local itemstring = item.itemstring local itemstring = item.itemstring
local itemstack = item.itemstack
if itemstring then if itemstring then
local stack = ItemStack(itemstring)
if item.amount_min and item.amount_max then if item.amount_min and item.amount_max then
itemstring = itemstring .. " " .. pr:next(item.amount_min, item.amount_max) stack:set_count(pr:next(item.amount_min, item.amount_max))
end end
if item.wear_min and item.wear_max then if item.wear_min and item.wear_max then
-- Sadly, PseudoRandom only allows very narrow ranges, so we set wear in steps of 10 -- Sadly, PseudoRandom only allows very narrow ranges, so we set wear in steps of 10
local wear_min = math.floor(item.wear_min / 10) local wear_min = math.floor(item.wear_min / 10)
local wear_max = math.floor(item.wear_max / 10) local wear_max = math.floor(item.wear_max / 10)
local wear = pr:next(wear_min, wear_max) * 10
if not item.amount_min and not item.amount_max then stack:set_wear(pr:next(wear_min, wear_max) * 10)
itemstring = itemstring .. " 1"
end end
itemstring = itemstring .. " " .. tostring(wear) if item.func then
item.func(stack, pr)
end end
table.insert(items, itemstring)
elseif itemstack then table.insert(items, stack)
table.insert(items, itemstack)
else else
minetest.log("error", "[mcl_loot] INTERNAL ERROR! Failed to select random loot item!") minetest.log("error", "[mcl_loot] INTERNAL ERROR! Failed to select random loot item!")
end end

@ -409,7 +409,7 @@ local init_trades = function(self, inv)
local offered_stack = ItemStack({name = offered_item, count = offered_count}) local offered_stack = ItemStack({name = offered_item, count = offered_count})
if mcl_enchanting.is_enchanted(offered_item) then if mcl_enchanting.is_enchanted(offered_item) then
if mcl_enchanting.is_book(offered_item) then if mcl_enchanting.is_book(offered_item) then
offered_stack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"}) mcl_enchanting.enchant_uniform_randomly(offered_stack, {"soul_speed"})
else else
mcl_enchanting.enchant_randomly(offered_stack, math.random(5, 19), false, false, true) mcl_enchanting.enchant_randomly(offered_stack, math.random(5, 19), false, false, true)
mcl_enchanting.unload_enchantments(offered_stack) mcl_enchanting.unload_enchantments(offered_stack)

@ -295,6 +295,16 @@ function mcl_enchanting.initialize()
end end
end end
function mcl_enchanting.random(pr, ...)
local r = pr and pr:next(...) or math.random(...)
if pr and not ({...})[1] then
r = r / 32767
end
return r
end
function mcl_enchanting.get_random_enchantment(itemstack, treasure, weighted, exclude, pr) function mcl_enchanting.get_random_enchantment(itemstack, treasure, weighted, exclude, pr)
local possible = {} local possible = {}
@ -310,23 +320,30 @@ function mcl_enchanting.get_random_enchantment(itemstack, treasure, weighted, ex
end end
end end
return #possible > 0 and possible[pr and pr:next(1, #possible) or math.random(#possible)] return #possible > 0 and possible[mcl_enchanting.random(pr, 1, #possible)]
end end
function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted) function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr)
local itemname = itemstack:get_name() local itemname = itemstack:get_name()
if not mcl_enchanting.can_enchant_freshly(itemname) and not ignore_already_enchanted then if not mcl_enchanting.can_enchant_freshly(itemname) and not ignore_already_enchanted then
return return
end end
itemstack = ItemStack(itemstack) itemstack = ItemStack(itemstack)
local enchantability = minetest.get_item_group(itemname, "enchantability") local enchantability = minetest.get_item_group(itemname, "enchantability")
enchantability = 1 + math.random(0, math.floor(enchantability / 4)) + math.random(0, math.floor(enchantability / 4)) enchantability = 1 + mcl_enchanting.random(pr, 0, math.floor(enchantability / 4)) + mcl_enchanting.random(pr, 0, math.floor(enchantability / 4))
enchantment_level = enchantment_level + enchantability enchantment_level = enchantment_level + enchantability
enchantment_level = enchantment_level + enchantment_level * (math.random() + math.random() - 1) * 0.15 enchantment_level = enchantment_level + enchantment_level * (mcl_enchanting.random(pr) + mcl_enchanting.random(pr) - 1) * 0.15
enchantment_level = math.max(math.floor(enchantment_level + 0.5), 1) enchantment_level = math.max(math.floor(enchantment_level + 0.5), 1)
local enchantments = {} local enchantments = {}
local description local description
enchantment_level = enchantment_level * 2 enchantment_level = enchantment_level * 2
repeat repeat
enchantment_level = math.floor(enchantment_level / 2) enchantment_level = math.floor(enchantment_level / 2)
@ -334,7 +351,7 @@ function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_leve
break break
end end
local selected_enchantment = mcl_enchanting.get_random_enchantment(itemstack, treasure, true) local selected_enchantment = mcl_enchanting.get_random_enchantment(itemstack, treasure, true, nil, pr)
if not selected_enchantment then if not selected_enchantment then
break break
@ -365,43 +382,41 @@ function mcl_enchanting.generate_random_enchantments(itemstack, enchantment_leve
enchantments[selected_enchantment] = enchantment_power enchantments[selected_enchantment] = enchantment_power
mcl_enchanting.enchant(itemstack, selected_enchantment, enchantment_power) mcl_enchanting.enchant(itemstack, selected_enchantment, enchantment_power)
end end
until not no_reduced_bonus_chance and math.random() >= (enchantment_level + 1) / 50
until not no_reduced_bonus_chance and mcl_enchanting.random(pr) >= (enchantment_level + 1) / 50
return enchantments, description return enchantments, description
end end
function mcl_enchanting.generate_random_enchantments_reliable(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted) function mcl_enchanting.generate_random_enchantments_reliable(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr)
local enchantments local enchantments
repeat repeat
enchantments = mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted) enchantments = mcl_enchanting.generate_random_enchantments(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr)
until enchantments until enchantments
return enchantments return enchantments
end end
function mcl_enchanting.enchant_randomly(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted) function mcl_enchanting.enchant_randomly(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr)
local enchantments = mcl_enchanting.generate_random_enchantments_reliable(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted, pr)
mcl_enchanting.set_enchanted_itemstring(itemstack) mcl_enchanting.set_enchanted_itemstring(itemstack)
mcl_enchanting.set_enchantments(itemstack, mcl_enchanting.generate_random_enchantments_reliable(itemstack, enchantment_level, treasure, no_reduced_bonus_chance, ignore_already_enchanted)) mcl_enchanting.set_enchantments(itemstack, enchantments)
return itemstack return itemstack
end end
function mcl_enchanting.get_randomly_enchanted_book(enchantment_level, treasure, no_reduced_bonus_chance)
return mcl_enchanting.enchant_randomly(ItemStack("mcl_books:book"), enchantment_level, treasure, no_reduced_bonus_chance, true)
end
function mcl_enchanting.enchant_uniform_randomly(stack, exclude, pr) function mcl_enchanting.enchant_uniform_randomly(stack, exclude, pr)
local enchantment = mcl_enchanting.get_random_enchantment(stack, true, weighted, exclude, pr) local enchantment = mcl_enchanting.get_random_enchantment(stack, true, false, exclude, pr)
if enchantment then if enchantment then
local max_level = mcl_enchanting.enchantments[enchantment].max_level mcl_enchanting.enchant(stack, enchantment, mcl_enchanting.random(pr, 1, mcl_enchanting.enchantments[enchantment].max_level))
mcl_enchanting.enchant(stack, enchantment, pr and pr:next(1, max_level) or math.random(max_level))
end end
return stack return stack
end end
function mcl_enchanting.get_uniform_randomly_enchanted_book(exclude, pr)
return mcl_enchanting.enchant_uniform_randomly(ItemStack("mcl_books:book"), exclude, pr)
end
function mcl_enchanting.get_random_glyph_row() function mcl_enchanting.get_random_glyph_row()
local glyphs = "" local glyphs = ""
local x = 1.3 local x = 1.3

@ -71,7 +71,9 @@ local fish = function(itemstack, player, pointed_thing)
{ itemstring = "mcl_fishing:salmon_raw", weight = 25 }, { itemstring = "mcl_fishing:salmon_raw", weight = 25 },
{ itemstring = "mcl_fishing:clownfish_raw", weight = 2 }, { itemstring = "mcl_fishing:clownfish_raw", weight = 2 },
{ itemstring = "mcl_fishing:pufferfish_raw", weight = 13 }, { itemstring = "mcl_fishing:pufferfish_raw", weight = 13 },
} },
stacks_min = 1,
stacks_max = 1,
}, pr) }, pr)
elseif r <= junk_value then elseif r <= junk_value then
-- Junk -- Junk
@ -88,21 +90,29 @@ local fish = function(itemstack, player, pointed_thing)
{ itemstring = "mcl_mobitems:bone", weight = 10 }, { itemstring = "mcl_mobitems:bone", weight = 10 },
{ itemstring = "mcl_dye:black", weight = 1, amount_min = 10, amount_max = 10 }, { itemstring = "mcl_dye:black", weight = 1, amount_min = 10, amount_max = 10 },
{ itemstring = "mcl_mobitems:string", weight = 10 }, -- TODO: Tripwire Hook { itemstring = "mcl_mobitems:string", weight = 10 }, -- TODO: Tripwire Hook
} },
stacks_min = 1,
stacks_max = 1,
}, pr) }, pr)
else else
-- Treasure -- Treasure
items = mcl_loot.get_loot({ items = mcl_loot.get_loot({
items = { items = {
-- TODO: Enchanted Bow { itemstring = "mcl_bows:bow", wear_min = 49144, wear_max = 65535, func = function(stack, pr)
{ itemstring = "mcl_bows:bow", wear_min = 49144, wear_max = 65535 }, -- 75%-100% damage mcl_enchanting.enchant_randomly(stack, 30, true, false, false, pr)
{ itemstack = mcl_enchanting.get_randomly_enchanted_book(30, true, true)}, end }, -- 75%-100% damage
-- TODO: Enchanted Fishing Rod { itemstring = "mcl_books:book", func = function(stack, pr)
{ itemstring = "mcl_fishing:fishing_rod", wear_min = 49144, wear_max = 65535 }, -- 75%-100% damage mcl_enchanting.enchant_randomly(stack, 30, true, true, false, pr)
end },
{ itemstring = "mcl_fishing:fishing_rod", wear_min = 49144, wear_max = 65535, func = function(stack, pr)
mcl_enchanting.enchant_randomly(stack, 30, true, false, false, pr)
end }, -- 75%-100% damage
{ itemstring = "mcl_mobs:nametag", }, { itemstring = "mcl_mobs:nametag", },
{ itemstring = "mcl_mobitems:saddle", }, { itemstring = "mcl_mobitems:saddle", },
{ itemstring = "mcl_flowers:waterlily", }, { itemstring = "mcl_flowers:waterlily", },
} },
stacks_min = 1,
stacks_max = 1,
}, pr) }, pr)
end end
local item local item

@ -323,6 +323,9 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param)
{ itemstring = "mcl_jukebox:record_4", weight = 15 }, { itemstring = "mcl_jukebox:record_4", weight = 15 },
{ itemstring = "mobs_mc:iron_horse_armor", weight = 15 }, { itemstring = "mobs_mc:iron_horse_armor", weight = 15 },
{ itemstring = "mcl_core:apple_gold", weight = 15 }, { itemstring = "mcl_core:apple_gold", weight = 15 },
{ itemstring = "mcl_books:book", weight = 10, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly({"soul_speed"}, pr)
end },
{ itemstack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"}, pr), weight = 10 }, { itemstack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"}, pr), weight = 10 },
{ itemstring = "mobs_mc:gold_horse_armor", weight = 10 }, { itemstring = "mobs_mc:gold_horse_armor", weight = 10 },
{ itemstring = "mobs_mc:diamond_horse_armor", weight = 5 }, { itemstring = "mobs_mc:diamond_horse_armor", weight = 5 },

@ -454,7 +454,9 @@ local function temple_placement_callback(p1, p2, size, rotation, pr)
{ itemstring = "mcl_mobitems:bone", weight = 25, amount_min = 4, amount_max=6 }, { itemstring = "mcl_mobitems:bone", weight = 25, amount_min = 4, amount_max=6 },
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 25, amount_min = 3, amount_max=7 }, { itemstring = "mcl_mobitems:rotten_flesh", weight = 25, amount_min = 3, amount_max=7 },
{ itemstring = "mcl_mobitems:spider_eye", weight = 25, amount_min = 1, amount_max=3 }, { itemstring = "mcl_mobitems:spider_eye", weight = 25, amount_min = 1, amount_max=3 },
{ itemstack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"}, pr), weight = 20, }, { itemstring = "mcl_books:book", weight = 20, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly({"soul_speed"}, pr)
end },
{ itemstring = "mcl_mobitems:saddle", weight = 20, }, { itemstring = "mcl_mobitems:saddle", weight = 20, },
{ itemstring = "mcl_core:apple_gold", weight = 20, }, { itemstring = "mcl_core:apple_gold", weight = 20, },
{ itemstring = "mcl_core:gold_ingot", weight = 15, amount_min = 2, amount_max = 7 }, { itemstring = "mcl_core:gold_ingot", weight = 15, amount_min = 2, amount_max = 7 },

@ -66,7 +66,9 @@ function tsm_railcorridors.get_treasures(pr)
items = { items = {
{ itemstring = "mcl_mobs:nametag", weight = 30 }, { itemstring = "mcl_mobs:nametag", weight = 30 },
{ itemstring = "mcl_core:apple_gold", weight = 20 }, { itemstring = "mcl_core:apple_gold", weight = 20 },
{ itemstack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"}, pr), weight = 10 }, { itemstring = "mcl_books:book", weight = 10, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly({"soul_speed"}, pr)
end },
{ itemstring = "", weight = 5}, { itemstring = "", weight = 5},
{ itemstring = "mcl_core:pick_iron", weight = 5 }, { itemstring = "mcl_core:pick_iron", weight = 5 },
{ itemstring = "mcl_core:apple_gold_enchanted", weight = 1 }, { itemstring = "mcl_core:apple_gold_enchanted", weight = 1 },