Fork into scriptblocks

This commit is contained in:
luk3yx 2018-09-06 15:04:07 +12:00
parent 1011eb14f3
commit a450b91c03
78 changed files with 989 additions and 1736 deletions

22
LICENSE.md Normal file
View File

@ -0,0 +1,22 @@
# MIT License
*Copyright © 2017 by rdococ*
*Copyright © 2018 by luk3yx*
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,35 +1,17 @@
# rmod
RMod mod for Minetest with various cool nodes.
# Scriptblocks
## Conveyors
A RMod fork that adds scriptblocks, allowing users to easily create programs
and send variables over long distances.
Conveyors are nodes that can carry entities, such as players and items. There are a few bugs with it, but it works fine for the most part.
## RMod compatibility
### Meseconveyors
The scriptblocks mod aims to keep backwards compatibility with rmod, so servers
that used to use or are even still using rmod will face no issues when changing
to scriptblocks. However, moving back from scriptblocks to rmod will void all
existing scriptblocks. Any complex scriptblocks machine (over 30 nodes long)
will be "cut off" by the new anti-denial-of-service system.
Meseconveyors are conveyors which can be activated and deactivated with mesecons.
### Digiconveyors
Digiconveyors can not only be turned on and off with digilines, but they can also be reversed (which flips their facing direction). The messages available at the moment are "on", "off", "toggle" (functions as both "on" and "off"), "reverse" (inverts the direction), "left" (turns left 90 degrees) and "right".
## Crates
Crates are like chests, but you can pick them up with the items inside. As a result, you can also stack crates indefinitely.
## Grates
Grates are nodes which let water flow through, but not players or items.
### Mesegrates
Mesegrates are self-explanatory - power them, and they let liquids flow.
### Digigrates
Digigrates can be adjusted by sending messages - they include "on", "off", "toggle" and "set". That last one, "set", is sent as a table {command = "sent", value = x}, substituting x for the percentage of water you want to pass through (although, tbh, it's more complicated than that).
## Scriptblocks
## Original description
Scriptblocks are blocks that you can use for creating simple programs. They are one of the most complicated parts of this mod, which can be a good thing or a bad thing depending on your viewpoint.

View File

@ -1,24 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>

View File

@ -1,119 +0,0 @@
local rmod_conveyor_top_animated = {
name = "rmod_conveyor_top_animated.png",
backface_culling = true,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1/8, -- it takes 1 second to move 16 pixels, thus 1/16 seconds to move one pixel. but this animation is two pixels per runthrough.
},
}
local rmod_conveyor_top_animated_2 = {
name = "rmod_conveyor_top_animated_2.png", -- Higher resolution version with 4 frames as opposed to 2.
backface_culling = true,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1/8, -- it takes 1 second to move 16 pixels, thus 1/16 seconds to move one pixel. but this animation is two pixels per runthrough.
},
}
local rmod_conveyor_top_animated_2_reversed = { -- Reversed animation for the Z+ face.
name = "rmod_conveyor_top_animated_2_reversed.png", -- Higher resolution version with 4 frames as opposed to 2.
backface_culling = true,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1/8, -- it takes 1 second to move 16 pixels, thus 1/16 seconds to move one pixel. but this animation is two pixels per runthrough.
},
}
minetest.register_node("rmod:conveyor", {
description = "Conveyor",
--[[tiles = {"rmod_conveyor_top.png", "rmod_conveyor_top.png", "rmod_conveyor_side.png", "rmod_conveyor_side.png", "rmod_conveyor_top.png", "rmod_conveyor_top.png"},]]
tiles = {
rmod_conveyor_top_animated_2, rmod_conveyor_top_animated_2,
"rmod_conveyor_side.png", "rmod_conveyor_side.png",
rmod_conveyor_top_animated_2_reversed, rmod_conveyor_top_animated_2 -- You have to reverse one of the faces to go UP, not DOWN.
},
groups = {oddly_breakable_by_hand = 1, conveyor = 1},
use_texture_alpha = true,
paramtype2 = "facedir",
})
local getnode = function (pos)
return minetest.get_node(pos)
end
local getname = function (pos)
return getnode(pos).name
end
local getdef = function (pos)
return minetest.registered_nodes[getname(pos)]
end
local round = function (n)
return math.floor(n + 0.5)
end
local timer = 0
minetest.register_globalstep(function (dtime)
timer = timer + dtime
if timer > 1 then timer = 0 else return end -- The code below should only execute once every second.
for _,entity in pairs(minetest.object_refs) do -- We cycle the entities because it then means we don't have to try to keep a queue of each entity.
local isplayer = entity:is_player()
local position = entity:getpos()
local roundedpos = {x=round(position.x), y=round(position.y), z=round(position.z)}
local surface = vector.subtract(roundedpos, {x=0,y=1,z=0})
local node = getnode(surface)
local name = getname(surface)
local def = getdef(surface)
if def and def.groups.conveyor == 1 then -- I might replace this with a group, e.g. def.groups.conveyor, so you can set the speed.
local facing = node.param2 -- Param2 is the facedir as defined above - conveyors face the opposite direction they move you.
local direction = minetest.facedir_to_dir(facing)
local movement = vector.multiply(direction, {x=1, y=1, z=1}) -- We reversed the facing system recently.
local newpos = vector.add(position, movement)
local newrpos = {x=round(newpos.x), y=round(newpos.y), z=round(newpos.z)}
local newnode = getnode(newrpos)
local newname = getname(newrpos)
local newdef = getdef(newrpos)
-- If we can move any entity forward and up, we'll need to check here.
-- If we can move the player forward, we'll need to check here anyway.
local upos = vector.add(newpos, {x=0, y=1, z=0})
local roundedupos = {x=round(upos.x), y=round(upos.y), z=round(upos.z)}
local unode = getnode(roundedupos)
local uname = getname(roundedupos)
local udef = getdef(roundedupos)
if newdef.walkable then
if newdef.groups.conveyor == 1 and newnode.param2 == facing then
-- Okay, so the entity will be moving into a node.
-- But it just so happens that this node is also a conveyor!
-- Plus, it's moving in the same direction!
-- Let's see if we can move the entity up and forward.
-- We should also probably check for the node above it, if the entity is a player.
-- We don't want their head in a node, after all.
local uupos = vector.add(upos, {x=0, y=1, z=0})
local roundeduupos = {x=round(uupos.x), y=round(uupos.y), z=round(uupos.z)}
local uunode = getnode(roundeduupos)
local uuname = getname(roundeduupos)
local uudef = getdef(roundeduupos)
if not udef.walkable and ((not isplayer) or (not uudef.walkable)) then -- Ooh! We /can/ move the entity here!
entity:setpos(upos)
end
end
elseif (not isplayer) or (not udef.walkable) then -- When we move the entity, either the entity's not a player, or they have head room.
entity:setpos(newpos)
end
end
end
end)

159
core.lua Normal file
View File

@ -0,0 +1,159 @@
--
-- Minetest scriptblocks mod - Core
--
--
-- scriptblock = function(pos, node, sender, info, last, main_channel)
-- 'pos' and 'node' are the position and the node information of the
-- scriptblock being ran.
-- 'sender' would be the position of the node responsible for activating it.
-- 'info' is any information the previous node has sent to it.
-- 'last' is the information that 'info' /was/ before it was last changed.
-- 'channel' is the channel in which variables are stored.
--
-- <insert function code here>
--
-- return new_info, faces
-- Information to pass to the next node(s), and information on which adjacent
-- spaces we should even try to signal to. This return statement is
-- optional and can be omitted entirely.
-- end
-- Original rmod functions
scriptblocks.stringify = function(t)
if type(t) ~= 'table' then return tostring(t) end
return minetest.serialize(t):sub(('return '):len()+1, -1)
end
scriptblocks.compare = function(a, b)
-- Compare two tables by comparing their values -
-- also make sure to support nested tables.
if type(a) ~= 'table' or type(b) ~= 'table' then return a == b end
for i,j in pairs(a) do
if not compare(j, b[i]) then return false end
end
for i,j in pairs(b) do
if not compare(j, a[i]) then return false end
end
return true
end
-- TODO: Replace these functions with better ones
scriptblocks.get_storage = function()
return minetest.deserialize(
scriptblocks.storage:get_string('scriptblock')
) or {}
end
scriptblocks.set_storage = function(data)
return scriptblocks.storage:set_string('scriptblock', minetest.serialize(data))
end
-- To avoid lag and stack overflows, we add the data to a queue and then execute it with a globalstep.
local queue = {}
-- Easily add items to the queue
scriptblocks.queue = function(pos, sender, info, last, channel)
table.insert(queue, {pos, sender, info, last, channel})
end
-- Directly execute a scriptblock and return a queue with more scriptblocks
scriptblocks.run = function(pos, sender, info, last, channel, executions)
local local_queue = {}
if executions == nil then
executions = scriptblocks.max_length
elseif executions <= 0 then
return
end
-- Get information about this script block we are told to execute.
local node = minetest.get_node(pos)
local name = node.name
local def = minetest.registered_nodes[name]
-- If the block is a script block...
if def and def.scriptblock then
local new_info, faces = def.scriptblock(pos, node, sender, info, last, channel)
if not faces then
faces = {true, true, true, true, true, true}
end
-- Check neighboring nodes; if they also have scriptblock and aren't the sender, execute them.
for i=1,6 do
if faces[i] then
local dir = vector.new(0, 0, 0)
if i == 1 then dir.y = 1
elseif i == 2 then dir.y = -1
elseif i == 3 then dir.x = 1
elseif i == 4 then dir.x = -1
elseif i == 5 then dir.z = 1
elseif i == 6 then dir.z = -1 end
local new_pos = vector.add(pos, dir)
-- This is required, otherwise you'd have an unintentional feedback loop.
-- Feedback loops can still be created intentionally, though.
if not vector.equals(new_pos, sender) then
local new_node = minetest.get_node(new_pos)
local new_name = new_node.name
local new_def = minetest.registered_nodes[new_name]
if new_def and new_def.scriptblock then
local new_last
if new_info ~= nil then -- If something has been pushed to the stack,
new_last = info -- we update @last.
else
new_info = info -- Why bother updating it?
new_last = last
end
table.insert(local_queue, { new_pos, pos, new_info,
new_last, channel, executions - 1 })
end
end
end
end
end
return local_queue
end
-- Escape text
scriptblocks.escape = function(text, info, last)
local info = tostring(info or '')
local last = tostring(last or '')
if text == '@info' then return info end
if text == '@last' then return last end
if type(info) == 'table' then info = scriptblocks.stringify(info) or '' end
if type(last) == 'table' then last = scriptblocks.stringify(last) or '' end
return text and text:gsub('@info', info):gsub('@last', last)
end
-- Handle queued scriptblocks
minetest.register_globalstep(function(dtime)
local new_queue = {}
for i,data in pairs(queue) do
local new_list = scriptblocks.run(unpack(data))
if new_list then
for _,new_item in pairs(new_list) do
table.insert(new_queue, new_item)
end
end
if i > scriptblocks.max_per_step then
queue = new_queue
return
end
end
queue = new_queue
end)
-- A register with alias function to automatically add aliases
-- Uses register_alias_force() to unregister the original rmod one first.
scriptblocks.register_with_alias = function(name, def)
local new_name = minetest.get_current_modname() .. ':' .. name
minetest.register_node(new_name, def)
minetest.register_alias_force('rmod:scriptblock_' .. name, new_name)
end

View File

@ -1,97 +0,0 @@
minetest.register_node("rmod:crate", {
description = "Crate",
on_construct = function (pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size("main", 8*4)
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
local item_meta = minetest.deserialize(itemstack:get_meta():get_string("inv"))
local node_meta = minetest.get_meta(pos)
node_meta:set_string("formspec", [[size[8, 9]
list[context;main;0,0;8,4;]
list[current_player;main;0,5;8,4;]
]])
local infotext = "Empty Crate"
if item_meta and #item_meta > 0 then
infotext = "Crate containing:"
local i = 0
for _,istack in pairs(item_meta) do
node_meta:get_inventory():add_item("main", ItemStack(istack))
if i < 3 then
local stack = ItemStack(istack)
local name = stack:get_name()
local def = minetest.registered_items[name] or minetest.registered_nodes[name]
local desc = def and def.description or name
local count = stack:get_count()
infotext = infotext .. "\n" .. tostring(count) .. "x " .. desc
end
i = i + 1
end
if i > 3 then
infotext = infotext .. "\n" .. "...and more."
end
end
node_meta:set_string("infotext", infotext)
print(dump(item_meta))
end,
on_receive_fields = function(pos)
local node_meta = minetest.get_meta(pos)
local string_inventory = {}
for _,istack in pairs(node_meta:get_inventory():get_list("main")) do
table.insert(string_inventory, istack:to_table())
end
local infotext = "Empty Crate"
if not node_meta:get_inventory():is_empty("main") then
infotext = "Crate containing:"
local i = 0
for _,istack in pairs(string_inventory) do
if i < 3 then
local stack = ItemStack(istack)
local name = stack:get_name()
local def = minetest.registered_items[name] or minetest.registered_nodes[name]
local desc = def and def.description or name
local count = stack:get_count()
infotext = infotext .. "\n" .. tostring(count) .. "x " .. desc
end
i = i + 1
end
if i > 3 then
infotext = infotext .. "\n" .. "...and more."
end
end
node_meta:set_string("infotext", infotext)
end,
on_dig = function(pos, node, player)
local node_meta = minetest.get_meta(pos)
local inv = player:get_inventory()
local stack = ItemStack( {name="rmod:crate", count=1, wear=0} )
local string_inventory = {}
for _,istack in pairs(node_meta:get_inventory():get_list("main")) do
table.insert(string_inventory, istack:to_table())
end
stack:get_meta():set_string("inv", minetest.serialize(string_inventory) )
print(dump(node_meta:to_table().inventory))
inv:add_item("main", stack)
minetest.remove_node(pos)
end,
tiles = {"rmod_crate.png"},
groups = {oddly_breakable_by_hand = 2, choppy = 2},
})

View File

@ -1,2 +1,3 @@
mesecons?
digilines?
rmod?

View File

@ -1 +0,0 @@
Multipurpose mod with conveyors, grates, crates and programming blocks.

View File

@ -1,166 +0,0 @@
local rmod_conveyor_top_animated = {
name = "rmod_conveyor_top_animated.png",
backface_culling = true,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1/8, -- it takes 1 second to move 16 pixels, thus 1/16 seconds to move one pixel. but this animation is two pixels per runthrough.
},
}
local rmod_conveyor_top_animated_2 = {
name = "rmod_conveyor_top_animated_2.png", -- Higher resolution version with 4 frames as opposed to 2.
backface_culling = true,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1/8, -- it takes 1 second to move 16 pixels, thus 1/16 seconds to move one pixel. but this animation is two pixels per runthrough.
},
}
local rmod_conveyor_top_animated_2_reversed = { -- Reversed animation for the Z+ face.
name = "rmod_conveyor_top_animated_2_reversed.png", -- Higher resolution version with 4 frames as opposed to 2.
backface_culling = true,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1/8, -- it takes 1 second to move 16 pixels, thus 1/16 seconds to move one pixel. but this animation is two pixels per runthrough.
},
}
local digiconveyor_rules = {
{x=0, y=0, z=-1},
{x=1, y=0, z=0},
{x=-1, y=0, z=0},
{x=0, y=0, z=1},
{x=1, y=1, z=0},
{x=1, y=-1, z=0},
{x=-1, y=1, z=0},
{x=-1, y=-1, z=0},
{x=0, y=1, z=1},
{x=0, y=-1, z=1},
{x=0, y=1, z=-1},
{x=0, y=-1, z=-1},
{x=0, y=-1, z=0},
}
local overlay_off = "^rmod_digiconveyor_overlay_off.png"
local overlay_on = "^rmod_digiconveyor_overlay_on.png"
local side_overlay_off = "^rmod_digiconveyor_side_overlay_off.png"
local side_overlay_on = "^rmod_digiconveyor_side_overlay_on.png"
local rmod_digiconveyor_top_off = "rmod_conveyor_top_off.png" .. overlay_off -- Un-animated version of the conveyor texture.
local rmod_digiconveyor_top_off_reversed = "rmod_conveyor_top_off_reversed.png" .. overlay_off -- I probably should just [rotate it.
local rmod_digiconveyor_top_animated_2 = rmod_conveyor_top_animated_2
rmod_digiconveyor_top_animated_2.name = rmod_conveyor_top_animated_2.name .. overlay_on
local rmod_digiconveyor_top_animated_2_reversed = rmod_conveyor_top_animated_2_reversed
rmod_digiconveyor_top_animated_2_reversed.name = rmod_conveyor_top_animated_2_reversed.name .. overlay_on
local function digiconveyor_off_digiline_receive (pos, node, channel, msg)
local setchan = minetest.get_meta(pos):get_string("channel")
local param2 = minetest.get_node(pos).param2
if channel == setchan then
if msg == "on" or msg == "toggle" then
minetest.swap_node(pos, {name = "rmod:digiconveyor_on", param2 = node.param2})
elseif msg == "reverse" then
minetest.swap_node(pos, {name = node.name, param2 = (node.param2 + 2) % 4})
elseif msg == "right" then
minetest.swap_node(pos, {name = node.name, param2 = (node.param2 + 1) % 4})
elseif msg == "left" then
minetest.swap_node(pos, {name = node.name, param2 = (node.param2 - 1) % 4})
end
end
end
local function digiconveyor_on_digiline_receive (pos, node, channel, msg)
local setchan = minetest.get_meta(pos):get_string("channel")
local param2 = minetest.get_node(pos).param2
if channel == setchan then
if msg == "off" or msg == "toggle" then
minetest.swap_node(pos, {name = "rmod:digiconveyor_off", param2 = node.param2})
elseif msg == "reverse" then
minetest.swap_node(pos, {name = node.name, param2 = (node.param2 + 2) % 4})
elseif msg == "right" then
minetest.swap_node(pos, {name = node.name, param2 = (node.param2 + 1) % 4})
elseif msg == "left" then
minetest.swap_node(pos, {name = node.name, param2 = (node.param2 - 1) % 4})
end
end
end
minetest.register_node("rmod:digiconveyor_off", {
description = "Digiconveyor",
tiles = {
rmod_digiconveyor_top_off, rmod_digiconveyor_top_off,
"rmod_conveyor_side.png" .. side_overlay_off, "rmod_conveyor_side.png" .. side_overlay_off,
rmod_digiconveyor_top_off_reversed, rmod_digiconveyor_top_off
},
groups = {oddly_breakable_by_hand = 1},
use_texture_alpha = true,
paramtype2 = "facedir",
digiline =
{
receptor = {},
effector = {
action = digiconveyor_off_digiline_receive
},
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", "field[channel;Channel;${channel}]")
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.channel) then
minetest.get_meta(pos):set_string("channel", fields.channel)
end
end,
})
minetest.register_node("rmod:digiconveyor_on", {
description = "Active Digiconveyor (you hacker you!)",
tiles = {
rmod_digiconveyor_top_animated_2, rmod_digiconveyor_top_animated_2,
"rmod_conveyor_side.png" .. side_overlay_on, "rmod_conveyor_side.png" .. side_overlay_on,
rmod_digiconveyor_top_animated_2_reversed, rmod_digiconveyor_top_animated_2
},
groups = {oddly_breakable_by_hand = 1, conveyor = 1, not_in_creative_inventory = 1},
drop = "rmod:digiconveyor_off",
use_texture_alpha = true,
paramtype2 = "facedir",
digiline =
{
receptor = {},
effector = {
action = digiconveyor_on_digiline_receive
},
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", "field[channel;Channel;${channel}]")
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.channel) then
minetest.get_meta(pos):set_string("channel", fields.channel)
end
end,
})

View File

@ -1,117 +0,0 @@
local function calculate_dec (value)
-- Our mission: convert a user-provided value (how open the grate should be),
-- into a dec value (how much the water should decrease when it flows through a grate).
-- 0 -> 8 = 2^3
-- 50% -> 4 = 2^2
-- 100% -> 2 = 2^1
local max = 100 -- atm
local dec = max - value -- 0-50-100 -> 100-50-0
dec = dec * 2 / max -- 100-50-0 -> 2-1-0
dec = dec + 1 -- 2-1-0 -> 3-2-1
dec = 2^dec -- 3-2-1 -> 8-4-2
if dec > 8 then dec = 8 end
if dec < 2 then dec = 2 end
return math.floor(dec + 0.5) -- We're storing the dec value as an int, simply because water cannot have a fractional level.
end
local function digigrate_off_digiline_receive (pos, node, channel, msg)
local setchan = minetest.get_meta(pos):get_string("channel")
local param2 = minetest.get_node(pos).param2
if channel == setchan then
if msg == "on" or msg == "toggle" then
minetest.swap_node(pos, {name = "rmod:digigrate_on"})
elseif type(msg) == "table" and msg.command == "set" and tonumber(msg.value) then
minetest.get_meta(pos):set_int("dec", calculate_dec(tonumber(msg.value)))
end
end
end
local function digigrate_on_digiline_receive (pos, node, channel, msg)
local setchan = minetest.get_meta(pos):get_string("channel")
local param2 = minetest.get_node(pos).param2
if channel == setchan then
if msg == "off" or msg == "toggle" then
minetest.swap_node(pos, {name = "rmod:digigrate_off"})
elseif type(msg) == "table" and msg.command == "set" and tonumber(msg.value) then
minetest.get_meta(pos):set_int("dec", calculate_dec(tonumber(msg.value)))
end
end
end
minetest.register_node("rmod:digigrate_off", {
description = "Digigrate",
tiles = {"rmod_grate.png^rmod_digigrate_overlay_off.png"},
groups = {oddly_breakable_by_hand = 1},
use_texture_alpha = true,
--drawtype = "glasslike",
paramtype = "light",
digiline =
{
receptor = {},
effector = {
action = digigrate_off_digiline_receive
},
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", "field[channel;Channel;${channel}]")
meta:set_int("dec", 2)
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.channel) then
minetest.get_meta(pos):set_string("channel", fields.channel)
end
end,
})
minetest.register_node("rmod:digigrate_on", {
description = "Active Digigrate (you hacker you!)",
tiles = {"rmod_grate.png^rmod_digigrate_overlay_on.png"},
groups = {oddly_breakable_by_hand = 1, not_in_creative_inventory = 1},
use_texture_alpha = true,
drawtype = "glasslike",
paramtype = "light",
digiline = {
receptor = {},
effector = {
action = digigrate_on_digiline_receive
},
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", "field[channel;Channel;${channel}]")
meta:set_int("dec", 2)
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.channel) then
minetest.get_meta(pos):set_string("channel", fields.channel)
end
end,
drop = "rmod:digigrate_off"
})
minetest.register_abm({
label = "Digigrate Step",
nodenames = {"rmod:digigrate_on"},
neighbors = {},
interval = 1,
chance = 1,
action = function (pos, node)
local meta = minetest.get_meta(pos)
local dec = meta:get_int("dec")
rmod.grate.flow(pos, node, dec)
end,
})

88
digilines.lua Normal file
View File

@ -0,0 +1,88 @@
--
-- Scriptblocks - Digilines
--
-- Digiline receivers
scriptblocks.register_with_alias('digiline_receiver', {
description = 'Scriptblocks: Digiline Receiver',
tiles = {'scriptblocks_digiline.png'},
groups = {oddly_breakable_by_hand = 1},
use_texture_alpha = true,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string('formspec', [[
field[progchannel;]] .. scriptblocks.program_channel .. [[;${progchannel}]
field[digichannel;Digiline channel;${digichannel}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.digichannel) then
minetest.get_meta(pos):set_string('digichannel', fields.digichannel)
end
if (fields.progchannel) then
minetest.get_meta(pos):set_string('progchannel', fields.progchannel)
end
end,
scriptblock = function (pos, node, sender, info, last, main_channel)
return
end,
digiline = {
receptor = {},
effector = {
action = function (pos, node, msgchannel, msg)
local meta = minetest.get_meta(pos)
local progchannel = meta:get_string('progchannel')
local digichannel = meta:get_string('digichannel')
if msgchannel ~= digichannel then return end
scriptblocks.queue(pos, pos, msg, '', progchannel or '')
end,
}}
})
-- Digiline senders
scriptblocks.register_with_alias('digiline_sender', {
description = 'Scriptblocks: Digiline Sender',
tiles = {'scriptblocks_digiline_sender.png'},
groups = {oddly_breakable_by_hand = 1},
use_texture_alpha = true,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string('formspec', [[
field[channel;Digiline channel;${channel}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.channel) then
minetest.get_meta(pos):set_string('channel', fields.channel)
end
end,
scriptblock = function (pos, node, sender, info, last, main_channel)
if not digiline then return end
local meta = minetest.get_meta(pos)
local channel = meta:get_string('channel')
digiline:receptor_send(pos, digiline.rules.default, channel, info)
return
end,
digiline = {
receptor = {},
effector = {action = function (pos, node, msgchannel, msg)
end,}
}
})
-- Legacy rmod alias
minetest.register_alias_force('rmod:scriptblock_digiline',
'scriptblocks:digiline_receiver')

117
grate.lua
View File

@ -1,117 +0,0 @@
minetest.register_node("rmod:grate", {
description = "Grate",
tiles = {"rmod_grate.png"},
groups = {oddly_breakable_by_hand = 1, grate = 2},
use_texture_alpha = true,
drawtype = "glasslike",
paramtype = "light",
})
local function get_level(node, def)
local level = node.param2 % 16
local falling = false
if level > 8 then level = level - 8; falling = true end
if def and def.liquidtype == "source" then level = 8 end -- Ooh, this node is a SOURCE! MAX LEVEL!
if def and def.liquidtype ~= "flowing" and def.liquidtype ~= "source" then
level = def.floodable and -1 or math.huge -- Okay, the node isn't liquid. But we can still determine whether it contains undisplaceable matter.
end
if not def then level = 8 end
return level, falling
end
local function get_variables(pos)
local node = minetest.get_node(pos)
local name
if node then name = node.name else return end
local def = minetest.registered_nodes[name]
local level, falling = get_level(node, def)
return node, name, def, level, falling
end
local function calculate_level(pos)
return ({get_variables(pos)})[4], ({get_variables(pos)})[5]
end
local function attempt_flow_to(pos1, pos2, dec)
-- Try flowing from pos1 to pos2.
local node1, name1, def1, level1, falling1 = get_variables(pos1)
-- Flowing1 is the node we may or may not eventually place.
local flowing1 = def1.liquid_alternative_flowing
-- Non-liquids can't flow, derrr.
if def1.liquidtype ~= "source" and def1.liquidtype ~= "flowing" then return end
if not flowing1 then return end
-- If this water is falling, it's not about to spread out just because a grate's nearby.
if falling1 then return end
local node2, name2, def2, level2, falling2 = get_variables(pos2)
-- If we're flowing down, gravity is most likely going to aid.
-- Therefore, we should set the values accordingly.
local gravity = false
if pos2.y < pos1.y then
gravity = true
-- Opposite reasoning of above.
elseif pos2.y > pos1.y then return end
local new_level = level1 - dec
if gravity then new_level = 15 end
-- When water flows normally, it slowly decreases as it spreads outwards.
-- Dec is the variable applied to the originating liquid's level, which
-- the resulting output flow is decreased by.
-- Usually this value is 2, but I'm allowing for customization.
if new_level <= level2 then return end
-- Well, duh! Water can't have a negative level!
if new_level < 0 then return end
minetest.set_node(pos2, {
name = flowing1,
param1 = pos1.param1,
param2 = new_level
})
return true
end
local function grate_step(pos, offset, grate)
local pos1 = vector.add(pos, offset)
if not attempt_flow_to(pos1, vector.subtract(pos, {x=0,y=1,z=0}), grate) then -- If we can't flow below...
local left_offset = {x = offset.z, y = 0, z = -offset.x}
local right_offset = {x = -offset.z, y = 0, z = offset.x}
attempt_flow_to(pos1, vector.subtract(pos, offset), grate) -- Try flowing forward.
attempt_flow_to(pos1, vector.add(pos, left_offset), grate) -- Try flowing left.
attempt_flow_to(pos1, vector.add(pos, right_offset), grate) -- And try flowing right.
end
end
rmod.grate = {}
rmod.grate.flow = function (pos, node, dec)
for i=1,5 do -- For each of our 5 neighbors, (excluding the node from below, of course)
-- Calculate where our neighbor is
local offset = {x=0,y=0,z=0}
if i == 1 then offset.y = 1 end
--if i == 2 then offset.y = -1 end
if i == 2 then offset.x = 1 end
if i == 3 then offset.x = -1 end
if i == 4 then offset.z = 1 end
if i == 5 then offset.z = -1 end
-- Then run the checking code
grate_step(pos, offset, dec)
end
end
minetest.register_abm({
label = "Grate Step",
nodenames = {"group:grate"},
neighbors = {},
interval = 1,
chance = 1,
action = function (pos, node) rmod.grate.flow(pos, node, 2) end
})

View File

@ -1,16 +1,34 @@
rmod = {} -- In case we need to allow other mods/files to access information.
local modpath = minetest.get_modpath("rmod")
--
-- Minetest scriptblocks mod
--
dofile(modpath .. "/grate.lua")
dofile(modpath .. "/conveyor.lua")
dofile(modpath .. "/crate.lua")
dofile(modpath .. "/scriptblock.lua")
-- Settings
scriptblocks = {
-- The maximum length of scriptblocks scripts.
max_length = 30,
-- The maximum amount of scriptblocks processed during a globalstep
max_per_step = 24,
}
if minetest.get_modpath("mesecons") then
dofile(modpath .. "/meseconveyor.lua")
dofile(modpath .. "/mesegrate.lua")
-- Get the mod path and storage
local modpath = minetest.get_modpath('scriptblocks')
scriptblocks.storage = minetest.get_mod_storage()
-- Load scriptblocks lua files
dofile(modpath .. '/core.lua')
dofile(modpath .. '/scriptblock.lua')
-- Load mesecons and digilines scriptblocks
if minetest.get_modpath('mesecons') then
dofile(modpath .. '/mesecons.lua')
end
if minetest.get_modpath("digilines") then
dofile(modpath .. "/digiconveyor.lua")
dofile(modpath .. "/digigrate.lua")
if minetest.get_modpath('digilines') then
dofile(modpath .. '/digilines.lua')
end
-- Override rmod scriptblock functions.
if minetest.get_modpath('rmod') then
rmod.scriptblock = scriptblocks
end

47
mesecons.lua Normal file
View File

@ -0,0 +1,47 @@
--
-- Scriptblocks - Mesecons
--
-- Mesecon receiver
scriptblocks.register_with_alias('mesecon_receiver', {
description = 'Scriptblocks: Mesecon Receiver',
tiles = {'scriptblocks_mesecon.png'},
groups = {oddly_breakable_by_hand = 1},
use_texture_alpha = true,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string('formspec', [[
field[channel;]] .. scriptblocks.program_channel .. [[;${channel}]
field[info;Starting @info;${info}]
]])
end,
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name()
if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, name)
return
end
if (fields.channel) then
minetest.get_meta(pos):set_string('channel', fields.channel)
end
if (fields.info) then
minetest.get_meta(pos):set_string('info', fields.info)
end
end,
scriptblock = function (pos, node, sender, info, last, main_channel)
return
end,
mesecons = {effector = {
action_on = function (pos, node)
local meta = minetest.get_meta(pos)
local channel = meta:get_string('channel')
local info = meta:get_string('info')
scriptblocks.queue(pos, pos, info or '', '', channel or '')
end,
}}
})
-- Legacy rmod alias
minetest.register_alias_force('rmod:scriptblock_mesecon',
'scriptblocks:mesecon_receiver')

View File

@ -1,86 +0,0 @@
local rmod_conveyor_top_animated = {
name = "rmod_conveyor_top_animated.png",
backface_culling = true,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1/8, -- it takes 1 second to move 16 pixels, thus 1/16 seconds to move one pixel. but this animation is two pixels per runthrough.
},
}
local rmod_conveyor_top_animated_2 = {
name = "rmod_conveyor_top_animated_2.png", -- Higher resolution version with 4 frames as opposed to 2.
backface_culling = true,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1/8, -- it takes 1 second to move 16 pixels, thus 1/16 seconds to move one pixel. but this animation is two pixels per runthrough.
},
}
local rmod_conveyor_top_animated_2_reversed = { -- Reversed animation for the Z+ face.
name = "rmod_conveyor_top_animated_2_reversed.png", -- Higher resolution version with 4 frames as opposed to 2.
backface_culling = true,
animation = {
type = "vertical_frames",
aspect_w = 32,
aspect_h = 32,
length = 1/8, -- it takes 1 second to move 16 pixels, thus 1/16 seconds to move one pixel. but this animation is two pixels per runthrough.
},
}
local overlay_off = "^rmod_meseconveyor_overlay_off.png"
local overlay_on = "^rmod_meseconveyor_overlay_on.png"
local side_overlay_off = "^rmod_meseconveyor_side_overlay_off.png"
local side_overlay_on = "^rmod_meseconveyor_side_overlay_on.png"
local rmod_meseconveyor_top_off = "rmod_conveyor_top_off.png" .. overlay_off -- Un-animated version of the conveyor texture.
local rmod_meseconveyor_top_off_reversed = "rmod_conveyor_top_off_reversed.png" .. overlay_off -- I probably should just [rotate it.
local rmod_meseconveyor_top_animated_2 = rmod_conveyor_top_animated_2
rmod_meseconveyor_top_animated_2.name = rmod_conveyor_top_animated_2.name .. overlay_on
local rmod_meseconveyor_top_animated_2_reversed = rmod_conveyor_top_animated_2_reversed
rmod_meseconveyor_top_animated_2_reversed.name = rmod_conveyor_top_animated_2_reversed.name .. overlay_on
minetest.register_node("rmod:meseconveyor_off", {
description = "Meseconveyor",
tiles = {
rmod_meseconveyor_top_off, rmod_meseconveyor_top_off,
"rmod_conveyor_side.png" .. side_overlay_off, "rmod_conveyor_side.png" .. side_overlay_off,
rmod_meseconveyor_top_off_reversed, rmod_meseconveyor_top_off
},
groups = {oddly_breakable_by_hand = 1, mesecon = 2},
use_texture_alpha = true,
paramtype2 = "facedir",
mesecons = {effector = {
--rules = meseconveyor_rules,
action_on = function (pos, node)
minetest.swap_node(pos, {name = "rmod:meseconveyor_on", param2 = node.param2})
end,
}}
})
minetest.register_node("rmod:meseconveyor_on", {
description = "Active Meseconveyor (you hacker you!)",
tiles = {
rmod_meseconveyor_top_animated_2, rmod_meseconveyor_top_animated_2,
"rmod_conveyor_side.png" .. side_overlay_on, "rmod_conveyor_side.png" .. side_overlay_on,
rmod_meseconveyor_top_animated_2_reversed, rmod_meseconveyor_top_animated_2
},
groups = {oddly_breakable_by_hand = 1, conveyor = 1, not_in_creative_inventory = 1, mesecon = 2},
drop = "rmod:meseconveyor_off",
use_texture_alpha = true,
paramtype2 = "facedir",
mesecons = {effector = {
--rules = meseconveyor_rules,
action_off = function (pos, node)
minetest.swap_node(pos, {name = "rmod:meseconveyor_off", param2 = node.param2})
end,
}}
})

View File

@ -1,42 +0,0 @@
minetest.register_node("rmod:mesegrate_off", {
description = "Mesegrate",
tiles = {"rmod_grate.png^rmod_mesegrate_overlay_off.png"},
groups = {oddly_breakable_by_hand = 1, mesecon = 2},
use_texture_alpha = true,
--drawtype = "glasslike",
paramtype = "light",
mesecons = {
conductor = {
-- rules = rules,
state = mesecon.state.off,
onstate = "rmod:mesegrate_on"
},
effector = {
action_on = function (pos, node)
minetest.swap_node(pos, {name = "rmod:mesegrate_on", param2 = node.param2})
end,
}
}
})
minetest.register_node("rmod:mesegrate_on", {
description = "Active Mesegrate (you hacker you!)",
tiles = {"rmod_grate.png^rmod_mesegrate_overlay_on.png"},
groups = {oddly_breakable_by_hand = 1, grate = 2, mesecon = 2, not_in_creative_inventory = 1},
use_texture_alpha = true,
drawtype = "glasslike",
paramtype = "light",
mesecons = {
conductor = {
-- rules = rules,
state = mesecon.state.on,
offstate = "rmod:mesegrate_off"
},
effector = {
action_off = function (pos, node)
minetest.swap_node(pos, {name = "rmod:mesegrate_off", param2 = node.param2})
end,
}
},
drop = "rmod:mesegrate_off"
})

View File

@ -1 +0,0 @@
name = rmod

14
mud.lua
View File

@ -1,14 +0,0 @@
minetest.register_node("rmod:mud", {
drawtype = "flowingliquid",
tiles = {"rmod_mud.png"},
groups = {oddly_breakable_by_hand = 1},
use_texture_alpha = true,
walkable = false,
after_place_node = function (pos)
local node = minetest.get_node(pos)
node.param2 = 0
minetest.set_node(pos, node)
end
})

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +0,0 @@
minetest.register_node("rmod:mud", {
drawtype = "flowingliquid",
tiles = {"rmod_mud.png"},
groups = {oddly_breakable_by_hand = 1},
use_texture_alpha = true,
walkable = false
after_place_node = function (pos)
local node = minetest.get_node(pos)
node.param2 = 0
minetest.set_node(pos, node)
end
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 B

View File

Before

Width:  |  Height:  |  Size: 226 B

After

Width:  |  Height:  |  Size: 226 B

View File

Before

Width:  |  Height:  |  Size: 251 B

After

Width:  |  Height:  |  Size: 251 B

View File

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 227 B

View File

Before

Width:  |  Height:  |  Size: 244 B

After

Width:  |  Height:  |  Size: 244 B

View File

Before

Width:  |  Height:  |  Size: 243 B

After

Width:  |  Height:  |  Size: 243 B

View File

Before

Width:  |  Height:  |  Size: 215 B

After

Width:  |  Height:  |  Size: 215 B

View File

Before

Width:  |  Height:  |  Size: 219 B

After

Width:  |  Height:  |  Size: 219 B

View File

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 253 B

View File

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 269 B

View File

Before

Width:  |  Height:  |  Size: 231 B

After

Width:  |  Height:  |  Size: 231 B

View File

Before

Width:  |  Height:  |  Size: 263 B

After

Width:  |  Height:  |  Size: 263 B

View File

Before

Width:  |  Height:  |  Size: 231 B

After

Width:  |  Height:  |  Size: 231 B

View File

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 264 B

View File

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 264 B

View File

Before

Width:  |  Height:  |  Size: 263 B

After

Width:  |  Height:  |  Size: 263 B

View File

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 238 B

View File

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 253 B

View File

Before

Width:  |  Height:  |  Size: 265 B

After

Width:  |  Height:  |  Size: 265 B

View File

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 269 B

View File

Before

Width:  |  Height:  |  Size: 278 B

After

Width:  |  Height:  |  Size: 278 B

View File

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 253 B

View File

Before

Width:  |  Height:  |  Size: 264 B

After

Width:  |  Height:  |  Size: 264 B

View File

Before

Width:  |  Height:  |  Size: 263 B

After

Width:  |  Height:  |  Size: 263 B

View File

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 227 B

View File

Before

Width:  |  Height:  |  Size: 246 B

After

Width:  |  Height:  |  Size: 246 B

View File

Before

Width:  |  Height:  |  Size: 271 B

After

Width:  |  Height:  |  Size: 271 B

View File

Before

Width:  |  Height:  |  Size: 267 B

After

Width:  |  Height:  |  Size: 267 B

View File

Before

Width:  |  Height:  |  Size: 216 B

After

Width:  |  Height:  |  Size: 216 B

View File

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 253 B

View File

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 253 B

View File

Before

Width:  |  Height:  |  Size: 216 B

After

Width:  |  Height:  |  Size: 216 B

View File

Before

Width:  |  Height:  |  Size: 240 B

After

Width:  |  Height:  |  Size: 240 B

View File

Before

Width:  |  Height:  |  Size: 245 B

After

Width:  |  Height:  |  Size: 245 B

View File

Before

Width:  |  Height:  |  Size: 225 B

After

Width:  |  Height:  |  Size: 225 B

View File

Before

Width:  |  Height:  |  Size: 249 B

After

Width:  |  Height:  |  Size: 249 B

View File

Before

Width:  |  Height:  |  Size: 254 B

After

Width:  |  Height:  |  Size: 254 B

View File

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 212 B

View File

Before

Width:  |  Height:  |  Size: 243 B

After

Width:  |  Height:  |  Size: 243 B