effect.lua 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. local status_effect_count = 0
  2. local timer_reducers = {}
  3. local reg_err = "Error registering status effect: "
  4. local do_nothing = function()end
  5. local storage = minetest.get_mod_storage()
  6. --constructor for status effect
  7. function status_effects.StatusEffect(def)
  8. local this = {}
  9. --storing name and callbacks from definition
  10. assert(type(def.name) == "string", reg_err .. "name must be a string")
  11. this.name = def.name
  12. --callback registering
  13. --------------------------------------------------------------------
  14. --on_elapsed
  15. --run function when timer has elapsed with player name as argument
  16. local do_on_elapsed = {}
  17. function this.register_on_elapsed(fn)
  18. table.insert(do_on_elapsed, fn)
  19. end
  20. local function on_elapsed(playername)
  21. for i, f in ipairs(do_on_elapsed)
  22. do
  23. f(playername)
  24. end
  25. end
  26. --on_given
  27. --run function when a player is given the effect with playername and
  28. --time as arguments, IF the player doesn't already have the effect
  29. local do_on_given = {}
  30. function this.register_on_given(fn)
  31. table.insert(do_on_given, fn)
  32. end
  33. local function on_given(playername, time)
  34. for i, f in ipairs(do_on_given)
  35. do
  36. f(playername, time)
  37. end
  38. end
  39. --on_fresh
  40. --run function EVERY TIME a player is given the effect with
  41. --playername, added time and total time as arguments
  42. local do_on_fresh = {}
  43. function this.register_on_fresh(fn)
  44. table.insert(do_on_fresh, fn)
  45. end
  46. local function on_fresh(playername, time)
  47. local total_time = this.get_remaining_time(playername) + time
  48. for i, f in ipairs(do_on_fresh)
  49. do
  50. f(playername, time, total_time)
  51. end
  52. end
  53. --on_save
  54. --runs when a player's timer is saved with playername as argument
  55. local do_on_save = {}
  56. function this.register_on_save(fn)
  57. table.insert(do_on_save, fn)
  58. end
  59. local function on_save(playername)
  60. for i, f in ipairs(do_on_save)
  61. do
  62. f(playername)
  63. end
  64. end
  65. --on_load
  66. --runs when a player's timer is loaded with playername as argument
  67. local do_on_load = {}
  68. function this.register_on_load(fn)
  69. table.insert(do_on_load, fn)
  70. end
  71. local function on_load(playername)
  72. for i, f in ipairs(do_on_load)
  73. do
  74. f(playername)
  75. end
  76. end
  77. --functions for giving or otherwise interacting with status effects
  78. --------------------------------------------------------------------
  79. local timer_count = 0
  80. local ids = {} --stores ids, indexed by player name
  81. local players = {} --stores player names, indexed by id
  82. local effect_timers = {} --stores remaining times, indexed by id
  83. --returns remaining time duh
  84. this.get_remaining_time = function(playername)
  85. local id = ids[playername]
  86. if id
  87. then
  88. return effect_timers[id]
  89. else
  90. return 0
  91. end
  92. end
  93. --increases timer for player by time
  94. this.give_to = function(playername, time)
  95. on_fresh(playername, time)
  96. local id = ids[playername]
  97. if id
  98. then
  99. effect_timers[id] = effect_timers[id] + time
  100. else
  101. on_given(playername, time)
  102. timer_count = timer_count + 1
  103. effect_timers[timer_count] = time
  104. ids[playername] = timer_count
  105. players[timer_count] = playername
  106. end
  107. end
  108. --returns true if player has effect, false otherwise
  109. this.player_has = function(name)
  110. return ids[name] ~= nil
  111. end
  112. this.revoke = function(playername)
  113. local time = this.get_remaining_time(playername)
  114. if time ~= 0
  115. then
  116. this.give_to(playername, -time)
  117. end
  118. end
  119. --decreasing the timers
  120. --------------------------------------------------------------------
  121. local function decrease_effect_time(index, dtime)
  122. local t = effect_timers[index] - dtime
  123. if t <= 0 --timer elapsed
  124. then
  125. if timer_count ~= index
  126. then
  127. effect_timers[index] = effect_timers[timer_count]
  128. local name = players[timer_count]
  129. players[index] = name
  130. ids[name] = index
  131. players[timer_count] = nil
  132. decrease_effect_time(index, dtime)
  133. else
  134. effect_timers[index] = nil
  135. local name = players[index]
  136. ids[name] = nil
  137. players[name] = nil
  138. end
  139. on_elapsed(players[index])
  140. timer_count = timer_count - 1
  141. else
  142. effect_timers[index] = t
  143. end
  144. end
  145. this.decrease_effect_times = function(dtime)
  146. for i = 1, timer_count
  147. do
  148. decrease_effect_time(i, dtime)
  149. end
  150. end
  151. status_effect_count = status_effect_count + 1
  152. timer_reducers[status_effect_count] = this.decrease_effect_times
  153. --storage stuff
  154. --------------------------------------------------------------------
  155. local storage_table = minetest.deserialize(storage:get_string(this.name)) or {}
  156. local function save_timer(playername, bulk)
  157. --store thing
  158. local id = ids[playername]
  159. if not id
  160. then
  161. return
  162. end
  163. ids[playername] = nil
  164. on_save(playername)
  165. do--store timer in mod storage
  166. storage_table[playername] = (id and effect_timers[id] or 0)
  167. if not bulk
  168. then
  169. storage:set_string(this.name, minetest.serialize(storage_table))
  170. end
  171. end
  172. --close gap in timer list
  173. effect_timers[id] = effect_timers[timer_count]
  174. local name = players[timer_count]
  175. players[id] = name
  176. ids[name] = id
  177. players[timer_count] = nil
  178. timer_count = timer_count - 1
  179. end
  180. local function load_timer(playername)
  181. local num = storage_table[playername] or 0
  182. if num ~= 0
  183. then
  184. on_load(playername)
  185. storage_table[playername] = nil
  186. this.give_to(playername, num)
  187. end
  188. end
  189. --actually storing
  190. minetest.register_on_joinplayer(function(player)
  191. local name = player:get_player_name()
  192. load_timer(name)
  193. end)
  194. minetest.register_on_leaveplayer(function(player)
  195. local name = player:get_player_name()
  196. save_timer(name, false)
  197. end)
  198. minetest.register_on_leaveplayer(function(player)
  199. local name = player:get_player_name()
  200. save_timer(name, false)
  201. end)
  202. minetest.register_on_shutdown(function()
  203. local players = minetest.get_connected_players()
  204. for _, p in pairs(players)
  205. do
  206. local name = p:get_player_name()
  207. save_timer(name, true)
  208. end
  209. storage:set_string(this.name, minetest.serialize(storage_table))
  210. end)
  211. return this
  212. end
  213. minetest.register_globalstep(
  214. function(dtime)
  215. for i = 1, status_effect_count
  216. do
  217. timer_reducers[i](dtime)
  218. end
  219. end)