init
This commit is contained in:
commit
2d26db1c5b
38 changed files with 2837 additions and 0 deletions
79
system/add_hunger_data.lua
Normal file
79
system/add_hunger_data.lua
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
-- Localize Hunger NG
|
||||
local a = hunger_ng.attributes
|
||||
local c = hunger_ng.configuration
|
||||
local e = hunger_ng.effects
|
||||
local f = hunger_ng.functions
|
||||
local s = hunger_ng.settings
|
||||
local S = hunger_ng.configuration.translator
|
||||
|
||||
|
||||
-- Localize Luanti
|
||||
local registered_items = core.registered_items
|
||||
local override_item = core.override_item
|
||||
|
||||
|
||||
-- Add custom _hunger_ng attribute to items
|
||||
--
|
||||
-- Checks if the item already has the attribute. If not, then the provided
|
||||
-- values are set.
|
||||
--
|
||||
-- The data table has to be the following.
|
||||
--
|
||||
-- {
|
||||
-- heals = n,
|
||||
-- satiates = n,
|
||||
-- returns = 'id'
|
||||
-- }
|
||||
--
|
||||
-- Where n is a number (can be negative to damage the player or make the
|
||||
-- player hungry) or a fraction of a number. If `returns` is set to an ID of
|
||||
-- a registered item this item will be returned when the food is eaten.
|
||||
--
|
||||
-- @param id The ID of the item to be modified.
|
||||
-- @param data The data table as described
|
||||
hunger_ng.functions.add_hunger_data = function (id, data)
|
||||
if registered_items[id] == nil then return end
|
||||
if registered_items[id]._hunger_ng ~= nil then return end
|
||||
if registered_items[id].on_use == nil then return end
|
||||
|
||||
local item_data = registered_items[id]
|
||||
local info = ''
|
||||
local satiates = data.satiates or 0
|
||||
local heals = data.heals or 0
|
||||
local returns = data.returns or false
|
||||
local timeout = data.timeout or s.hunger.timeout
|
||||
|
||||
if satiates > 0 then
|
||||
info = info..'\n'..S('Satiates: @1', satiates)
|
||||
hunger_ng.food_items.satiating = hunger_ng.food_items.satiating + 1
|
||||
elseif satiates < 0 then
|
||||
info = info..'\n'..S('Deprives: @1', math.abs(satiates))
|
||||
hunger_ng.food_items.starving = hunger_ng.food_items.starving + 1
|
||||
end
|
||||
|
||||
if heals > 0 then
|
||||
info = info..'\n'..S('Heals: @1', data.heals)
|
||||
hunger_ng.food_items.healing = hunger_ng.food_items.healing + 1
|
||||
elseif heals < 0 then
|
||||
info = info..'\n'..S('Injures: @1', math.abs(heals))
|
||||
hunger_ng.food_items.injuring = hunger_ng.food_items.injuring + 1
|
||||
end
|
||||
|
||||
if returns and registered_items[returns] then
|
||||
local return_name = registered_items[returns].description
|
||||
info = info..'\n'..S('Returns: @1', return_name)
|
||||
end
|
||||
|
||||
if data.returns and not registered_items[returns] then
|
||||
data.returns = nil
|
||||
end
|
||||
|
||||
if timeout > 0 then
|
||||
info = info..'\n'..S('Eating timeout: @1 seconds', timeout)
|
||||
end
|
||||
|
||||
override_item(id, {
|
||||
description = item_data.description..info,
|
||||
_hunger_ng = data
|
||||
})
|
||||
end
|
||||
252
system/chat_commands.lua
Normal file
252
system/chat_commands.lua
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
-- Localize Hunger NG
|
||||
local a = hunger_ng.attributes
|
||||
local c = hunger_ng.configuration
|
||||
local e = hunger_ng.effects
|
||||
local f = hunger_ng.functions
|
||||
local s = hunger_ng.settings
|
||||
local S = hunger_ng.configuration.translator
|
||||
|
||||
|
||||
-- Localize Luanto
|
||||
local chat_send = core.chat_send_player
|
||||
local log = core.log
|
||||
local player_exists = core.player_exists
|
||||
local get_player_by_name = core.get_player_by_name
|
||||
local get_connected_players = core.get_connected_players
|
||||
|
||||
|
||||
-- Set hunger to given value
|
||||
--
|
||||
-- Sets the hunger of the given player to the given value. If the player name
|
||||
-- is omitted own hunger is set.
|
||||
--
|
||||
-- @param name The name of the target player
|
||||
-- @param value The hunger value to set to
|
||||
-- @param caller The player who invoked the command
|
||||
-- @return mixed `void` if player exists, otherwise `nil`
|
||||
local set_hunger = function (name, value, caller)
|
||||
local message = ''
|
||||
|
||||
if not get_player_by_name(name) then
|
||||
chat_send(caller, S('The player @1 is not online', name))
|
||||
return
|
||||
end
|
||||
|
||||
if f.hunger_disabled(name) then
|
||||
chat_send(caller, S('Hunger for @1 is disabled', name))
|
||||
return
|
||||
end
|
||||
|
||||
if value > s.hunger.maximum then value = s.hunger.maximum end
|
||||
if value < 0 then value = 0 end
|
||||
|
||||
f.alter_hunger(name, -s.hunger.maximum, 'chat set 0')
|
||||
f.alter_hunger(name, value, 'chat set target')
|
||||
|
||||
if name ~= caller then
|
||||
chat_send(caller, S('Hunger for @1 set to @2', name, value))
|
||||
chat_send(name, S('@1 set your hunger to @2', caller, value))
|
||||
message = caller..' sets hunger for '..name..' to '..value
|
||||
else
|
||||
chat_send(caller, S('Hunger set to @1', value))
|
||||
message = caller..' sets own hunger to '..value
|
||||
end
|
||||
|
||||
log('action', '[hunger_ng] '..message)
|
||||
end
|
||||
|
||||
|
||||
-- Change the hunger value
|
||||
--
|
||||
-- Changes the hunger value of the given player by the given value. Use
|
||||
-- negative values to substract hunger. If the player name is omitted the own
|
||||
-- hunger gets changed.
|
||||
--
|
||||
-- @param name The name of the target player
|
||||
-- @param value The hunger value to change by
|
||||
-- @param caller The player who invoked the command
|
||||
-- @return mixed `void` if player exists, otherwise `nil`
|
||||
local change_hunger = function (name, value, caller)
|
||||
local message = ''
|
||||
|
||||
if not get_player_by_name(name) then
|
||||
chat_send(caller, S('The player @1 is not online', name))
|
||||
return
|
||||
end
|
||||
|
||||
if f.hunger_disabled(name) then
|
||||
chat_send(caller, S('Hunger for @1 is disabled', name))
|
||||
return
|
||||
end
|
||||
|
||||
if value > s.hunger.maximum then value = s.hunger.maximum end
|
||||
if value < -s.hunger.maximum then value = -s.hunger.maximum end
|
||||
|
||||
f.alter_hunger(name, value, 'chat change')
|
||||
|
||||
if name ~= caller then
|
||||
chat_send(caller, S('Hunger for @1 changed by @2', name, value))
|
||||
chat_send(name, S('@1 changed your hunger by @2', caller, value))
|
||||
message = caller..'changes hunger for '..name..' by '..value
|
||||
else
|
||||
chat_send(caller, S('Hunger changed by @1', value))
|
||||
message = caller..' changes own hunger by '..value
|
||||
end
|
||||
|
||||
log('action', '[hunger_ng] '..message)
|
||||
end
|
||||
|
||||
|
||||
-- Toggle hunger being enabled
|
||||
--
|
||||
-- Toggles the hunger for the given player from enabled to disabled.
|
||||
--
|
||||
-- @param name The name of the target player
|
||||
-- @param caller The player who invoked the command
|
||||
-- @return mixed `void` if player exists, otherwise `nil`
|
||||
local toggle_hunger = function (name, value, caller)
|
||||
local message = ''
|
||||
local action = ''
|
||||
local name = name == '' and caller or name
|
||||
|
||||
if not get_player_by_name(name) then
|
||||
chat_send(caller, S('The player @1 is not online', name))
|
||||
return
|
||||
end
|
||||
|
||||
if f.hunger_disabled(name) then
|
||||
hunger_ng.configure_hunger(name, 'enable')
|
||||
action = 'enabled'
|
||||
else
|
||||
hunger_ng.configure_hunger(name, 'disable')
|
||||
action = 'disabled'
|
||||
end
|
||||
|
||||
if name ~= caller then
|
||||
chat_send(caller, S('Hunger for @1 was toggled', name))
|
||||
chat_send(name, S('@1 toggled your hunger', caller))
|
||||
message = caller..' '..action..' hunger for '..name
|
||||
else
|
||||
chat_send(caller, S('Own hunger was toggled'))
|
||||
message = caller..' '..action..' own hunger'
|
||||
end
|
||||
|
||||
log('action', '[hunger_ng] '..message)
|
||||
end
|
||||
|
||||
|
||||
-- Get the hunger value
|
||||
--
|
||||
-- When called without name parameter it gets the hunger values from all
|
||||
-- currently connected players. If a name is given the hunger value for that
|
||||
-- player is returned if the player is online
|
||||
--
|
||||
-- @param name The name of the target player
|
||||
-- @param caller The player who invoked the command
|
||||
-- @return void
|
||||
local get_hunger = function(name, caller)
|
||||
local message = ''
|
||||
|
||||
if name == '' then name = get_connected_players()
|
||||
else name = { get_player_by_name(name) } end
|
||||
|
||||
for _,player in pairs(name) do
|
||||
if player:is_player() then
|
||||
local player_name = player:get_player_name()
|
||||
local player_hunger = f.get_data(player_name, a.hunger_value)
|
||||
local hunger_disabled = f.hunger_disabled(player_name)
|
||||
|
||||
if not hunger_disabled then
|
||||
chat_send(caller, player_name..': '..player_hunger)
|
||||
else
|
||||
chat_send(caller, player_name..': '..S('Hunger is disabled'))
|
||||
end
|
||||
|
||||
if player_name == caller then
|
||||
message = caller..' gets own hunger value'
|
||||
else
|
||||
message = caller..' gets hunger value for '..player_name
|
||||
end
|
||||
|
||||
log('action', '[hunger_ng] '..message)
|
||||
end
|
||||
end
|
||||
|
||||
if #name == 0 then
|
||||
chat_send(caller, S('No player matches your criteria'))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Show the help message
|
||||
--
|
||||
-- Shows the help message to the caller
|
||||
--
|
||||
-- @param caller The player who invoked the command
|
||||
-- @return void
|
||||
local show_help = function (caller)
|
||||
chat_send(caller, S('run `/help hunger` to show help'))
|
||||
end
|
||||
|
||||
|
||||
-- Register privilege for hunger control
|
||||
core.register_privilege('manage_hunger', {
|
||||
description = S('Player can view and alter own and others hunger values.')
|
||||
})
|
||||
|
||||
|
||||
-- Administrative chat command definition
|
||||
core.register_chatcommand('hunger', {
|
||||
params = '<set/change/get/toggle> <name> <value>',
|
||||
description = S('Modify or get hunger values'),
|
||||
privs = { manage_hunger = true },
|
||||
func = function (caller, parameters)
|
||||
local pt= {}
|
||||
for p in parameters:gmatch("%S+") do table.insert(pt, p) end
|
||||
local action = pt[1] or ''
|
||||
local name = pt[2] or ''
|
||||
local value = pt[3] or ''
|
||||
|
||||
-- Name parameter missing
|
||||
if not player_exists(name) and tonumber(name) and value == '' then
|
||||
value = name
|
||||
name = caller
|
||||
end
|
||||
|
||||
-- Convert value to number or print error message when trying to set
|
||||
-- a value but no proper value was given
|
||||
if tonumber(value) then
|
||||
value = tonumber(value)
|
||||
else
|
||||
if action ~= 'get' and action ~= 'toggle' then
|
||||
show_help(caller)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Execute the corresponding function for the defined action
|
||||
if action == 'set' then set_hunger(name, value, caller)
|
||||
elseif action == 'change' then change_hunger(name, value, caller)
|
||||
elseif action == 'get' then get_hunger(name, caller)
|
||||
elseif action == 'toggle' then toggle_hunger(name, value, caller)
|
||||
else show_help(caller) end
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
-- Personal information chat command
|
||||
core.register_chatcommand('myhunger', {
|
||||
params = 'name',
|
||||
description = S('Show own hunger value'),
|
||||
privs = { interact = true },
|
||||
func = function (caller)
|
||||
local player_hunger = f.get_data(caller, a.hunger_value)
|
||||
local hunger_disabled = f.hunger_disabled(caller)
|
||||
if hunger_disabled then
|
||||
chat_send(caller, S('Your hunger is disabled'))
|
||||
else
|
||||
chat_send(caller, S('Your hunger value is @1', player_hunger))
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
283
system/hunger_functions.lua
Normal file
283
system/hunger_functions.lua
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
-- Localize Hunger NG
|
||||
local a = hunger_ng.attributes
|
||||
local c = hunger_ng.configuration
|
||||
local e = hunger_ng.effects
|
||||
local f = hunger_ng.functions
|
||||
local s = hunger_ng.settings
|
||||
local S = hunger_ng.configuration.translator
|
||||
|
||||
-- Localize Luanti
|
||||
local core_log = core.log
|
||||
local get_player_by_name = core.get_player_by_name
|
||||
local get_current_modname = core.get_current_modname
|
||||
|
||||
|
||||
-- Gets and returns the given player-related data
|
||||
--
|
||||
-- To gain more flexibility this function is used wherever something from the
|
||||
-- player has to be loaded either as custom player attribute or as planned
|
||||
-- player meta data.
|
||||
--
|
||||
-- @param playername The name of the player to get the information from
|
||||
-- @param field The field that has to be get.
|
||||
-- @param as_string Optionally return the value of the field as string
|
||||
-- @return bool|string|number
|
||||
local get_data = function (playername, field, as_string)
|
||||
local player = get_player_by_name(playername)
|
||||
if not player then return false end
|
||||
|
||||
local player_meta = player:get_meta()
|
||||
|
||||
if as_string then
|
||||
return tostring(player_meta:get(field) or 'invalid')
|
||||
else
|
||||
return tonumber(player_meta:get(field) or nil)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Sets a player-related attribute
|
||||
--
|
||||
-- To gain more flexibility on the player-related functions this function can
|
||||
-- be used wherever a player-related attribute has to be set.
|
||||
--
|
||||
-- @param playername The name of the player to set the attribute to
|
||||
-- @param field The field to set
|
||||
-- @param value The value to set the field to
|
||||
-- @return void
|
||||
local set_data = function (playername, field, value)
|
||||
local player = get_player_by_name(playername)
|
||||
if not player then return false end
|
||||
local player_meta = player:get_meta()
|
||||
player_meta:set_string(field, value)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Print health and hunger changes
|
||||
--
|
||||
-- This function prints all health and hunger changes that are triggered by
|
||||
-- this mod. The following information will be shown for every change.
|
||||
--
|
||||
-- t: Ingame time when the change was applied
|
||||
-- p: player name affected by the change
|
||||
-- w: Information on what was changes (hunger/health)
|
||||
-- n: The new value as defined by the definition
|
||||
-- d: definition (calculation) of the change (old + change = new)
|
||||
--
|
||||
-- @param playername Name of the player (p)
|
||||
-- @param what Description on what was changed (w, hunger/health)
|
||||
-- @param old The old value
|
||||
-- @param new The new value
|
||||
-- @param change The change amount
|
||||
-- @param reason The given reason for the change
|
||||
-- @return void
|
||||
local debug_log = function (playername, what, old, new, change, reason)
|
||||
if not c.debug_mode then return end
|
||||
local timestamp = 24 * 60 * core.get_timeofday()
|
||||
local h = tostring((math.floor(timestamp/60) % 60))
|
||||
local m = tostring((math.floor(timestamp) % 60))
|
||||
local text = ('t: +t, p: +p, w: +w, n: +n, d: +o + +c, r: +r'):gsub('+.', {
|
||||
['+t'] = string.rep('0', 2-#h)..h..':'..string.rep('0', 2-#m)..m,
|
||||
['+p'] = playername,
|
||||
['+w'] = what,
|
||||
['+o'] = old,
|
||||
['+n'] = new,
|
||||
['+c'] = change,
|
||||
['+r'] = reason or 'n/a'
|
||||
})
|
||||
core_log('action', c.log_prefix..text)
|
||||
end
|
||||
|
||||
|
||||
-- Returns if hunger is disabled for the given player
|
||||
--
|
||||
-- When the player is no `interact` permission or has the `hunger_disabled`
|
||||
-- parameter set then this function returns boolean true. Otherwise boolean
|
||||
-- false will be returned.
|
||||
--
|
||||
-- @param playername The name of the player to check
|
||||
-- @return bool
|
||||
local hunger_disabled = function (playername)
|
||||
local interact = core.check_player_privs(playername, { interact=true })
|
||||
local disabled = get_data(playername, a.hunger_disabled)
|
||||
if core.is_yes(disabled) or not interact then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- Configures hunger effects for the player
|
||||
--
|
||||
-- The function can enable or disable hunger for a player. It is meant to be
|
||||
-- used by other mods to disable or enable hunger effects for a specific
|
||||
-- player. For example a magic item that prevents players from getting hungry.
|
||||
--
|
||||
-- The parameter `action` can be either `disable`, `enable`. The actions are
|
||||
-- very self-explainatory.
|
||||
--
|
||||
-- @param playername The name of the player whose hunger is to be configured
|
||||
-- @param action The action that will be taken as described
|
||||
local configure_hunger = function (playername, action)
|
||||
if not action then return end
|
||||
|
||||
if action == 'enable' then
|
||||
set_data(playername, a.hunger_disabled, 0)
|
||||
elseif action == 'disable' then
|
||||
set_data(playername, a.hunger_disabled, 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Get the current hunger information
|
||||
--
|
||||
-- Gets (Returns) the current hunger information for the given player. See API
|
||||
-- documentation for a detailled overview of the returned table.
|
||||
--
|
||||
-- @param playername The name of the player whose hunger value is to be get
|
||||
-- @return table The table as described
|
||||
hunger_ng.functions.get_hunger_information = function (playername)
|
||||
local player = get_player_by_name(playername)
|
||||
if not player then return { invalid = true, player_name = playername } end
|
||||
|
||||
local last_eaten = get_data(playername, a.eating_timestamp) or 0
|
||||
local current_hunger = get_data(playername, a.hunger_value)
|
||||
local player_properties = player:get_properties()
|
||||
|
||||
local e_heal = get_data(playername, a.effect_heal, true) == 'enabled'
|
||||
local e_hunger = get_data(playername, a.effect_hunger, true) == 'enabled'
|
||||
local e_starve = get_data(playername, a.effect_starve, true) == 'enabled'
|
||||
|
||||
return {
|
||||
player_name = playername,
|
||||
hunger = {
|
||||
floored = math.floor(current_hunger),
|
||||
ceiled = math.ceil(current_hunger),
|
||||
disabled = hunger_disabled(playername),
|
||||
exact = current_hunger,
|
||||
enabled = e_heal
|
||||
},
|
||||
maximum = {
|
||||
hunger = s.hunger.maximum,
|
||||
health = player_properties.hp_max,
|
||||
breath = player_properties.breath_max
|
||||
},
|
||||
effects = {
|
||||
starving = {
|
||||
enabled = e_starve,
|
||||
status = current_hunger < e.starve.below
|
||||
},
|
||||
healing = {
|
||||
enabled = e_heal,
|
||||
status = current_hunger > e.heal.above
|
||||
},
|
||||
current_breath = player:get_breath(),
|
||||
},
|
||||
timestamps = {
|
||||
last_eaten = tonumber(last_eaten),
|
||||
request = tonumber(os.time())
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
-- Alter health by given value
|
||||
--
|
||||
-- @param playername The name of a player whose health value should be altered
|
||||
-- @param change The health change (can be negative to damage the player)
|
||||
hunger_ng.functions.alter_health = function (playername, change, reason)
|
||||
local player = get_player_by_name(playername)
|
||||
local hp_max = player:get_properties().hp_max
|
||||
|
||||
if player == nil then return end
|
||||
if hunger_disabled(playername) then return end
|
||||
|
||||
local current_health = player:get_hp()
|
||||
local new_health = current_health + change
|
||||
|
||||
if new_health > hp_max then new_health = hp_max end
|
||||
if new_health < 0 then new_health = 0 end
|
||||
|
||||
player:set_hp(new_health, { hunger = reason })
|
||||
debug_log(playername, 'health', current_health, new_health, change, reason)
|
||||
end
|
||||
|
||||
|
||||
-- Alter hunger by the given value
|
||||
--
|
||||
-- @param playername The name of a player whose hunger value should be altered
|
||||
-- @param change The hunger change (can be negative to make player hungry)
|
||||
hunger_ng.functions.alter_hunger = function (playername, change, reason)
|
||||
local player = get_player_by_name(playername)
|
||||
|
||||
if player == nil then return end
|
||||
if hunger_disabled(playername) then return end
|
||||
|
||||
local current_hunger = get_data(playername, a.hunger_value)
|
||||
local new_hunger = current_hunger + change
|
||||
local bar_id = get_data(playername, a.hunger_bar_id)
|
||||
|
||||
if new_hunger > s.hunger.maximum then new_hunger = s.hunger.maximum end
|
||||
if new_hunger < 0 then new_hunger = 0 end
|
||||
|
||||
set_data(playername, a.hunger_value, new_hunger)
|
||||
|
||||
if s.hunger_bar.use then
|
||||
player:hud_change(bar_id, 'number', math.ceil(new_hunger))
|
||||
end
|
||||
|
||||
debug_log(playername, 'hunger', current_hunger, new_hunger, change, reason)
|
||||
end
|
||||
|
||||
|
||||
-- Set hunger effect metadata
|
||||
--
|
||||
-- The hunger effect meta data can be set by mods to temporary disable hunger
|
||||
-- effects for the given player. Everything works normal but hunger effects
|
||||
-- like hunger itself, starving and healing are not performed even if the
|
||||
-- player is in a state where this would happen.
|
||||
--
|
||||
-- The effect is not persistent. When a player rejoins the setting is actively
|
||||
-- removed during join time of that player. Mods need to actively track the
|
||||
-- status if they want the setting persist between joins.
|
||||
--
|
||||
-- @see hunger_ng.alter_hunger
|
||||
-- @see system/timers.lua
|
||||
--
|
||||
-- @param playername Name of the player to set the effect for
|
||||
-- @param effect The effect name as described
|
||||
-- @param setting Either `enabled` or `disabled`
|
||||
-- @return void
|
||||
hunger_ng.set_effect = function (playername, effect, setting)
|
||||
local attribute = a['effect_'..effect] or false
|
||||
local allowed_values = { enabled = true, disabled = true }
|
||||
|
||||
-- Warn in server log when a mod tries to configure an unknown effect
|
||||
if attribute == false then
|
||||
core_log('warning', ('+t +m tried to set +v for +p'):gsub('+.', {
|
||||
['+t'] = '[hunger_ng]',
|
||||
['+m'] = get_current_modname(),
|
||||
['+v'] = 'unknown effect '..effect,
|
||||
['+p'] = playername
|
||||
}))
|
||||
return
|
||||
end
|
||||
|
||||
-- Set the attribute according to what the mod wants and log that setting
|
||||
if allowed_values[setting] == true then
|
||||
set_data(playername, attribute, setting)
|
||||
core_log('verbose', ('+t +m sets +a to +v for +p'):gsub('+.', {
|
||||
['+t'] = '[hunger_ng]',
|
||||
['+m'] = get_current_modname(),
|
||||
['+a'] = attribute,
|
||||
['+v'] = setting,
|
||||
['+p'] = playername
|
||||
}))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Globalize the set and get function for player data for use in other files
|
||||
hunger_ng.functions.get_data = get_data
|
||||
hunger_ng.functions.set_data = set_data
|
||||
hunger_ng.functions.hunger_disabled = hunger_disabled
|
||||
hunger_ng.functions.configure_hunger = configure_hunger
|
||||
37
system/interoperability.lua
Normal file
37
system/interoperability.lua
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
-- Localize Hunger NG
|
||||
local a = hunger_ng.attributes
|
||||
local c = hunger_ng.configuration
|
||||
local e = hunger_ng.effects
|
||||
local f = hunger_ng.functions
|
||||
local s = hunger_ng.settings
|
||||
local S = hunger_ng.configuration.translator
|
||||
|
||||
|
||||
-- Localize Luanti
|
||||
local get_modpath = core.get_modpath
|
||||
local get_dir_list = core.get_dir_list
|
||||
local log = core.log
|
||||
|
||||
-- Load needed data
|
||||
local mod_path = core.get_modpath('hunger_ng')
|
||||
local i14y_path = mod_path..DIR_DELIM..'interoperability'..DIR_DELIM
|
||||
|
||||
-- Load interoperability file when the corresponding mod was loaded
|
||||
core.register_on_mods_loaded(function()
|
||||
for _,i14y_file in pairs(get_dir_list(i14y_path)) do
|
||||
local modname = i14y_file:gsub('%..*', '')
|
||||
if get_modpath(modname) and i14y_file ~= 'README.md' then
|
||||
dofile(i14y_path..i14y_file)
|
||||
log('info', c.log_prefix..'Loaded built-in '..modname..' support')
|
||||
end
|
||||
end
|
||||
|
||||
if hunger_ng.food_items.satiating == 0 then
|
||||
local message = {
|
||||
'There are NO satiating food items registered!',
|
||||
'Hunger is disabled!',
|
||||
'Enable at least one of the supported mods.'
|
||||
}
|
||||
log('warning', '[hunger_ng] '..table.concat(message, ' '))
|
||||
end
|
||||
end)
|
||||
173
system/register_on.lua
Normal file
173
system/register_on.lua
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
-- vim: set sw=2:
|
||||
-- Set Vim’s shiftwidth to 2 instead of 4 because the functions in this file
|
||||
-- are deeply nested and there are some long lines. 2 instead of 4 gives a tiny
|
||||
-- bit more space for each indentation level.
|
||||
|
||||
|
||||
-- Localize Hunger NG
|
||||
local a = hunger_ng.attributes
|
||||
local c = hunger_ng.configuration
|
||||
local e = hunger_ng.effects
|
||||
local f = hunger_ng.functions
|
||||
local s = hunger_ng.settings
|
||||
local S = hunger_ng.configuration.translator
|
||||
local costs = hunger_ng.costs
|
||||
|
||||
-- Localize Luanti
|
||||
local chat_send = core.chat_send_player
|
||||
local core_log = core.log
|
||||
|
||||
|
||||
-- When a player digs or places a node the corresponding hunger alteration
|
||||
-- will be applied
|
||||
core.register_on_dignode(function(p, on, digger)
|
||||
if digger then
|
||||
f.alter_hunger(digger:get_player_name(), -costs.dig, 'digging')
|
||||
end
|
||||
end)
|
||||
core.register_on_placenode(function(p, nn, placer, on, is, pt)
|
||||
if placer then
|
||||
f.alter_hunger(placer:get_player_name(), -costs.place, 'placing')
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
-- If a player dies and respawns the hunger value will be properly deleted and
|
||||
-- after respawn it will be set again. This avoids the player healing even if
|
||||
-- the player died.
|
||||
core.register_on_dieplayer(function(player)
|
||||
f.alter_hunger(player:get_player_name(), -s.hunger.maximum, 'death')
|
||||
return true
|
||||
end)
|
||||
core.register_on_respawnplayer(function(player)
|
||||
f.alter_hunger(player:get_player_name(), s.hunger.start_with, 'respawn')
|
||||
end)
|
||||
|
||||
|
||||
-- Custom eating function
|
||||
--
|
||||
-- When the player eats an item it is checked if the item has the custom
|
||||
-- _hunger_ng attribute set. If no, the eating won’t be intercepted by the
|
||||
-- function and the item will be eat regularly.
|
||||
--
|
||||
-- If the item has the attribute set then it will be processed and the heal
|
||||
-- and hunger values will be applied according to the item’s settings.
|
||||
--
|
||||
-- If the item has a timeout and the timeout is still active the user gets an
|
||||
-- information about this mentioning the timeout and how long the user has to
|
||||
-- wait before being able to eat again.
|
||||
core.register_on_item_eat(function(hpc, rwi, itemstack, user, pt)
|
||||
local definition = itemstack:get_definition()
|
||||
local hunger_def = definition._hunger_ng
|
||||
|
||||
-- Make sure to run the Hunger NG actions only if the item has hunger
|
||||
-- information registered.
|
||||
if user:is_player() ~= true or hunger_def == nil then return end
|
||||
|
||||
local player_name = user:get_player_name()
|
||||
local current_hunger = f.get_data(player_name, a.hunger_value)
|
||||
local hunger_disabled = f.get_data(player_name, a.hunger_disabled)
|
||||
local item_sound = definition.sound or {}
|
||||
local eating_sound = item_sound.eat or 'hunger_ng_eat'
|
||||
|
||||
-- If hunger is disabled by configuration the reular eating functionality
|
||||
-- is restored with chat message on eating.
|
||||
if core.is_yes(hunger_disabled) then
|
||||
chat_send(player_name, S('Hunger is disabled for you! Eating normally.'))
|
||||
return
|
||||
end
|
||||
|
||||
-- If a mod disabled the hunger effect the regular eating functionality
|
||||
-- is restored without chat message.
|
||||
if f.get_data(player_name,a.effect_hunger,true) == 'disabled' then return end
|
||||
|
||||
local heals = hunger_def.heals or 0
|
||||
local satiates = hunger_def.satiates or 0
|
||||
|
||||
if current_hunger == s.hunger.maximum and heals <= 0 and satiates >= 0 then
|
||||
chat_send(player_name, S('You’re fully satiated already!'))
|
||||
return itemstack
|
||||
end
|
||||
|
||||
if hunger_def.returns then
|
||||
local inventory = user:get_inventory()
|
||||
if not inventory:room_for_item('main', hunger_def.returns..' 1') then
|
||||
local message = S('You have no inventory space to keep the leftovers.')
|
||||
chat_send(player_name, message)
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
|
||||
local timeout = hunger_def.timeout or s.hunger.timeout
|
||||
local current_timestamp = os.time()
|
||||
local player_timestamp = f.get_data(player_name, a.eating_timestamp)
|
||||
|
||||
if current_timestamp < player_timestamp + timeout then
|
||||
local wait = player_timestamp + timeout - current_timestamp
|
||||
local message = S('You’re eating too fast!')
|
||||
local info = S('Wait for eating timeout to end: @1s', wait)
|
||||
chat_send(player_name, message..' '..info)
|
||||
return itemstack
|
||||
else
|
||||
f.set_data(player_name, a.eating_timestamp, current_timestamp)
|
||||
end
|
||||
|
||||
core.sound_play(eating_sound, { to_player = player_name })
|
||||
f.alter_hunger(player_name, satiates, 'eating')
|
||||
f.alter_health(player_name, heals, 'eating')
|
||||
itemstack:take_item(1)
|
||||
|
||||
if hunger_def.returns then
|
||||
local inventory = user:get_inventory()
|
||||
inventory:add_item('main', hunger_def.returns..' 1')
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end)
|
||||
|
||||
|
||||
-- Initial hunger and hunger bar configuration
|
||||
--
|
||||
-- When a player joins it is checked if the custom attribute for hunger is set.
|
||||
-- If hunger persistence is used then the value gets read and applied to the
|
||||
-- hunger bar.
|
||||
--
|
||||
-- If the value is not set or hunger persistence is not used then the hunger
|
||||
-- value to start with will be used. This can be different from the maximum
|
||||
-- hunger value.
|
||||
core.register_on_joinplayer(function(player)
|
||||
local player_name = player:get_player_name()
|
||||
local unset = not f.get_data(player_name, a.hunger_value)
|
||||
local reset = f.get_data(player_name, a.hunger_value) and not s.hunger.persistent
|
||||
|
||||
-- Only set if the value is not set or if hunger is configured not
|
||||
-- being persistent.
|
||||
if unset or reset then
|
||||
if c.debug_mode then
|
||||
local message = 'Set initial hunger values for '..player_name
|
||||
core_log('action', c.log_prefix..message)
|
||||
end
|
||||
f.set_data(player_name, a.hunger_value, s.hunger.start_with)
|
||||
f.set_data(player_name, a.eating_timestamp, 0)
|
||||
f.set_data(player_name, a.hunger_disabled, 0)
|
||||
end
|
||||
|
||||
-- Always reset (enable) hunger effect settings
|
||||
f.set_data(player_name, a.effect_hunger, 'enabled')
|
||||
f.set_data(player_name, a.effect_heal, 'enabled')
|
||||
f.set_data(player_name, a.effect_starve, 'enabled')
|
||||
|
||||
-- Only set hunger bar ID if hunger bar is configured to be used
|
||||
if s.hunger_bar.use then
|
||||
f.set_data(player_name, a.hunger_bar_id, player:hud_add({
|
||||
type = 'statbar',
|
||||
position = { x=0.5, y=1 },
|
||||
text = hunger_ng.hunger_bar_image,
|
||||
direction = 0,
|
||||
number = f.get_data(player_name, a.hunger_value),
|
||||
size = { x=24, y=24 },
|
||||
offset = {x=25,y=-(48+24+16)},
|
||||
}))
|
||||
end
|
||||
|
||||
end)
|
||||
130
system/timers.lua
Normal file
130
system/timers.lua
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
-- vim: set sw=2:
|
||||
-- Set Vim’s shiftwidth to 2 instead of 4 because the functions in this file
|
||||
-- are deeply nested and there are some long lines. 2 instead of 4 gives a tiny
|
||||
-- bit more space for each indentation level.
|
||||
|
||||
local alter_health = hunger_ng.functions.alter_health
|
||||
local alter_hunger = hunger_ng.functions.alter_hunger
|
||||
local base_interval = hunger_ng.settings.timers.basal_metabolism
|
||||
local costs_base = hunger_ng.costs.base
|
||||
local costs_movement = hunger_ng.costs.movement
|
||||
local effect_heal = hunger_ng.attributes.effect_heal
|
||||
local effect_hunger = hunger_ng.attributes.effect_hunger
|
||||
local effect_starve = hunger_ng.attributes.effect_starve
|
||||
local get_data = hunger_ng.functions.get_data
|
||||
local heal_above = hunger_ng.effects.heal.above
|
||||
local heal_amount = hunger_ng.effects.heal.amount
|
||||
local heal_interval = hunger_ng.settings.timers.heal
|
||||
local hunger_attribute = hunger_ng.attributes.hunger_value
|
||||
local hunger_bar_id = hunger_ng.attributes.hunger_bar_id
|
||||
local hunger_disabled_attribute = hunger_ng.attributes.hunger_disabled
|
||||
local move_interval = hunger_ng.settings.timers.movement
|
||||
local starve_amount = hunger_ng.effects.starve.amount
|
||||
local starve_below = hunger_ng.effects.starve.below
|
||||
local starve_die = hunger_ng.effects.starve.die
|
||||
local starve_interval = hunger_ng.settings.timers.starve
|
||||
local use_hunger_bar = hunger_ng.settings.hunger_bar.use
|
||||
|
||||
-- Localize Luanti
|
||||
is_yes = core.is_yes
|
||||
get_connected_players = core.get_connected_players
|
||||
|
||||
-- Initiate globalstep timers
|
||||
local base_timer = 0
|
||||
local heal_timer = 0
|
||||
local move_timer = 0
|
||||
local starve_timer = 0
|
||||
|
||||
|
||||
core.register_globalstep(function(dtime)
|
||||
|
||||
-- Do not run if there are no satiating food items registered
|
||||
if hunger_ng.food_items.satiating == 0 then return end
|
||||
|
||||
-- Raise timer values if needed
|
||||
if costs_base ~= 0 then base_timer = base_timer + dtime end
|
||||
if heal_amount ~= 0 then heal_timer = heal_timer + dtime end
|
||||
if costs_movement ~= 0 then move_timer = move_timer + dtime end
|
||||
if starve_amount ~= 0 then starve_timer = starve_timer + dtime end
|
||||
|
||||
-- Reset timers if needed
|
||||
if costs_base ~= 0 and base_timer >= base_interval then base_timer = 0 end
|
||||
if heal_amount ~= 0 and heal_timer >= heal_interval then heal_timer = 0 end
|
||||
if costs_movement ~= 0 and move_timer >= move_interval then move_timer=0 end
|
||||
if starve_amount~=0 and starve_timer>=starve_interval then starve_timer=0 end
|
||||
|
||||
-- Iterate over all players
|
||||
--
|
||||
-- If the value and the timer for the corresponding attribute are not zero
|
||||
-- (value) and zero (timer) then the alteration of that attribute is executed.
|
||||
for _,player in ipairs(get_connected_players()) do
|
||||
if player:is_player() then
|
||||
local playername = player:get_player_name()
|
||||
local hp_max = player:get_properties().hp_max
|
||||
local e_heal = get_data(playername, effect_heal, true) == 'enabled'
|
||||
local e_hunger = get_data(playername, effect_hunger, true) == 'enabled'
|
||||
local e_starve = get_data(playername, effect_starve, true) == 'enabled'
|
||||
|
||||
-- Basal metabolism costs
|
||||
if costs_base ~= 0 and base_timer == 0 and e_hunger then
|
||||
alter_hunger(player:get_player_name(), -costs_base, 'base')
|
||||
end
|
||||
|
||||
-- Heal player if possible and needed
|
||||
if heal_amount ~= 0 and heal_timer == 0 then
|
||||
local hunger = get_data(playername, hunger_attribute)
|
||||
local health = player:get_hp()
|
||||
local awash = player:get_breath() < player:get_properties().breath_max
|
||||
local can_heal = hunger >= heal_above and not awash
|
||||
local needs_health = health < hp_max
|
||||
if can_heal and needs_health and e_heal then
|
||||
alter_health(playername, heal_amount, 'healing')
|
||||
end
|
||||
end
|
||||
|
||||
-- Alter hunger based on movement costs
|
||||
if costs_movement ~= 0 and move_timer == 0 then
|
||||
local move = player:get_player_control()
|
||||
local moving = move.up or move.down or move.left or move.right
|
||||
if moving and e_hunger then
|
||||
alter_hunger(playername, -costs_movement, 'movement')
|
||||
end
|
||||
end
|
||||
|
||||
-- Starve player if starvation requirements are fulfilled
|
||||
if starve_amount ~= 0 and starve_timer == 0 then
|
||||
local hunger = get_data(playername, hunger_attribute)
|
||||
local health = player:get_hp()
|
||||
local starves = hunger < starve_below
|
||||
local playername = player:get_player_name()
|
||||
if starves and e_starve then
|
||||
if health == 1 and not starve_die then return end
|
||||
alter_health(playername, -starve_amount, 'starving')
|
||||
end
|
||||
end
|
||||
|
||||
end -- is player
|
||||
end -- players iteration
|
||||
|
||||
end)
|
||||
|
||||
|
||||
-- Show/hide hunger bar on player breath status or functionality status
|
||||
if use_hunger_bar then
|
||||
core.register_globalstep(function(dtime)
|
||||
for _,player in ipairs(get_connected_players()) do
|
||||
if player:is_player() then
|
||||
local player_name = player:get_player_name()
|
||||
local bar_id = get_data(player_name, hunger_bar_id)
|
||||
local awash = player:get_breath() < player:get_properties().breath_max
|
||||
local disabled = get_data(player_name, hunger_disabled_attribute)
|
||||
local no_food = hunger_ng.food_items.satiating == 0
|
||||
if awash or is_yes(disabled) or no_food then
|
||||
player:hud_change(bar_id, 'text', '')
|
||||
else
|
||||
player:hud_change(bar_id, 'text', hunger_ng.hunger_bar_image)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue