techage/basic_machines/quarry.lua

412 lines
12 KiB
Lua

--[[
TechAge
=======
Copyright (C) 2019 Joachim Stolberg
GPL v3
See LICENSE.txt for more information
Gravel Sieve, sieving gravel to find ores
quarry.lua
Quarry machine to dig stones and other ground blocks.
The Quarry digs a hole 5x5 blocks large and up to 80 blocks deep.
It starts at the given level (0 is same level as the quarry block,
1 is one level higher and so on)) and goes down to the given depth number.
It digs one block every 4 seconds.
]]--
-- for lazy programmers
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
local S2P = minetest.string_to_pos
local M = minetest.get_meta
-- Consumer Related Data
local CRD = function(pos) return (minetest.registered_nodes[techage.get_node_lvm(pos).name] or {}).consumer end
local S = techage.S
local CYCLE_TIME = 4
local STANDBY_TICKS = 4
local COUNTDOWN_TICKS = 4
local Side2Facedir = {F=0, R=1, B=2, L=3, D=4, U=5}
local Depth2Idx = {[1]=1 ,[2]=2, [3]=3, [5]=4, [10]=5, [15]=6, [20]=7, [25]=8, [40]=9, [60]=10, [80]=11}
local Level2Idx = {[2]=1, [1]=2, [0]=3, [-1]=4, [-2]=5, [-3]=6,
[-5]=7, [-10]=8, [-15]=9, [-20]=10}
local function formspec(self, pos, nvm)
local tooltip = S("Start level = 0\nmeans the same Y-level\nas the quarry is placed")
local level = "-"
local index = "-"
if nvm.quarry_pos then
level = nvm.quarry_pos.y - pos.y
index = nvm.idx
end
local depth_list = "1,2,3,5,10,15,20,25,40,60,80"
if CRD(pos).stage == 3 then
depth_list = "1,2,3,5,10,15,20,25,40"
elseif CRD(pos).stage == 2 then
depth_list = "1,2,3,5,10,15,20"
end
nvm.quarry_depth = nvm.quarry_depth or 1
nvm.start_level = nvm.start_level or -1
return "size[8,8]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"box[0,-0.1;7.8,0.5;#c6e8ff]"..
"label[3.5,-0.1;"..minetest.colorize( "#000000", S("Quarry")).."]"..
techage.question_mark_help(8, tooltip)..
"dropdown[0,0.8;1.5;level;2,1,0,-1,-2,-3,-5,-10,-15,-20;"..Level2Idx[nvm.start_level].."]"..
"label[1.6,0.9;"..S("Start level").."]"..
"dropdown[0,1.8;1.5;depth;"..depth_list..";"..Depth2Idx[nvm.quarry_depth].."]"..
"label[1.6,1.9;"..S("Digging depth").."]"..
"label[0,2.9;"..S("level=")..level..", "..S("pos=")..index.."/25]"..
"list[context;main;5,0.8;3,3;]"..
"image[4,0.8;1,1;"..techage.get_power_image(pos, nvm).."]"..
"image_button[4,2.8;1,1;".. self:get_state_button_image(nvm) ..";state_button;]"..
"tooltip[4,2.8;1,1;"..self:get_state_tooltip(nvm).."]"..
"list[current_player;main;0,4.3;8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"
end
local function play_sound(pos)
local mem = techage.get_mem(pos)
if not mem.handle or mem.handle == -1 then
mem.handle = minetest.sound_play("techage_quarry", {
pos = pos,
gain = 1.5,
max_hear_distance = 15,
loop = true})
if mem.handle == -1 then
minetest.after(1, play_sound, pos)
end
end
end
local function stop_sound(pos)
local mem = techage.get_mem(pos)
if mem.handle then
minetest.sound_stop(mem.handle)
mem.handle = nil
end
end
local function on_node_state_change(pos, old_state, new_state)
if new_state == techage.RUNNING then
play_sound(pos)
elseif new_state == techage.STOP then
local nvm = techage.get_nvm(pos)
nvm.quarry_pos = nil
stop_sound(pos)
else
local nvm = techage.get_nvm(pos)
stop_sound(pos)
end
end
local function get_pos(pos, facedir, side, steps)
facedir = (facedir + Side2Facedir[side]) % 4
local dir = vector.multiply(minetest.facedir_to_dir(facedir), steps or 1)
return vector.add(pos, dir)
end
local function allow_metadata_inventory_put(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local function allow_metadata_inventory_take(pos, listname, index, stack, player)
if minetest.is_protected(pos, player:get_player_name()) then
return 0
end
return stack:get_count()
end
local QuarrySchedule = {3,0,0,3,3,3,3,2,2,2,2,1,1,1,1,0,3,0,0,3,3,2,2,1,0}
local function get_next_pos(pos, facedir, dir)
facedir = (facedir + dir) % 4
return vector.add(pos, core.facedir_to_dir(facedir))
end
local function get_corner_positions(pos, facedir, y_pos)
local start_pos = get_pos(pos, facedir, "L")
local pos1 = get_pos(start_pos, facedir, "F", 2)
local pos2 = get_pos(start_pos, facedir, "B", 2)
pos2 = get_pos(pos2, facedir, "L", 4)
pos1.y = y_pos
pos2.y = y_pos
return pos1, pos2
end
local function check_protection(pos, nvm, facedir, owner)
local pos1, pos2 = get_corner_positions(pos, facedir, nvm.start_y)
while true do
if minetest.is_protected(pos1, owner) then
return false
end
if minetest.is_protected(pos2, owner) then
return false
end
if pos1.y < nvm.stop_y then
break
end
pos1.y = pos1.y - 5
pos2.y = pos2.y - 5
end
return true
end
local function skip_air_levels(pos, nvm, facedir, owner)
local pos1, pos2
pos1, pos2 = get_corner_positions(pos, facedir, nvm.start_y)
while pos1.y >= nvm.stop_y do
local lPos = minetest.find_nodes_in_area(pos1, pos2, {"air"})
if #lPos ~= 25 then break end
pos1.y = pos1.y - 1
pos2.y = pos2.y - 1
end
-- quarry block position with start y-level
nvm.quarry_pos = {x = pos.x, y = pos2.y, z = pos.z}
pos1.y = pos1.y + 0.2
techage.mark_cube(owner, pos1, pos2, "quarry", "#FF0000", 20)
end
local function can_start(pos, nvm, state)
local facedir = minetest.get_node(pos).param2
local owner = M(pos):get_string("owner")
nvm.start_level = nvm.start_level or 0
nvm.quarry_depth = nvm.quarry_depth or 1
nvm.start_y = pos.y + nvm.start_level
nvm.stop_y = nvm.start_y - nvm.quarry_depth + 1
nvm.idx = nvm.idx or 1
if state == techage.STOPPED then
nvm.idx = 1
end
if not check_protection(pos, nvm, facedir, owner) then
return S("Quarry area is protected")
end
skip_air_levels(pos, nvm, facedir, owner)
return true
end
local function on_rightclick(pos, node, clicker)
local nvm = techage.get_nvm(pos)
techage.set_activeformspec(pos, clicker)
M(pos):set_string("formspec", formspec(CRD(pos).State, pos, nvm))
end
local function quarry_next_node(pos, crd, nvm, inv)
if nvm.quarry_pos then
local facedir = minetest.get_node(pos).param2
if nvm.idx <= #QuarrySchedule then
nvm.quarry_pos = get_next_pos(nvm.quarry_pos, facedir, QuarrySchedule[nvm.idx])
nvm.idx = nvm.idx + 1
elseif nvm.quarry_pos.y > nvm.stop_y then
local owner = M(pos):get_string("owner")
local pos1, pos2
pos1, pos2 = get_corner_positions(pos, facedir, nvm.quarry_pos.y - 1)
-- quarry block position with new y-level
nvm.quarry_pos = {x = pos.x, y = pos2.y, z = pos.z}
nvm.idx = 1
pos1.y = pos1.y + 0.2
techage.mark_cube(owner, pos1, pos2, "quarry", "#FF0000", 20)
else
nvm.idx = 1
nvm.quarry_pos = nil
crd.State:stop(pos, nvm)
return
end
local node = techage.get_node_lvm(nvm.quarry_pos)
local ndef = minetest.registered_nodes[node.name]
if techage.can_node_dig(node, ndef) then
local drop_name = techage.dropped_node(node, ndef)
if drop_name then
local inv = M(pos):get_inventory()
if inv:room_for_item("main", {name = drop_name}) then
minetest.remove_node(nvm.quarry_pos)
inv:add_item("main", {name = drop_name})
crd.State:keep_running(pos, nvm, COUNTDOWN_TICKS, 1)
else
crd.State:blocked(pos, nvm)
end
end
end
end
end
local function keep_running(pos, elapsed)
local nvm = techage.get_nvm(pos)
local crd = CRD(pos)
local inv = M(pos):get_inventory()
if inv then
quarry_next_node(pos, crd, nvm, inv)
end
if techage.is_activeformspec(pos) then
M(pos):set_string("formspec", formspec(crd.State, pos, nvm))
end
end
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local inv = M(pos):get_inventory()
return inv:is_empty("main")
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
end
local nvm = techage.get_nvm(pos)
if fields.depth then
if tonumber(fields.depth) ~= nvm.quarry_depth then
nvm.quarry_depth = tonumber(fields.depth)
nvm.quarry_pos = nil
CRD(pos).State:stop(pos, nvm)
end
end
if fields.level then
if tonumber(fields.level) ~= nvm.start_level then
nvm.start_level = tonumber(fields.level)
nvm.quarry_pos = nil
CRD(pos).State:stop(pos, nvm)
end
end
CRD(pos).State:state_button_event(pos, nvm, fields)
end
local tiles = {}
-- '#' will be replaced by the stage number
tiles.pas = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_quarry_left.png",
"techage_filling_ta#.png^techage_appl_quarry.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_quarry.png^techage_frame_ta#.png",
}
tiles.act = {
-- up, down, right, left, back, front
"techage_filling_ta#.png^techage_frame_ta#_top.png",
"techage_filling_ta#.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png",
{
image = "techage_frame14_ta#.png^techage_quarry_left14.png",
backface_culling = false,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 2.0,
},
},
"techage_filling_ta#.png^techage_appl_quarry.png^techage_frame_ta#.png",
"techage_filling_ta#.png^techage_appl_quarry.png^techage_frame_ta#.png",
}
local tubing = {
on_pull_item = function(pos, in_dir, num)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.get_items(inv, "main", num)
end
end,
on_push_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("push_dir") == in_dir or in_dir == 5 then
local inv = M(pos):get_inventory()
CRD(pos).State:start_if_standby(pos)
return techage.put_items(inv, "main", stack)
end
end,
on_unpull_item = function(pos, in_dir, stack)
local meta = minetest.get_meta(pos)
if meta:get_int("pull_dir") == in_dir then
local inv = M(pos):get_inventory()
return techage.put_items(inv, "main", stack)
end
end,
on_recv_message = function(pos, src, topic, payload)
local resp = CRD(pos).State:on_receive_message(pos, topic, payload)
if resp then
return resp
else
return "unsupported"
end
end,
on_node_load = function(pos, node)
CRD(pos).State:on_node_load(pos)
local nvm = techage.get_nvm(pos)
if nvm.techage_state == techage.RUNNING then
play_sound(pos)
end
end,
}
local node_name_ta2, node_name_ta3, node_name_ta4 =
techage.register_consumer("quarry", S("Quarry"), tiles, {
drawtype = "normal",
cycle_time = CYCLE_TIME,
standby_ticks = STANDBY_TICKS,
formspec = formspec,
tubing = tubing,
can_start = can_start,
on_state_change = on_node_state_change,
after_place_node = function(pos, placer)
local inv = M(pos):get_inventory()
local nvm = techage.get_nvm(pos)
inv:set_size('main', 9)
nvm.quarry_pos = nil
M(pos):set_string("owner", placer:get_player_name())
end,
can_dig = can_dig,
node_timer = keep_running,
on_receive_fields = on_receive_fields,
on_rightclick = on_rightclick,
allow_metadata_inventory_put = allow_metadata_inventory_put,
allow_metadata_inventory_take = allow_metadata_inventory_take,
groups = {choppy=2, cracky=2, crumbly=2},
sounds = default.node_sound_wood_defaults(),
num_items = {0,1,1,1},
power_consumption = {0,10,12,12},
}
)
minetest.register_craft({
output = node_name_ta2,
recipe = {
{"default:steel_ingot", "default:diamond", "default:steel_ingot"},
{"techage:tubeS", "basic_materials:gear_steel", "techage:tubeS"},
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
},
})
minetest.register_craft({
output = node_name_ta3,
recipe = {
{"", "default:diamond", ""},
{"", "node_name_ta2", ""},
{"", "techage:vacuum_tube", ""},
},
})