esprint.lua 8.2 KB

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