aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authororwell96 <orwell@bleipb.de>2023-04-12 21:31:14 +0200
committerorwell96 <orwell@bleipb.de>2023-05-27 12:26:15 +0200
commitbc8c04d146cea83e6b7c6e63c1778abff6cd0b68 (patch)
treea6bc6842edefd8df862635e32ad48d68be1a80ea
parentf693e1e6d09b15391b4ff6a795e854f485ac4178 (diff)
downloadadvtrains-bc8c04d146cea83e6b7c6e63c1778abff6cd0b68.tar.gz
advtrains-bc8c04d146cea83e6b7c6e63c1778abff6cd0b68.tar.bz2
advtrains-bc8c04d146cea83e6b7c6e63c1778abff6cd0b68.zip
Trackmap: get started
-rw-r--r--advtrains_trackmap/fsrender.lua23
-rw-r--r--advtrains_trackmap/grid.lua90
-rw-r--r--advtrains_trackmap/init.lua14
-rw-r--r--advtrains_trackmap/mod.conf6
-rw-r--r--advtrains_trackmap/viewer.lua44
5 files changed, 177 insertions, 0 deletions
diff --git a/advtrains_trackmap/fsrender.lua b/advtrains_trackmap/fsrender.lua
new file mode 100644
index 0000000..607f3cd
--- /dev/null
+++ b/advtrains_trackmap/fsrender.lua
@@ -0,0 +1,23 @@
+-- fsrender.lua
+-- Rendering of a grid of characters into a formspec
+
+local tm = advtrains.trackmap
+
+function tm.render_grid(grid, origin_pos, width, height)
+ local s = {"label[0,0;"}
+ for z=height-1, 0, -1 do
+ -- render a row
+ for x=0,width-1 do
+ local apos_x = origin_pos.x + x
+ local apos_z = origin_pos.z + z
+ local chr = "░"
+ if grid[apos_x] and grid[apos_x][apos_z] then
+ chr = grid[apos_x][apos_z]
+ end
+ table.insert(s, chr)
+ end
+ table.insert(s,"\n")
+ end
+ table.insert(s, "]")
+ return table.concat(s)
+end \ No newline at end of file
diff --git a/advtrains_trackmap/grid.lua b/advtrains_trackmap/grid.lua
new file mode 100644
index 0000000..9f367cb
--- /dev/null
+++ b/advtrains_trackmap/grid.lua
@@ -0,0 +1,90 @@
+-- grid.lua
+-- routines taking the tracks and building a grid out of them
+
+local tm = advtrains.trackmap
+
+-- Maximum scan length for track iterator
+local TS_MAX_SCAN = 1000
+
+-- Get a character matching the class requested by chr, in the correct orientation for conndir
+-- The characters will be chosen from the unicode frame set if appropriate
+-- valid character classes -, =, |
+local char_equiv = {
+ ["-"] = {"│", "/", "─", "\\"}, -- single-line
+ ["="] = {"║", "/", "═", "\\"}, -- double-line
+ ["|"] = {"─", "\\", "│", "/"}, -- break (i.e. TCB, perpendicular to orientation)
+}
+local dir_to_charmap = {
+ [15] = 1,
+ [ 0] = 1,
+ [ 1] = 1,
+ [ 2] = 2,
+ [ 3] = 3,
+ [ 4] = 3,
+ [ 5] = 3,
+ [ 6] = 4,
+ [ 7] = 1,
+ [ 8] = 1,
+ [ 9] = 1,
+ [10] = 2,
+ [11] = 3,
+ [12] = 3,
+ [13] = 3,
+ [14] = 4,
+}
+function tm.rotate_char_class_by_conn(chr, conndir)
+ return char_equiv[chr][dir_to_charmap[conndir]]
+end
+
+-- Generate a grid map by walking tracks starting from the given position start_pos
+-- For every track that is visited, node_callback is called.
+-- signature: node_callback(pos, conns, connid)
+-- should return a table as follows:
+-- {
+-- char = "X" -- the character to use in this place, defaults to guessing a fitting frame character
+-- stop = false -- if true, the iterator will stop following this branch
+-- }
+-- Returning nil will assume defaults.
+-- return value: a table:
+-- {
+-- grid = <grid> - access abs_grid[x][y] - contains one character per cell
+-- min_pos = <pos> - the minimum pos contained in this grid
+-- max_pos = <pos> - the maximum pos
+-- }
+function tm.generate_grid_map(start_pos, node_callback)
+ local ti = advtrains.get_track_iterator(start_pos, nil, TS_MAX_SCAN, true)
+ local grid = {} -- grid[x][y]
+ local gminx, gmaxx, gminz, gmaxz = start_pos.x, start_pos.x, start_pos.z, start_pos.z
+
+ while ti:has_next_branch() do
+ pos, connid = ti:next_branch()
+ repeat
+ local ok, conns = advtrains.get_rail_info_at(pos)
+ local c = node_callback(pos, conns, connid)
+ local chr = c and c.char
+ if not chr then
+ chr = tm.rotate_char_class_by_conn("=", conns[connid])
+ end
+
+ -- add the char to the grid
+ if not grid[pos.x] then
+ grid[pos.x] = {}
+ end
+ grid[pos.x][pos.z] = chr
+
+ gminx = math.min(gminx, pos.x)
+ gmaxx = math.max(gmaxx, pos.x)
+ gminz = math.min(gminz, pos.z)
+ gmaxz = math.max(gmaxz, pos.z)
+
+ if c and c.stop then break end
+ pos, connid = ti:next_track()
+ until not pos
+ end
+ return {
+ grid = grid,
+ min_pos = {x=gminx, z=gminz},
+ max_pos = {x=gmaxx, z=gmaxz},
+ }
+end
+
diff --git a/advtrains_trackmap/init.lua b/advtrains_trackmap/init.lua
new file mode 100644
index 0000000..060e597
--- /dev/null
+++ b/advtrains_trackmap/init.lua
@@ -0,0 +1,14 @@
+-- Advtrains track map
+-- Replacement of itrainmap
+
+advtrains.trackmap = {}
+
+
+local modpath = minetest.get_modpath(minetest.get_current_modname()) .. DIR_DELIM
+
+
+dofile(modpath.."grid.lua")
+dofile(modpath.."fsrender.lua")
+dofile(modpath.."viewer.lua")
+
+
diff --git a/advtrains_trackmap/mod.conf b/advtrains_trackmap/mod.conf
new file mode 100644
index 0000000..633f1e2
--- /dev/null
+++ b/advtrains_trackmap/mod.conf
@@ -0,0 +1,6 @@
+name=advtrains_trackmap
+title=Advanced Trains Track Map
+description=Formspec-based map to display track layouts
+author=orwell96
+
+depends=advtrains
diff --git a/advtrains_trackmap/viewer.lua b/advtrains_trackmap/viewer.lua
new file mode 100644
index 0000000..d1921d8
--- /dev/null
+++ b/advtrains_trackmap/viewer.lua
@@ -0,0 +1,44 @@
+-- viewer.lua
+-- standalone chatcommand/tool trackmap viewer window
+
+local tm = advtrains.trackmap
+
+local function node_left_click(pos, pname)
+ local node_ok, conns, rail_y=advtrains.get_rail_info_at(pos)
+ if not node_ok then
+ minetest.chat_send_player(pname, "Node is not a track!")
+ return
+ end
+
+ local function node_callback()
+ return nil
+ end
+
+ local gridtbl = tm.generate_grid_map(pos, node_callback)
+ local fslabel = tm.render_grid(gridtbl.grid, gridtbl.min_pos, 100, 100)
+
+ minetest.show_formspec(pname, "advtrains_trackmap:test", "size[20,20]"..fslabel)
+end
+
+
+minetest.register_craftitem("advtrains_trackmap:tool",{
+ description = "Trackmap Tool\nPunch: Show map",
+ groups = {cracky=1}, -- key=name, value=rating; rating=1..3.
+ inventory_image = "at_il_tool.png",
+ wield_image = "at_il_tool.png",
+ stack_max = 1,
+ on_use = function(itemstack, player, pointed_thing)
+ local pname = player:get_player_name()
+ if not pname then
+ return
+ end
+ if not minetest.check_player_privs(pname, {interlocking=true}) then
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
+ return
+ end
+ if pointed_thing.type=="node" then
+ local pos=pointed_thing.under
+ node_left_click(pos, pname)
+ end
+ end
+}) \ No newline at end of file