init.lua 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. cold = {}
  2. cold.items = {}
  3. local mod_path = minetest.get_modpath("cold")
  4. dofile(mod_path.."/items.lua")
  5. COLD_MAX = 20
  6. COLD_FACTOR = .07
  7. COLD_SHIVER = .5
  8. COLD_FREEZE = 1.5
  9. COLD_SHIVER_LVL = 15
  10. COLD_FREEZE_LVL = 19
  11. COLD_SHIVER_CHANCE = 5
  12. COLD_SUN_FACTOR = 10.5
  13. COLD_LAT_FACTOR = 10
  14. COLD_LAT_OFFSET = 0 -- -0.4 -- .5 for even. lower is warmer.
  15. COLD_UNDERGROUND_TEMP = 12 -- target temp to approach
  16. COLD_UNDERGROUND_Y = -12 -- height before underground temp takes over
  17. COLD_ELV_OFFSET = -55 -- lower makes higher elevations warmer
  18. COLD_ELV_RATE = .035 -- .01 for 1 degree every 100 nodes
  19. COLD_DEEP_Y = -512 -- height where the earth starts to get warm on its own
  20. COLD_DEEP_RATE = .01 -- higher makes deeper levels get warmer, per node
  21. COLD_SEASON_FACTOR = 2
  22. -- read/write
  23. function cold.read(player)
  24. local inv = player:get_inventory()
  25. if not inv then
  26. return nil
  27. end
  28. local hgp = inv:get_stack("cold", 1):get_count()
  29. if hgp == 0 then
  30. hgp = 21
  31. inv:set_stack("cold", 1, ItemStack({name = ":", count = hgp}))
  32. else
  33. hgp = hgp
  34. end
  35. if tonumber(hgp) > COLD_MAX + 1 then
  36. hgp = COLD_MAX + 1
  37. end
  38. return hgp - 1
  39. end
  40. function cold.save(player)
  41. local inv = player:get_inventory()
  42. local name = player:get_player_name()
  43. local value = cold[name].lvl
  44. if not inv or not value then
  45. return nil
  46. end
  47. if value > COLD_MAX then
  48. value = COLD_MAX
  49. end
  50. if value < 0 then
  51. value = 0
  52. end
  53. inv:set_stack("cold", 1, ItemStack({name = ":", count = value + 1}))
  54. return true
  55. end
  56. local function sigmoid(x)
  57. return 1 / (1 + math.exp(.001 * (x - 20)))
  58. end
  59. function cold.update_cold(player, new_lvl)
  60. local name = player:get_player_name() or nil
  61. if not name or not cold[name] then
  62. return false
  63. end
  64. local env
  65. local ppos = player:getpos()
  66. local lvl = cold[name].lvl
  67. if ppos.y < COLD_DEEP_Y then -- it gets warmer as you go really deep
  68. env = (ppos.y + COLD_DEEP_Y) * COLD_DEEP_RATE
  69. --print("deep: ".. env)
  70. elseif ppos.y < COLD_UNDERGROUND_Y then -- caves near the surface have even, cool temp
  71. -- approach the underground temp
  72. -- env = (COLD_UNDERGROUND_TEMP - lvl) * .5
  73. env = COLD_UNDERGROUND_TEMP -- now it's just chilly down there
  74. --print("und: ".. env)
  75. else -- normal surface calculations
  76. local season, season_time = seasons.get_season()
  77. local seas = 0
  78. if season == "winter" then
  79. seas = 1
  80. elseif season == "spring" then
  81. seas = 1 - season_time
  82. elseif season == "fall" then
  83. seas = season_time
  84. end
  85. local sun = (math.sin(minetest.get_timeofday() * math.pi) * -2) + .5
  86. local lat = math.sin(ppos.z / (16000)) + COLD_LAT_OFFSET
  87. local elv = math.max(ppos.y + COLD_ELV_OFFSET, 0)
  88. --print("elv: " .. elv * COLD_ELV_RATE)
  89. env = sun * COLD_SUN_FACTOR +
  90. lat * COLD_LAT_FACTOR +
  91. elv * COLD_ELV_RATE +
  92. seas * COLD_SEASON_FACTOR
  93. --print("\n cold sun: " .. (sun * COLD_SUN_FACTOR))
  94. --print(" cold lat: " .. (lat * COLD_LAT_FACTOR))
  95. --print(" cold elv: " .. (elv * COLD_ELV_RATE))
  96. --print(" cold ssn: " .. (seas * COLD_SEASON_FACTOR))
  97. end
  98. -- TODO need to check if the player is swimming
  99. --print("cold env: " .. env)
  100. local pos
  101. local coldfactor = 0
  102. -- look for hot things nearby
  103. pos = minetest.find_node_near(ppos, 10, {
  104. "campfire:campfire",
  105. "default:furnace_active",
  106. "fire:basic_flame",
  107. "fire:permanent_flame",
  108. "default:lava_souce",
  109. "default:lava_flowing",
  110. })
  111. if pos ~= nil then
  112. coldfactor = -20
  113. else
  114. -- look for really cold things
  115. pos = minetest.find_node_near(ppos, 20, {
  116. "default:snow",
  117. "default:snowblock",
  118. "default:ice",
  119. "default:dirt_with_snow",
  120. })
  121. if pos ~= nil then
  122. coldfactor = 30
  123. else -- look for chilly things
  124. local pos = minetest.find_node_near(ppos, 20, {
  125. "default:dirt_with_coniferous_litter",
  126. -- "default:silver_sand", -- cold desert -- also appears underground randomly, making you randomly freeze
  127. })
  128. if pos ~= nil then
  129. coldfactor = 15
  130. end
  131. end
  132. end
  133. if minetest.setting_getbool("enable_damage") == false then
  134. cold[name] = 0
  135. return
  136. end
  137. -- bonuses from items like clothes
  138. local clothes = 0
  139. local cslots = {}
  140. if burden.players[name] then
  141. for i,c in ipairs(burden.players[name].hotbar) do
  142. local ins = minetest.get_item_group(c, "insulation")
  143. if ins > 0 then
  144. local slot
  145. if minetest.get_item_group(c, "hat") then
  146. slot = "hat"
  147. elseif minetest.get_item_group(c, "gloves") then
  148. slot = "gloves"
  149. elseif minetest.get_item_group(c, "boots") then
  150. slot = "boots"
  151. elseif minetest.get_item_group(c, "coat") then
  152. slot = "coat"
  153. else
  154. slot = "none"
  155. end
  156. -- note that bonues must be subtracted to get warmth
  157. if cslots[slot] < ins then
  158. clothes = clothes + cslots[slot]
  159. end
  160. cslots[slot] = ins
  161. clothes = clothes - ins
  162. end
  163. end
  164. end
  165. local effective_temp = coldfactor + env + clothes
  166. --print("effective_temp: "..effective_temp)
  167. if new_lvl > 0 then
  168. lvl = new_lvl
  169. else
  170. -- lvl = lvl + (coldfactor * COLD_FACTOR) + env + clothes
  171. SHIVER_RATE = .2
  172. local diff = (effective_temp - lvl)
  173. local lvl_d = diff * sigmoid(diff)
  174. --print("lvl_d: "..lvl_d)
  175. lvl = lvl + lvl_d
  176. end
  177. if lvl > COLD_MAX then
  178. lvl = COLD_MAX
  179. elseif lvl < 0 then
  180. lvl = 0
  181. end
  182. cold[name].lvl = lvl
  183. --print("coldfactor: " .. (coldfactor))
  184. --print("coldness: " ..lvl)
  185. if lvl >= COLD_SHIVER_LVL then
  186. local hp = player:get_hp()
  187. if lvl >= COLD_FREEZE_LVL then
  188. hp = hp - COLD_FREEZE
  189. else
  190. if 0 == math.random(0, COLD_SHIVER_CHANCE) then
  191. hp = hp - COLD_SHIVER
  192. end
  193. end
  194. player:set_hp(hp)
  195. end
  196. hud.change_item(player, "cold", {number = lvl})
  197. cold.save(player)
  198. end
  199. local update_cold = cold.update_cold
  200. if minetest.setting_getbool("enable_damage") then
  201. minetest.register_on_joinplayer(function(player)
  202. local inv = player:get_inventory()
  203. inv:set_size("cold", 1)
  204. local name = player:get_player_name()
  205. cold[name] = {}
  206. cold[name].lvl = cold.read(player)
  207. cold[name].exhaus = 0
  208. local lvl = cold[name].lvl
  209. if lvl > 20 then
  210. lvl = 20
  211. end
  212. minetest.after(0.8, function()
  213. hud.swap_statbar(player, "cold", "armor")
  214. hud.change_item(player, "cold", {number = lvl, max = 20})
  215. end)
  216. end)
  217. -- for exhaustion
  218. minetest.register_on_respawnplayer(function(player)
  219. cold.update_cold(player, 0)
  220. end)
  221. end
  222. hud.register("cold", {
  223. hud_elem_type = "statbar",
  224. position = {x = 0,y = 2},
  225. size = {x = 24, y = 24},
  226. text = "cold_hud_snowflake.png",
  227. number = 20,
  228. alignment = {x = -1, y = -1},
  229. offset = {x = 10, y = -30},
  230. background = "",
  231. --autohide_bg = true,
  232. max = 20,
  233. })
  234. local function update(player)
  235. update_cold(player, -1)
  236. end
  237. local function cyclic_update()
  238. for _, player in ipairs(minetest.get_connected_players()) do
  239. update(player)
  240. end
  241. minetest.after(7, cyclic_update)
  242. end
  243. minetest.after(7, cyclic_update)