Merge pull request 'Add MC hold to eat delay' (#4144) from Eliy21/MineClone2:eating_delay into master
Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/4144 Reviewed-by: the-real-herowl <the-real-herowl@noreply.git.minetest.land>patch_skins
commit
1175be45fb
|
@ -181,6 +181,67 @@ local function eat_gapple(itemstack, placer, pointed_thing)
|
||||||
return gapple_hunger_restore(itemstack, placer, pointed_thing)
|
return gapple_hunger_restore(itemstack, placer, pointed_thing)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function eat_gapple_delayed(itemstack, placer, pointed_thing)
|
||||||
|
|
||||||
|
if pointed_thing.type == "node" then
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
if placer and not placer:get_player_control().sneak then
|
||||||
|
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||||
|
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif pointed_thing.type == "object" then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
local function eat_gapple(itemstack, placer, pointed_thing)
|
||||||
|
if pointed_thing.type == "node" then
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
if placer and not placer:get_player_control().sneak then
|
||||||
|
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||||
|
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif pointed_thing.type == "object" then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
local regen_duration, absorbtion_factor = 5, 1
|
||||||
|
if itemstack:get_name() == "mcl_core:apple_gold_enchanted" then
|
||||||
|
regen_duration, absorbtion_factor = 20, 4
|
||||||
|
mcl_potions.fire_resistance_func(placer, 1, 300)
|
||||||
|
mcl_potions.leaping_func(placer, 1, 300)
|
||||||
|
if enable_fapples then
|
||||||
|
mcl_potions.swiftness_func(placer, absorbtion_factor, 120)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- TODO: Absorbtion
|
||||||
|
mcl_potions.regeneration_func(placer, 2, regen_duration)
|
||||||
|
--return gapple_hunger_restore(itemstack, placer, pointed_thing)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Wrapper for handling mcl_hunger delayed eating
|
||||||
|
local name = placer:get_player_name()
|
||||||
|
mcl_hunger.eat_internal[name]._custom_itemstack = itemstack -- Used as comparison to make sure the custom wrapper executes only when the same item is eaten
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var = {
|
||||||
|
itemstack = itemstack,
|
||||||
|
placer = placer,
|
||||||
|
pointed_thing = pointed_thing,
|
||||||
|
}
|
||||||
|
mcl_hunger.eat_internal[name]._custom_func = eat_gapple
|
||||||
|
mcl_hunger.eat_internal[name]._custom_wrapper = function(name)
|
||||||
|
|
||||||
|
mcl_hunger.eat_internal[name]._custom_func(
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.itemstack,
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.placer,
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.pointed_thing
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
--mcl_hunger.eat_internal[name]._custom_do_delayed = true -- Only _custom_wrapper will be executed after holding RMB or LMB within a specified delay
|
||||||
|
minetest.do_item_eat(4, nil, itemstack, placer, pointed_thing)
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_craftitem("mcl_core:apple_gold", {
|
minetest.register_craftitem("mcl_core:apple_gold", {
|
||||||
-- TODO: Add special highlight color
|
-- TODO: Add special highlight color
|
||||||
description = S("Golden Apple"),
|
description = S("Golden Apple"),
|
||||||
|
@ -188,8 +249,10 @@ minetest.register_craftitem("mcl_core:apple_gold", {
|
||||||
wield_image = "mcl_core_apple_golden.png",
|
wield_image = "mcl_core_apple_golden.png",
|
||||||
inventory_image = "mcl_core_apple_golden.png",
|
inventory_image = "mcl_core_apple_golden.png",
|
||||||
stack_max = 64,
|
stack_max = 64,
|
||||||
on_place = eat_gapple,
|
--on_place = eat_gapple, -- Will do effect immediately but not reduce item count until eating delay ends which makes it exploitable by deliberately not finishing delay
|
||||||
on_secondary_use = eat_gapple,
|
--on_secondary_use = eat_gapple,
|
||||||
|
on_place = eat_gapple_delayed,
|
||||||
|
on_secondary_use = eat_gapple_delayed,
|
||||||
groups = { food = 2, eatable = 4, can_eat_when_full = 1 },
|
groups = { food = 2, eatable = 4, can_eat_when_full = 1 },
|
||||||
_mcl_saturation = 9.6,
|
_mcl_saturation = 9.6,
|
||||||
})
|
})
|
||||||
|
@ -200,8 +263,10 @@ minetest.register_craftitem("mcl_core:apple_gold_enchanted", {
|
||||||
wield_image = "mcl_core_apple_golden.png" .. mcl_enchanting.overlay,
|
wield_image = "mcl_core_apple_golden.png" .. mcl_enchanting.overlay,
|
||||||
inventory_image = "mcl_core_apple_golden.png" .. mcl_enchanting.overlay,
|
inventory_image = "mcl_core_apple_golden.png" .. mcl_enchanting.overlay,
|
||||||
stack_max = 64,
|
stack_max = 64,
|
||||||
on_place = eat_gapple,
|
--on_place = eat_gapple,
|
||||||
on_secondary_use = eat_gapple,
|
--on_secondary_use = eat_gapple,
|
||||||
|
on_place = eat_gapple_delayed,
|
||||||
|
on_secondary_use = eat_gapple_delayed,
|
||||||
groups = { food = 2, eatable = 4, can_eat_when_full = 1 },
|
groups = { food = 2, eatable = 4, can_eat_when_full = 1 },
|
||||||
_mcl_saturation = 9.6,
|
_mcl_saturation = 9.6,
|
||||||
})
|
})
|
||||||
|
|
|
@ -157,7 +157,7 @@ minetest.register_craftitem("mcl_farming:beetroot_soup", {
|
||||||
wield_image = "mcl_farming_beetroot_soup.png",
|
wield_image = "mcl_farming_beetroot_soup.png",
|
||||||
on_place = minetest.item_eat(6, "mcl_core:bowl"),
|
on_place = minetest.item_eat(6, "mcl_core:bowl"),
|
||||||
on_secondary_use = minetest.item_eat(6, "mcl_core:bowl"),
|
on_secondary_use = minetest.item_eat(6, "mcl_core:bowl"),
|
||||||
groups = { food = 3, eatable = 6 },
|
groups = { food = 2, eatable = 6 },
|
||||||
_mcl_saturation = 7.2,
|
_mcl_saturation = 7.2,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,52 @@ local function drink_milk(itemstack, player, pointed_thing)
|
||||||
return bucket
|
return bucket
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function drink_milk_delayed(itemstack, player, pointed_thing)
|
||||||
|
|
||||||
|
if pointed_thing.type == "node" then
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
if player and not player:get_player_control().sneak then
|
||||||
|
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||||
|
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, player, itemstack) or itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif pointed_thing.type == "object" then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
local function drink_milk(itemstack, player, pointed_thing)
|
||||||
|
--local bucket = minetest.do_item_eat(0, "mcl_buckets:bucket_empty", itemstack, player, pointed_thing)
|
||||||
|
-- Check if we were allowed to drink this (eat delay check)
|
||||||
|
--if mcl_hunger.active and (bucket:get_name() ~= "mcl_mobitems:milk_bucket" or minetest.is_creative_enabled(player:get_player_name())) then
|
||||||
|
if mcl_hunger.active and (player:get_inventory():get_stack("main", player:get_wield_index(), itemstack) == "mcl_mobitems:milk_bucket" or minetest.is_creative_enabled(player:get_player_name())) then
|
||||||
|
mcl_hunger.stop_poison(player)
|
||||||
|
end
|
||||||
|
mcl_potions._reset_player_effects(player)
|
||||||
|
return bucket
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Wrapper for handling mcl_hunger delayed eating
|
||||||
|
local name = player:get_player_name()
|
||||||
|
mcl_hunger.eat_internal[name]._custom_itemstack = itemstack -- Used as comparison to make sure the custom wrapper executes only when the same item is eaten
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var = {
|
||||||
|
itemstack = itemstack,
|
||||||
|
player = player,
|
||||||
|
pointed_thing = pointed_thing,
|
||||||
|
}
|
||||||
|
mcl_hunger.eat_internal[name]._custom_func = drink_milk
|
||||||
|
mcl_hunger.eat_internal[name]._custom_wrapper = function(name)
|
||||||
|
|
||||||
|
mcl_hunger.eat_internal[name]._custom_func(
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.itemstack,
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.player,
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.pointed_thing
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
--mcl_hunger.eat_internal[name]._custom_do_delayed = true -- Only _custom_wrapper will be executed after holding RMB or LMB within a specified delay
|
||||||
|
minetest.do_item_eat(0, "mcl_buckets:bucket_empty", itemstack, player, pointed_thing)
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_craftitem("mcl_mobitems:milk_bucket", {
|
minetest.register_craftitem("mcl_mobitems:milk_bucket", {
|
||||||
description = S("Milk"),
|
description = S("Milk"),
|
||||||
_tt_help = minetest.colorize(mcl_colors.GREEN, S("Removes all status effects")),
|
_tt_help = minetest.colorize(mcl_colors.GREEN, S("Removes all status effects")),
|
||||||
|
@ -152,8 +198,10 @@ minetest.register_craftitem("mcl_mobitems:milk_bucket", {
|
||||||
_doc_items_usagehelp = S("Use the placement key to drink the milk."),
|
_doc_items_usagehelp = S("Use the placement key to drink the milk."),
|
||||||
inventory_image = "mcl_mobitems_bucket_milk.png",
|
inventory_image = "mcl_mobitems_bucket_milk.png",
|
||||||
wield_image = "mcl_mobitems_bucket_milk.png",
|
wield_image = "mcl_mobitems_bucket_milk.png",
|
||||||
on_place = drink_milk,
|
--on_place = drink_milk, -- Will do effect immediately but not reduce item count until eating delay ends which makes it exploitable by deliberately not finishing delay
|
||||||
on_secondary_use = drink_milk,
|
--on_secondary_use = drink_milk,
|
||||||
|
on_place = drink_milk_delayed,
|
||||||
|
on_secondary_use = drink_milk_delayed,
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
groups = { food = 3, can_eat_when_full = 1 },
|
groups = { food = 3, can_eat_when_full = 1 },
|
||||||
})
|
})
|
||||||
|
@ -298,7 +346,7 @@ minetest.register_craftitem("mcl_mobitems:rabbit_stew", {
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
on_place = minetest.item_eat(10, "mcl_core:bowl"),
|
on_place = minetest.item_eat(10, "mcl_core:bowl"),
|
||||||
on_secondary_use = minetest.item_eat(10, "mcl_core:bowl"),
|
on_secondary_use = minetest.item_eat(10, "mcl_core:bowl"),
|
||||||
groups = { food = 3, eatable = 10 },
|
groups = { food = 2, eatable = 10 },
|
||||||
_mcl_saturation = 12.0,
|
_mcl_saturation = 12.0,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ minetest.register_craftitem("mcl_mushrooms:mushroom_stew", {
|
||||||
inventory_image = "farming_mushroom_stew.png",
|
inventory_image = "farming_mushroom_stew.png",
|
||||||
on_place = minetest.item_eat(6, "mcl_core:bowl"),
|
on_place = minetest.item_eat(6, "mcl_core:bowl"),
|
||||||
on_secondary_use = minetest.item_eat(6, "mcl_core:bowl"),
|
on_secondary_use = minetest.item_eat(6, "mcl_core:bowl"),
|
||||||
groups = { food = 3, eatable = 6 },
|
groups = { food = 2, eatable = 6 },
|
||||||
_mcl_saturation = 7.2,
|
_mcl_saturation = 7.2,
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
})
|
})
|
||||||
|
|
|
@ -61,7 +61,26 @@ function return_on_use(def, effect, dur)
|
||||||
return itemstack
|
return itemstack
|
||||||
end
|
end
|
||||||
|
|
||||||
def.on_use(user, effect, dur)
|
--def.on_use(user, effect, dur) -- Will do effect immediately but not reduce item count until eating delay ends which makes it exploitable by deliberately not finishing delay
|
||||||
|
|
||||||
|
-- Wrapper for handling mcl_hunger delayed eating
|
||||||
|
local name = user:get_player_name()
|
||||||
|
mcl_hunger.eat_internal[name]._custom_itemstack = itemstack -- Used as comparison to make sure the custom wrapper executes only when the same item is eaten
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var = {
|
||||||
|
user = user,
|
||||||
|
effect = effect,
|
||||||
|
dur = dur,
|
||||||
|
}
|
||||||
|
mcl_hunger.eat_internal[name]._custom_func = def.on_use
|
||||||
|
mcl_hunger.eat_internal[name]._custom_wrapper = function(name)
|
||||||
|
|
||||||
|
mcl_hunger.eat_internal[name]._custom_func(
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.user,
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.effect,
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.dur
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
local old_name, old_count = itemstack:get_name(), itemstack:get_count()
|
local old_name, old_count = itemstack:get_name(), itemstack:get_count()
|
||||||
itemstack = minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing)
|
itemstack = minetest.do_item_eat(0, "mcl_potions:glass_bottle", itemstack, user, pointed_thing)
|
||||||
if old_name ~= itemstack:get_name() or old_count ~= itemstack:get_count() then
|
if old_name ~= itemstack:get_name() or old_count ~= itemstack:get_count() then
|
||||||
|
|
|
@ -78,6 +78,50 @@ local function eat_stew(itemstack, user, pointed_thing)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function eat_stew_delayed(itemstack, user, pointed_thing)
|
||||||
|
|
||||||
|
if pointed_thing.type == "node" then
|
||||||
|
if user and not user:get_player_control().sneak then
|
||||||
|
-- Use pointed node's on_rightclick function first, if present
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
if user and not user:get_player_control().sneak then
|
||||||
|
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||||
|
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif pointed_thing.type == "object" then
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Wrapper for handling mcl_hunger delayed eating
|
||||||
|
local name = user:get_player_name()
|
||||||
|
mcl_hunger.eat_internal[name]._custom_itemstack = itemstack -- Used as comparison to make sure the custom wrapper executes only when the same item is eaten
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var = {
|
||||||
|
itemstack = itemstack,
|
||||||
|
user = user,
|
||||||
|
pointed_thing = pointed_thing,
|
||||||
|
}
|
||||||
|
mcl_hunger.eat_internal[name]._custom_func = eat_stew
|
||||||
|
mcl_hunger.eat_internal[name]._custom_wrapper = function(name)
|
||||||
|
|
||||||
|
mcl_hunger.eat_internal[name]._custom_func(
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.itemstack,
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.user,
|
||||||
|
mcl_hunger.eat_internal[name]._custom_var.pointed_thing
|
||||||
|
)
|
||||||
|
|
||||||
|
local user = mcl_hunger.eat_internal[name]._custom_var.user
|
||||||
|
|
||||||
|
minetest.after(0, function()
|
||||||
|
user:get_inventory():set_stack("main", user:get_wield_index(), "mcl_core:bowl")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
mcl_hunger.eat_internal[name]._custom_do_delayed = true -- Only _custom_wrapper will be executed after holding RMB or LMB within a specified delay
|
||||||
|
--minetest.do_item_eat(0, "mcl_core:bowl", itemstack, user, pointed_thing)
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
|
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
|
||||||
if itemstack:get_name() ~= "mcl_sus_stew:stew" then return end
|
if itemstack:get_name() ~= "mcl_sus_stew:stew" then return end
|
||||||
for f,e in pairs(flower_effect) do
|
for f,e in pairs(flower_effect) do
|
||||||
|
@ -96,8 +140,10 @@ minetest.register_craftitem("mcl_sus_stew:stew",{
|
||||||
description = S("Suspicious Stew"),
|
description = S("Suspicious Stew"),
|
||||||
inventory_image = "sus_stew.png",
|
inventory_image = "sus_stew.png",
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
on_place = eat_stew,
|
--on_place = eat_stew,
|
||||||
on_secondary_use = eat_stew,
|
--on_secondary_use = eat_stew,
|
||||||
|
on_place = eat_stew_delayed,
|
||||||
|
on_secondary_use = eat_stew_delayed,
|
||||||
groups = { food = 2, eatable = 4, can_eat_when_full = 1, not_in_creative_inventory=1,},
|
groups = { food = 2, eatable = 4, can_eat_when_full = 1, not_in_creative_inventory=1,},
|
||||||
_mcl_saturation = 7.2,
|
_mcl_saturation = 7.2,
|
||||||
})
|
})
|
||||||
|
|
|
@ -49,3 +49,7 @@ Initial release
|
||||||
- Fix mod not working with both intllib and mod security enabled
|
- Fix mod not working with both intllib and mod security enabled
|
||||||
- Add missing screenshot
|
- Add missing screenshot
|
||||||
- Rewrite README and use Markdown format
|
- Rewrite README and use Markdown format
|
||||||
|
|
||||||
|
0.6.0
|
||||||
|
-----
|
||||||
|
- Add eating delay
|
||||||
|
|
|
@ -38,7 +38,26 @@ function minetest.do_item_eat(hp_change, replace_with_item, itemstack, user, poi
|
||||||
local can_eat_when_full = creative or (mcl_hunger.active == false)
|
local can_eat_when_full = creative or (mcl_hunger.active == false)
|
||||||
or minetest.get_item_group(itemstack:get_name(), "can_eat_when_full") == 1
|
or minetest.get_item_group(itemstack:get_name(), "can_eat_when_full") == 1
|
||||||
-- Don't allow eating when player has full hunger bar (some exceptional items apply)
|
-- Don't allow eating when player has full hunger bar (some exceptional items apply)
|
||||||
if can_eat_when_full or (mcl_hunger.get_hunger(user) < 20) then
|
if not no_eat_delay and not mcl_hunger.eat_internal[name].is_eating and not mcl_hunger.eat_internal[name].do_item_eat and (can_eat_when_full or (mcl_hunger.get_hunger(user) < 20)) then
|
||||||
|
local itemname = itemstack:get_name()
|
||||||
|
table.update(mcl_hunger.eat_internal[name], {
|
||||||
|
is_eating = true,
|
||||||
|
is_eating_no_padding = true,
|
||||||
|
itemname = itemname,
|
||||||
|
item_definition = minetest.registered_items[itemname],
|
||||||
|
hp_change = hp_change,
|
||||||
|
replace_with_item = replace_with_item,
|
||||||
|
itemstack = itemstack,
|
||||||
|
user = user,
|
||||||
|
pointed_thing = pointed_thing
|
||||||
|
})
|
||||||
|
elseif (mcl_hunger.eat_internal[name].do_item_eat or no_eat_delay) and (can_eat_when_full or (mcl_hunger.get_hunger(user) < 20)) then
|
||||||
|
if mcl_hunger.eat_internal[name]._custom_itemstack and
|
||||||
|
mcl_hunger.eat_internal[name]._custom_wrapper and
|
||||||
|
mcl_hunger.eat_internal[name]._custom_itemstack == itemstack then
|
||||||
|
|
||||||
|
mcl_hunger.eat_internal[name]._custom_wrapper(name)
|
||||||
|
end
|
||||||
itemstack = mcl_hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
itemstack = mcl_hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
||||||
for _, callback in pairs(minetest.registered_on_item_eats) do
|
for _, callback in pairs(minetest.registered_on_item_eats) do
|
||||||
local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing, old_itemstack)
|
local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing, old_itemstack)
|
||||||
|
@ -47,6 +66,7 @@ function minetest.do_item_eat(hp_change, replace_with_item, itemstack, user, poi
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
mcl_hunger.last_eat[name] = os.time()
|
mcl_hunger.last_eat[name] = os.time()
|
||||||
|
user:get_inventory():set_stack("main", user:get_wield_index(), itemstack)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -129,49 +149,9 @@ function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poiso
|
||||||
--local hp = user:get_hp()
|
--local hp = user:get_hp()
|
||||||
|
|
||||||
local pos = user:get_pos()
|
local pos = user:get_pos()
|
||||||
-- player height
|
local def = minetest.registered_items[itemname]
|
||||||
pos.y = pos.y + 1.5
|
|
||||||
local foodtype = minetest.get_item_group(itemname, "food")
|
mcl_hunger.eat_effects(user, itemname, pos, hunger_change, def)
|
||||||
if foodtype == 3 then
|
|
||||||
-- Item is a drink, only play drinking sound (no particle)
|
|
||||||
minetest.sound_play("survival_thirst_drink", {
|
|
||||||
max_hear_distance = 12,
|
|
||||||
gain = 1.0,
|
|
||||||
pitch = 1 + math.random(-10, 10)*0.005,
|
|
||||||
object = user,
|
|
||||||
}, true)
|
|
||||||
else
|
|
||||||
-- Assume the item is a food
|
|
||||||
-- Add eat particle effect and sound
|
|
||||||
local def = minetest.registered_items[itemname]
|
|
||||||
local texture = def.inventory_image
|
|
||||||
if not texture or texture == "" then
|
|
||||||
texture = def.wield_image
|
|
||||||
end
|
|
||||||
-- Special item definition field: _food_particles
|
|
||||||
-- If false, force item to not spawn any food partiles when eaten
|
|
||||||
if def._food_particles ~= false and texture and texture ~= "" then
|
|
||||||
local v = user:get_velocity() or user:get_player_velocity()
|
|
||||||
for i = 0, math.min(math.max(8, hunger_change*2), 25) do
|
|
||||||
minetest.add_particle({
|
|
||||||
pos = { x = pos.x, y = pos.y, z = pos.z },
|
|
||||||
velocity = vector.add(v, { x = math.random(-1, 1), y = math.random(1, 2), z = math.random(-1, 1) }),
|
|
||||||
acceleration = { x = 0, y = math.random(-9, -5), z = 0 },
|
|
||||||
expirationtime = 1,
|
|
||||||
size = math.random(1, 2),
|
|
||||||
collisiondetection = true,
|
|
||||||
vertical = false,
|
|
||||||
texture = "[combine:3x3:" .. -i .. "," .. -i .. "=" .. texture,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
minetest.sound_play("mcl_hunger_bite", {
|
|
||||||
max_hear_distance = 12,
|
|
||||||
gain = 1.0,
|
|
||||||
pitch = 1 + math.random(-10, 10)*0.005,
|
|
||||||
object = user,
|
|
||||||
}, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
if mcl_hunger.active and hunger_change then
|
if mcl_hunger.active and hunger_change then
|
||||||
-- Add saturation (must be defined in item table)
|
-- Add saturation (must be defined in item table)
|
||||||
|
@ -226,6 +206,61 @@ function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poiso
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function mcl_hunger.eat_effects(user, itemname, pos, hunger_change, item_def, pitch)
|
||||||
|
if user and itemname and pos and hunger_change and item_def then
|
||||||
|
local name = user:get_player_name()
|
||||||
|
if mcl_hunger.eat_internal[name] and mcl_hunger.eat_internal[name].do_item_eat then
|
||||||
|
pitch = 0.95
|
||||||
|
end
|
||||||
|
local def = item_def
|
||||||
|
-- player height
|
||||||
|
pos.y = pos.y + 1.5
|
||||||
|
local foodtype = minetest.get_item_group(itemname, "food")
|
||||||
|
if foodtype == 3 then
|
||||||
|
-- Item is a drink, only play drinking sound (no particle)
|
||||||
|
minetest.sound_play("survival_thirst_drink", {
|
||||||
|
max_hear_distance = 12,
|
||||||
|
gain = 1.0,
|
||||||
|
pitch = pitch or 1 + math.random(-10, 10)*0.005,
|
||||||
|
object = user,
|
||||||
|
}, true)
|
||||||
|
else
|
||||||
|
-- Assume the item is a food
|
||||||
|
-- Add eat particle effect and sound
|
||||||
|
--local def = minetest.registered_items[itemname]
|
||||||
|
local texture = def.inventory_image
|
||||||
|
if not texture or texture == "" then
|
||||||
|
texture = def.wield_image
|
||||||
|
end
|
||||||
|
-- Special item definition field: _food_particles
|
||||||
|
-- If false, force item to not spawn any food partiles when eaten
|
||||||
|
if def._food_particles ~= false and texture and texture ~= "" then
|
||||||
|
local v = user:get_velocity() or user:get_player_velocity()
|
||||||
|
for i = 0, math.min(math.max(8, hunger_change*2), 25) do
|
||||||
|
minetest.add_particle({
|
||||||
|
pos = { x = pos.x, y = pos.y, z = pos.z },
|
||||||
|
velocity = vector.add(v, { x = math.random(-1, 1), y = math.random(1, 2), z = math.random(-1, 1) }),
|
||||||
|
acceleration = { x = 0, y = math.random(-9, -5), z = 0 },
|
||||||
|
expirationtime = 1,
|
||||||
|
size = math.random(1, 2),
|
||||||
|
collisiondetection = true,
|
||||||
|
vertical = false,
|
||||||
|
texture = "[combine:3x3:" .. -i .. "," .. -i .. "=" .. texture,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
minetest.sound_play("mcl_hunger_bite", {
|
||||||
|
max_hear_distance = 12,
|
||||||
|
gain = 1.0,
|
||||||
|
pitch = pitch or 1 + math.random(-10, 10)*0.005,
|
||||||
|
object = user,
|
||||||
|
}, true)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if mcl_hunger.active then
|
if mcl_hunger.active then
|
||||||
-- player-action based hunger changes
|
-- player-action based hunger changes
|
||||||
minetest.register_on_dignode(function(pos, oldnode, player)
|
minetest.register_on_dignode(function(pos, oldnode, player)
|
||||||
|
|
|
@ -30,6 +30,10 @@ mcl_hunger.EXHAUST_REGEN = 6000 -- Regenerate 1 HP
|
||||||
mcl_hunger.EXHAUST_HUNGER = 5 -- Hunger status effect at base level.
|
mcl_hunger.EXHAUST_HUNGER = 5 -- Hunger status effect at base level.
|
||||||
mcl_hunger.EXHAUST_LVL = 4000 -- at what exhaustion player saturation gets lowered
|
mcl_hunger.EXHAUST_LVL = 4000 -- at what exhaustion player saturation gets lowered
|
||||||
|
|
||||||
|
mcl_hunger.EATING_DELAY = tonumber(minetest.settings:get("mcl_eating_delay")) or 1.61
|
||||||
|
mcl_hunger.EATING_WALK_SPEED = tonumber(minetest.settings:get("movement_speed_crouch")) / tonumber(minetest.settings:get("movement_speed_walk"))
|
||||||
|
mcl_hunger.EATING_TOUCHSCREEN_DELAY_PADDING = 0.75
|
||||||
|
|
||||||
mcl_hunger.SATURATION_INIT = 5 -- Initial saturation for new/respawning players
|
mcl_hunger.SATURATION_INIT = 5 -- Initial saturation for new/respawning players
|
||||||
|
|
||||||
-- Debug Mode. If enabled, saturation and exhaustion are shown as well.
|
-- Debug Mode. If enabled, saturation and exhaustion are shown as well.
|
||||||
|
@ -39,6 +43,53 @@ mcl_hunger.debug = false
|
||||||
-- Cooldown timers for each player, to force a short delay between consuming 2 food items
|
-- Cooldown timers for each player, to force a short delay between consuming 2 food items
|
||||||
mcl_hunger.last_eat = {}
|
mcl_hunger.last_eat = {}
|
||||||
|
|
||||||
|
-- Is player eating API
|
||||||
|
function mcl_hunger.is_eating(name)
|
||||||
|
local result
|
||||||
|
if name then
|
||||||
|
if type(name) ~= "string" then
|
||||||
|
name = name:get_player_name()
|
||||||
|
end
|
||||||
|
result = mcl_hunger.eat_internal[name].is_eating_no_padding
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Variables for each player, to handle delayed eating
|
||||||
|
mcl_hunger.eat_internal = {}
|
||||||
|
|
||||||
|
-- Set per player internal variables for delayed eating
|
||||||
|
minetest.register_on_joinplayer(function(player)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
|
||||||
|
mcl_hunger.eat_internal[name] = {
|
||||||
|
is_eating = false,
|
||||||
|
is_eating_no_padding = false,
|
||||||
|
itemname = nil,
|
||||||
|
item_definition = nil,
|
||||||
|
hp_change = nil,
|
||||||
|
replace_with_item = nil,
|
||||||
|
itemstack = nil,
|
||||||
|
user = nil,
|
||||||
|
pointed_thing = nil,
|
||||||
|
pitch = nil,
|
||||||
|
do_item_eat = false,
|
||||||
|
_custom_itemstack = nil, -- Used as comparison to make sure _custom_wrapper only executes when the same item is eaten
|
||||||
|
_custom_var = {}, -- Variables that can be used by _custom_var and _custom_wrapper
|
||||||
|
_custom_func = nil, -- Can be executed by _custom_wrapper
|
||||||
|
_custom_wrapper = nil, -- Will execute alongside minetest.do_item_eat if not empty and _custom_itemstack is equal to current player itemstack
|
||||||
|
_custom_do_delayed = false, -- If true, then will execute only _custom_wrapper after holding RMB or LMB within a delay specified by mcl_hunger.EATING_DELAY (Use to bypass minetest.do_item_eat entirely)
|
||||||
|
}
|
||||||
|
playerphysics.remove_physics_factor(player, "speed", "mcl_hunger:eating_speed")
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Clear when player leaves
|
||||||
|
minetest.register_on_leaveplayer(function(player)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
|
||||||
|
mcl_hunger.eat_internal[name] = nil
|
||||||
|
end)
|
||||||
|
|
||||||
dofile(modpath.."/api.lua")
|
dofile(modpath.."/api.lua")
|
||||||
dofile(modpath.."/hunger.lua")
|
dofile(modpath.."/hunger.lua")
|
||||||
dofile(modpath.."/register_foods.lua")
|
dofile(modpath.."/register_foods.lua")
|
||||||
|
@ -138,6 +189,35 @@ minetest.register_on_player_hpchange(function(player, hp_change)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local food_tick_timers = {} -- one food_tick_timer per player, keys are the player-objects
|
local food_tick_timers = {} -- one food_tick_timer per player, keys are the player-objects
|
||||||
|
local eat_start_timers = {}
|
||||||
|
local eat_tick_timers = {}
|
||||||
|
local eat_effects_cooldown = {}
|
||||||
|
|
||||||
|
local function clear_eat_internal_and_timers(player, player_name)
|
||||||
|
playerphysics.remove_physics_factor(player, "speed", "mcl_hunger:eating_speed")
|
||||||
|
mcl_hunger.eat_internal[player_name] = {
|
||||||
|
is_eating = false,
|
||||||
|
is_eating_no_padding = false,
|
||||||
|
itemname = nil,
|
||||||
|
item_definition = nil,
|
||||||
|
hp_change = nil,
|
||||||
|
replace_with_item = nil,
|
||||||
|
itemstack = nil,
|
||||||
|
user = nil,
|
||||||
|
pointed_thing = nil,
|
||||||
|
pitch = nil,
|
||||||
|
do_item_eat = false,
|
||||||
|
_custom_itemstack = nil,
|
||||||
|
_custom_var = {},
|
||||||
|
_custom_func = nil,
|
||||||
|
_custom_wrapper = nil,
|
||||||
|
_custom_do_delayed = false,
|
||||||
|
}
|
||||||
|
eat_start_timers[player] = 0
|
||||||
|
eat_tick_timers[player] = 0
|
||||||
|
eat_effects_cooldown[player] = 0
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
for _,player in pairs(minetest.get_connected_players()) do
|
for _,player in pairs(minetest.get_connected_players()) do
|
||||||
|
|
||||||
|
@ -184,6 +264,109 @@ minetest.register_globalstep(function(dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
food_tick_timers[player] = food_tick_timer -- update food_tick_timer table
|
food_tick_timers[player] = food_tick_timer -- update food_tick_timer table
|
||||||
|
|
||||||
|
-- Eating delay code
|
||||||
|
if mcl_hunger.eat_internal[player_name].is_eating or mcl_hunger.eat_internal[player_name]._custom_do_delayed then
|
||||||
|
mcl_hunger.eat_internal[player_name].is_eating = true
|
||||||
|
mcl_hunger.eat_internal[player_name].is_eating_no_padding = true
|
||||||
|
|
||||||
|
local control = player:get_player_control()
|
||||||
|
local inv = player:get_inventory()
|
||||||
|
local current_itemstack = player:get_wielded_item()
|
||||||
|
|
||||||
|
if not eat_start_timers[player] then
|
||||||
|
eat_start_timers[player] = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
eat_start_timers[player] = eat_start_timers[player] + dtime
|
||||||
|
|
||||||
|
if not eat_tick_timers[player] then
|
||||||
|
eat_tick_timers[player] = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if not eat_effects_cooldown[player] then
|
||||||
|
eat_effects_cooldown[player] = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if not mcl_hunger.eat_internal[player_name].pitch then
|
||||||
|
mcl_hunger.eat_internal[player_name].pitch = 1 + math.random(-10, 10)*0.005
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check if holding RMB (or LMB as workaround for touchscreen)
|
||||||
|
if (current_itemstack == mcl_hunger.eat_internal[player_name].itemstack or current_itemstack == mcl_hunger.eat_internal[player_name]._custom_itemstack) and (control.RMB or control.LMB) then
|
||||||
|
eat_tick_timers[player] = eat_tick_timers[player] + dtime
|
||||||
|
eat_effects_cooldown[player] = eat_effects_cooldown[player] + dtime
|
||||||
|
|
||||||
|
playerphysics.add_physics_factor(player, "speed", "mcl_hunger:eating_speed", mcl_hunger.EATING_WALK_SPEED)
|
||||||
|
|
||||||
|
if eat_effects_cooldown[player] > 0.2 then
|
||||||
|
eat_effects_cooldown[player] = 0
|
||||||
|
|
||||||
|
if not mcl_hunger.eat_internal[player_name].user then
|
||||||
|
mcl_hunger.eat_internal[player_name].user = player
|
||||||
|
end
|
||||||
|
|
||||||
|
if not mcl_hunger.eat_internal[player_name].itemname then
|
||||||
|
mcl_hunger.eat_internal[player_name].itemname = current_itemstack:get_name()
|
||||||
|
end
|
||||||
|
|
||||||
|
if not mcl_hunger.eat_internal[player_name].hp_change then
|
||||||
|
mcl_hunger.eat_internal[player_name].hp_change = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos = player:get_pos()
|
||||||
|
local itemname = mcl_hunger.eat_internal[player_name].itemname
|
||||||
|
local def = minetest.registered_items[itemname]
|
||||||
|
|
||||||
|
mcl_hunger.eat_effects(
|
||||||
|
mcl_hunger.eat_internal[player_name].user,
|
||||||
|
mcl_hunger.eat_internal[player_name].itemname,
|
||||||
|
pos,
|
||||||
|
mcl_hunger.eat_internal[player_name].hp_change,
|
||||||
|
def,
|
||||||
|
mcl_hunger.eat_internal[player_name].pitch
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check if eating delay is over
|
||||||
|
if eat_tick_timers[player] >= mcl_hunger.EATING_DELAY then
|
||||||
|
|
||||||
|
if not mcl_hunger.eat_internal[player_name]._custom_do_delayed then
|
||||||
|
mcl_hunger.eat_internal[player_name].do_item_eat = true
|
||||||
|
|
||||||
|
minetest.do_item_eat(
|
||||||
|
mcl_hunger.eat_internal[player_name].hp_change,
|
||||||
|
mcl_hunger.eat_internal[player_name].replace_with_item,
|
||||||
|
mcl_hunger.eat_internal[player_name].itemstack,
|
||||||
|
mcl_hunger.eat_internal[player_name].user,
|
||||||
|
mcl_hunger.eat_internal[player_name].pointed_thing
|
||||||
|
)
|
||||||
|
|
||||||
|
-- bypass minetest.do_item_eat and only execute _custom_wrapper
|
||||||
|
elseif mcl_hunger.eat_internal[player_name]._custom_itemstack and
|
||||||
|
mcl_hunger.eat_internal[player_name]._custom_wrapper and
|
||||||
|
mcl_hunger.eat_internal[player_name]._custom_itemstack == current_itemstack then
|
||||||
|
|
||||||
|
mcl_hunger.eat_internal[player_name]._custom_wrapper(player_name)
|
||||||
|
|
||||||
|
player:get_inventory():set_stack("main", player:get_wield_index(), itemstack)
|
||||||
|
end
|
||||||
|
|
||||||
|
clear_eat_internal_and_timers(player, player_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif eat_start_timers[player] and eat_start_timers[player] > 0.2 then
|
||||||
|
playerphysics.remove_physics_factor(player, "speed", "mcl_hunger:eating_speed")
|
||||||
|
mcl_hunger.eat_internal[player_name].is_eating_no_padding = false
|
||||||
|
|
||||||
|
elseif eat_start_timers[player] and eat_start_timers[player] > mcl_hunger.EATING_TOUCHSCREEN_DELAY_PADDING then
|
||||||
|
clear_eat_internal_and_timers(player, player_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if eat_start_timers[player] and eat_start_timers[player] > mcl_hunger.EATING_DELAY + mcl_hunger.EATING_TOUCHSCREEN_DELAY_PADDING then
|
||||||
|
clear_eat_internal_and_timers(player, player_name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,10 @@ mcl_hunger_debug (Hunger debug) bool false
|
||||||
# Default: 0.5 s
|
# Default: 0.5 s
|
||||||
mcl_health_regen_delay (Health regen delay) float 0.5 0
|
mcl_health_regen_delay (Health regen delay) float 0.5 0
|
||||||
|
|
||||||
|
# Eating delay while holding right-click
|
||||||
|
# Default: 1.61 s
|
||||||
|
mcl_eating_delay (Eating delay) float 1.61 0
|
||||||
|
|
||||||
[Mobs]
|
[Mobs]
|
||||||
# If enabled, mobs will spawn naturally. This does not affect
|
# If enabled, mobs will spawn naturally. This does not affect
|
||||||
# affect mob spawners.
|
# affect mob spawners.
|
||||||
|
|
Loading…
Reference in New Issue