EinsDreiDreiSieben/mods/researcher/src/bonuses.lua
2025-05-04 16:01:41 +02:00

183 lines
No EOL
7.2 KiB
Lua

-- Research level group bonus
if researcher.settings.group_research_bonus > 0 and researcher.settings.group_research_bonus_max > 0 then
researcher.register_bonus({
name = "researcher:research_group_research_bonus",
reason = "Group Research",
calculate = function(item,player_data)
local bonus = 0
for subject,research in pairs(player_data.research) do
if researcher.do_items_share_groups(item,subject) then
bonus = bonus + (research.level - 1) * researcher.settings.group_research_bonus
end
end
return bonus
end,
initialize_player_data = function()
-- all bonus calculation comes from research; nothing to initialize
end,
})
else
researcher.register_bonus({
name = "researcher:research_group_research_bonus",
reason = "Group Research",
calculate = function() return 0 end,
initialize_player_data = function()
-- bonus is calculated from research; nothing to initialize
end,
})
end
-- Focused research bonus
if researcher.settings.focused_research_bonus_max > 0 and (researcher.settings.focused_research_bonus_exact > 0 or researcher.settings.focused_research_bonus_group > 0) then
researcher.register_bonus({
name = "researcher:focused_research_bonus",
reason = "Focused Research",
calculate = function(item,player_data)
-- Calculate bonus value
if item == player_data.focused_research.item then
player_data.focused_research.bonus = player_data.focused_research.bonus + researcher.settings.focused_research_bonus_exact
elseif researcher.do_items_share_groups(item,player_data.focused_research.item) then
player_data.focused_research.bonus = player_data.focused_research.bonus + researcher.settings.focused_research_bonus_group
else
player_data.focused_research.bonus = 0
end
-- Set focused item
player_data.focused_research.item = item
-- Return capped bonus value
player_data.focused_research.bonus = math.min(player_data.focused_research.bonus,researcher.settings.focused_research_bonus_max)
return player_data.focused_research.bonus
end,
initialize_player_data = function(player_data)
player_data.focused_research = {
item = "",
bonus = 0,
}
end,
})
else
researcher.register_bonus({
name = "researcher:focused_research_bonus",
reason = "Focused Research",
calculate = function() return 0 end,
initialize_player_data = function(player_data)
player_data.focused_research = {
item = "",
bonus = 0,
}
end,
})
end
-- Research table bonus
if researcher.settings.research_table_bonus_exact > 0 or researcher.settings.research_table_bonus_group > 0 or (researcher.settings.research_table_adjacency_bonus > 0 and researcher.settings.research_table_adjacency_max > 0) then
researcher.register_bonus({
name = "researcher:research_table_bonus",
reason = "Research Table",
calculate = function(item,player_data)
-- Initialize bonus and max flag
local bonus = 0
local bonusmax = false
-- Track limits when tallying bonuses
local nadj = 0
local function rtbonus(bonus,increment,adjacency)
local result = bonus
if adjacency then
local adj_bounded = math.min(adjacency,researcher.settings.research_table_adjacency_max - nadj)
nadj = nadj + adj_bounded
result = result + researcher.settings.research_table_adjacency_bonus * adj_bounded
else
result = bonus + increment
end
return math.min(result,researcher.settings.research_table_bonus_max), (result >= researcher.settings.research_table_bonus_max or nadj >= researcher.settings.research_table_adjacency_max)
end
-- Scan radius around player for research tables
local player = minetest.get_player_by_name(player_data.name)
local research_table = nil
if player then
local pos = player:get_pos()
local radius = researcher.settings.research_table_player_radius
for _,rt in ipairs(minetest.find_nodes_in_area(pos:add(-radius),pos:add(radius),"researcher:research_table")) do
-- Get research table's focus
local meta = minetest.get_meta(rt)
local inventory = meta:get_inventory()
local itemstack = inventory:get_stack("focus",1)
local name = itemstack:get_name()
-- If the focus item matches the item in question, then add to the
-- calculated bonus accordingly
if item == name then
bonus, bonusmax = rtbonus(bonus,(research_table and (researcher.settings.research_table_bonus_exact - researcher.settings.research_table_bonus_group) or researcher.settings.research_table_bonus_exact))
if bonusmax then
return bonus
end
research_table = rt
break -- cannot do better than an exact match
elseif not research_table and researcher.do_items_share_groups(item,name) then
bonus, bonusmax = rtbonus(bonus,researcher.settings.research_table_bonus_group)
if bonusmax then
return bonus
end
research_table = rt
-- keep scanning for better matches
end
end
-- Calculate adjacency bonus for research table
if research_table then
local radius = researcher.settings.research_table_adjacency_radius
local pos1 = research_table:add(-radius)
local pos2 = research_table:add(radius)
-- Check nearby node groups
bonus, bonusmax = rtbonus(bonus,researcher.settings.research_table_adjacency_bonus,#minetest.find_nodes_in_area(pos1,pos2,(function()
local groups = {}
for group,_ in pairs(researcher.registered_items[item].groups) do
table.insert(groups,"group:" .. group)
end
return groups
end)()))
if bonusmax then
return bonus
end
-- Check nearby node inventories
for _,node in ipairs(minetest.find_nodes_with_meta(pos1,pos2)) do
if not node:equals(research_table) then
local nodemeta = minetest.get_meta(node)
local nodeinventory = nodemeta:get_inventory()
if nodeinventory then
for list,stacks in pairs(nodeinventory:get_lists() or {}) do
for _,itemstack in ipairs(stacks or {}) do
if not itemstack:is_empty() and researcher.do_items_share_groups(item,itemstack:get_name()) then
bonus, bonusmax = rtbonus(bonus,researcher.settings.research_table_adjacency_bonus,itemstack:get_count())
if bonusmax then
return bonus
end
end
end
end
end
end
end
else
return 0 -- no bonus if no research table was found
end
else
return 0 -- no bonus if player is mysteriously not found
end
-- Return partial bonus total
return bonus
end,
})
else
researcher.register_bonus({
name = "researcher:research_table_bonus",
reason = "Research Table",
calculate = function() return 0 end,
})
end