Alpha-v0.0.2a #1

Closed
thunderdog1138 wants to merge 321 commits from Alpha-v0.0.2a into master
5 changed files with 693 additions and 0 deletions
Showing only changes of commit 0a6c32ab67 - Show all commits

70
mods/stamina/README.txt Normal file
View File

@ -0,0 +1,70 @@
Minetest mod "Stamina"
=====================
(C) 2015 - BlockMen
(C) 2016 - Auke Kok <sofar@foo-projects.org>
About this mod:
---------------
This mod adds a stamina, or "hunger" mechanic to Minetest. Actions like
crafting, walking, digging or fighting make the player exhausted. When
enough exhaustion has been accumulated, the player gets more hungry,
and loses stamina.
If a player is low on stamina, they start taking periodical damage,
and ultimately will die if they do not eat food.
Eating food no longer heals the player. Instead, it increases the
stamina of the player. The stamina bar shows how well fed the player
is. More bread pieces means more stamina.
Walking while holding down Aux1 (usually E key) will make player sprint so
long as their stamina bar is 3 or more bread. This will make the player run
that bit faster and jump a tiny bit higher.
Q&A time: Why won't I move the stamina bar to the right?
Answer: this conflicts with the builtin breath bar. To move the
builtin breath bar, I basically have to entirely re-implement it
in lua including timers to catch breath changes for each online
player, which is all a waste of time, just to move a few pixels
around.
For Modders:
------------
This mod intercepts minetest.item_eat(), and applies the hp_change
as stamina change. The value can be positive (increase stamina) or
negative (periodically damage the player by 1 hp).
Callbacks that are registered via minetest.register_on_item_eat()
are called after this mod, so the itemstack will have changed already
when callbacks are called. You can get the original itemstack as 6th
parameter of your function then.
A global function is available for mods to change player stamina levels:
stamina.change(player, change)
TenPlus1 Additions:
-------------------
- Added support for POVA and player_monoids
- Added Pipeworks checks for fake players
- Added 60 second drunk effect when foods have {alcohol=1} group (eat 4 or more)
- Moved exhaustion and hud_id to player table instead of player attributes
License:
--------
Code:
- all code LGPL-2.1+
Textures:
- stamina_hud_poison.png - BlockMen (CC-BY 3.0)
- stamina_hud_fg.png - PilzAdam (WTFPL), modified by BlockMen
- stamina_hud_bg.png - PilzAdam (WTFPL), modified by BlockMen
Sounds:
- stamina_eat.*.ogg - http://www.freesound.org/people/sonictechtonic/sounds/242215/ CC-BY-3.0

View File

@ -0,0 +1 @@
Adds stamina and hunger effects.

621
mods/stamina/init.lua Normal file
View File

@ -0,0 +1,621 @@
stamina = {players = {}}
STAMINA_TICK = 800 -- time in seconds after that 1 stamina point is taken
STAMINA_TICK_MIN = 4 -- stamina ticks won't reduce stamina below this level
STAMINA_HEALTH_TICK = 4 -- time in seconds after player gets healed/damaged
STAMINA_MOVE_TICK = 0.5 -- time in seconds after the movement is checked
STAMINA_POISON_TICK = 1.25 -- time in seconds after player is poisoned
STAMINA_EXHAUST_DIG = 3 -- exhaustion increased this value after digged node
STAMINA_EXHAUST_PLACE = 1 -- .. after digging node
STAMINA_EXHAUST_MOVE = 1.5 -- .. if player movement detected
STAMINA_EXHAUST_JUMP = 5 -- .. if jumping
STAMINA_EXHAUST_CRAFT = 20 -- .. if player crafts
STAMINA_EXHAUST_PUNCH = 40 -- .. if player punches another player
STAMINA_EXHAUST_LVL = 160 -- at what exhaustion player saturation gets lowered
STAMINA_HEAL = 1 -- number of HP player gets healed after STAMINA_HEALTH_TICK
STAMINA_HEAL_LVL = 5 -- lower level of saturation needed to get healed
STAMINA_STARVE = 1 -- number of HP player gets damaged by stamina after STAMINA_HEALTH_TICK
STAMINA_STARVE_LVL = 3 -- level of staturation that causes starving
STAMINA_VISUAL_MAX = 20 -- hud bar extends only to 20
SPRINT_SPEED = 0.3 -- how much faster player can run if satiated
SPRINT_JUMP = 0.1 -- how much higher player can jump if satiated
SPRINT_DRAIN = 0.35 -- how fast to drain satation while sprinting (0-1)
local function get_int_attribute(player, key)
-- pipeworks fake player check
if not player.get_attribute then
return nil
end
local level = player:get_attribute(key)
if level then
return tonumber(level)
end
return nil
end
local function stamina_update_level(player, level)
-- pipeworks fake player check
if not player.get_attribute then
return nil
end
local old = get_int_attribute(player, "stamina:level")
if level == old then -- To suppress HUD update
return
end
-- players without interact priv cannot eat
if not minetest.check_player_privs(player, {interact = true}) then
return
end
player:set_attribute("stamina:level", level)
player:hud_change(stamina.players[player:get_player_name()].hud_id,
"number", math.min(STAMINA_VISUAL_MAX, level))
end
-- global function for mods to amend stamina level
stamina.change = function(player, change)
local name = player:get_player_name()
if not name or not change or change == 0 then
return false
end
local level = get_int_attribute(player, "stamina:level") + change
if level < 0 then level = 0 end
if level > STAMINA_VISUAL_MAX then level = STAMINA_VISUAL_MAX end
stamina_update_level(player, level)
return true
end
local function exhaust_player(player, v)
if not player
or not player.is_player
or not player:is_player()
or not player.set_attribute then
return
end
local name = player:get_player_name()
if not name then
return
end
local exhaustion = stamina.players[name].exhaustion + v
if exhaustion > STAMINA_EXHAUST_LVL then
exhaustion = 0
local h = get_int_attribute(player, "stamina:level")
if h > 0 then
stamina_update_level(player, h - 1)
end
end
stamina.players[name].exhaustion = exhaustion
end
-- Sprint settings and function
local enable_sprint = minetest.setting_getbool("sprint") ~= false
local enable_sprint_particles = minetest.setting_getbool("sprint_particles") ~= false
local monoids = minetest.get_modpath("player_monoids")
local pova_mod = minetest.get_modpath("pova")
local function set_sprinting(name, sprinting)
local player = minetest.get_player_by_name(name)
-- get player physics
local def = player:get_physics_override()
--print ("---", def.speed, def.jump)
if sprinting == true and not stamina.players[name].sprint then
if monoids then
stamina.players[name].sprint = player_monoids.speed:add_change(
player, def.speed + SPRINT_SPEED)
stamina.players[name].jump = player_monoids.jump:add_change(
player, def.jump + SPRINT_JUMP)
elseif pova_mod then
pova.add_override(name, "sprint",
{speed = SPRINT_SPEED, jump = SPRINT_JUMP})
pova.do_override(player)
stamina.players[name].sprint = true
else
player:set_physics_override({
speed = def.speed + SPRINT_SPEED,
jump = def.jump + SPRINT_JUMP,
})
stamina.players[name].sprint = true
end
elseif sprinting == false and stamina.players[name].sprint then
if monoids then
player_monoids.speed:del_change(player, stamina.players[name].speed)
player_monoids.jump:del_change(player, stamina.players[name].jump)
stamina.players[name].sprint = nil
stamina.players[name].jump = nil
elseif pova_mod then
pova.del_override(name, "sprint")
pova.do_override(player)
stamina.players[name].sprint = nil
else
player:set_physics_override({
speed = def.speed - SPRINT_SPEED,
jump = def.jump - SPRINT_JUMP,
})
stamina.players[name].sprint = nil
end
end
end
-- Time based stamina functions
local stamina_timer = 0
local health_timer = 0
local action_timer = 0
local poison_timer = 0
local drunk_timer = 0
local function stamina_globaltimer(dtime)
stamina_timer = stamina_timer + dtime
health_timer = health_timer + dtime
action_timer = action_timer + dtime
poison_timer = poison_timer + dtime
drunk_timer = drunk_timer + dtime
local players = minetest.get_connected_players()
-- simulate drunk walking (thanks LumberJ)
if drunk_timer > 1.0 then
for _,player in pairs(players) do
local name = player:get_player_name()
if stamina.players[name]
and stamina.players[name].drunk then
stamina.players[name].drunk = stamina.players[name].drunk - 1
if stamina.players[name].drunk < 1 then
stamina.players[name].drunk = nil
stamina.players[name].units = 0
player:hud_change(stamina.players[name].hud_id,
"text", "stamina_hud_fg.png")
end
-- effect only works when not riding boat/cart/horse etc.
if not player:get_attach() then
local yaw = player:get_look_horizontal()
yaw = yaw + math.random(-0.5, 0.5)
player:set_look_horizontal(yaw)
end
end
drunk_timer = 0
end
end
-- hurt player when poisoned
if poison_timer > STAMINA_POISON_TICK then
for _,player in pairs(players) do
local name = player:get_player_name()
if stamina.players[name].poisoned
and stamina.players[name].poisoned > 0 then
stamina.players[name].poisoned =
stamina.players[name].poisoned - 1
local hp = player:get_hp() - 1
if hp > 0 then
player:set_hp(hp)
end
elseif stamina.players[name].poisoned then
player:hud_change(stamina.players[name].hud_id,
"text", "stamina_hud_fg.png")
stamina.players[name].poisoned = nil
end
poison_timer = 0
end
end
-- sprint control and particle animation
if action_timer > STAMINA_MOVE_TICK then
for _,player in pairs(players) do
local controls = player:get_player_control()
-- Determine if the player is walking
if controls.jump then
exhaust_player(player, STAMINA_EXHAUST_JUMP)
elseif controls.up
or controls.down
or controls.left
or controls.right then
exhaust_player(player, STAMINA_EXHAUST_MOVE)
end
--- START sprint
if enable_sprint then
local name = player:get_player_name()
-- check if player can sprint (stamina must be over 6 points)
if not stamina.players[name].poisoned
and not stamina.players[name].drunk
and controls.aux1 and controls.up
and not minetest.check_player_privs(player, {fast = true})
and get_int_attribute(player, "stamina:level") > 6 then
set_sprinting(name, true)
-- create particles behind player when sprinting
if enable_sprint_particles then
local pos = player:get_pos()
local node = minetest.get_node({
x = pos.x, y = pos.y - 1, z = pos.z})
if node.name ~= "air" then
minetest.add_particlespawner({
amount = 5,
time = 0.01,
minpos = {x = pos.x - 0.25, y = pos.y + 0.1, z = pos.z - 0.25},
maxpos = {x = pos.x + 0.25, y = pos.y + 0.1, z = pos.z + 0.25},
minvel = {x = -0.5, y = 1, z = -0.5},
maxvel = {x = 0.5, y = 2, z = 0.5},
minacc = {x = 0, y = -5, z = 0},
maxacc = {x = 0, y = -12, z = 0},
minexptime = 0.25,
maxexptime = 0.5,
minsize = 0.5,
maxsize = 1.0,
vertical = false,
collisiondetection = false,
texture = "default_dirt.png",
})
end
end
-- Lower the player's stamina when sprinting
local level = get_int_attribute(player, "stamina:level")
stamina_update_level(player,
level - (SPRINT_DRAIN * STAMINA_MOVE_TICK))
else
set_sprinting(name, false)
end
end
-- END sprint
action_timer = 0
end
end
-- lower saturation by 1 point after STAMINA_TICK
if stamina_timer > STAMINA_TICK then
for _,player in pairs(players) do
local h = get_int_attribute(player, "stamina:level")
if h > STAMINA_TICK_MIN then
stamina_update_level(player, h - 1)
end
stamina_timer = 0
end
end
-- heal or damage player, depending on saturation
if health_timer > STAMINA_HEALTH_TICK then
for _,player in pairs(players) do
local air = player:get_breath() or 0
local hp = player:get_hp()
local h = get_int_attribute(player, "stamina:level")
local name = player:get_player_name()
-- damage player by 1 hp if saturation is < 2 (of 30)
if h < STAMINA_STARVE_LVL
and hp > 0 then
player:set_hp(hp - STAMINA_STARVE)
end
-- don't heal if drowning or dead or poisoned
if h >= STAMINA_HEAL_LVL
and h >= hp
and hp > 0
and air > 0
and not stamina.players[name].poisoned then
player:set_hp(hp + STAMINA_HEAL)
stamina_update_level(player, h - 1)
end
health_timer = 0
end
end
end
-- override core.do_item_eat() so we can redirect hp_change to stamina
core.do_item_eat = function(hp_change, replace_with_item, itemstack, user, pointed_thing)
if user.is_fake_player then
return -- abort if called by fake player (eg. pipeworks-wielder)
end
local old_itemstack = itemstack
itemstack = stamina.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
for _, callback in pairs(core.registered_on_item_eats) do
local result = callback(hp_change, replace_with_item, itemstack, user,
pointed_thing, old_itemstack)
if result then
return result
end
end
return itemstack
end
-- not local since it's called from within core context
function stamina.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
if not itemstack or not user then
return itemstack
end
local level = get_int_attribute(user, "stamina:level") or 0
if level >= STAMINA_VISUAL_MAX then
return itemstack
end
local name = user:get_player_name()
if hp_change > 0 then
stamina_update_level(user, level + hp_change)
elseif hp_change < 0 then
-- assume hp_change < 0
user:hud_change(stamina.players[name].hud_id, "text",
"stamina_hud_poison.png")
stamina.players[name].poisoned = -hp_change
end
minetest.sound_play("stamina_eat", {to_player = name, gain = 0.7})
-- particle effect when eating
local pos = user:get_pos() ; pos.y = pos.y + 1.5 -- mouth level
local itemname = itemstack:get_name()
local texture = minetest.registered_items[itemname].inventory_image
local dir = user:get_look_dir()
minetest.add_particlespawner({
amount = 5,
time = 0.1,
minpos = pos,
maxpos = pos,
minvel = {x = dir.x - 1, y = dir.y, z = dir.z - 1},
maxvel = {x = dir.x + 1, y = dir.y, z = dir.z + 1},
minacc = {x = 0, y = -5, z = 0},
maxacc = {x = 0, y = -9, z = 0},
minexptime = 1,
maxexptime = 1,
minsize = 1,
maxsize = 2,
texture = texture,
})
itemstack:take_item()
if replace_with_item then
if itemstack:is_empty() then
itemstack:add_item(replace_with_item)
else
local inv = user:get_inventory()
if inv:room_for_item("main", {name = replace_with_item}) then
inv:add_item("main", replace_with_item)
else
pos.y = math.floor(pos.y - 1.0)
core.add_item(pos, replace_with_item)
end
end
end
-- check for alcohol
local units = minetest.registered_items[itemname].groups
and minetest.registered_items[itemname].groups.alcohol or 0
if units > 0 then
stamina.players[name].units = (stamina.players[name].units or 0) + 1
if stamina.players[name].units > 3 then
stamina.players[name].drunk = 60
stamina.players[name].units = 0
user:hud_change(stamina.players[name].hud_id, "text",
"stamina_hud_poison.png")
minetest.chat_send_player(name,
minetest.get_color_escape_sequence("#1eff00")
.. "You suddenly feel tipsy!")
end
end
return itemstack
end
-- stamina is disabled if damage is disabled
if minetest.setting_getbool("enable_damage")
and minetest.setting_get("enable_stamina") ~= false then
minetest.register_on_joinplayer(function(player)
local level = STAMINA_VISUAL_MAX -- TODO
if get_int_attribute(player, "stamina:level") then
level = math.min(get_int_attribute(player, "stamina:level"),
STAMINA_VISUAL_MAX)
else
player:set_attribute("stamina:level", level)
end
local name = player:get_player_name()
local id = player:hud_add({
name = "stamina",
hud_elem_type = "statbar",
position = {x = 0.5, y = 1},
size = {x = 24, y = 24},
text = "stamina_hud_fg.png",
number = level,
alignment = {x = -1, y = -1},
offset = {x = -266, y = -110},
max = 0,
})
stamina.players[name] = {
hud_id = id,
exhaustion = 0,
poisoned = nil,
drunk = nil,
sprint = nil,
}
end)
minetest.register_on_respawnplayer(function(player)
local name = player:get_player_name()
if stamina.players[name].poisoned
or stamina.players[name].drunk then
player:hud_change(stamina.players[name].hud_id,
"text", "stamina_hud_fg.png")
end
stamina.players[name].exhaustion = 0
stamina.players[name].poisoned = nil
stamina.players[name].drunk = nil
stamina.players[name].sprint = nil
stamina_update_level(player, STAMINA_VISUAL_MAX)
end)
minetest.register_globalstep(stamina_globaltimer)
minetest.register_on_placenode(function(pos, oldnode, player, ext)
exhaust_player(player, STAMINA_EXHAUST_PLACE)
end)
minetest.register_on_dignode(function(pos, oldnode, player, ext)
exhaust_player(player, STAMINA_EXHAUST_DIG)
end)
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
exhaust_player(player, STAMINA_EXHAUST_CRAFT)
end)
minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
exhaust_player(hitter, STAMINA_EXHAUST_PUNCH)
end)
else
-- create player table on join
minetest.register_on_joinplayer(function(player)
stamina.players[player:get_player_name()] = {
poisoned = nil, sprint = nil, drunk = nil, exhaustion = 0}
end)
end
-- clear when player leaves
minetest.register_on_leaveplayer(function(player)
stamina.players[player:get_player_name()] = nil
end)

1
mods/stamina/mod.conf Normal file
View File

@ -0,0 +1 @@
name = stamina

BIN
mods/stamina/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB