esprint.lua 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. --[[
  2. Sprint mod for Minetest by GunshipPenguin
  3. To the extent possible under law, the author(s)
  4. have dedicated all copyright and related and neighboring rights
  5. to this software to the public domain worldwide. This software is
  6. distributed without any warranty.
  7. ]]
  8. sprint.players = sprint.players or {}
  9. sprint.stamina_hud = sprint.stamina_hud or {}
  10. -- Localize.
  11. local players = sprint.players
  12. local staminaHud = sprint.stamina_hud
  13. local floor = math.floor
  14. local math_random = math.random
  15. function sprint.on_joinplayer(player)
  16. local playerName = player:get_player_name()
  17. players[playerName] = {
  18. sprinting = false,
  19. timeOut = 0,
  20. stamina = 0,
  21. shouldSprint = false,
  22. bars = 0,
  23. }
  24. -- Background images.
  25. -- Add them first, since draw order is determined by ID.
  26. player:hud_add({
  27. hud_elem_type = "statbar",
  28. position = {x=0.5,y=1},
  29. size = {x=16, y=16},
  30. text = "sprint_stamina_icon_bg.png",
  31. number = SPRINT_HUD_ICONS,
  32. alignment = {x=0,y=1},
  33. offset = {x=-((16*23)/2), y=-87},
  34. })
  35. -- Main stat icons.
  36. players[playerName].hud = player:hud_add({
  37. hud_elem_type = "statbar",
  38. position = {x=0.5,y=1},
  39. size = {x=16, y=16},
  40. text = "sprint_stamina_icon.png",
  41. number = 0,
  42. alignment = {x=0,y=1},
  43. offset = {x=-((16*23)/2), y=-87},
  44. })
  45. sprint.set_stamina(player, 0)
  46. end
  47. function sprint.on_leaveplayer(player, timedout)
  48. local playerName = player:get_player_name()
  49. players[playerName] = nil
  50. end
  51. -- Public API function.
  52. function sprint.set_stamina(player, sta)
  53. local pname = player:get_player_name()
  54. if players[pname] then
  55. if sta > SPRINT_STAMINA then sta = SPRINT_STAMINA end
  56. local hp_max = pova.get_active_modifier(player, "properties").hp_max
  57. local maxstamina = floor((player:get_hp() / hp_max) * SPRINT_STAMINA)
  58. if sta > maxstamina then
  59. sta = maxstamina
  60. end
  61. players[pname]["stamina"] = sta
  62. local numBars = floor((sta/SPRINT_STAMINA)*SPRINT_HUD_ICONS)
  63. player:hud_change(players[pname]["hud"], "number", numBars)
  64. end
  65. end
  66. -- Public API function.
  67. function sprint.add_stamina(player, sta)
  68. local pname = player:get_player_name()
  69. if players[pname] then
  70. local stamina = players[pname]["stamina"]
  71. stamina = stamina + sta
  72. if stamina > SPRINT_STAMINA then stamina = SPRINT_STAMINA end
  73. if stamina < 0 then stamina = 0 end
  74. local hp_max = pova.get_active_modifier(player, "properties").hp_max
  75. local maxstamina = floor((player:get_hp() / hp_max) * SPRINT_STAMINA)
  76. if stamina > maxstamina then
  77. stamina = maxstamina
  78. end
  79. players[pname]["stamina"] = stamina
  80. local numBars = floor((stamina/SPRINT_STAMINA)*SPRINT_HUD_ICONS)
  81. player:hud_change(players[pname]["hud"], "number", numBars)
  82. end
  83. end
  84. function sprint.get_stamina(player)
  85. local pname = player:get_player_name()
  86. if players[pname] then
  87. local stamina = players[pname]["stamina"]
  88. return stamina
  89. end
  90. return 0
  91. end
  92. function sprint.on_respawnplayer(player)
  93. sprint.set_stamina(player, 0)
  94. return true
  95. end
  96. local hunger_timer = 0
  97. local particle_timer = 0
  98. function sprint.globalstep(dtime)
  99. local do_hunger = false
  100. local do_particle = false
  101. hunger_timer = hunger_timer + dtime
  102. particle_timer = particle_timer + dtime
  103. if hunger_timer > 5 then
  104. hunger_timer = 0
  105. do_hunger = true
  106. end
  107. if particle_timer > 0.5 then
  108. particle_timer = 0
  109. do_particle = true
  110. end
  111. --Loop through all connected players
  112. for playerName, playerInfo in pairs(players) do
  113. local player = minetest.get_player_by_name(playerName)
  114. if player ~= nil then
  115. --Check if the player should be sprinting
  116. local control = player:get_player_control()
  117. if control["aux1"] and control["up"] then
  118. players[playerName]["shouldSprint"] = true
  119. else
  120. players[playerName]["shouldSprint"] = false
  121. end
  122. --If the player is sprinting, create particles behind him/her
  123. if do_particle and playerInfo["sprinting"] == true then
  124. if not gdac_invis.is_invisible(playerName) then
  125. local numParticles = math_random(1, 2)
  126. local playerPos = player:get_pos()
  127. local playerNode = minetest.get_node({x=playerPos["x"], y=playerPos["y"]-1, z=playerPos["z"]})
  128. if playerNode["name"] ~= "air" then
  129. for i=1, numParticles, 1 do
  130. minetest.add_particle({
  131. pos = {x=playerPos["x"]+math_random(-1,1)*math_random()/2,y=playerPos["y"]+0.1,z=playerPos["z"]+math_random(-1,1)*math_random()/2},
  132. velocity = {x=0, y=5, z=0},
  133. acceleration = {x=0, y=-13, z=0},
  134. expirationtime = math_random(),
  135. size = math_random()+0.5,
  136. collisiondetection = true,
  137. vertical = false,
  138. texture = "sprint_particle.png",
  139. })
  140. end
  141. end
  142. end
  143. end
  144. -- Player is sprinting?
  145. if do_hunger and playerInfo["sprinting"] == true then
  146. hunger.increase_hunger(player, 1)
  147. hunger.increase_exhaustion(player, 6)
  148. end
  149. -- Player moving in water? Increase hunger and exhaustion.
  150. if do_hunger and (control.jump or control.left or control.right or control.up or control.down) then
  151. local node_inside = sky.get_last_walked_nodeabove(playerName)
  152. local ndef = minetest.reg_ns_nodes[node_inside]
  153. if ndef and ndef.groups and ndef.groups.liquid then
  154. hunger.increase_hunger(player, 1)
  155. hunger.increase_exhaustion(player, 10)
  156. elseif control.jump then
  157. -- Player is probably climbing a ladder.
  158. hunger.increase_exhaustion(player, 7)
  159. end
  160. end
  161. --Adjust player states
  162. if players[playerName]["shouldSprint"] == true then --Stopped
  163. sprint.set_sprinting(playerName, true)
  164. elseif players[playerName]["shouldSprint"] == false then
  165. sprint.set_sprinting(playerName, false)
  166. end
  167. --Lower the player's stamina by dtime if he/she is sprinting and set his/her state to 0 if stamina is zero
  168. if playerInfo["sprinting"] == true then
  169. playerInfo["stamina"] = playerInfo["stamina"] - (dtime * SPRINT_USE_RATE)
  170. if playerInfo["stamina"] <= 0 then
  171. playerInfo["stamina"] = 0
  172. sprint.set_sprinting(playerName, false)
  173. end
  174. --Increase player's stamina if he/she is not sprinting and his/her stamina is less than SPRINT_STAMINA
  175. elseif playerInfo["sprinting"] == false and playerInfo["stamina"] < SPRINT_STAMINA then
  176. if hunger.get_hunger(player) >= 10 then
  177. local mult = 0.4
  178. -- If moving, stamina comes back more slowly.
  179. if control.up or control.left or control.right or control.down then
  180. mult = 0.01
  181. end
  182. -- If player is not hungry, they get stamina quicker.
  183. if hunger.get_hunger(player) >= 30 then
  184. mult = mult + 0.5
  185. end
  186. -- If player is in good health, they regain stamina more quickly.
  187. local max_hp = pova.get_active_modifier(player, "properties").hp_max
  188. if player:get_hp() >= max_hp then
  189. mult = mult + 0.3
  190. elseif player:get_hp() >= (max_hp * 0.9) then
  191. mult = mult + 0.2
  192. end
  193. -- Cloaking device uses energy from YOU.
  194. -- Rate is equal to whatever your stamina-regain rate is.
  195. if cloaking.is_cloaked(playerName) then
  196. mult = 0
  197. end
  198. mult = mult * hunger.get_stamina_boost(playerName)
  199. playerInfo["stamina"] = playerInfo["stamina"] + (dtime * mult)
  200. end
  201. end
  202. -- Cap stamina at SPRINT_STAMINA
  203. if playerInfo["stamina"] > SPRINT_STAMINA then
  204. playerInfo["stamina"] = SPRINT_STAMINA
  205. end
  206. local hp_max = pova.get_active_modifier(player, "properties").hp_max
  207. local maxstamina = floor((player:get_hp() / hp_max) * SPRINT_STAMINA)
  208. if playerInfo["stamina"] > maxstamina then
  209. playerInfo["stamina"] = maxstamina
  210. end
  211. -- Update the players's hud sprint stamina bar
  212. local numBars = floor((playerInfo["stamina"]/SPRINT_STAMINA)*SPRINT_HUD_ICONS)
  213. -- Don't send hud update every frame.
  214. if numBars ~= playerInfo["bars"] then
  215. player:hud_change(playerInfo["hud"], "number", numBars)
  216. playerInfo["bars"] = numBars
  217. --minetest.chat_send_all("# Server: Updating HUD!")
  218. end
  219. end
  220. end
  221. end
  222. function sprint.set_sprinting(playerName, sprinting) --Sets the state of a player (0=stopped/moving, 1=sprinting)
  223. local player = minetest.get_player_by_name(playerName)
  224. -- Speed multiplier based on player's health relative to max.
  225. -- This is as good a place as any to run this computation.
  226. local hp = player:get_hp()
  227. local max_hp = pova.get_active_modifier(player, "properties").hp_max
  228. local hp_mult = 1
  229. if hp <= (max_hp * 0.2) then
  230. hp_mult = 0.8
  231. elseif hp <= (max_hp * 0.5) then
  232. hp_mult = 0.9
  233. elseif hp >= (max_hp * 0.95) then
  234. hp_mult = 1.1
  235. end
  236. if players[playerName] then
  237. local was_sprinting = players[playerName]["sprinting"]
  238. players[playerName]["sprinting"] = sprinting
  239. if sprinting ~= was_sprinting then
  240. if sprinting == true then
  241. pova.set_modifier(player, "physics", {
  242. speed = SPRINT_SPEED * hp_mult,
  243. jump = SPRINT_JUMP * hp_mult,
  244. }, "sprinting")
  245. elseif sprinting == false then
  246. pova.set_modifier(player, "physics", {
  247. speed = hp_mult,
  248. jump = hp_mult,
  249. }, "sprinting")
  250. end
  251. end
  252. return true
  253. end
  254. return false
  255. end