Merge pull request #10 from mt-mods/rewrite

Rewrite and improvement
This commit is contained in:
OgelGames 2021-06-22 16:17:47 +10:00 committed by GitHub
commit 31f76337a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 804 additions and 729 deletions

107
README.md
View File

@ -4,99 +4,56 @@
A Minetest mod for user-generated teleportation pads.
Version: 0.5.0
![screenshot](screenshot.png?raw=true "screenshot")
License:
Code: LGPL 2.1 (see included LICENSE file)
Textures: CC-BY-SA (see http://creativecommons.org/licenses/by-sa/4.0/)
textures/telemosaic_beacon_protected_overlay.png MIT (https://notabug.org/TenPlus1/protector)
## Description
Report bugs or request help on the forum topic.
This is a mod for Minetest. It provides teleportation pads, called "beacons". Unlike other teleportation mods, no menus or GUIs are used; you set the destination with a simple "key" item. There is no tooltip for the destination either, so signs are recommended.
Description
-----------
Another difference is the limited default range of the beacons. To increase the range, you need to place "extenders" around the beacon. The extenders come in different colors, allowing the extenders to form a pretty pattern; hence the name "telemosaic".
This is a mod for MineTest. It provides teleportation pads, called
"beacons". Unlike other teleportation mods, no menus or GUIs are used;
you set the destination with a simple "key" item. There is no
tooltip for the destination either, so signs are recommended.
## Notes
Another difference is the limited default range of the beacons.
To increase the range, you need to place "extenders" around the beacon.
The extenders come in different colors, allowing the extenders to
form a pretty pattern; hence the name "telemosaic".
This is a maintained fork of https://github.com/bendeutsch/minetest-telemosaic with various improvements and changes, optimized for multiplayer environments.
Current behavior
----------------
* Beacons no longer teleport players automatically, they must be right-clicked by a player.
* More chat messages are sent to inform and help players with non-functional telemosaics.
* Telemosaic keys can be preserved by holding shift when right-clicking a beacon.
* Beacons can be enabled and disabled by punching them with a telemosaic key.
* If the `digilines` mod is installed, beacons can be controlled by digilines.
* and other small changes...
Beacons are created with 2 diamonds, 3 obsidian blocks, and a wooden
door: first row diamond, door, diamond; second row the obsidian blocks.
## Usage
Right-clicking a beacon with a default mese crystal fragment remembers
the position in the fragment, which turns into a telemosaic key.
Right-clicking a second beacon with the key sets up a teleportation
route from the second beacon to the first beacon. To set up a return
path, right-click the second beacon with the fragment, and the first
beacon with the resulting key again.
Right-clicking a beacon with a default mese crystal fragment creates a telemosaic key with the position of the beacon.
The beacons do not need to be strictly paired this way: rings or
star-shaped networks are also possible. Each beacon has only a
single destination, but can itself be the destination of several
others.
Right-clicking a second beacon with the key sets the destination of the second beacon to the position of the first beacon. To set up a return path, right-click the second beacon with the fragment, and then first beacon with the resulting key again.
Beacons will check that their destination is sane: the destination
still needs to be a beacon, and the two nodes above it should be
clear for walking / standing in. If your Minetest version supports
it, the beacon will emerge the area prior to checking and teleporting.
Emerging is merely a convenience, though.
The beacons do not need to be strictly paired this way: rings or star-shaped networks are also possible. Each beacon has only a single destination, but can itself be the destination of several others.
Beacons have a maximum range of 20 nodes. If the destination is
too far away, the beacon will turn red and will not function.
To extend the range for a beacon, place "extenders" next to it,
within a 7x7 horizontal square centered on the beacon.
Once linked, you teleport between beacons by right-clicking them. Before teleporting, beacons will check that their destination is sane: the destination still needs to be a beacon, and the two nodes above it should be clear for walking/standing in.
Extenders come in three tiers: tier 1 extends all affected beacons
by 5 nodes, tier 2 by 20 nodes, and tier 3 by 80 nodes. Placing
or digging extenders will update affected beacons.
Beacons have a default range of 20 nodes. If the destination is too far away, the beacon will turn red and will not function. To extend the range for a beacon, place "extenders" next to it, within a 7x7 horizontal square centered on the beacon, and at the same level or one node below the beacon.
Tier 1 extenders are crafted by placing an obsidian block, a wooden
door, and another obsidian block in a horizontal row. Tier 2 extenders
are crafted with an obsidian block in the middle, surrounded by a cross
of four tier 1 extenders. Tier 3 extenders are crafted with an obsidian
block surrounded by four tier 2 extenders.
Extenders come in three tiers, with each being more powerful than the tier below. By default, tier 1, tier 2, and tier 3 extenders increase the range of nearby beacons by 5, 20, and 80 nodes, respectively.
Extenders can be colored with any of the dyes found in the dye mod.
Colored extenders work just like regular extenders, both for
teleporting and for recipes. To "uncolor" an extender, dye it grey.
Extenders can be colored with any of the dyes found in the `dye` mod. Colored extenders work just like regular extenders, both for teleporting and for recipes.
Settings
------------
## Digilines
* `telemosaic_right_click_teleport` allow teleport on rightclick
When the `digilines` mod is installed, telemosaic beacons can be controlled by sending digiline messages. By default, all beacons use the channel "telemosaic", but you can change the channel name via digilines.
Future plans
------------
For full documentaion, see [digilines.md](digilines.md).
* Particle and sound effects
* Protected beacons (will not teleport if protected)
## Dependencies
Dependencies
------------
* default
* doors
* dye (optional)
* `default`
* `doors`
* `dye` (optional)
* `digilines` (optional)
Installation
------------
## License
Unzip the archive, rename the folder to to `bewarethedark` and
place it in minetest/mods/
( Linux: If you have a linux system-wide installation place
it in ~/.minetest/mods/. )
( If you only want this to be used in a single world, place
the folder in worldmods/ in your worlddirectory. )
For further information or help see:
http://wiki.minetest.com/wiki/Installing_Mods
* Code: LGPL 2.1 (see included LICENSE file)
* Textures: CC-BY-SA (see http://creativecommons.org/licenses/by-sa/4.0/)
* textures/telemosaic_beacon_protected_overlay.png MIT (https://notabug.org/TenPlus1/protector)

26
abm.lua
View File

@ -1,30 +1,22 @@
minetest.register_abm({
label = "Telemosaic beacon effect",
nodenames = {"telemosaic:beacon"},
interval = 2.0,
chance = 2,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
minetest.add_particlespawner({
label = "Telemosaic beacon effect",
nodenames = {"group:telemosaic_active"},
interval = 2.0,
chance = 2,
catch_up = false,
action = function(pos)
minetest.add_particlespawner({
amount = 4,
time = 2,
minpos = vector.add(pos, {x=-0.2, y=0, z=-0.2}),
maxpos = vector.add(pos, {x=0.2, y=0, z=0.2}),
minvel = {x=0, y=1, z=0},
maxvel = {x=0, y=2, z=0},
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 1,
maxexptime = 2,
minsize = 1,
maxsize = 1.7,
collisiondetection = false,
collision_removal = false,
object_collision = false,
vertical = false,
texture = "telemosaic_particle_arrival.png",
glow = 9
glow = 9
})
end
end
})

78
beacon.lua Normal file
View File

@ -0,0 +1,78 @@
for _,protected in pairs({true, false}) do
local node_name_suffix = protected and "_protected" or ""
local texture_overlay = protected and "^telemosaic_beacon_protected_overlay.png" or ""
local description_prefix = protected and "Protected " or ""
minetest.register_node("telemosaic:beacon_off"..node_name_suffix, {
description = description_prefix.."Telemosaic Beacon",
tiles = {
"telemosaic_beacon_off.png"..texture_overlay,
"telemosaic_beacon_side.png",
},
paramtype = "light",
groups = {cracky = 2, telemosaic = 1, telemosaic_off = 1},
on_rightclick = telemosaic.rightclick,
digilines = telemosaic.digilines,
})
minetest.register_node("telemosaic:beacon"..node_name_suffix, {
description = description_prefix.."Telemosaic Beacon Active (you hacker you!)",
tiles = {
"telemosaic_beacon_top.png"..texture_overlay,
"telemosaic_beacon_side.png",
},
paramtype = "light",
groups = {cracky = 2, not_in_creative_inventory = 1, telemosaic = 1, telemosaic_active = 1},
drop = "telemosaic:beacon_off"..node_name_suffix,
on_rightclick = telemosaic.rightclick,
digilines = telemosaic.digilines,
})
minetest.register_node("telemosaic:beacon_err"..node_name_suffix, {
description = description_prefix.."Telemosaic Beacon Error (you hacker you!)",
tiles = {
"telemosaic_beacon_err.png"..texture_overlay,
"telemosaic_beacon_side.png",
},
paramtype = "light",
groups = {cracky = 2, not_in_creative_inventory = 1, telemosaic = 1, telemosaic_error = 1},
drop = "telemosaic:beacon_off"..node_name_suffix,
on_rightclick = telemosaic.rightclick,
digilines = telemosaic.digilines,
})
minetest.register_node("telemosaic:beacon_disabled"..node_name_suffix, {
description = description_prefix.."Telemosaic Beacon Disabled (you hacker you!)",
tiles = {
"telemosaic_beacon_disabled.png"..texture_overlay,
"telemosaic_beacon_side.png",
},
paramtype = "light",
groups = {cracky = 2, not_in_creative_inventory = 1, telemosaic = 1, telemosaic_disabled = 1},
drop = "telemosaic:beacon_off"..node_name_suffix,
on_rightclick = telemosaic.rightclick,
digilines = telemosaic.digilines,
})
end
minetest.register_craft({
output = "telemosaic:beacon_off",
recipe = {
{"default:diamond", "doors:door_wood", "default:diamond"},
{"default:obsidian","default:obsidian","default:obsidian"}
}
})
minetest.register_craft({
output = "telemosaic:beacon_off_protected",
type = "shapeless",
recipe = {"telemosaic:beacon_off", "default:steel_ingot"}
})
minetest.register_craft({
output = "telemosaic:beacon_off",
type = "shapeless",
recipe = {"telemosaic:beacon_off_protected"}
})

View File

@ -1,46 +0,0 @@
minetest.register_craft({
output = 'telemosaic:beacon_off',
recipe = {
{'default:diamond', 'doors:door_wood', 'default:diamond'},
{'default:obsidian','default:obsidian','default:obsidian'}
}
})
minetest.register_craft({
output = 'telemosaic:beacon_off_protected',
type = 'shapeless',
recipe = {"telemosaic:beacon_off", "default:steel_ingot"}
})
minetest.register_craft({
output = 'telemosaic:extender_one',
recipe = {
{'default:obsidian','doors:door_wood','default:obsidian'}
}
})
minetest.register_craft({
output = 'telemosaic:extender_two',
recipe = {
{'', 'group:telemosaic_extender_one',''},
{'group:telemosaic_extender_one','default:obsidian','group:telemosaic_extender_one'},
{'', 'group:telemosaic_extender_one',''}
}
})
minetest.register_craft({
output = 'telemosaic:extender_three',
recipe = {
{'', 'group:telemosaic_extender_two',''},
{'group:telemosaic_extender_two','default:obsidian','group:telemosaic_extender_two'},
{'', 'group:telemosaic_extender_two',''}
}
})
-- how to recycle a key
minetest.register_craft({
type = 'shapeless',
recipe = {'telemosaic:key'},
output = 'default:mese_crystal_fragment'
})

View File

@ -1,4 +0,0 @@
default
doors
dye?
digilines?

80
digilines.lua Normal file
View File

@ -0,0 +1,80 @@
local function digiline_receive(pos, _, channel, msg)
local meta = minetest.get_meta(pos)
local set_channel = meta:get("channel") or telemosaic.default_channel
if channel ~= set_channel then
return
end
if type(msg) == "string" then
-- Convert string command to table
if msg == "get" or msg == "GET" then
msg = {command = "get"}
elseif msg == "enable" or msg == "disable" then
msg = {command = msg}
elseif msg:match("^setchannel .+") then
local c = string.split(msg, " ", true, 1)
msg = {command = c[1], channel = c[2]}
elseif msg:match("^setdest .+") then
local c = string.split(msg, " ", true, 1)
local p = string.split(c[2], ",")
msg = {command = c[1], x = p[1], y = p[2], z = p[3]}
end
end
if type(msg) ~= "table" or not msg.command then
return
end
if msg.command == "get" then
local dest = telemosaic.get_destination(pos)
digilines.receptor_send(pos, digilines.rules.default, set_channel, {
state = telemosaic.get_state(pos),
origin = pos,
target = dest,
pos = pos,
destination = dest,
})
elseif msg.command == "setchannel" then
if type(msg.channel) == "string" then
meta:set_string("channel", msg.channel)
end
elseif msg.command == "enable" then
if telemosaic.get_state(pos) == "disabled" then
telemosaic.set_state(pos, "active")
end
elseif msg.command == "disable" then
if telemosaic.get_state(pos) == "active" then
telemosaic.set_state(pos, "disabled")
end
elseif msg.command == "setdest" then
local dest = msg.pos or {
x = msg.x,
y = msg.y,
z = msg.z
}
if type(dest) ~= "table" then
return
end
dest.x = tonumber(dest.x)
dest.y = tonumber(dest.y)
dest.z = tonumber(dest.z)
if dest.x and dest.y and dest.z then
telemosaic.set_destination(pos, dest)
end
end
end
telemosaic.digilines = {
effector = {
action = digiline_receive
}
}

75
digilines.md Normal file
View File

@ -0,0 +1,75 @@
# Telemosaic digilines documentation
An overview of all commands and functionality, with example Lua code.
For convenience, and for using digiline buttons, all commands can also be sent as text.
### Change the digiline channel
**Lua:**
```lua
digiline_send("telemosaic", {command = "setchannel", channel = "whatever"})
```
**Text:** `setchannel whatever`
### Disable a beacon
**Lua:**
```lua
digiline_send("telemosaic", {command = "disable"})
```
**Text:** `disable`
### Enable a beacon
**Lua:**
```lua
digiline_send("telemosaic", {command = "enable"})
```
**Text:** `enable`
### Set a new destination
**Lua:**
```lua
digiline_send("telemosaic", {command = "setdest", x = 0, y = 0, z = 0})
```
or
```lua
digiline_send("telemosaic", {command = "setdest", pos = {x = 0, y = 0, z = 0}})
```
**Text:** `setdest 0,0,0`
Note that the destination will only be set if it's valid (beacon at destination).
### Get data from a beacon
**Lua**
```lua
digiline_send("telemosaic", {command = "get"})
```
**Text:** `get` or `GET`
Returns a table containing the following:
```lua
{
state = "active", -- or "disabled", "off", or "error"
pos = {x = 1, y = 2, z = 3},
destination = {x = 4, y = 5, z = 6},
origin = {x = 1, y = 2, z = 3}, -- same as 'pos'
target = {x = 4, y = 5, z = 6}, -- same as 'destination'
}
```

84
extender.lua Normal file
View File

@ -0,0 +1,84 @@
local has_dye = minetest.get_modpath("dye")
local function pretty_str(s)
s = string.upper(string.sub(s, 1, 1))..string.sub(s, 2)
local i = string.find(s, "_")
if i then
local c = string.upper(string.sub(s, i + 1, i + 1))
s = string.gsub(s, "_.", " "..c)
end
return s
end
local tiers = {"one", "two", "three"}
for i, range in pairs(telemosaic.extender_ranges) do
local tier = tiers[i]
minetest.register_node("telemosaic:extender_"..tier, {
description = "Telemosaic Extender, Tier "..i..(has_dye and " (Grey)" or ""),
tiles = {
"telemosaic_extender_"..tier..".png"
},
paramtype = "light",
groups = {cracky = 2, telemosaic_extender = range, ["telemosaic_extender_"..tier] = 1},
after_place_node = telemosaic.extender_place,
after_dig_node = telemosaic.extender_dig,
})
if has_dye then
minetest.register_craft({
type = "shapeless",
output = "telemosaic:extender_"..tier,
recipe = {"group:telemosaic_extender_"..tier, "dye:grey"},
})
for name, color in pairs(telemosaic.extender_colors) do
minetest.register_node("telemosaic:extender_"..tier.."_"..name, {
description = "Telemosaic Extender, Tier "..i.." ("..pretty_str(name)..")",
tiles = {
"telemosaic_extender_"..tier..".png^[colorize:"..color
},
paramtype = "light",
groups = {
cracky = 2, not_in_creative_inventory = 1,
telemosaic_extender = range, ["telemosaic_extender_"..tier] = 1
},
after_place_node = telemosaic.extender_place,
after_dig_node = telemosaic.extender_dig,
})
minetest.register_craft({
type = "shapeless",
output = "telemosaic:extender_"..tier.."_"..name,
recipe = {"group:telemosaic_extender_"..tier, "dye:"..name},
})
end
end
end
minetest.register_craft({
output = "telemosaic:extender_one",
recipe = {
{"default:obsidian", "doors:door_wood", "default:obsidian"}
}
})
minetest.register_craft({
output = "telemosaic:extender_two",
recipe = {
{"", "group:telemosaic_extender_one", ""},
{"group:telemosaic_extender_one", "default:obsidian", "group:telemosaic_extender_one"},
{"", "group:telemosaic_extender_one", ""}
}
})
minetest.register_craft({
output = "telemosaic:extender_three",
recipe = {
{"", "group:telemosaic_extender_two", ""},
{"group:telemosaic_extender_two", "default:obsidian", "group:telemosaic_extender_two"},
{"", "group:telemosaic_extender_two", ""}
}
})

367
functions.lua Normal file
View File

@ -0,0 +1,367 @@
-- Keeps a track of players to prevent teleport spamming
local recent_teleports = {}
-- Not the same as `minetest.hash_node_position` and `minetest.get_position_from_hash`
local function hash_pos(pos)
return math.floor(pos.x + 0.5)..':'..
math.floor(pos.y + 0.5)..':'..
math.floor(pos.z + 0.5)
end
local function unhash_pos(hash)
local list = string.split(hash, ':')
local p = {
x = tonumber(list[1]),
y = tonumber(list[2]),
z = tonumber(list[3])
}
if p.x and p.y and p.z then
return p
end
end
-- Wrap this function to incorporate travel checks from another mod
function telemosaic.travel_allowed(player, src, dest)
return true
end
function telemosaic.is_protected_beacon(pos, player_name)
if minetest.get_node(pos).name == "telemosaic:beacon_protected" then
if minetest.is_protected(pos, player_name) then
return true
end
end
return false
end
function telemosaic.get_state(pos)
local node = minetest.get_node(pos)
local def = minetest.registered_nodes[node.name]
if not def or not def.groups then return "invalid" end
if def.groups.telemosaic_off then return "off" end
if def.groups.telemosaic_active then return "active" end
if def.groups.telemosaic_disabled then return "disabled" end
if def.groups.telemosaic_error then return "error" end
return "invalid"
end
function telemosaic.set_state(pos, state)
local node = minetest.get_node(pos)
if not string.match(node.name, "^telemosaic:beacon") then
return -- Not a telemosaic!
end
local new_name = "telemosaic:beacon"
if state == "off" then
new_name = new_name.."_off"
elseif state == "error" then
new_name = new_name.."_err"
elseif state == "disabled" then
new_name = new_name.."_disabled"
elseif state ~= "active" then
return -- Can't set a state that doesn't exist
end
if string.match(node.name, "protected$") then
new_name = new_name.."_protected"
end
-- Swap node instead of set node to keep the metadata
minetest.swap_node(pos, {name = new_name})
end
function telemosaic.is_valid_destination(pos)
local pos_above = {x = pos.x, y = pos.y + 1, z = pos.z}
local pos_top = {x = pos.x, y = pos.y + 2, z = pos.z}
local node = minetest.get_node_or_nil(pos)
local node_above = minetest.get_node_or_nil(pos_above)
local node_top = minetest.get_node_or_nil(pos_top)
if not node or not node_above or not node_top then
-- Need to load the map
minetest.get_voxel_manip():read_from_map(pos, pos_top)
node = node or minetest.get_node(pos)
node_above = node_above or minetest.get_node(pos_above)
node_top = node_top or minetest.get_node(pos_top)
end
local valid = true
-- Check if there is a telemosaic at the destination
if not string.match(node.name, "^telemosaic:beacon") then
valid = false
end
-- Check if the nodes above are not walkable (yes, confusing naming)
if node_above.name ~= "air" and node_above.name ~= "vacuum:vacuum" then
local def = minetest.registered_nodes[node_above.name]
if def and def.walkable then
return valid, false
end
end
if node_top.name ~= "air" and node_top.name ~= "vacuum:vacuum" then
local def = minetest.registered_nodes[node_top.name]
if def and def.walkable then
return valid, false
end
end
return valid, true
end
function telemosaic.check_beacon(pos, player_name, all_checks)
local meta = minetest.get_meta(pos)
local dest = unhash_pos(meta:get_string("telemosaic:dest"))
local state = telemosaic.get_state(pos)
if not dest or state == "invalid" then
return false
end
local dist = vector.distance(pos, dest)
local range = telemosaic.beacon_range
local pos1 = {x = pos.x - 3, y = pos.y - 1, z = pos.z - 3}
local pos2 = {x = pos.x + 3, y = pos.y, z = pos.z + 3}
local _, nodes = minetest.find_nodes_in_area(pos1, pos2, "group:telemosaic_extender")
for node_name, num in pairs(nodes) do
range = range + (minetest.get_item_group(node_name, "telemosaic_extender") * num)
end
if dist > range then
-- Destination out of range, set beacon to error state
telemosaic.set_state(pos, "error")
if player_name then
local needed = math.ceil(dist - range)
minetest.chat_send_player(player_name,
"You need to add extenders for "..needed.." nodes."
)
end
return false
elseif state == "error" or state == "off" then
-- Not out of range anymore, set to active
telemosaic.set_state(pos, "active")
end
if not all_checks then
return true -- Skip the destination check
end
local valid, open = telemosaic.is_valid_destination(dest)
if not valid then
if player_name then
minetest.chat_send_player(player_name,
"No telemosaic at destination."
)
end
return false
elseif not open then
if player_name then
minetest.chat_send_player(player_name,
"Destination is blocked."
)
end
return false
end
return true
end
function telemosaic.get_destination(pos)
local dest_hash = minetest.get_meta(pos):get_string("telemosaic:dest")
return unhash_pos(dest_hash)
end
function telemosaic.set_destination(pos, dest)
local dest_hash = hash_pos(dest)
local src_hash = hash_pos(pos)
if src_hash == dest_hash or not telemosaic.is_valid_destination(dest) then
return -- Don't allow setting invalid destination
end
minetest.get_meta(pos):set_string("telemosaic:dest", dest_hash)
telemosaic.check_beacon(pos)
end
function telemosaic.teleport(player, src, dest)
local player_name = player:get_player_name()
-- Prevent teleport spamming
recent_teleports[player_name] = true
minetest.after(telemosaic.teleport_delay,
function(name)
recent_teleports[name] = nil
end,
player_name
)
if telemosaic.digilines then
-- Send a digiline message about the teleport
local channel = minetest.get_meta(src):get("channel") or telemosaic.default_channel
digilines.receptor_send(src, digilines.rules.default, channel, {
player = player_name,
origin = src,
target = dest,
pos = src,
destination = dest,
})
end
dest.y = dest.y + 0.5 -- Teleport the player to above the telemosaic
player:set_pos(dest)
minetest.sound_play({name = "telemosaic_departure", gain = 1}, {pos = src, max_hear_distance = 30})
minetest.sound_play({name = "telemosaic_arrival", gain = 1}, {pos = dest, max_hear_distance = 30})
minetest.add_particlespawner({
amount = 100,
time = 0.25,
minpos = {x = src.x, y = src.y + 0.3, z = src.z},
maxpos = {x = src.x, y = src.y + 2, z = src.z},
minvel = {x = 1, y = -6, z = 1},
maxvel = {x = -1, y = -1, z = -1},
minacc = {x = 0, y = -2, z = 0},
maxacc = {x = 0, y = -6, z = 0},
minexptime = 0.1,
minsize = 0.5,
maxsize = 1.5,
texture = "telemosaic_particle_departure.png",
glow = 15,
})
minetest.add_particlespawner({
amount = 100,
time = 0.25,
minpos = {x = dest.x, y = dest.y + 0.3, z = dest.z},
maxpos = {x = dest.x, y = dest.y + 2, z = dest.z},
minvel = {x = -1, y = 1, z = -1},
maxvel = {x = 1, y = 6, z = 1},
minacc = {x = 0, y = -2, z = 0},
maxacc = {x = 0, y = -6, z = 0},
minexptime = 0.1,
minsize = 0.5,
maxsize = 1.5,
texture = "telemosaic_particle_arrival.png",
glow = 15,
})
end
function telemosaic.rightclick(pos, node, player, itemstack, pointed_thing)
if player.is_fake_player or not minetest.is_player(player) then
return itemstack -- No fake players!
end
local item = itemstack:get_name()
local player_name = player:get_player_name()
local state = telemosaic.get_state(pos)
if item == "default:mese_crystal_fragment" then
-- Try to create a telemosaic key
if itemstack:get_count() ~= 1 then
minetest.chat_send_player(player_name,
"You can only use a singular mese crystal fragment to create a telemosaic key."
)
else
return ItemStack({name = "telemosaic:key", metadata = hash_pos(pos)})
end
elseif item == "telemosaic:key" then
-- Try to set a new destination
local dest_hash = itemstack:get_metadata()
local src_hash = hash_pos(pos)
if dest_hash ~= src_hash and not minetest.is_protected(pos, player_name) then
local dest = unhash_pos(dest_hash)
if not dest then
-- This should never happen, but tell the player if it does
minetest.chat_send_player(player_name,
"Telemosaic key is invalid."
)
elseif not telemosaic.is_valid_destination(dest) then
-- No point setting a destination that doesn't exist
minetest.chat_send_player(player_name,
"No telemosaic at new destination."
)
else
-- Everything is good, set the destination and update the telemosaic
minetest.get_meta(pos):set_string("telemosaic:dest", dest_hash)
telemosaic.check_beacon(pos, player_name)
end
if player:get_player_control().sneak then
return itemstack -- Don't destroy key
end
return ItemStack("default:mese_crystal_fragment")
end
elseif state == "off" or player:get_player_control().sneak then
-- Allow player to build on telemosaic
local def = minetest.registered_nodes[item]
if def and def.on_place and not vector.equals(pos, pointed_thing.above) then
-- Need to create a fake pointed_thing to prevent recursion
local new_pointed_thing = {
type = "node",
under = vector.new(pointed_thing.above),
above = vector.new(pointed_thing.above)
}
return def.on_place(itemstack, player, new_pointed_thing)
end
elseif state == "active" and not telemosaic.is_protected_beacon(pos, player_name) then
if recent_teleports[player_name] then
return itemstack -- Prevent teleport spamming, fail silently
end
local meta = minetest.get_meta(pos)
local dest = unhash_pos(meta:get_string("telemosaic:dest"))
if telemosaic.check_beacon(pos, player_name, true) then
if telemosaic.travel_allowed(player, pos, dest) then
-- Teleport the player!
telemosaic.teleport(player, pos, dest)
else
minetest.chat_send_player(player_name,
"Travel to destination is not allowed."
)
end
end
elseif state == "disabled" then
-- Tell the player why they can't use this telemosaic
minetest.chat_send_player(player_name,
"Telemosaic is disabled."
)
elseif state == "error" then
-- Check why the beacon is in error state, and tell the player
telemosaic.check_beacon(pos, player_name)
end
return itemstack
end
function telemosaic.extender_place(pos, player, itemstack, pointed_thing)
local pos1 = {x = pos.x - 3, y = pos.y, z = pos.z - 3}
local pos2 = {x = pos.x + 3, y = pos.y + 1, z = pos.z + 3}
local nodes = minetest.find_nodes_in_area(pos1, pos2, "group:telemosaic_error")
for _, node_pos in pairs(nodes) do
-- Update telemosaic, and tell them if they need more extenders
telemosaic.check_beacon(node_pos, player:get_player_name())
end
end
function telemosaic.extender_dig(pos, oldnode, oldmetadata, player)
local pos1 = {x = pos.x - 3, y = pos.y, z = pos.z - 3}
local pos2 = {x = pos.x + 3, y = pos.y + 1, z = pos.z + 3}
local nodes = minetest.find_nodes_in_area(pos1, pos2, {"group:telemosaic_active", "group:telemosaic_disabled"})
for _, node_pos in pairs(nodes) do
-- Update the telemosaic, but don't tell the player anything, they are probably removing it anyway
telemosaic.check_beacon(node_pos)
end
end

View File

@ -7,44 +7,43 @@ A mod which provides player-placed teleport pads
Copyright (C) 2015 Ben Deutsch <ben@bendeutsch.de>
License
-------
This library is free software; you can redistribute it and/or
modify it under 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 the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
]]
telemosaic = {
-- configuration
config = {
-- keep emerge_delay lower than teleport_delay!
emerge_delay = 0.5, -- seconds
teleport_delay = tonumber(minetest.settings:get("telemosaic_teleport_delay")) or 2.0, -- seconds
beacon_range = tonumber(minetest.settings:get("telemosaic_beacon_range")) or 20.0, -- max teleport distance
extender_ranges = {
-- note: not adding beacons here, since they don't extend
-- also: base name of colored versions
['telemosaic:extender_one'] = tonumber(minetest.settings:get("telemosaic_extender_one_range")) or 5.0,
['telemosaic:extender_two'] = tonumber(minetest.settings:get("telemosaic_extender_two_range")) or 20.0,
['telemosaic:extender_three'] = tonumber(minetest.settings:get("telemosaic_extender_three_range")) or 80.0,
},
},
teleport_delay = tonumber(minetest.settings:get("telemosaic_teleport_delay")) or 1.0,
beacon_range = tonumber(minetest.settings:get("telemosaic_beacon_range")) or 20.0,
default_channel = minetest.settings:get("telemosaic_default_channel") or "telemosaic",
extender_ranges = {
tonumber(minetest.settings:get("telemosaic_extender_one_range")) or 5.0,
tonumber(minetest.settings:get("telemosaic_extender_two_range")) or 20.0,
tonumber(minetest.settings:get("telemosaic_extender_three_range")) or 80.0,
},
extender_colors = {
white = "#ffffffa0",
dark_grey = "#00000090",
black = "#000000e0",
violet = "#400080b0",
blue = "#0000ffb0",
cyan = "#00ffffb0",
dark_green = "#007000b0",
green = "#00ff00b0",
yellow = "#ffff00b0",
brown = "#402000c0",
orange = "#ff8000b0",
red = "#ff0000b0",
magenta = "#ff00ffb0",
pink = "#ff8080b0",
},
}
local modpath = minetest.get_modpath(minetest.get_current_modname())
dofile(modpath.."/teleport.lua")
dofile(modpath.."/crafts.lua")
dofile(modpath.."/abm.lua")
local MP = minetest.get_modpath("telemosaic")
if minetest.get_modpath("digilines") then
dofile(MP.."/digilines.lua")
end
dofile(MP.."/functions.lua")
dofile(MP.."/beacon.lua")
dofile(MP.."/extender.lua")
dofile(MP.."/key.lua")
dofile(MP.."/abm.lua")

27
key.lua Normal file
View File

@ -0,0 +1,27 @@
minetest.register_tool("telemosaic:key", {
description = "Telemosaic Key",
inventory_image = "telemosaic_key.png",
stack_max = 1,
groups = {not_in_creative_inventory = 1},
on_use = function(itemstack, player, pointed_thing)
if pointed_thing.type == "node" then
-- Use key to toggle telemosaic on/off
local name = player:get_player_name()
local pos = pointed_thing.under
local state = telemosaic.get_state(pos)
if state == "active" and not minetest.is_protected(pos, name) then
telemosaic.set_state(pos, "disabled")
elseif state == "disabled" and not minetest.is_protected(pos, name) then
telemosaic.set_state(pos, "active")
end
end
return itemstack
end,
})
minetest.register_craft({
type = "shapeless",
recipe = {"telemosaic:key"},
output = "default:mese_crystal_fragment"
})

4
mod.conf Normal file
View File

@ -0,0 +1,4 @@
name = telemosaic
description = A Minetest mod for user-generated teleportation pads.
depends = default, doors
optional_depends = dye, digilines

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -1,14 +1,17 @@
#The range of the teleport beacon
telemosaic_beacon_range (Beacon range) string 20.0
#The base range of the teleport beacon
telemosaic_beacon_range (Beacon range) int 20
#The range of the tier one extender
telemosaic_extender_one_range (Extender tier one range) string 5.0
#The extending range of the tier 1 extender
telemosaic_extender_one_range (Extender tier 1 range) int 5
#The range of the tier two extender
telemosaic_extender_two_range (Extender tier two range) string 20.0
#The extending range of the tier 2 extender
telemosaic_extender_two_range (Extender tier 2 range) int 20
#The range of the tier three extender
telemosaic_extender_three_range (Extender tier three range) string 80.0
#The extending range of the tier 3 extender
telemosaic_extender_three_range (Extender tier 2 range) int 80
#The delay before player is teleported
telemosaic_teleport_delay (Teleport delay) string 2.0
#The minimum delay between player teleports
telemosaic_teleport_delay (Teleport delay) float 1.0
# The default digilines channel for beacons
telemosaic_default_channel (Default channel) string telemosaic

View File

@ -1,541 +0,0 @@
local C = telemosaic.config
local recent_teleports = {}
local function hash_pos(pos)
return math.floor(pos.x + 0.5) .. ':' ..
math.floor(pos.y + 0.5) .. ':' ..
math.floor(pos.z + 0.5)
end
local function unhash_pos(hash)
local pos = {}
local list = string.split(hash, ':')
pos.x = tonumber(list[1])
pos.y = tonumber(list[2])
pos.z = tonumber(list[3])
return pos
end
local function count_extenders(pos)
local extended = 0.0
for z=-3,3 do
for x=-3,3 do
local node = minetest.get_node({ x=pos.x+x, y=pos.y, z=pos.z+z})
local name = node.name
-- trim color off the back
name = string.gsub(name, '^(telemosaic:extender_%a+)_.+', '%1')
extended = extended + ( C.extender_ranges[name] or 0.0 )
end
end
--print("Total extended: " .. extended)
return extended
end
-- returns true if the beacon is in an error state (protected or not)
local function is_err_beacon(pos)
local node = minetest.get_node(pos)
if not node then
-- no node or name
return false
end
return node.name == "telemosaic:beacon_err" or node.name == "telemosaic:beacon_err_protected"
end
-- returns true if the beacon is disabled state (protected or not)
local function is_disabled_beacon(pos)
local node = minetest.get_node(pos)
if not node then
-- no node or name
return false
end
return node.name == "telemosaic:beacon_disabled" or node.name == "telemosaic:beacon_disabled_protected"
end
-- swaps out the beacon with the new state suffix
local function swap_beacon(pos, new_state_suffix)
local node = minetest.get_node(pos)
if not node then
-- no node at pos
return
end
local name = node.name
local new_node_name = "telemosaic:beacon" .. new_state_suffix
if string.match(name, "_protected") then
-- protected beacon
new_node_name = new_node_name .. "_protected"
end
minetest.swap_node(pos, { name = new_node_name })
end
local function extender_place(placepos, placer, itemstack, pointed_thing)
-- go over all possible *err* beacons, and update them
for z=-3,3 do
for x=-3,3 do
local pos = { x=placepos.x+x, y=placepos.y, z=placepos.z+z }
if is_err_beacon(pos) then
-- candidate!
local dest_hash = minetest.get_meta(pos):get_string('telemosaic:dest')
if dest_hash ~= nil and dest_hash ~= '' then
local dest = unhash_pos(dest_hash)
local extended = count_extenders(pos)
local dist = vector.distance(pos, dest)
if dist <= C.beacon_range + extended then
-- upgrade :-)
swap_beacon(pos, "")
else
local count = math.ceil(dist - (C.beacon_range + extended))
minetest.chat_send_player(
placer:get_player_name(),
"You still need to add extensions for "..count.." nodes"
)
end
end
end
end
end
end
local function extender_dig(digpos, oldnode, oldmetadata, digger)
-- go over all possible *actual* beacons, and update them
for z=-3,3 do
for x=-3,3 do
local pos = { x=digpos.x+x, y=digpos.y, z=digpos.z+z }
local node = minetest.get_node(pos)
if node ~= nil and (node.name == 'telemosaic:beacon'
or node.name == 'telemosaic:beacon_disabled') then
-- candidate!
local dest_hash = minetest.get_meta(pos):get_string('telemosaic:dest')
if dest_hash ~= nil and dest_hash ~= '' then
local dest = unhash_pos(dest_hash)
local extended = count_extenders(pos)
local dist = vector.distance(pos, dest)
if dist > C.beacon_range + extended then
-- downgrade :-(
swap_beacon(pos, "_err")
end
end
end
end
end
end
local function check_teleport_dest(dest)
-- check the destination node for beacons, and the two nodes
-- above for "walkthrough"
-- "ignore" is ok, we could not emerge in time then.
local dest_bot = minetest.get_node({ x = dest.x, y = dest.y , z = dest.z })
local dest_mid = minetest.get_node({ x = dest.x, y = dest.y+1, z = dest.z })
local dest_top = minetest.get_node({ x = dest.x, y = dest.y+2, z = dest.z })
--print ("Looking at " .. dest_bot.name .. ", " .. dest_mid.name .. ", " .. dest_top.name)
local dest_ok = true
if dest_bot.name ~= 'ignore' and not string.match(dest_bot.name, '^telemosaic:beacon') then
dest_ok = false
--print("Bottom is not beacon")
end
if dest_mid.name ~= 'ignore' and dest_mid.name ~= 'air' then
local def = minetest.registered_nodes[dest_mid.name]
if def and def.walkable then
dest_ok = false
--print("Mid is walkable")
end
end
if dest_top.name ~= 'ignore' and dest_top.name ~= 'air' then
local def = minetest.registered_nodes[dest_top.name]
if def and def.walkable then
dest_ok = false
--print("Top is walkable")
end
end
return dest_ok
end
local function is_protected_beacon(pos, player)
if minetest.get_node(pos).name == 'telemosaic:beacon_protected' then
-- check protection on protected telemosaic
if minetest.is_protected(pos, player:get_player_name()) then
-- protected telemosaic
return true
end
end
-- not a protected telemosaic
return false
end
-- digilines optional support
local DEFAULT_CHANNEL = "telemosaic"
local on_digiline_receive = function(pos, _, channel, msg)
local meta = minetest.get_meta(pos)
local setchan = meta:contains("channel") and meta:get_string("channel") or DEFAULT_CHANNEL
if channel ~= setchan then
return false
end
if type(msg) == "string" then
local a = string.split(msg, " ")
msg = { command = a[1], channel = a[2] }
elseif type(msg) ~= "table" then
return false
end
if msg.command == "setchannel" then
if type(msg.channel) == "string" then
meta:set_string("channel", msg.channel)
end
return false
end
return true
end
-- for all states but disabled and active beacons: just accept wiring and channel setting
local telemosaic_digiline_base = {
receptor = {},
effector = { action = on_digiline_receive }
}
-- for active and disabled beacon , also implement state switching
local telemosaic_digiline_switching = {
receptor = {},
effector = {
action = function(pos, _, channel, msg)
if on_digiline_receive(pos, _, channel, msg) then
local cmd = (type(msg) == "table") and msg.command or msg
if cmd == "enable" then
swap_beacon(pos, "")
elseif cmd == "disable" then
swap_beacon(pos, "_disabled")
end
end
end
}
}
-- teleports the player with given telemosaic pos
local function do_teleport(pos, player)
-- prevent teleport spamming
local player_name = player:get_player_name()
if recent_teleports[player_name] then
return
end
if is_err_beacon(pos) or is_disabled_beacon(pos) then
return
end
local meta = minetest.get_meta(pos)
local dest_hash = meta:get_string('telemosaic:dest')
if dest_hash ~= nil and dest_hash ~= '' then
local dest = unhash_pos(dest_hash)
-- test destination nodes
local dest_ok = check_teleport_dest(dest)
--print("Ping to " .. dest_hash)
local extended = count_extenders(pos)
-- check for range before teleport (with leeway)
local dist = vector.distance(pos, dest)
--print("Dist :" .. (dist-0.5) .. " to " .. (C.beacon_range + extended))
if dest_ok and dist - 0.5 <= C.beacon_range + extended and telemosaic.travel_allowed(player, pos, dest) then
if telemosaic_digiline_switching ~= nil then
local chan = meta:contains("channel") and meta:get_string("channel") or DEFAULT_CHANNEL
digilines.receptor_send(pos, digilines.rules.default, chan, {
player = player:get_player_name(),
hashpos = { origin = hash_pos(pos), target = dest_hash },
origin = pos,
target = dest,
})
end
dest.y = dest.y + 0.5
minetest.sound_play( {name="telemosaic_set", gain=1}, {pos=pos, max_hear_distance=30})
minetest.add_particlespawner({
amount = 100,
time = 0.25,
minpos = {x=pos.x, y=pos.y+0.3, z=pos.z},
maxpos = {x=pos.x, y=pos.y+2, z=pos.z},
minvel = {x = 1, y = -6, z = 1},
maxvel = {x = -1, y = -1, z = -1},
minacc = {x = 0, y = -2, z = 0},
maxacc = {x = 0, y = -6, z = 0},
minexptime = 0.1,
maxexptime = 1,
minsize = 0.5,
maxsize = 1.5,
texture = "telemosaic_particle_departure.png",
glow = 15,
})
player:set_pos(dest)
minetest.sound_play( {name="telemosaic_teleport", gain=1}, {pos=dest, max_hear_distance=30})
minetest.add_particlespawner({
amount = 100,
time = 0.25,
minpos = {x=dest.x, y=dest.y+0.3, z=dest.z},
maxpos = {x=dest.x, y=dest.y+2, z=dest.z},
minvel = {x = -1, y = 1, z = -1},
maxvel = {x = 1, y = 6, z = 1},
minacc = {x = 0, y = -2, z = 0},
maxacc = {x = 0, y = -6, z = 0},
minexptime = 0.1,
maxexptime = 1,
minsize = 0.5,
maxsize = 1.5,
texture = "telemosaic_particle_arrival.png",
glow = 15,
})
-- prevent teleport spamming
recent_teleports[player_name] = true
minetest.after(1,
function(name)
recent_teleports[name] = nil
end,
player_name)
-- else
-- beacon is in error, one way or another.
-- but don't swap it out - we won't get it back otherwise!
end
end
end
local function beacon_rightclick(pos, node, player, itemstack, pointed_thing)
local name = itemstack:get_name()
--print("Clicked by a " ..name)
if name == 'default:mese_crystal_fragment' and itemstack:get_count() == 1 then
--print("Clicked by a single key")
itemstack = ItemStack({
name = "telemosaic:key",
count = 1,
wear = 0,
metadata = hash_pos(pointed_thing.under),
})
elseif name == 'telemosaic:key' then
local posstring = itemstack:get_metadata()
local thispos = hash_pos(pointed_thing.under)
--print("Key with metadata " .. posstring)
if posstring ~= thispos and not minetest.is_protected(pointed_thing.under, player:get_player_name()) then
local dest_pos = unhash_pos(posstring)
local extended = count_extenders(pointed_thing.under)
if vector.distance(dest_pos, pointed_thing.under) <= C.beacon_range + extended then
swap_beacon(pointed_thing.under, "")
else
swap_beacon(pointed_thing.under, "_err")
end
-- set the destination anyway, it just won't work as
-- long as the beacon is in err state
local meta = minetest.get_meta(pointed_thing.under)
meta:set_string('telemosaic:dest', posstring)
--print ("set to " .. meta:get_string('telemosaic:dest'))
itemstack = ItemStack({
name = "default:mese_crystal_fragment",
count = 1, wear = 0,
})
end
-- elseif player:get_player_control().sneak then
-- NOTE: shift-place commented out due to recursion-issue
-- NOTE: https://github.com/pandorabox-io/pandorabox.io/issues/439
-- NOTE: workaround: place another node below/behind to build on the beacon
-- normal place
-- local def = minetest.registered_nodes[itemstack:get_name()]
-- if def then
-- return def.on_place(itemstack, player, pointed_thing)
-- end
elseif not is_protected_beacon(pos, player) then
-- teleport when right-clicked
do_teleport(pos, player)
end
return itemstack
end
-- register protected and plain beacons with different suffixes, names and textures
for _,is_protected in pairs({ true, false }) do
local node_name_suffix = ""
local texture_overlay = ""
local description_prefix = ""
if is_protected then
node_name_suffix = "_protected"
texture_overlay = "^telemosaic_beacon_protected_overlay.png"
description_prefix = "Protected "
end
minetest.register_node('telemosaic:beacon' .. node_name_suffix, {
description = description_prefix .. 'Telemosaic beacon (on)',
tiles = {
'telemosaic_beacon_top.png' .. texture_overlay,
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
},
paramtype = 'light',
groups = { cracky = 2, not_in_creative_inventory = 1 },
drop = 'telemosaic:beacon_off',
on_rightclick = beacon_rightclick,
digiline = telemosaic_digiline_switching
})
minetest.register_node('telemosaic:beacon_err' .. node_name_suffix, {
description = description_prefix .. 'Telemosaic beacon (err)',
tiles = {
'telemosaic_beacon_err.png' .. texture_overlay,
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
},
paramtype = 'light',
groups = { cracky = 2, not_in_creative_inventory = 1 },
drop = 'telemosaic:beacon_off',
on_rightclick = beacon_rightclick,
digiline = telemosaic_digiline_base
})
minetest.register_node('telemosaic:beacon_off' .. node_name_suffix, {
description = description_prefix .. 'Telemosaic beacon',
tiles = {
'telemosaic_beacon_off.png' .. texture_overlay,
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
},
paramtype = 'light',
groups = { cracky = 2 },
on_rightclick = beacon_rightclick,
on_construct = function(pos)
minetest.get_meta(pos):set_string("channel", DEFAULT_CHANNEL)
end,
digiline = telemosaic_digiline_base
})
minetest.register_node('telemosaic:beacon_disabled' .. node_name_suffix, {
description = description_prefix .. 'Telemosaic beacon (disabled)',
tiles = {
'telemosaic_beacon_disabled.png' .. texture_overlay,
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
'telemosaic_beacon_side.png',
},
paramtype = 'light',
groups = { cracky = 2, not_in_creative_inventory = 1 },
drop = 'telemosaic:beacon_off',
on_rightclick = beacon_rightclick,
digiline = telemosaic_digiline_switching
})
end
minetest.register_tool('telemosaic:key', {
description = 'Telemosaic key',
inventory_image = 'telemosaic_key.png',
stack_max = 1,
groups = { not_in_creative_inventory = 1 },
})
-- extenders come in three strengths, and many colors
local strengths = {
-- index starts at 1
'one',
'two',
'three',
}
local colors = {
-- TODO: localisation
-- default: { name= 'grey', value= '#ffffff00'},
{ name= 'white', value= '#ffffff80'},
{ name= 'dark_grey', value= '#00000080'},
{ name= 'black', value= '#000000c0'},
{ name= 'violet', value= '#40008080'},
{ name= 'blue', value= '#0000ff80'},
{ name= 'cyan', value= '#00ffff80'},
{ name= 'dark_green', value= '#00800080'},
{ name= 'green', value= '#00ff0080'},
{ name= 'yellow', value= '#ffff0080'},
{ name= 'brown', value= '#80400080'},
{ name= 'orange', value= '#ff800080'},
{ name= 'red', value= '#ff000080'},
{ name= 'magenta', value= '#ff00ff80'},
{ name= 'pink', value= '#ff808080'},
}
for num, strength in ipairs(strengths) do
minetest.register_node(string.format('telemosaic:extender_%s', strength), {
description = string.format('Telemosaic extender, tier %d', num),
tiles = {
string.format('telemosaic_extender_%s.png', strength)
},
paramtype = 'light',
groups = { cracky = 2, [string.format('telemosaic_extender_%s', strength)] = 1 },
after_place_node = extender_place,
after_dig_node = extender_dig,
})
-- colored versions, not in creative inventory, if dyes available
if minetest.get_modpath('dye') then
for _,c in ipairs(colors) do
minetest.register_node(string.format('telemosaic:extender_%s_%s', strength, c.name), {
description = string.format('Telemosaic extender, tier %d (%s)', num, c.name),
tiles = {
string.format('telemosaic_extender_%s.png^[colorize:%s', strength, c.value),
},
paramtype = 'light',
groups = {
cracky = 2,
[string.format('telemosaic_extender_%s', strength)] = 1,
not_in_creative_inventory = 1
},
after_place_node = extender_place,
after_dig_node = extender_dig,
})
end
end
end
-- coloring recipes
if minetest.get_modpath('dye') then
for num, strength in ipairs(strengths) do
-- uncolor
minetest.register_craft({
type = "shapeless",
output = string.format('telemosaic:extender_%s', strength),
recipe = { string.format('group:telemosaic_extender_%s', strength), 'dye:grey' },
})
-- color with dye
for _,c in ipairs(colors) do
minetest.register_craft({
type = "shapeless",
output = string.format('telemosaic:extender_%s_%s', strength, c.name),
recipe = { string.format('group:telemosaic_extender_%s', strength), string.format('dye:%s', c.name) },
})
end
end
end
telemosaic.travel_allowed = function(player, src, dest)
return true
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 B

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 B

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 B

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 B

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 81 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 B

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 B

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 365 B

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 B

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 B

After

Width:  |  Height:  |  Size: 92 B