From caac9047fd57b33ad364e6436c4764711819dfb5 Mon Sep 17 00:00:00 2001 From: TenPlus1 Date: Thu, 26 Apr 2018 12:30:26 +0100 Subject: [PATCH] added support for POVA, player_monoids, and poisoning lasts n seconds depending on -number from food. --- README.txt | 3 + depends.txt | 2 + init.lua | 244 ++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 173 insertions(+), 76 deletions(-) diff --git a/README.txt b/README.txt index 9ac57d1..f4b3601 100644 --- a/README.txt +++ b/README.txt @@ -47,6 +47,9 @@ A global function is available for mods to change player stamina levels: stamina.change(player, change) +This mod has added support for POVA and player_monoids for overrides to play +nicely. + License: -------- diff --git a/depends.txt b/depends.txt index c12cc51..7c7fa76 100644 --- a/depends.txt +++ b/depends.txt @@ -1,2 +1,4 @@ default 3d_armor? +player_monoids? +pova? diff --git a/init.lua b/init.lua index 3870476..8e8091f 100644 --- a/init.lua +++ b/init.lua @@ -5,6 +5,7 @@ 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 @@ -21,12 +22,15 @@ STAMINA_STARVE_LVL = 3 -- level of staturation that causes starving STAMINA_VISUAL_MAX = 20 -- hud bar extends only to 20 -SPRINT_SPEED = 0.8 -- how much faster player can run if satiated +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) + local level = player:get_attribute(key) + if level then return tonumber(level) else @@ -34,7 +38,9 @@ local function get_int_attribute(player, key) end end + local function stamina_update_level(player, level) + local old = get_int_attribute(player, "stamina:level") if level == old then -- To suppress HUD update @@ -46,52 +52,50 @@ local function stamina_update_level(player, level) player:hud_change(player:get_attribute("stamina:hud_id"), "number", math.min(STAMINA_VISUAL_MAX, level)) end -local function stamina_is_poisoned(player) - return player:get_attribute("stamina:poisoned") == "yes" -end - -local function stamina_set_poisoned(player, poisoned) - if poisoned then - player:set_attribute("stamina:poisoned", "yes") - else - player:set_attribute("stamina:poisoned", "no") - end -end - -local function stamina_get_exhaustion(player) - return get_int_attribute(player, "stamina:exhaustion") -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_get_exhaustion(player) or 0 + local exhaustion = get_int_attribute(player, "stamina:exhaustion") or 0 exhaustion = 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 @@ -100,51 +104,115 @@ local function exhaust_player(player, v) player:set_attribute("stamina: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 armor_mod = minetest.get_modpath("3d_armor") +local monoids = minetest.get_modpath("player_monoids") +local pova_mod = minetest.get_modpath("pova") + +stamina.players = {} + +local function set_sprinting(name, sprinting) -function set_sprinting(name, sprinting) local player = minetest.get_player_by_name(name) - local def = {} - -- Get player physics from 3d_armor mod - if armor_mod and armor and armor.def then - def.speed = armor.def[name].speed - def.jump = armor.def[name].jump - def.gravity = armor.def[name].gravity + + -- 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) + stamina.players[name].sprint = nil + player_monoids.jump:del_change(player, stamina.players[name].jump) + 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 - - def.speed = def.speed or 1 - def.jump = def.jump or 1 - def.gravity = def.gravity or 1 - - if sprinting == true then - - def.speed = def.speed + SPRINT_SPEED - def.jump = def.jump + SPRINT_JUMP - end - - player:set_physics_override({ - speed = def.speed, - jump = def.jump, - gravity = def.gravity - }) end + -- Time based stamina functions local stamina_timer = 0 local health_timer = 0 local action_timer = 0 +local poison_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 + + for _,player in ipairs(minetest.get_connected_players()) do + + -- hurt player when poisoned + if poison_timer > STAMINA_POISON_TICK then + + 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 - STAMINA_POISON_TICK + + local hp = player:get_hp() - 1 or 0 + if hp > 0 then + player:set_hp(hp) + end + + elseif stamina.players[name].poisoned then + player:hud_change(player:get_attribute("stamina:hud_id"), "text", "stamina_hud_fg.png") + stamina.players[name].poisoned = nil + end + + poison_timer = 0 + end + + -- sprint control and particle animation + if action_timer > STAMINA_MOVE_TICK then - if action_timer > STAMINA_MOVE_TICK then - for _,player in ipairs(minetest.get_connected_players()) do local controls = player:get_player_control() + -- Determine if the player is walking if controls.jump then exhaust_player(player, STAMINA_EXHAUST_JUMP) @@ -158,7 +226,8 @@ local function stamina_globaltimer(dtime) local name = player:get_player_name() -- check if player can sprint (stamina must be over 6 points) - if controls.aux1 and controls.up + if not stamina.players[name].poisoned + and controls.aux1 and controls.up and not minetest.check_player_privs(player, {fast = true}) and get_int_attribute(player, "stamina:level") > 6 then @@ -196,6 +265,7 @@ local function stamina_globaltimer(dtime) -- 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) @@ -203,33 +273,35 @@ local function stamina_globaltimer(dtime) end -- END sprint + action_timer = 0 end - action_timer = 0 - end - -- lower saturation by 1 point after STAMINA_TICK second(s) - if stamina_timer > STAMINA_TICK then - for _,player in ipairs(minetest.get_connected_players()) do + -- lower saturation by 1 point after STAMINA_TICK second(s) + if stamina_timer > STAMINA_TICK then + local h = get_int_attribute(player, "stamina:level") + if h > STAMINA_TICK_MIN then stamina_update_level(player, h - 1) end - end - stamina_timer = 0 - end - -- heal or damage player, depending on saturation - if health_timer > STAMINA_HEALTH_TICK then - for _,player in ipairs(minetest.get_connected_players()) do + stamina_timer = 0 + end + + -- heal or damage player, depending on saturation + if health_timer > STAMINA_HEALTH_TICK then + local air = player:get_breath() or 0 local hp = player:get_hp() - -- don't heal if drowning or dead - -- TODO: don't heal if poisoned? + -- don't heal if drowning or dead or poisoned local h = get_int_attribute(player, "stamina:level") + if h >= STAMINA_HEAL_LVL and h >= hp and hp > 0 and air > 0 - and not stamina_is_poisoned(player) then + and not stamina.players[player:get_player_name()].poisoned then + player:set_hp(hp + STAMINA_HEAL) + stamina_update_level(player, h - 1) end @@ -237,41 +309,36 @@ local function stamina_globaltimer(dtime) if get_int_attribute(player, "stamina:level") < STAMINA_STARVE_LVL then player:set_hp(hp - STAMINA_STARVE) end + + health_timer = 0 end - - health_timer = 0 - end + end -- player loop end -local function poison_player(ticks, time, elapsed, user) - if elapsed <= ticks then - minetest.after(time, poison_player, ticks, time, elapsed + 1, user) - stamina_set_poisoned(user,true) - else - user:hud_change(user:get_attribute("stamina:hud_id"), "text", "stamina_hud_fg.png") - stamina_set_poisoned(user,false) - end - local hp = user:get_hp() -1 or 0 - if hp > 0 then - user:set_hp(hp) - 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) + 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 then return itemstack end @@ -281,6 +348,7 @@ function stamina.eat(hp_change, replace_with_item, itemstack, user, pointed_thin end local level = get_int_attribute(user, "stamina:level") or 0 + if level >= STAMINA_VISUAL_MAX then return itemstack end @@ -288,10 +356,10 @@ function stamina.eat(hp_change, replace_with_item, itemstack, user, pointed_thin if hp_change > 0 then level = level + hp_change stamina_update_level(user, level) - else + elseif hp_change < 0 then -- assume hp_change < 0. user:hud_change(user:get_attribute("stamina:hud_id"), "text", "stamina_hud_poison.png") - poison_player(2.0, -hp_change, 0, user) + stamina.players[user:get_player_name()].poisoned = -hp_change end minetest.sound_play("stamina_eat", {to_player = user:get_player_name(), gain = 0.7}) @@ -322,10 +390,12 @@ function stamina.eat(hp_change, replace_with_item, itemstack, user, pointed_thin 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 @@ -338,15 +408,22 @@ function stamina.eat(hp_change, replace_with_item, itemstack, user, pointed_thin return itemstack end + -- stamina is disabled if damage is disabled -if minetest.setting_getbool("enable_damage") and minetest.is_yes(minetest.setting_get("enable_stamina") or "1") then +if minetest.setting_getbool("enable_damage") +--and minetest.is_yes(minetest.setting_get("enable_stamina") or "1") then +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 id = player:hud_add({ name = "stamina", hud_elem_type = "statbar", @@ -358,6 +435,7 @@ if minetest.setting_getbool("enable_damage") and minetest.is_yes(minetest.settin offset = {x = -266, y = -110}, max = 0, }) + player:set_attribute("stamina:hud_id", id) end) @@ -380,3 +458,17 @@ if minetest.setting_getbool("enable_damage") and minetest.is_yes(minetest.settin stamina_update_level(player, STAMINA_VISUAL_MAX) end) end + + +-- create player table on join +minetest.register_on_joinplayer(function(player) + + stamina.players[player:get_player_name()] = {poisoned = nil, sprint = nil} +end) + + +-- clear when player leaves +minetest.register_on_leaveplayer(function(player) + + stamina.players[ player:get_player_name() ] = nil +end)