283 lines
8.8 KiB
Lua
283 lines
8.8 KiB
Lua
--[[
|
|
Ore spawners let player craft ore spawneres and get back lumps from ingots.
|
|
Copyright (C) 2016 - 2023 SaKeL <juraj.vajda@gmail.com>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it pos the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to juraj.vajda@gmail.com
|
|
--]]
|
|
|
|
-- main tables
|
|
spawners_ores = {}
|
|
local percent = 10
|
|
|
|
-- how often node timers for minerals will tick, +/- some random value
|
|
function spawners_ores.tick(pos)
|
|
minetest.get_node_timer(pos):start(math.random(30, 60))
|
|
end
|
|
|
|
-- how often a growth failure tick is retried (e.g. not enough place to spawn minerals)
|
|
function spawners_ores.tick_short(pos)
|
|
minetest.get_node_timer(pos):start(math.random(15, 20))
|
|
end
|
|
|
|
-- adds smoke particles
|
|
function spawners_ores.add_effects(pos, radius)
|
|
minetest.add_particlespawner({
|
|
amount = 32,
|
|
time = 2,
|
|
minpos = vector.subtract({ x = pos.x, y = pos.y + 1, z = pos.z }, radius / 2),
|
|
maxpos = vector.add({ x = pos.x, y = pos.y + 1, z = pos.z }, radius / 2),
|
|
minvel = { x = -0.5, y = 3, z = -0.5 },
|
|
maxvel = { x = 0.5, y = 10, z = 0.5 },
|
|
minacc = vector.new(),
|
|
maxacc = vector.new(),
|
|
minexptime = 0.5,
|
|
maxexptime = 2,
|
|
minsize = 0.5,
|
|
maxsize = 8,
|
|
texture = 'spawners_ores_smoke_particle.png^[transform' .. math.random(0, 3)
|
|
})
|
|
end
|
|
|
|
-- start spawning ores
|
|
function spawners_ores.start_spawning_ores(pos, ore_name, how_many)
|
|
if not pos or not ore_name then return end
|
|
local _how_many = how_many or 1
|
|
|
|
for i = 1, _how_many do
|
|
|
|
if i > 1 then
|
|
pos = spawners_ores.get_available_node(pos, 'default:stone')
|
|
|
|
if not pos then return end
|
|
|
|
minetest.sound_play('spawners_ores_strike', {
|
|
pos = pos,
|
|
max_hear_distance = 16,
|
|
gain = 10,
|
|
})
|
|
|
|
minetest.set_node(pos, { name = ore_name })
|
|
spawners_ores.add_effects(pos, 1)
|
|
else
|
|
minetest.sound_play('spawners_ores_strike', {
|
|
pos = pos,
|
|
max_hear_distance = 16,
|
|
gain = 10,
|
|
})
|
|
|
|
minetest.set_node(pos, { name = ore_name })
|
|
spawners_ores.add_effects(pos, 1)
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function spawners_ores.get_available_node(pos, check_node, radius)
|
|
if not pos then return end
|
|
|
|
local _check_node = check_node or 'default:stone'
|
|
local _radius = radius or 2
|
|
|
|
local node_ore_pos = minetest.find_node_near(pos, _radius, { _check_node })
|
|
|
|
if node_ore_pos and node_ore_pos ~= nil then
|
|
return node_ore_pos
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
-- build form for spawners
|
|
function spawners_ores.get_formspec(pos, table)
|
|
-- Inizialize metadata and variables
|
|
local _table = table or {}
|
|
local meta = minetest.get_meta(pos)
|
|
local mineral = _table.ore or meta:get_string('mineral')
|
|
local ingot = _table.ore or meta:get_string('mineral')
|
|
local status = meta:get_string('status')
|
|
local inv = meta:get_inventory()
|
|
local stack = inv:get_stack('fuel', 1)
|
|
|
|
-- fix different Ingot namings
|
|
if ingot == 'iron' then
|
|
ingot = 'steel'
|
|
end
|
|
|
|
-- add extra ores based on percentage
|
|
local stack_per_obj = spawners_ores.stack_per({
|
|
stack_count = stack:get_count(),
|
|
percent = percent
|
|
})
|
|
local stack_per = stack_per_obj.stack_per or 0
|
|
local extra_per = stack_per_obj.extra_per or 0
|
|
|
|
local colorize = {
|
|
gold = '^[colorize:#ffe4008C',
|
|
tin = '^[colorize:#d0d0d08C',
|
|
iron = '^[colorize:#b66d498C',
|
|
copper = '^[colorize:#b587528C',
|
|
}
|
|
|
|
local colorize_arrow = ''
|
|
local button = ''
|
|
|
|
if status == 'active' then
|
|
colorize_arrow = colorize[mineral]
|
|
elseif status == 'waiting' then
|
|
button = 'button[1.8,2.5;2,1.5;restart;RE-START]'
|
|
end
|
|
|
|
-- dynamic formspec
|
|
local formspec = 'size[8,8.5]' ..
|
|
default.gui_bg ..
|
|
default.gui_bg_img ..
|
|
default.gui_slots ..
|
|
'label[1.8,0.3;Input ' .. ingot .. ' Ingot]' ..
|
|
'list[current_name;fuel;1.8,1;1,1;]' ..
|
|
'image[1.8,1;1,1;spawners_ores_ingot_slot.png]' ..
|
|
'list[current_player;main;0,4.25;8,1;]' ..
|
|
'list[current_player;main;0,5.5;8,3;8]' ..
|
|
'image[2.9,1;1,1;gui_furnace_arrow_bg.png^[transformR270' .. colorize_arrow .. ']' ..
|
|
'label[1.8,2;' .. stack_per .. ' minerals (' .. extra_per .. ' extra)]' ..
|
|
'image[4,1;1,1;spawners_ores_stone_with_' .. mineral .. '.png]' ..
|
|
button ..
|
|
'listring[current_name;fuel]' ..
|
|
'listring[current_player;main]' ..
|
|
default.get_hotbar_bg(0, 4.25)
|
|
|
|
meta:set_string('formspec', formspec)
|
|
|
|
-- infotext
|
|
local infotext = mineral .. ' fuel: ' .. inv:get_stack('fuel', 1):get_count()
|
|
|
|
if inv:is_empty('fuel') then
|
|
infotext = mineral .. ' ore spawner is empty.'
|
|
elseif status == 'waiting' then
|
|
infotext = 'Waiting - no default:stone was found near by, ' .. mineral .. ' fuel: ' .. inv:get_stack('fuel', 1):get_count()
|
|
end
|
|
|
|
meta:set_string('infotext', infotext)
|
|
end
|
|
|
|
-- check if is fuel empty in the node
|
|
function spawners_ores.can_dig(pos, player)
|
|
local meta = minetest.get_meta(pos);
|
|
local inv = meta:get_inventory()
|
|
return inv:is_empty('fuel')
|
|
end
|
|
|
|
-- add extra percentage on top of the stack
|
|
function spawners_ores.stack_per(table)
|
|
local _table = table or {}
|
|
local stack_count = _table.stack_count or nil
|
|
local extra_per = (stack_count / 100) * percent
|
|
|
|
extra_per = math.floor(extra_per)
|
|
|
|
local stack_per = extra_per + stack_count
|
|
|
|
-- print(percent .. '% from stack(' .. stack_count .. ') = ' .. stack_per .. ' (' .. extra_per .. ' extra ore(s))')
|
|
|
|
return {
|
|
stack_per = stack_per,
|
|
extra_per = extra_per
|
|
}
|
|
end
|
|
|
|
-- set status and update formspec/infotext
|
|
function spawners_ores.on_timer(pos, elapsed)
|
|
|
|
local available_node = spawners_ores.get_available_node(pos, 'default:stone')
|
|
|
|
local meta = minetest.get_meta(pos)
|
|
local inv = meta:get_inventory()
|
|
local stack = inv:get_stack('fuel', 1)
|
|
local how_many = 1
|
|
|
|
local ore_name = meta:get_string('ore_name')
|
|
local status = meta:get_string('status')
|
|
local tick = meta:get_int('tick')
|
|
|
|
--
|
|
-- active
|
|
--
|
|
if available_node and inv:is_empty('fuel') ~= true then
|
|
-- make sure the right node status is shown
|
|
if status ~= 'active' then
|
|
meta:set_string('status', 'active')
|
|
|
|
spawners_ores.get_formspec(pos)
|
|
minetest.swap_node(pos, { name = 'spawners_ores:' .. ore_name .. '_spawner_active' })
|
|
end
|
|
|
|
-- start spawning only on proper 'tick'
|
|
if tick ~= 0 then
|
|
if stack:get_count() % percent == 0 then
|
|
-- TODO: should get countent based on 'percent'
|
|
how_many = 2
|
|
end
|
|
|
|
-- enough place to spawn more ores
|
|
spawners_ores.start_spawning_ores(available_node, 'default:' .. ore_name, how_many)
|
|
|
|
-- take fuel
|
|
stack:take_item()
|
|
inv:set_stack('fuel', 1, stack)
|
|
|
|
spawners_ores.get_formspec(pos)
|
|
end
|
|
|
|
-- dont wait for proper 'tick' and change state after 1 sec.
|
|
local next_available_node = spawners_ores.get_available_node(pos, 'default:stone')
|
|
|
|
if inv:is_empty('fuel') or next_available_node == false then
|
|
minetest.get_node_timer(pos):start(1.0)
|
|
return
|
|
end
|
|
|
|
if tick == 0 then
|
|
-- start new proper timer
|
|
meta:set_int('tick', 1)
|
|
end
|
|
|
|
-- start new proper timer
|
|
spawners_ores.tick(pos)
|
|
--
|
|
-- default
|
|
--
|
|
elseif inv:is_empty('fuel') then
|
|
-- empty / no fuel -- stop timer
|
|
-- make sure that default status/node is shown
|
|
meta:set_string('status', '')
|
|
minetest.swap_node(pos, { name = 'spawners_ores:' .. ore_name .. '_spawner' })
|
|
|
|
spawners_ores.get_formspec(pos)
|
|
return
|
|
|
|
--
|
|
-- waiting
|
|
--
|
|
else
|
|
-- stop timer and show 'refresh' button in order to start timer again
|
|
-- make sure that waiting status/node is shown
|
|
if status ~= 'waiting' then
|
|
meta:set_string('status', 'waiting')
|
|
minetest.swap_node(pos, { name = 'spawners_ores:' .. ore_name .. '_spawner_waiting' })
|
|
end
|
|
|
|
spawners_ores.get_formspec(pos)
|
|
return
|
|
end
|
|
end
|