123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- local status_effect_count = 0
- local timer_reducers = {}
- local reg_err = "Error registering status effect: "
- local do_nothing = function()end
- local storage = minetest.get_mod_storage()
- --constructor for status effect
- function status_effects.StatusEffect(def)
- local this = {}
- --storing name and callbacks from definition
- assert(type(def.name) == "string", reg_err .. "name must be a string")
- this.name = def.name
- --callback registering
- --------------------------------------------------------------------
- --on_elapsed
- --run function when timer has elapsed with player name as argument
- local do_on_elapsed = {}
- function this.register_on_elapsed(fn)
- table.insert(do_on_elapsed, fn)
- end
- local function on_elapsed(playername)
- for i, f in ipairs(do_on_elapsed)
- do
- f(playername)
- end
- end
- --on_given
- --run function when a player is given the effect with playername and
- --time as arguments, IF the player doesn't already have the effect
- local do_on_given = {}
- function this.register_on_given(fn)
- table.insert(do_on_given, fn)
- end
- local function on_given(playername, time)
- for i, f in ipairs(do_on_given)
- do
- f(playername, time)
- end
- end
- --on_fresh
- --run function EVERY TIME a player is given the effect with
- --playername, added time and total time as arguments
- local do_on_fresh = {}
- function this.register_on_fresh(fn)
- table.insert(do_on_fresh, fn)
- end
- local function on_fresh(playername, time)
- local total_time = this.get_remaining_time(playername) + time
- for i, f in ipairs(do_on_fresh)
- do
- f(playername, time, total_time)
- end
- end
- --on_save
- --runs when a player's timer is saved with playername as argument
- local do_on_save = {}
- function this.register_on_save(fn)
- table.insert(do_on_save, fn)
- end
- local function on_save(playername)
- for i, f in ipairs(do_on_save)
- do
- f(playername)
- end
- end
- --on_load
- --runs when a player's timer is loaded with playername as argument
- local do_on_load = {}
- function this.register_on_load(fn)
- table.insert(do_on_load, fn)
- end
- local function on_load(playername)
- for i, f in ipairs(do_on_load)
- do
- f(playername)
- end
- end
- --functions for giving or otherwise interacting with status effects
- --------------------------------------------------------------------
- local timer_count = 0
- local ids = {} --stores ids, indexed by player name
- local players = {} --stores player names, indexed by id
- local effect_timers = {} --stores remaining times, indexed by id
- --returns remaining time duh
- this.get_remaining_time = function(playername)
- local id = ids[playername]
- if id
- then
- return effect_timers[id]
- else
- return 0
- end
- end
- --increases timer for player by time
- this.give_to = function(playername, time)
- on_fresh(playername, time)
- local id = ids[playername]
- if id
- then
- effect_timers[id] = effect_timers[id] + time
- else
- on_given(playername, time)
- timer_count = timer_count + 1
- effect_timers[timer_count] = time
- ids[playername] = timer_count
- players[timer_count] = playername
- end
- end
- --returns true if player has effect, false otherwise
- this.player_has = function(name)
- return ids[name] ~= nil
- end
- this.revoke = function(playername)
- local time = this.get_remaining_time(playername)
- if time ~= 0
- then
- this.give_to(playername, -time)
- end
- end
- --decreasing the timers
- --------------------------------------------------------------------
- local function decrease_effect_time(index, dtime)
- local t = effect_timers[index] - dtime
- if t <= 0 --timer elapsed
- then
- if timer_count ~= index
- then
- effect_timers[index] = effect_timers[timer_count]
- local name = players[timer_count]
- players[index] = name
- ids[name] = index
- players[timer_count] = nil
- decrease_effect_time(index, dtime)
- else
- effect_timers[index] = nil
- local name = players[index]
- ids[name] = nil
- players[name] = nil
- end
- on_elapsed(players[index])
- timer_count = timer_count - 1
- else
- effect_timers[index] = t
- end
- end
- this.decrease_effect_times = function(dtime)
- for i = 1, timer_count
- do
- decrease_effect_time(i, dtime)
- end
- end
- status_effect_count = status_effect_count + 1
- timer_reducers[status_effect_count] = this.decrease_effect_times
- --storage stuff
- --------------------------------------------------------------------
- local storage_table = minetest.deserialize(storage:get_string(this.name)) or {}
- local function save_timer(playername, bulk)
- --store thing
- local id = ids[playername]
- if not id
- then
- return
- end
- ids[playername] = nil
- on_save(playername)
- do--store timer in mod storage
- storage_table[playername] = (id and effect_timers[id] or 0)
- if not bulk
- then
- storage:set_string(this.name, minetest.serialize(storage_table))
- end
- end
- --close gap in timer list
- effect_timers[id] = effect_timers[timer_count]
- local name = players[timer_count]
- players[id] = name
- ids[name] = id
- players[timer_count] = nil
- timer_count = timer_count - 1
- end
- local function load_timer(playername)
- local num = storage_table[playername] or 0
- if num ~= 0
- then
- on_load(playername)
- storage_table[playername] = nil
- this.give_to(playername, num)
- end
- end
- --actually storing
- minetest.register_on_joinplayer(function(player)
- local name = player:get_player_name()
- load_timer(name)
- end)
- minetest.register_on_leaveplayer(function(player)
- local name = player:get_player_name()
- save_timer(name, false)
- end)
- minetest.register_on_leaveplayer(function(player)
- local name = player:get_player_name()
- save_timer(name, false)
- end)
- minetest.register_on_shutdown(function()
- local players = minetest.get_connected_players()
- for _, p in pairs(players)
- do
- local name = p:get_player_name()
- save_timer(name, true)
- end
- storage:set_string(this.name, minetest.serialize(storage_table))
- end)
- return this
- end
- minetest.register_globalstep(
- function(dtime)
- for i = 1, status_effect_count
- do
- timer_reducers[i](dtime)
- end
- end)
|