mods that hopefully work for a TechAge-based pack
This commit is contained in:
@@ -0,0 +1,288 @@
|
||||
--[[
|
||||
|
||||
Hyperloop Mod
|
||||
=============
|
||||
|
||||
Copyright (C) 2017-2019 Joachim Stolberg
|
||||
|
||||
LGPLv2.1+
|
||||
See LICENSE.txt for more information
|
||||
|
||||
Station and elevator network management
|
||||
]]--
|
||||
|
||||
-- for lazy programmers
|
||||
local S = function(pos) if pos then return minetest.pos_to_string(pos) end end
|
||||
local P = minetest.string_to_pos
|
||||
--local M = minetest.get_meta
|
||||
|
||||
-- Convert to list and add pos based on key string
|
||||
local function table_to_list(table)
|
||||
local lRes = {}
|
||||
for key,item in pairs(table) do
|
||||
item.pos = P(key)
|
||||
lRes[#lRes+1] = item
|
||||
end
|
||||
return lRes
|
||||
end
|
||||
|
||||
local function distance(pos1, pos2)
|
||||
return math.floor(math.abs(pos1.x - pos2.x) +
|
||||
math.abs(pos1.y - pos2.y) + math.abs(pos1.z - pos2.z))
|
||||
end
|
||||
|
||||
-- Add the distance to pos to each list item
|
||||
local function add_distance_to_list(lStations, pos)
|
||||
for _,item in ipairs(lStations) do
|
||||
item.distance = distance(item.pos, pos)
|
||||
end
|
||||
return lStations
|
||||
end
|
||||
|
||||
-- Add the index to each list item
|
||||
local function add_index_to_list(lStations)
|
||||
-- walk through the list of floors for the next connection
|
||||
local get_next = function(key, idx)
|
||||
for _,floor in ipairs(lStations) do
|
||||
if floor.conn[6] == key then -- upward match?
|
||||
floor.idx = idx
|
||||
return S(floor.pos) -- return floor key
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local key = nil
|
||||
for idx = 1,#lStations do
|
||||
key = get_next(key, idx)
|
||||
end
|
||||
return lStations
|
||||
end
|
||||
|
||||
-- Return a table with all stations, the given station (as 'sKey') is connected with
|
||||
-- tRes is used for the resulting table (recursive call)
|
||||
local function get_stations(tStations, sKey, tRes)
|
||||
if not tStations[sKey] or not tStations[sKey].conn then
|
||||
return {}
|
||||
end
|
||||
for dir,dest in pairs(tStations[sKey].conn) do
|
||||
-- Not already visited?
|
||||
if not tRes[dest] then
|
||||
-- Known station?
|
||||
if tStations[dest] then
|
||||
tStations[dest].name = tStations[dest].name or ""
|
||||
tRes[dest] = tStations[dest]
|
||||
get_stations(tStations, dest, tRes)
|
||||
end
|
||||
end
|
||||
end
|
||||
return tRes
|
||||
end
|
||||
|
||||
-- Return a list with sorted elevators, beginning with the top car
|
||||
-- with no shaft upwards
|
||||
local function sort_based_on_level(tStations)
|
||||
local lStations = table_to_list(table.copy(tStations))
|
||||
-- to be able to sort the list, an index has to be added
|
||||
lStations = add_index_to_list(lStations)
|
||||
table.sort(lStations, function(a,b) return (a.idx or 9999) < (b.idx or 9999) end)
|
||||
return lStations
|
||||
end
|
||||
|
||||
-- Return a list with sorted stations
|
||||
local function sort_based_on_distance(tStations, pos)
|
||||
local lStations = table_to_list(table.copy(tStations))
|
||||
-- to be able to sort the list, the distance to pos has to be added
|
||||
lStations = add_distance_to_list(lStations, pos)
|
||||
table.sort(lStations, function(a,b) return a.distance < b.distance end)
|
||||
return lStations
|
||||
end
|
||||
|
||||
-- Return a list with sorted stations
|
||||
local function sort_based_on_name(tStations, pos)
|
||||
local lStations = table_to_list(table.copy(tStations))
|
||||
-- Add distance
|
||||
lStations = add_distance_to_list(lStations, pos)
|
||||
table.sort(lStations, function(a,b) return a.name < b.name end)
|
||||
return lStations
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Class Network
|
||||
--
|
||||
|
||||
--[[
|
||||
tStations["(x,y,z)"] = {
|
||||
["conn"] = {
|
||||
dir = "(200,0,20)",
|
||||
},
|
||||
}
|
||||
change_counter = n,
|
||||
]]--
|
||||
|
||||
|
||||
local Network = {}
|
||||
hyperloop.Network = Network
|
||||
|
||||
function Network:new()
|
||||
local o = {
|
||||
tStations = {},
|
||||
change_counter = 0,
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
-- Set an elevator or station entry.
|
||||
-- tAttr is a table with additional attributes to be stored.
|
||||
function Network:set(pos, name, tAttr)
|
||||
if pos then
|
||||
local sKey = S(pos)
|
||||
if not self.tStations[sKey] then
|
||||
self.tStations[sKey] = {
|
||||
conn = {},
|
||||
}
|
||||
end
|
||||
self.tStations[sKey].name = name or ""
|
||||
for k,v in pairs(tAttr) do
|
||||
self.tStations[sKey][k] = v
|
||||
end
|
||||
self.change_counter = self.change_counter + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Update an elevator or station entry.
|
||||
-- tAttr is a table with additional attributes to be stored.
|
||||
function Network:update(pos, tAttr)
|
||||
if pos then
|
||||
local sKey = S(pos)
|
||||
if self.tStations[sKey] then
|
||||
for k,v in pairs(tAttr) do
|
||||
if v == "nil" then
|
||||
self.tStations[sKey][k] = nil
|
||||
else
|
||||
self.tStations[sKey][k] = v
|
||||
end
|
||||
end
|
||||
self.change_counter = self.change_counter + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Network:get(pos)
|
||||
return pos and self.tStations[S(pos)]
|
||||
end
|
||||
|
||||
-- Delete an elevator or station entry.
|
||||
function Network:delete(pos)
|
||||
if pos then
|
||||
self.tStations[S(pos)] = nil
|
||||
self.change_counter = self.change_counter + 1
|
||||
end
|
||||
end
|
||||
|
||||
function Network:changed(counter)
|
||||
return self.change_counter > counter, self.change_counter
|
||||
end
|
||||
|
||||
-- Update the connection data base. The output dir information is needed
|
||||
-- to be able to delete a connection, if necessary.
|
||||
-- Returns true, if data base is changed.
|
||||
function Network:update_connections(pos, out_dir, conn_pos)
|
||||
local sKey = S(pos)
|
||||
local res = false
|
||||
if not self.tStations[sKey] then
|
||||
self.tStations[sKey] = {}
|
||||
res = true
|
||||
end
|
||||
if not self.tStations[sKey].conn then
|
||||
self.tStations[sKey].conn = {}
|
||||
res = true
|
||||
end
|
||||
conn_pos = S(conn_pos)
|
||||
if self.tStations[sKey].conn[out_dir] ~= conn_pos then
|
||||
self.tStations[sKey].conn[out_dir] = conn_pos
|
||||
res = true
|
||||
end
|
||||
if res then
|
||||
self.change_counter = self.change_counter + 1
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
-- Return the nearest station position
|
||||
function Network:get_next_station(pos)
|
||||
local min_dist = 999999
|
||||
local min_key = nil
|
||||
local dist
|
||||
for key,item in pairs(self.tStations) do
|
||||
if not item.junction then
|
||||
dist = distance(pos, P(key))
|
||||
if dist < min_dist then
|
||||
min_dist = dist
|
||||
min_key = key
|
||||
end
|
||||
end
|
||||
end
|
||||
return P(min_key)
|
||||
end
|
||||
|
||||
-- Return a sorted list of stations
|
||||
-- Param pos: player pos
|
||||
-- Param station_pos: next station pos or nil.
|
||||
-- Used to generate list with connected stations only
|
||||
-- Param sorted: either "dist" or "level"
|
||||
function Network:station_list(pos, station_pos, sorted)
|
||||
local tStations, lStations
|
||||
if station_pos then
|
||||
local tRes = {}
|
||||
tStations = get_stations(self.tStations, S(station_pos), tRes) -- reduced
|
||||
else
|
||||
tStations = self.tStations -- all stations
|
||||
end
|
||||
if sorted == "dist" then
|
||||
lStations = sort_based_on_distance(tStations, pos)
|
||||
elseif sorted == "level" then
|
||||
lStations = sort_based_on_level(tStations)
|
||||
else
|
||||
-- delete own station from list
|
||||
tStations[S(station_pos)] = nil
|
||||
lStations = sort_based_on_name(tStations, pos)
|
||||
end
|
||||
return lStations
|
||||
end
|
||||
|
||||
-- Check the complete table by means of the provided callback bool = func(pos)
|
||||
function Network:filter(callback)
|
||||
local lKeys = {}
|
||||
for key,_ in pairs(self.tStations) do
|
||||
lKeys[#lKeys+1] = key
|
||||
end
|
||||
for _,key in ipairs(lKeys) do
|
||||
if not callback(P(key)) then
|
||||
self.tStations[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Network:deserialize(data)
|
||||
if data ~= "" then
|
||||
data = minetest.deserialize(data)
|
||||
self.tStations = data.tStations
|
||||
self.change_counter = data.change_counter
|
||||
end
|
||||
end
|
||||
|
||||
function Network:serialize()
|
||||
return minetest.serialize(self)
|
||||
end
|
||||
|
||||
-- Return a pos/item table with all network nodes, the node at pos is connected with
|
||||
function Network:get_node_table(pos)
|
||||
local tRes = {}
|
||||
local key = S(pos)
|
||||
get_stations(self.tStations, key, tRes)
|
||||
tRes[key] = nil
|
||||
return tRes
|
||||
end
|
||||
Reference in New Issue
Block a user