esprint.lua 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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:get_pos()
  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. elseif control.jump then
  171. -- Player is probably climbing a ladder.
  172. hunger.increase_exhaustion(player, 7)
  173. end
  174. end
  175. --Adjust player states
  176. if players[playerName]["shouldSprint"] == true then --Stopped
  177. sprint.set_sprinting(playerName, true)
  178. elseif players[playerName]["shouldSprint"] == false then
  179. sprint.set_sprinting(playerName, false)
  180. end
  181. --Lower the player's stamina by dtime if he/she is sprinting and set his/her state to 0 if stamina is zero
  182. if playerInfo["sprinting"] == true then
  183. playerInfo["stamina"] = playerInfo["stamina"] - dtime
  184. if playerInfo["stamina"] <= 0 then
  185. playerInfo["stamina"] = 0
  186. sprint.set_sprinting(playerName, false)
  187. end
  188. --Increase player's stamina if he/she is not sprinting and his/her stamina is less than SPRINT_STAMINA
  189. elseif playerInfo["sprinting"] == false and playerInfo["stamina"] < SPRINT_STAMINA then
  190. if hunger.get_hunger(player) >= 10 then
  191. local div = 3
  192. if control.up or control.left or control.right or control.down then
  193. -- If moving, stamina comes back more slowly.
  194. div = 6
  195. end
  196. -- If player is in good health, they regain stamina more quickly.
  197. if player:get_hp() >= 20 then
  198. div = div - 2
  199. elseif player:get_hp() >= 18 then
  200. div = div - 1
  201. end
  202. playerInfo["stamina"] = playerInfo["stamina"] + (dtime / div)
  203. end
  204. end
  205. -- Cap stamina at SPRINT_STAMINA
  206. if playerInfo["stamina"] > SPRINT_STAMINA then
  207. playerInfo["stamina"] = SPRINT_STAMINA
  208. end
  209. local maxstamina = floor((player:get_hp()/20)*SPRINT_STAMINA)
  210. if playerInfo["stamina"] > maxstamina then
  211. playerInfo["stamina"] = maxstamina
  212. end
  213. -- Update the players's hud sprint stamina bar
  214. local numBars = floor((playerInfo["stamina"]/SPRINT_STAMINA)*SPRINT_HUD_ICONS)
  215. -- Don't send hud update every frame.
  216. if numBars ~= playerInfo["bars"] then
  217. player:hud_change(playerInfo["hud"], "number", numBars)
  218. playerInfo["bars"] = numBars
  219. --minetest.chat_send_all("# Server: Updating HUD!")
  220. end
  221. end
  222. end
  223. end
  224. function sprint.set_sprinting(playerName, sprinting) --Sets the state of a player (0=stopped/moving, 1=sprinting)
  225. local player = minetest.get_player_by_name(playerName)
  226. -- Speed multiplier based on player's health relative to max.
  227. -- This is as good a place as any to run this computation.
  228. local hp = player:get_hp()
  229. local max_hp = player:get_properties().hp_max
  230. local hp_mult = 1
  231. if hp <= (max_hp * 0.2) then
  232. hp_mult = 0.8
  233. elseif hp <= (max_hp * 0.5) then
  234. hp_mult = 0.9
  235. elseif hp >= (max_hp * 0.95) 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