esprint.lua 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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.on_respawnplayer(player)
  101. sprint.set_stamina(player, 0)
  102. return true
  103. end
  104. local hunger_timer = 0
  105. local particle_timer = 0
  106. function sprint.globalstep(dtime)
  107. local do_hunger = false
  108. local do_particle = false
  109. hunger_timer = hunger_timer + dtime
  110. particle_timer = particle_timer + dtime
  111. if hunger_timer > 5 then
  112. hunger_timer = 0
  113. do_hunger = true
  114. end
  115. if particle_timer > 0.5 then
  116. particle_timer = 0
  117. do_particle = true
  118. end
  119. --Loop through all connected players
  120. for playerName,playerInfo in pairs(players) do
  121. local player = minetest.get_player_by_name(playerName)
  122. if player ~= nil then
  123. --Check if the player should be sprinting
  124. local control = player:get_player_control()
  125. if control["aux1"] and control["up"] then
  126. players[playerName]["shouldSprint"] = true
  127. else
  128. players[playerName]["shouldSprint"] = false
  129. end
  130. --If the player is sprinting, create particles behind him/her
  131. if do_particle and playerInfo["sprinting"] == true then
  132. local numParticles = math_random(1, 2)
  133. local playerPos = player:getpos()
  134. local playerNode = minetest.get_node({x=playerPos["x"], y=playerPos["y"]-1, z=playerPos["z"]})
  135. if playerNode["name"] ~= "air" then
  136. for i=1, numParticles, 1 do
  137. minetest.add_particle({
  138. 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},
  139. vel = {x=0, y=5, z=0},
  140. acc = {x=0, y=-13, z=0},
  141. expirationtime = math_random(),
  142. size = math_random()+0.5,
  143. collisiondetection = true,
  144. vertical = false,
  145. texture = "sprint_particle.png",
  146. })
  147. end
  148. end
  149. end
  150. -- Player is sprinting?
  151. if do_hunger and playerInfo["sprinting"] == true then
  152. hunger.increase_hunger(player, 1)
  153. hunger.increase_exhaustion(player, 6)
  154. end
  155. -- Player moving in water? Increase hunger and exhaustion.
  156. if do_hunger and (control.jump or control.left or control.right or control.up or control.down) then
  157. local node_inside = sky.get_last_walked_nodeabove(playerName)
  158. local ndef = minetest.reg_ns_nodes[node_inside]
  159. if ndef and ndef.groups and ndef.groups.liquid then
  160. hunger.increase_hunger(player, 1)
  161. hunger.increase_exhaustion(player, 10)
  162. --minetest.chat_send_player("MustTest", "Moving in water!")
  163. elseif control.jump then
  164. -- Player is probably climbing a ladder.
  165. hunger.increase_exhaustion(player, 7)
  166. end
  167. end
  168. --Adjust player states
  169. if players[playerName]["shouldSprint"] == true then --Stopped
  170. sprint.set_sprinting(playerName, true)
  171. elseif players[playerName]["shouldSprint"] == false then
  172. sprint.set_sprinting(playerName, false)
  173. end
  174. --Lower the player's stamina by dtime if he/she is sprinting and set his/her state to 0 if stamina is zero
  175. if playerInfo["sprinting"] == true then
  176. playerInfo["stamina"] = playerInfo["stamina"] - dtime
  177. if playerInfo["stamina"] <= 0 then
  178. playerInfo["stamina"] = 0
  179. sprint.set_sprinting(playerName, false)
  180. end
  181. --Increase player's stamina if he/she is not sprinting and his/her stamina is less than SPRINT_STAMINA
  182. elseif playerInfo["sprinting"] == false and playerInfo["stamina"] < SPRINT_STAMINA then
  183. if hunger.get_hunger(player) >= 10 then
  184. local div = 3
  185. if control.up or control.left or control.right or control.down then
  186. -- If moving, stamina comes back more slowly.
  187. div = 6
  188. end
  189. -- If player is in good health, they regain stamina more quickly.
  190. if player:get_hp() >= 20 then
  191. div = div - 2
  192. elseif player:get_hp() >= 18 then
  193. div = div - 1
  194. end
  195. playerInfo["stamina"] = playerInfo["stamina"] + (dtime / div)
  196. end
  197. end
  198. -- Cap stamina at SPRINT_STAMINA
  199. if playerInfo["stamina"] > SPRINT_STAMINA then
  200. playerInfo["stamina"] = SPRINT_STAMINA
  201. end
  202. local maxstamina = floor((player:get_hp()/20)*SPRINT_STAMINA)
  203. if playerInfo["stamina"] > maxstamina then
  204. playerInfo["stamina"] = maxstamina
  205. end
  206. -- Update the players's hud sprint stamina bar
  207. local numBars = floor((playerInfo["stamina"]/SPRINT_STAMINA)*SPRINT_HUD_ICONS)
  208. -- Don't send hud update every frame.
  209. if numBars ~= playerInfo["bars"] then
  210. player:hud_change(playerInfo["hud"], "number", numBars)
  211. playerInfo["bars"] = numBars
  212. --minetest.chat_send_all("# Server: Updating HUD!")
  213. end
  214. end
  215. end
  216. end
  217. function sprint.set_sprinting(playerName, sprinting) --Sets the state of a player (0=stopped/moving, 1=sprinting)
  218. local player = minetest.get_player_by_name(playerName)
  219. -- Speed multiplier based on player's health.
  220. -- This is as good a place as any to run this computation.
  221. local hp = player:get_hp()
  222. local hp_mult = 1
  223. if hp <= 4 then
  224. hp_mult = 0.8
  225. elseif hp <= 10 then
  226. hp_mult = 0.9
  227. elseif hp >= 20 then
  228. hp_mult = 1.1
  229. end
  230. if players[playerName] then
  231. players[playerName]["sprinting"] = sprinting
  232. if sprinting == true then
  233. player:set_physics_override({speed=speedmults[playerName]*SPRINT_SPEED*hp_mult,jump=jumpmults[playerName]*SPRINT_JUMP*hp_mult})
  234. elseif sprinting == false then
  235. player:set_physics_override({speed=speedmults[playerName]*hp_mult, jump=jumpmults[playerName]*hp_mult})
  236. end
  237. return true
  238. end
  239. return false
  240. end
  241. setSprinting = sprint.set_sprinting