Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port locate-ore for DFHack/dfhack#2081 #489

Merged
merged 3 commits into from
Dec 20, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
204 changes: 204 additions & 0 deletions locate-ore.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
-- scan the map for ore veins
local tile_attrs = df.tiletype.attrs

local function extractKeys(target_table)
local keyset = {}

for k, _ in pairs(target_table) do
table.insert(keyset, k)
end

return keyset
end

local function getRandomTableKey(target_table)
if not target_table then
return nil
end

local keyset = extractKeys(target_table)
if #keyset == 0 then
return nil
end

return keyset[math.random(#keyset)]
end

local function getRandomFromTable(target_table)
if not target_table then
return nil
end

local key = getRandomTableKey(target_table)
if not key then
return nil
end

return target_table[key]
end

local function randomSort(target_table)
local rnd = {}
table.sort( target_table,
function ( a, b)
rnd[a] = rnd[a] or math.random()
rnd[b] = rnd[b] or math.random()
return rnd[a] > rnd[b]
end )
end

local function sequence(min, max)
local tbl = {}
for i=min,max do
table.insert(tbl, i)
end
return tbl
end

local function sortTableBy(tbl, sort_func)
local sorted = {}
for _, value in pairs(tbl) do
table.insert(sorted, value)
end

table.sort(sorted, sort_func)

return sorted
end

local function matchesMetalOreById(mat_indices, target_ore)
for _, mat_index in ipairs(mat_indices) do
local metal_raw = df.global.world.raws.inorganics[mat_index]
if metal_raw ~= nil and string.lower(metal_raw.id) == target_ore then
return true
end
end

return false
end

local function findOreVeins(target_ore)
if target_ore then
target_ore = string.lower(target_ore)
end

local ore_veins = {}
for _, block in pairs(df.global.world.map.map_blocks) do
for _, bevent in pairs(block.block_events) do
if bevent:getType() ~= df.block_square_event_type.mineral then
goto skipevent
end

local ino_raw = df.global.world.raws.inorganics[bevent.inorganic_mat]
if not ino_raw.flags.METAL_ORE then
goto skipevent
end

local lower_raw = string.lower(ino_raw.id)
if not target_ore or lower_raw == target_ore or matchesMetalOreById(ino_raw.metal_ore.mat_index, target_ore) then
if not ore_veins[bevent.inorganic_mat] then
local vein_info = {
inorganic_id = ino_raw.id,
inorganic_mat = bevent.inorganic_mat,
metal_ore = ino_raw.metal_ore,
positions = {}
}
ore_veins[bevent.inorganic_mat] = vein_info
end

table.insert(ore_veins[bevent.inorganic_mat].positions, block.map_pos)
end

:: skipevent ::
end
end

return ore_veins
end

local function designateDig(pos)
local block = dfhack.maps.getTileBlock(pos)
local designation = block.designation[pos.x%16][pos.y%16]
AridTag marked this conversation as resolved.
Show resolved Hide resolved
designation.dig = df.tile_dig_designation.Default
end

local function getOreDescription(ore)
local str = ("%s ("):format(string.lower(tostring(ore.inorganic_id)))
for _, mat_index in ipairs(ore.metal_ore.mat_index) do
local metal_raw = df.global.world.raws.inorganics[mat_index]
str = ("%s%s, "):format(str, string.lower(metal_raw.id))
end

str = str:gsub(", %s*$", "") .. ')'
return str
end

local args = {...}
local target = args[1]

if not target or target == "help" then
print(dfhack.script_help())
return
end

if target == "list" then
local veins = findOreVeins(nil)
local sorted = sortTableBy(veins, function(a, b) return #a.positions < #b.positions end)
for _, vein in ipairs(sorted) do
print(" " .. getOreDescription(vein))
end
else
local veins = findOreVeins(target)
local vein_keys = extractKeys(veins)
if #vein_keys == 0 then
qerror("Cannot find unmined " .. target)
end

local target_vein = getRandomFromTable(veins)
if target_vein == nil then
-- really shouldn't happen at this point
qerror("Failed to choose vein from available choices")
end

local pos_keyset = extractKeys(target_vein.positions)
local dxs = sequence(0, 15)
local dys = sequence(0, 15)

randomSort(pos_keyset)
randomSort(dxs)
randomSort(dys)

local target_pos = nil
for _, k in pairs(pos_keyset) do
local block_pos = target_vein.positions[k]
for _, dx in pairs(dxs) do
for _, dy in pairs(dys) do
local pos = { x = block_pos.x + dx, y = block_pos.y + dy, z = block_pos.z }
-- Enforce world boundaries
if pos.x <= 0 or pos.x >= df.global.world.map.x_count or pos.y <= 0 or pos.y >= df.global.world.map.y_count then
goto skip_pos
end

local tile_type = dfhack.maps.getTileType(pos)
local tile_mat = tile_attrs[tile_type].material
local shape = tile_attrs[tile_type].shape
local block = dfhack.maps.getTileBlock(pos)
local designation = block.designation[pos.x%16][pos.y%16]
AridTag marked this conversation as resolved.
Show resolved Hide resolved
if tile_mat == df.tiletype_material.MINERAL and designation.dig == df.tile_dig_designation.No and shape == df.tiletype_shape.WALL then
target_pos = pos
goto complete
end

:: skip_pos ::
end
end
end
:: complete ::

if target_pos ~= nil then
dfhack.gui.pauseRecenter(target_pos)
designateDig(target_pos)
print(("Here is some %s at (%d, %d, %d)"):format(target_vein.inorganic_id, target_pos.x, target_pos.y, target_pos.z))
end
end

102 changes: 0 additions & 102 deletions locate-ore.rb

This file was deleted.