hunger.lua 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. -- Keep these for backwards compatibility
  2. function hbhunger.save_hunger(player)
  3. hbhunger.set_hunger_raw(player)
  4. end
  5. function hbhunger.load_hunger(player)
  6. hbhunger.get_hunger_raw(player)
  7. end
  8. -- wrapper for minetest.item_eat (this way we make sure other mods can't break this one)
  9. local org_eat = minetest.do_item_eat
  10. minetest.do_item_eat = function(hp_change, replace_with_item, itemstack, user, pointed_thing)
  11. local old_itemstack = itemstack
  12. itemstack = hbhunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
  13. for _, callback in pairs(minetest.registered_on_item_eats) do
  14. local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing, old_itemstack)
  15. if result then
  16. return result
  17. end
  18. end
  19. return itemstack
  20. end
  21. -- food functions
  22. local food = hbhunger.food
  23. function hbhunger.register_food(name, hunger_change, replace_with_item, poisen, heal, sound)
  24. food[name] = {}
  25. food[name].saturation = hunger_change -- hunger points added
  26. food[name].replace = replace_with_item -- what item is given back after eating
  27. food[name].poisen = poisen -- time its poisening
  28. food[name].healing = heal -- amount of HP
  29. food[name].sound = sound -- special sound that is played when eating
  30. end
  31. function hbhunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
  32. local item = itemstack:get_name()
  33. local def = food[item]
  34. if not def then
  35. def = {}
  36. if type(hp_change) ~= "number" then
  37. hp_change = 1
  38. minetest.log("error", "Wrong on_use() definition for item '" .. item .. "'")
  39. end
  40. def.saturation = hp_change * 1.3
  41. def.replace = replace_with_item
  42. end
  43. local func = hbhunger.item_eat(def.saturation, def.replace, def.poisen, def.healing, def.sound)
  44. return func(itemstack, user, pointed_thing)
  45. end
  46. -- Poison player
  47. local function poisenp(tick, time, time_left, player)
  48. -- First check if player is still there
  49. if not player:is_player() then
  50. return
  51. end
  52. time_left = time_left + tick
  53. if time_left < time then
  54. minetest.after(tick, poisenp, tick, time, time_left, player)
  55. else
  56. hbhunger.poisonings[player:get_player_name()] = hbhunger.poisonings[player:get_player_name()] - 1
  57. if hbhunger.poisonings[player:get_player_name()] <= 0 then
  58. -- Reset HUD bar color
  59. hb.change_hudbar(player, "health", nil, nil, "hudbars_icon_health.png", nil, "hudbars_bar_health.png")
  60. end
  61. end
  62. if player:get_hp()-1 > 0 then
  63. player:set_hp(player:get_hp()-1)
  64. end
  65. end
  66. function hbhunger.item_eat(hunger_change, replace_with_item, poisen, heal, sound)
  67. return function(itemstack, user, pointed_thing)
  68. if itemstack:take_item() ~= nil and user ~= nil then
  69. local name = user:get_player_name()
  70. local h = tonumber(hbhunger.hunger[name])
  71. local hp = user:get_hp()
  72. if h == nil or hp == nil then
  73. return
  74. end
  75. if user:is_player() then
  76. local object, object_pos
  77. -- Check if user is a "fake player" (unofficial imitation of a the player data structure)
  78. if type(user) == "userdata" then
  79. object = user
  80. else
  81. object_pos = user:get_pos()
  82. end
  83. minetest.sound_play(
  84. {name = sound or "hbhunger_eat_generic",
  85. gain = 1},
  86. {object=object,
  87. pos=object_pos,
  88. max_hear_distance = 16,
  89. pitch = 1 + math.random(-10, 10)*0.005,},
  90. true
  91. )
  92. end
  93. -- Saturation
  94. if h < hbhunger.SAT_MAX and hunger_change then
  95. h = h + hunger_change
  96. if h > hbhunger.SAT_MAX then h = hbhunger.SAT_MAX end
  97. hbhunger.hunger[name] = h
  98. hbhunger.set_hunger_raw(user)
  99. end
  100. -- we must respect the real maximun hp of the player already set
  101. local max_hp = user:get_properties().hp_max
  102. -- Healing
  103. if hp < max_hp then
  104. -- heal is not defines due way of hbhunger.register_food
  105. if not heal then heal = 1 end
  106. -- eating something not give you inmediate life, give you statiation to get recovery
  107. if hp < 6 and hp > 0 and heal > 0 then hp = hp + heal end
  108. -- so if you are in good shape and losing healt just give it only for one chance, NSSM specific
  109. if hbhunger.permitgainhp then
  110. local hpreca = math.random (6, 10)
  111. local hprecb = math.random (11, hb.settings.hp_player_maximun - 1)
  112. if hp < hprecb and hp > hpreca then hp = hp + 1 end
  113. end
  114. -- so do not hardcoded hp to 20 when eating
  115. if hp > max_hp then hp = max_hp end
  116. -- this will work only when valid then
  117. user:set_hp(hp)
  118. end
  119. -- Poison
  120. if poisen then
  121. -- Set poison bar
  122. hb.change_hudbar(user, "health", nil, nil, "hbhunger_icon_health_poison.png", nil, "hbhunger_bar_health_poison.png")
  123. hbhunger.poisonings[name] = hbhunger.poisonings[name] + 1
  124. poisenp(1, poisen, 0, user)
  125. end
  126. if itemstack:get_count() == 0 then
  127. itemstack:add_item(replace_with_item)
  128. else
  129. local inv = user:get_inventory()
  130. if inv:room_for_item("main", replace_with_item) then
  131. inv:add_item("main", replace_with_item)
  132. else
  133. minetest.add_item(user:get_pos(), replace_with_item)
  134. end
  135. end
  136. end
  137. return itemstack
  138. end
  139. end
  140. -- player-action based hunger changes
  141. function hbhunger.handle_node_actions(pos, oldnode, player, ext)
  142. -- is_fake_player comes from the pipeworks, we are not interested in those
  143. if not player or not player:is_player() or player.is_fake_player == true then
  144. return
  145. end
  146. local name = player:get_player_name()
  147. local exhaus = hbhunger.exhaustion[name]
  148. if exhaus == nil then return end
  149. local new = hbhunger.EXHAUST_PLACE
  150. -- placenode event
  151. if not ext then
  152. new = hbhunger.EXHAUST_DIG
  153. end
  154. -- assume its send by main timer when movement detected
  155. if not pos and not oldnode then
  156. new = hbhunger.EXHAUST_MOVE
  157. end
  158. exhaus = exhaus + new
  159. if exhaus > hbhunger.EXHAUST_LVL then
  160. exhaus = 0
  161. local h = tonumber(hbhunger.hunger[name])
  162. h = h - 1
  163. if h < 0 then h = 0 end
  164. hbhunger.hunger[name] = h
  165. hbhunger.set_hunger_raw(player)
  166. end
  167. hbhunger.exhaustion[name] = exhaus
  168. end
  169. minetest.register_on_placenode(hbhunger.handle_node_actions)
  170. minetest.register_on_dignode(hbhunger.handle_node_actions)