init.lua 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. if not minetest.global_exists("bandages") then bandages = {} end
  2. bandages.modpath = minetest.get_modpath("bandages")
  3. bandages.players = bandages.players or {}
  4. -- Localize vector.distance() for performance.
  5. local vector_distance = vector.distance
  6. local math_floor = math.floor
  7. if minetest.get_modpath("reload") then
  8. local c = "bandages:core"
  9. local f = bandages.modpath .. "/init.lua"
  10. if not reload.file_registered(c) then
  11. reload.register_file(c, f, false)
  12. end
  13. end
  14. bandages.movement_limit_from_level = function(level)
  15. if level == 1 then
  16. return 20
  17. elseif level == 2 then
  18. return 6
  19. elseif level == 3 then
  20. return 1
  21. end
  22. return 0
  23. end
  24. bandages.hp_from_level = function(level, hp, hp_max)
  25. local heal = 0
  26. -- Hmm hmm hmmm, I'm a genius.
  27. local function mod1(hp, max)
  28. local a = (hp / hp_max)
  29. return a * a
  30. end
  31. -- This function is proof that I failed algebra.
  32. -- There's a way to do this in one line with no conditional, I just can't
  33. -- figure out what it is.
  34. local function mod2(hp, max)
  35. local a = hp / max
  36. local b
  37. if a <= 0.5 then
  38. b = a / 0.5
  39. else
  40. b = ((a - 0.5) / 0.5) * -1 + 1
  41. end
  42. return b * b
  43. end
  44. -- But this function makes me feel better.
  45. local function mod3(hp, max)
  46. local a = ((hp / hp_max) * -1 + 1)
  47. return a * a
  48. end
  49. if level == 1 then
  50. -- You receive the maximum heal bonus if you are only slightly hurt.
  51. -- Simple bandages become worse for the job the more hurt you are.
  52. heal = hp_max * 0.1 * mod1(hp, hp_max)
  53. elseif level == 2 then
  54. -- You get the most benefit from the basic medkit when used to heal
  55. -- non-lifethreatening wounds which need more care than a simple bandaging.
  56. heal = hp_max * 0.15 * mod2(hp, hp_max)
  57. elseif level == 3 then
  58. -- Trama medkits are best used on severe injuries. Using them for light
  59. -- scrapes is wasteful, and provides little benefit.
  60. heal = hp_max * 0.3 * mod3(hp, hp_max)
  61. end
  62. return heal
  63. end
  64. bandages.delay_from_level = function(level)
  65. if level == 1 then
  66. return 1.5
  67. elseif level == 2 then
  68. return 2.0
  69. elseif level == 3 then
  70. return 2.5
  71. end
  72. return 0
  73. end
  74. bandages.target_not_hurt = function(pname, tname)
  75. minetest.chat_send_player(pname, "# Server: <" .. rename.gpn(tname) .. "> is not wounded.")
  76. --easyvend.sound_error(pname)
  77. end
  78. bandages.player_not_hurt = function(pname)
  79. minetest.chat_send_player(pname, "# Server: You are not wounded.")
  80. --easyvend.sound_error(pname)
  81. end
  82. bandages.player_bandages_self = function(pname, hp, hp_max)
  83. local pc = math_floor((hp / hp_max) * 100)
  84. minetest.chat_send_player(pname, "# Server: You use bandages on yourself. Your health is now " .. pc .. "%.")
  85. end
  86. bandages.target_is_dead = function(pname, tname)
  87. minetest.chat_send_player(pname, "# Server: <" .. rename.gpn(tname) .. "> is dead!")
  88. --easyvend.sound_error(pname)
  89. end
  90. bandages.player_is_dead = function(pname)
  91. minetest.chat_send_player(pname, "# Server: You are dead!")
  92. --easyvend.sound_error(pname)
  93. end
  94. bandages.player_bandages_target = function(pname, tname, hp, hp_max)
  95. local pc = math_floor((hp / hp_max) * 100)
  96. minetest.chat_send_player(tname, "# Server: Player <" .. rename.gpn(pname) .. "> used a bandage on you.")
  97. minetest.chat_send_player(pname, "# Server: <" .. rename.gpn(tname) .. ">'s health improves to " .. pc .. "%.")
  98. end
  99. bandages.medkit_already_in_use = function(pname)
  100. minetest.chat_send_player(pname, "# Server: You are already using a medkit; wait to be done.")
  101. --easyvend.sound_error(pname)
  102. end
  103. bandages.player_moved_too_much = function(pname)
  104. minetest.chat_send_player(pname, "# Server: You must hold still while using a medkit!")
  105. --easyvend.sound_error(pname)
  106. end
  107. bandages.target_moved_too_much = function(pname, tname)
  108. minetest.chat_send_player(pname, "# Server: Player <" .. rename.gpn(tname) .. "> must hold still for you to use medkit!")
  109. minetest.chat_send_player(tname, "# Server: Player <" .. rename.gpn(pname) .. "> is trying to use a medkit on you; hold still!")
  110. --easyvend.sound_error(pname)
  111. end
  112. bandages.get_sound_range_from_level = function(level)
  113. if level == 1 then
  114. return 8
  115. elseif level == 2 then
  116. return 16
  117. elseif level == 3 then
  118. return 32
  119. end
  120. return 0
  121. end
  122. bandages.get_sound_gain_from_level = function(level)
  123. if level == 1 then
  124. return 0.5
  125. elseif level == 2 then
  126. return 0.7
  127. elseif level == 3 then
  128. return 1.0
  129. end
  130. return 0
  131. end
  132. bandages.play_sound_effects = function(pos, level)
  133. local range = bandages.get_sound_range_from_level(level)
  134. local gain = bandages.get_sound_gain_from_level(level)
  135. ambiance.sound_play("bandages_bandaging", pos, gain, range)
  136. -- Increase length of sound effect for higher levels.
  137. if level >= 2 then
  138. minetest.after(1.0, function()
  139. ambiance.sound_play("bandages_bandaging", pos, gain, range)
  140. end)
  141. end
  142. if level >= 3 then
  143. minetest.after(2.0, function()
  144. ambiance.sound_play("bandages_bandaging", pos, gain, range)
  145. end)
  146. end
  147. end
  148. function bandages.heal_target(itemstack, user, target, level)
  149. local pname = user:get_player_name()
  150. local tname = target:get_player_name()
  151. local hp = target:get_hp()
  152. local hp_max = pova.get_active_modifier(target, "properties").hp_max
  153. if hp >= hp_max then
  154. return bandages.target_not_hurt(pname, tname)
  155. end
  156. if hp <= 0 then
  157. return bandages.target_is_dead(pname, tname)
  158. end
  159. if bandages.players[pname] or bandages.players[tname] then
  160. return bandages.medkit_already_in_use(pname)
  161. end
  162. bandages.play_sound_effects(target:get_pos(), level)
  163. bandages.players[tname] = {pos=target:get_pos()}
  164. bandages.players[pname] = {pos=user:get_pos()}
  165. minetest.after(bandages.delay_from_level(level), function()
  166. local pos = bandages.players[tname].pos
  167. bandages.players[tname] = nil
  168. bandages.players[pname] = nil
  169. local target = minetest.get_player_by_name(tname)
  170. if not target or not target:is_player() then return end
  171. if vector_distance(target:get_pos(), pos) > bandages.movement_limit_from_level(level) then
  172. return bandages.target_moved_too_much(pname, tname)
  173. end
  174. -- Don't heal target if already dead.
  175. -- This solves an exploit people have found.
  176. local hp = target:get_hp()
  177. if hp == 0 then return end
  178. armor.notify_set_hp_reason({reason="bandage"})
  179. target:set_hp(hp + bandages.hp_from_level(level, hp, hp_max))
  180. bandages.player_bandages_target(pname, tname, target:get_hp(), hp_max)
  181. end)
  182. itemstack:take_item()
  183. return itemstack
  184. end
  185. function bandages.heal_self(itemstack, user, level)
  186. local pname = user:get_player_name()
  187. local hp = user:get_hp()
  188. local hp_max = pova.get_active_modifier(user, "properties").hp_max
  189. if hp >= hp_max then
  190. return bandages.player_not_hurt(pname)
  191. end
  192. if hp <= 0 then
  193. return bandages.player_is_dead(pname)
  194. end
  195. if bandages.players[pname] then
  196. return bandages.medkit_already_in_use(pname)
  197. end
  198. bandages.play_sound_effects(user:get_pos(), level)
  199. bandages.players[pname] = {pos=user:get_pos()}
  200. minetest.after(bandages.delay_from_level(level), function()
  201. local pos = bandages.players[pname].pos
  202. bandages.players[pname] = nil
  203. local user = minetest.get_player_by_name(pname)
  204. if not user or not user:is_player() then return end
  205. if vector_distance(user:get_pos(), pos) > bandages.movement_limit_from_level(level) then
  206. return bandages.player_moved_too_much(pname)
  207. end
  208. -- Don't heal user if already dead.
  209. -- This solves an exploit people have found.
  210. local hp = user:get_hp()
  211. if hp == 0 then return end
  212. user:set_hp(hp + bandages.hp_from_level(level, hp, hp_max))
  213. bandages.player_bandages_self(pname, user:get_hp(), hp_max)
  214. end)
  215. itemstack:take_item()
  216. return itemstack
  217. end
  218. bandages.use_bandage = function(itemstack, user, pointed_thing, level)
  219. if not user or not user:is_player() then return end
  220. if pointed_thing.type == "object" then
  221. local target = pointed_thing.ref
  222. if not target or not target:is_player() then
  223. return bandages.heal_self(itemstack, user, level)
  224. end
  225. return bandages.heal_target(itemstack, user, target, level)
  226. else
  227. return bandages.heal_self(itemstack, user, level)
  228. end
  229. end
  230. -- Execute registrations once only.
  231. if not bandages.registered then
  232. minetest.register_craftitem("bandages:bandage_1", {
  233. description = "Simple Bandage\n\nBest used for light scrapes and scratches.\nUse on yourself or another.",
  234. inventory_image = "bandage_1.png",
  235. on_use = function(itemstack, user, pointed_thing)
  236. return bandages.use_bandage(itemstack, user, pointed_thing, 1)
  237. end,
  238. })
  239. minetest.register_craftitem("bandages:bandage_2", {
  240. description = "Basic Medkit\n\nHeals moderate wounds (best around 50% health).\nUse on yourself or another.",
  241. inventory_image = "bandage_2.png",
  242. on_use = function(itemstack, user, pointed_thing)
  243. return bandages.use_bandage(itemstack, user, pointed_thing, 2)
  244. end,
  245. })
  246. minetest.register_craftitem("bandages:bandage_3", {
  247. description = "Trauma Medkit\n\nAids in recovery from severe, debilitating injuries.\nUse on yourself or another.",
  248. inventory_image = "bandage_3.png",
  249. on_use = function(itemstack, user, pointed_thing)
  250. return bandages.use_bandage(itemstack, user, pointed_thing, 3)
  251. end,
  252. })
  253. minetest.register_craft({
  254. output = 'bandages:bandage_1 3',
  255. recipe = {
  256. {'default:paper', 'farming:string', 'default:paper'},
  257. }
  258. })
  259. minetest.register_craft({
  260. output = 'bandages:bandage_2 3',
  261. recipe = {
  262. {'default:paper', 'farming:cloth', 'default:paper'},
  263. }
  264. })
  265. minetest.register_craft({
  266. output = 'bandages:bandage_3 3',
  267. recipe = {
  268. {'', 'aloevera:aloe_gel', ''},
  269. {'default:paper', 'farming:cloth', 'default:paper'},
  270. {'', 'dye:green', ''},
  271. }
  272. })
  273. bandages.registered = true
  274. end