esprint.lua 8.4 KB

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