123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542 |
- -- lantern.lua
- assert(type(lantern) == "table")
- -- NOTE: Lantern overfill up to 124% is a feature, not a bug. ;-)
- -- but be carefull overfilling the lantern, may cause a fire.
- -- ==== SETTINGS ====
- -- fuel material
- lantern.fuel = "basic_materials:oil_extract"
- -- fuel max in bottles
- lantern.fuel_max = 4
- -- fuel time in seconds (per fuel bottle)
- lantern.fuel_time = 15*60
- -- fuel multiplier on dim light (x times longer burn)
- -- low fuel is fuel_time/fuel_dim, on this level lamp only turns dim
- lantern.fuel_dim = 4
- -- fuel multiplier on med light (x times longer burn)
- lantern.fuel_med = 2
- -- mode light duration
- -- ==== ==-==== =====
- -- full 13 100% 1.00
- -- med 9 69% 1.50
- -- dim 6 46% 2.20
- -- off 1 7% 14.30 N/A
- lantern.bright_full = 13
- lantern.bright_med = 9
- lantern.bright_dim = 6
- lantern.bright_off = 1
- -- == GENERIC ==
- lantern.nodelist = {
- "lantern:lantern_floor_on",
- "lantern:lantern_floor_med",
- "lantern:lantern_floor_dim",
- "lantern:lantern_floor_off",
- "lantern:lantern_ceiling_on",
- "lantern:lantern_ceiling_med",
- "lantern:lantern_ceiling_dim",
- "lantern:lantern_ceiling_off",
- "lantern:lantern_wall_on",
- "lantern:lantern_wall_med",
- "lantern:lantern_wall_dim",
- "lantern:lantern_wall_off"
- }
- local function listcontains(list, obj)
- for i, v in ipairs(list) do
- if obj == v then
- return true
- end
- end
- return false
- end
- function lantern.turnoff(pos)
- -- stop dim timer
- -- stop on timer
- -- update burntime
- local sside = lantern.get_side(pos)
- local sname = string.format("lantern:lantern_%s_", sside)
- local node = minetest.get_node(pos)
- local timer = minetest.get_node_timer(pos)
- --if not timer:is_started() then
- -- return false
- --end
- local meta = minetest.get_meta(pos)
- local burntime = meta:get_int("burntime") or 0
- local timeout = timer:get_timeout()
- local elapsed = timer:get_elapsed()
- timer:stop()
- if node.name == sname .. "on" then
- -- TURN OFF
- if elapsed < burntime then
- burntime = burntime - elapsed
- else
- burntime = 0
- end
- elseif node.name == sname .. "med" then
- -- TURN OFF (med)
- burntime = burntime * lantern.fuel_med
- if elapsed < burntime then
- burntime = burntime - elapsed
- burntime = math.floor(burntime / lantern.fuel_med)
- else
- burntime = 0
- end
- elseif node.name == sname .. "dim" then
- -- TURN OFF (dim)
- burntime = burntime * lantern.fuel_dim
- if elapsed < burntime then
- burntime = burntime - elapsed
- burntime = math.floor(burntime / lantern.fuel_dim)
- else
- burntime = 0
- end
- end
- node.name = sname .. "off"
- minetest.swap_node(pos, node)
- meta:set_int("burntime", burntime)
- -- meta:set_string("infotext", string.format("Lantern [%d]", burntime))
- lantern.update_info(pos)
- --return true
- end
- function lantern.turndim(pos)
- -- timer must be stopped
- -- start dim timer
- local timer = minetest.get_node_timer(pos)
- if timer:is_started() then
- return false
- end
-
- local fuel_min = math.floor(lantern.fuel_time / lantern.fuel_dim)
- local meta = minetest.get_meta(pos)
- local burntime = meta:get_int("burntime") or 0
- if burntime <= 0 then
- -- no fuel
- return false
- end
- -- burntime multiplier on low consumption (dim)
- burntime = burntime * lantern.fuel_dim
- timer:start(burntime)
-
- local node = minetest.get_node(pos)
- local sside = lantern.get_side(pos)
- local sname = string.format("lantern:lantern_%s_dim", sside)
- node.name = sname
- minetest.swap_node(pos, node)
- return true
- end
- function lantern.turnmed(pos)
- -- timer must be stopped
- -- start med timer
- local timer = minetest.get_node_timer(pos)
- if timer:is_started() then
- return false
- end
-
- local fuel_min = math.floor(lantern.fuel_time / lantern.fuel_dim)
- local meta = minetest.get_meta(pos)
- local burntime = meta:get_int("burntime") or 0
- if burntime <= 0 then
- -- no fuel
- return false
- end
- -- burntime multiplier on med consumption (med)
- burntime = burntime * lantern.fuel_med
- timer:start(burntime)
-
- local node = minetest.get_node(pos)
- local sside = lantern.get_side(pos)
- local sname = string.format("lantern:lantern_%s_med", sside)
- node.name = sname
- minetest.swap_node(pos, node)
- return true
- end
- function lantern.turnon(pos)
- -- timer must be stopped
- -- start on timer
- local timer = minetest.get_node_timer(pos)
- if timer:is_started() then
- return false
- end
- local fuel_min = math.floor(lantern.fuel_time / lantern.fuel_dim)
- local meta = minetest.get_meta(pos)
- local burntime = meta:get_int("burntime") or 0
-
- if burntime < fuel_min then
- -- low fuel, turn dim instead
- return false
- end
- -- at low fuel only turn dim
- timer:start(burntime - fuel_min)
-
- local sside = lantern.get_side(pos)
- local sname = string.format("lantern:lantern_%s_on", sside)
- local node = minetest.get_node(pos)
- node.name = sname
- minetest.swap_node(pos, node)
- return true
- end
- function lantern.get_side(pos)
- local node = minetest.get_node(pos)
- if not node then
- return nil
- end
- local sside
- if node.param2 == 0 then
- -- ceiling
- sside = "ceiling"
- elseif node.param2 == 1 then
- -- floor
- sside = "floor"
- else
- -- wall
- sside = "wall"
- end
- return sside
- end
- -- switch lamp on/dim/off
- function lantern.switch(pos)
- local node = minetest.get_node(pos)
- if not node then
- return false
- end
- local sside = lantern.get_side(pos)
- local sname = string.format("lantern:lantern_%s_", sside)
- local timer = minetest.get_node_timer(pos)
- local meta = minetest.get_meta(pos)
- if node.name == sname .. "off" then
- -- TURN DIM
- -- lantern.chat_debug("boxface", "try turning dim")
- if lantern.turndim(pos) then
- --lantern.chat_debug("boxface", "success")
- else
- --lantern.chat_debug("boxface", "failed")
- end
- elseif node.name == sname .. "dim" then
- lantern.turnoff(pos)
- -- TURN MED
- if not lantern.turnmed(pos) then
- lantern.turnoff(pos)
- end
- elseif node.name == sname .. "med" then
- lantern.turnoff(pos)
- -- TURN ON
- --lantern.chat_debug("boxface", "try turning on full")
- -- if low fuel turn off
- if not lantern.turnon(pos) then
- --lantern.chat_debug("boxface", "failed! wtf?")
- lantern.turnoff(pos)
- end
- elseif node.name == sname .. "on" then
- -- TURN OFF
- -- lantern.chat_debug("boxface", "try turning off")
- lantern.turnoff(pos)
- end
- return true
- end
- function lantern.refuel(pos)
- -- DONE: check refueling when lamp is on, may have a bug
- local meta = minetest.get_meta(pos)
- local node = minetest.get_node(pos)
- if not node then
- return false
- end
- local oldstate = lantern.get_state(pos)
- local timer = minetest.get_node_timer(pos)
- if timer:is_started() then
- -- refueling when lamp is on
- -- Do you want to make a fire?
- -- DONE: stop timer before refueling, then turn it back on.
- lantern.turnoff(pos)
- end
- if listcontains(lantern.nodelist, node.name) then
- local burntime = meta:get_int("burntime") or 0
- if burntime < (lantern.fuel_max * lantern.fuel_time) then
- burntime = burntime + lantern.fuel_time
- meta:set_int("burntime", burntime)
- -- meta:set_string("infotext", "Lantern [" .. burntime .. "]")
- lantern.update_info(pos)
- -- set old state
- --lantern.chat_debug("boxface", "Old state was: [" .. oldstate .. "]")
- if oldstate ~= "off" then
- --lantern.chat_debug("boxface", "set old state")
- lantern.set_state(pos, oldstate)
- end
- return true
- end
- end
- -- if lamp was turned off, if not refueled turn it back on
- if oldstate ~= "off" then
- lantern.set_state(pos, oldstate)
- end
- return false
- end
- function lantern.take_fuel(pos, itemstack)
- -- DONE: turn off timer when taking fuel (bug)
- local meta = minetest.get_meta(pos)
- local oldstate = lantern.get_state(pos)
- if oldstate ~= "off" then
- lantern.turnoff(pos)
- end
- local burntime = meta:get_int("burntime") or 0
- if burntime >= lantern.fuel_time then
- if itemstack:item_fits(lantern.fuel) then
- itemstack:add_item(lantern.fuel)
- burntime = burntime - lantern.fuel_time
- meta:set_int("burntime", burntime)
-
- -- meta:set_string("infotext", "Lantern [" .. burntime .. "]")
- lantern.update_info(pos)
- end
- end
- if oldstate ~= "off" then
- lantern.set_state(pos, oldstate)
- end
- return itemstack
- end
- function lantern.get_state(pos)
- local sside = lantern.get_side(pos)
- local sname = string.format("lantern:lantern_%s_", sside)
- local node = minetest.get_node(pos)
-
- local is_off = (node.name == sname .. "off")
- local is_on = (node.name == sname .. "on")
- local is_med = (node.name == sname .. "med")
- local is_dim = (node.name == sname .. "dim")
- if is_off then
- return "off"
- elseif is_on then
- return "on"
- elseif is_med then
- return "med"
- elseif is_dim then
- return "dim"
- else
- return "error"
- end
- end
- function lantern.set_state(pos, state)
- if state == "off" then
- return lantern.turnoff(pos)
- elseif state == "on" then
- return lantern.turnon(pos)
- elseif state == "med" then
- return lantern.turnmed(pos)
- elseif state == "dim" then
- return lantern.turndim(pos)
- end
- end
- function lantern.update_info(pos)
- -- update info text
- -- DONE: get fuel in percent and display on infotext.
- local meta = minetest.get_meta(pos)
- local burntime = meta:get_int("burntime") or 0
- local sstate = lantern.get_state(pos)
- local is_off = (sstate == "off")
- local is_on = (sstate == "on")
- local is_med = (sstate == "med")
- local is_dim = (sstate == "dim")
- if is_off then
- local burn_max = lantern.fuel_max * lantern.fuel_time
- local perc = math.floor(burntime / burn_max * 100)
- local s = string.format("Lantern: %d%%", perc)
- meta:set_string("infotext", s)
- return
- elseif is_on then
- local timer = minetest.get_node_timer(pos)
- local elapsed = timer:get_elapsed()
- local burn = burntime - elapsed
- local burn_max = lantern.fuel_max * lantern.fuel_time
- local perc = math.floor(burn / burn_max * 100)
- local s = string.format("Lantern: %d%%", perc)
- meta:set_string("infotext", s)
- return
- elseif is_med then
- local timer = minetest.get_node_timer(pos)
- local elapsed = timer:get_elapsed()
- local burn = burntime * lantern.fuel_med - elapsed
- local burn_max = lantern.fuel_max * lantern.fuel_time * lantern.fuel_med
- local perc = math.floor(burn / burn_max * 100)
- local s = string.format("Lantern: %d%%", perc)
- meta:set_string("infotext", s)
- return
- elseif is_dim then
- local timer = minetest.get_node_timer(pos)
- local elapsed = timer:get_elapsed()
- local burn = burntime * lantern.fuel_dim - elapsed
- local burn_max = lantern.fuel_max * lantern.fuel_time * lantern.fuel_dim
- local perc = math.floor(burn / burn_max * 100)
- local s = string.format("Lantern: %d%%", perc)
- meta:set_string("infotext", s)
- return
- end
- end
- -- == CALLBACKS ==
- function lantern.do_after_dig_node(pos, oldnode, oldmetadata, digger)
- -- TODO: Find a way to keep unused fuel when is less than a bottle.
- -- TODO: use lantern.turnoff() instead of calculating fuel again. (review)
- local timer = minetest.get_node_timer(pos)
- if timer:is_started() then
- -- lantern.chat_debug("boxface", "WARNING: timer was on after dig")
- timer:stop()
- end
- --lantern.chat_debug("boxface", "After Dig!")
- --lantern.chat_debug("boxface", dump(oldmetadata))
- local burntime = oldmetadata.fields["burntime"] or 0
- local fuelcount = math.floor(burntime / lantern.fuel_time)
- local inv = digger:get_inventory()
- -- take back or drop unused fuel
- if fuelcount > 0 then
- local str = string.format("%s %d", lantern.fuel, fuelcount)
- local stackfuel = ItemStack(str)
- local leftover = inv:add_item("main", stackfuel)
- if leftover:get_count() > 0 then
- minetest.item_drop(leftover, digger, pos)
- end
- end
- end
- function lantern.do_construct(pos)
- end
- function lantern.do_place(itemstack, placer, pointed_thing)
- local under = pointed_thing.under
- local above = pointed_thing.above
- local node = minetest.get_node(under)
- local wdir = minetest.dir_to_wallmounted(vector.subtract(under, above))
- -- possible bug?
- local fakestack = itemstack
- local stackname = itemstack:get_name()
- if stackname == "lantern:lantern_floor_off" then
- if wdir == 0 then
- -- ceiling
- fakestack:set_name("lantern:lantern_ceiling_off")
- elseif wdir == 1 then
- -- floor
- fakestack:set_name("lantern:lantern_floor_off")
- else
- -- wall
- fakestack:set_name("lantern:lantern_wall_off")
- end
- itemstack = minetest.item_place(fakestack, placer, pointed_thing, wdir)
- local meta = minetest.get_meta(above)
- meta:set_string("infotext", "Lantern (off)")
- itemstack:set_name("lantern:lantern_floor_off")
- end
- return itemstack
- end
- function lantern.do_punch(pos, node, puncher, pointed_thing)
- -- TODO: if shift key pressed switch down light (bright to dim)
- lantern.switch(pos)
- lantern.update_info(pos)
- end
- function lantern.do_timer(pos, elapsed)
- local sside = lantern.get_side(pos)
- local sname = string.format("lantern:lantern_%s_", sside)
- local node = minetest.get_node(pos)
-
- local is_on = (node.name == sname .. "on")
- local is_med = (node.name == sname .. "med")
- if is_on or is_med then
- -- lantern.chat_debug("boxface", "lamp runs low on fuel")
- -- patch set fuel to low level
- local meta = minetest.get_meta(pos)
- local fuel_low = math.floor(lantern.fuel_time / lantern.fuel_dim)
- meta:set_int("burntime", fuel_low)
- lantern.turnoff(pos)
- lantern.turndim(pos)
- elseif node.name == sname .. "dim" then
- -- lantern.chat_debug("boxface", "lamp runs out of fuel")
- -- patch set fuel to zero
- local meta = minetest.get_meta(pos)
- meta:set_int("burntime", 0)
- lantern.turnoff(pos)
- end
- end
- function lantern.do_rightclick(pos, node, clicker, itemstack, pointed_thing)
- local pname = clicker:get_player_name()
- local control = clicker:get_player_control()
- -- ==== extract fuel ====
- if control.aux1 then
- --lantern.chat_debug("boxface", "rightclick aux1")
-
- if itemstack:is_empty() or itemstack:get_name() == lantern.fuel then
- itemstack = lantern.take_fuel(pos, itemstack)
- end
- return
- end
- -- ==== refuel lamps ====
- if itemstack:get_name() == lantern.fuel then
- local isRefueled = lantern.refuel(pos)
- if isRefueled then
- itemstack:take_item(1)
- -- lantern.chat_debug(pname, "Lantern refueled")
- else
- -- lantern.chat_debug(pname, "Lantern is full")
- end
- else
- -- swith lantern on/dim/off
- -- TODO: move to on_punch
- --lantern.switch(pos)
- end
- end
|