19 Commits

Author SHA1 Message Date
59a217ceb9 move router to its own file 2022-02-22 21:33:09 -05:00
0dbc57cbbe restructure format 2022-02-20 22:53:29 -05:00
ee4cbef811 remove unused node registration function 2022-02-20 22:39:40 -05:00
fc7c0ff095 reformat node file structure 2022-02-20 22:36:46 -05:00
1f28124569 split tetris out to seperate file 2022-02-20 22:22:12 -05:00
1ea698a1e1 update documentation 2022-02-20 22:05:23 -05:00
c46ec76c63 meow 2022-02-20 20:28:41 -05:00
aca2f138a8 add limited network functionality 2022-02-20 19:03:52 -05:00
8267c4d71f improve browser tab default 2022-02-19 16:06:17 -05:00
fa1f4894af add lua sandbox, tabs, stuff 2022-02-18 17:29:31 -05:00
2593c55ee3 priv gate things + bugfixes 2022-02-13 10:43:41 -05:00
3e4e65e01b additional security 2022-02-13 00:44:14 -05:00
2060c59920 add missing filepaths 2022-02-13 00:33:22 -05:00
4cfacb1abc add filesystem 2022-02-13 00:31:20 -05:00
ef2ceed755 add commands to terminal 2022-02-12 21:56:17 -05:00
d0a4ace94e mvp terminal 2022-02-12 20:52:12 -05:00
1397b08bcb add tab views 2022-02-12 19:21:39 -05:00
a844c7ec5e add demo formspec 2022-02-12 17:13:16 -05:00
f57b1642b9 init 2022-02-12 16:36:11 -05:00
81 changed files with 2355 additions and 890 deletions

View File

@ -7,7 +7,7 @@ globals = {
"minetest", "core",
--mod provided
"home_vending_machines",
"home_vending_machines", "computers",
}
read_globals = {
@ -21,5 +21,5 @@ read_globals = {
"vector", "ItemStack", "dump", "DIR_DELIM", "VoxelArea", "Settings", "PcgRandom", "VoxelManip", "PseudoRandom",
--mod produced
"default", "screwdriver", "unifieddyes", "computers", "farming", "xcompat",
"default", "screwdriver", "unifieddyes", "formspec_ast",
}

View File

@ -1,38 +0,0 @@
version 0.2.3:
- Added animated router front
- Added all crafts for new items
version 0.2.2:
- Added printer
- Added server
version 0.2.1:
- Added modern tower pc
- Added wifi router
- Added flatscreen LCD and keyboard
Version 0.2.0:
- Added recipes.
- Partly re-written.
- Removed original baby tower (seemed out of place).
- You can now turn devices on and off by right-clicking.
- Mod is now on github.
Version 0.1.4:
- Added Admiral 64 & 128 (Commodore 64 & 128 lookalikes)
Version 0.1.3:
- Added SX Spectre (Sinclair ZX Spectrum lookalike)
- Added Pony SlayStation 2 (Sony PlayStation lookalike)
- Minor fixes to textures.
Version 0.1.2:
- Nodes now use the node box as selection box.
- Added Pony SlayStation (Sony PlayStation lookalike)
- Added Pony Vanio (Sony VAIO lookalike...err...just a generic laptop)
Version 0.1.1:
- Added SheFriend SOO (Amiga 500 lookalike)
Version 0.1.0:
- Initial Version only a baby tower.

37
computers/README.md Normal file
View File

@ -0,0 +1,37 @@

# Minetest Computers Mod
By [Diego Martínez](kaeza@users.sf.net) and Contributors
License: [MIT](https://spdx.org/licenses/MIT.html)
Adds interactive computers and networking to minetest
## Links
[Github](https://github.com/mt-mods/home_workshop_modpack)
[Contentdb](https://content.minetest.net/packages/VanessaE/home_workshop_modpack/)
## Setup
You should have recieved this mod as a part of the home workshop modpack.
place the modpack in your /mods folder and enable the computer mod and its dependancies
from the minetest GUI. For further information or help see:
http://wiki.minetest.com/wiki/Installing_Mods
## Privs
This mod provides the computers_filesystem priv which is used to limit the access
of players without it.
## Notes
Much thanks goes to the maintainers of the mod:
* Diego Martínez
* VannessaE
* mt-mods organization
Additional thanks goes to those who helped/advised with the core functionality of computers:
* Luk3yx
* BuckarooBanzai
* OgelGames

View File

@ -1,50 +0,0 @@

Decorative Computers Mod for Minetest
by Diego Martínez <kaeza@users.sf.net> and contributors
license [MIT](https://spdx.org/licenses/MIT.html)
How to install:
Unzip the archive an place it in minetest-base-directory/mods/minetest/
if you have a windows client or a linux run-in-place client. If you have
a linux system-wide instalation place it in ~/.minetest/mods/minetest/.
If you want to install this mod only in one world create the folder
worldmods/ in your worlddirectory.
For further information or help see:
http://wiki.minetest.com/wiki/Installing_Mods
How to use the mod:
For now just use creative mode or the `/give' or `/giveme' chat commands
to get the items.
These are the items currently defined by this mod:
"computers:shefriendSOO",
"computers:vanio",
"computers:vanio_off",
"computers:slaystation",
"computers:slaystation2",
"computers:specter",
"computers:wee",
"computers:piepad",
"computers:admiral64",
"computers:admiral128",
"computers:hueg_box",
"computers:monitor",
"computers:monitor_on",
"computers:router",
"computers:tower",
"computers:server",
"computers:server_on",
"computers:printer",
"computers:tetris_arcade",
There's also a `computers:computer' alias to `computers:babytower'.
Thanks to all the people in the forums and the #minetest IRC channel for
their support and suggestions; in no particular order:
OldCoder, Josh, tonyka, VanessaE, davidpace, Jordach, and all the other
sirs/madammes that I forgot to mention (sorry, please remind me if it
was you ;) ).
See also:
http://minetest.net/

View File

@ -1,29 +0,0 @@
TO-DO List:
- New Nodes:
- Computers:
- Mainframe (well me have a rackserver now)
- My Computer :P
- Peripherals:
- Scanner ( well we have a printer/scanner combo now)
- Consoles:
- NES
- SNES
- DC
- Handhelds
- GB/C
- GBA
- Calculator
- Smartphone
- Animated screens
- Implement some kind of games (take code from `tetris' mod?). [It would be
nice if Minetest provided a "canvas" GUI widget :)].
- Get more suggestions :)

View File

@ -0,0 +1,7 @@
{
"name": "cat",
"license": "MIT",
"version": 0.1,
"engine": 0.44,
"help": "output file to the terminal"
}

View File

@ -0,0 +1,15 @@
function cat(pos, input, data)
local path = computers.devicepath .. "/" .. minetest.hash_node_position(pos) .. data.element.pwd
local files = computers.api.get_dir_keyed_list(path, false)
if files[input] then
local f = io.open(path .. "/" .. input)
local fdata = f:read("*all")
f:close()
return fdata
else
return "file not found"
end
end
return cat

View File

@ -0,0 +1,7 @@
{
"name": "cd",
"license": "MIT",
"version": 0.11,
"engine": 0.41,
"help": "move in and out of folders"
}

View File

@ -0,0 +1,28 @@
function cd(pos, input, data)
if not minetest.check_player_privs(data.player, "computers_filesystem") then
return "ERROR: permision denied"
end
local path = computers.devicepath .. "/" .. minetest.hash_node_position(pos) .. data.element.pwd
if input and input ~= "" and not input:find("/") and not input:find("\\") then
if input == ".." then
local uri = data.element.pwd:split("/")
uri[#uri] = nil
data.element.pwd = "/" .. table.concat(uri, "/")
if data.element.pwd == "/" then data.element.pwd = "" end
return "sucess"
else
for _, folder in pairs(minetest.get_dir_list(path, true)) do
if folder == input then
data.element.pwd = data.element.pwd .. "/" .. input
return "sucess"
end
end
return "ERROR: path not found"
end
else
return "invalid or missing input"
end
end
return cd

View File

@ -0,0 +1,7 @@
{
"name": "echo",
"license": "MIT",
"version": 0.1,
"engine": 0.3,
"help": "prints out input to the terminal"
}

View File

@ -0,0 +1,5 @@
function echo(pos, input, data)
return input
end
return echo

View File

@ -0,0 +1,7 @@
{
"name": "exit",
"license": "MIT",
"version": 0.1,
"engine": 0.42,
"help": "exits the computer"
}

View File

@ -0,0 +1,7 @@
function exit(pos, input, data)
minetest.close_formspec(data.player:get_player_name(), "")
return "you shouldnt see this"
end
return exit

View File

@ -0,0 +1,7 @@
{
"name": "expr",
"license": "MIT",
"version": 0.1,
"engine": 0.42,
"help": "exicutes mathmatical expresions"
}

View File

@ -0,0 +1,14 @@
function expr(pos, input, data)
local output
local func = computers.sandbox.loadstring("return " .. input, {env={}})
if func then output = func() end
if type(output) ~= "number" or output == nil then
return "Error: invalid or missing input"
end
return tostring(output)
end
return expr

View File

@ -0,0 +1,7 @@
{
"name": "help",
"license": "MIT",
"version": 0.1,
"engine": 0.4,
"help": "prints out help"
}

View File

@ -0,0 +1,9 @@
function help(pos, input, data)
local output = ""
for command, def in pairs(computers.registered_confs) do
output = output .. "\n" .. command .. ": " .. def.help
end
return output
end
return help

View File

@ -0,0 +1,7 @@
{
"name": "ls",
"license": "MIT",
"version": 0.1,
"engine": 0.4,
"help": "lists out all files and folders in the current path"
}

View File

@ -0,0 +1,9 @@
function ls(pos, input, data)
local path = computers.devicepath .. "/" .. minetest.hash_node_position(pos) .. data.element.pwd
--make dir to be safe
minetest.mkdir(path)
return table.concat(minetest.get_dir_list(path), " ")
end
return ls

View File

@ -0,0 +1,7 @@
{
"name": "mkdir",
"license": "MIT",
"version": 0.11,
"engine": 0.41,
"help": "makes a dir in the current path"
}

View File

@ -0,0 +1,15 @@
function mkdir(pos, input, data)
if not minetest.check_player_privs(data.player, "computers_filesystem") then
return "ERROR: permision denied"
end
local path = computers.devicepath .. "/" .. minetest.hash_node_position(pos) .. data.element.pwd
if input and input ~= "" and not input:find("/") and not input:find("\\") then
minetest.mkdir(path .. "/" .. input)
return "folder " .. input .. " created"
else
return "invalid or missing input"
end
end
return mkdir

View File

@ -0,0 +1,7 @@
{
"name": "nano",
"license": "MIT",
"version": 0.1,
"engine": 0.42,
"help": "allows editing of files"
}

View File

@ -0,0 +1,113 @@
function nano(pos, input, data)
local path = computers.devicepath .. "/" .. minetest.hash_node_position(pos) .. data.element.pwd
local files = computers.api.get_dir_keyed_list(path, false)
if not input then return "no file designated" end
if not files[input:split(" ")[1]] then return "file " .. input:split(" ")[1] .. " not found" end
if computers.formspec.get_index_by_name(
computers.formspec.registered_kast[data.player:get_player_name()],
"nano_btn"
) then return "nano is already open, please close it" end
local f = io.open(path .. "/" .. input:split(" ")[1])
if not f then return "error reading file" end
local file = f:read("*all")
f:close()
--clean up if there exists a legacy nano_ctn
local nctn = computers.formspec.get_index_by_name(
computers.formspec.registered_kast[data.player:get_player_name()],
"nano_ctn"
)
if nctn then
local fs = computers.formspec.registered_kast[data.player:get_player_name()]
table.remove(fs, nctn)
computers.formspec.registered_kast[data.player:get_player_name()] = fs
minetest.chat_send_all(dump(fs))
end
local form = computers.gui.add_tab(data.player, "Nano", {
type = "container",
name = "nano_ctn",
state = 1,
x = 0,
y = 1,
{
type = "background",
x = 0,
y = 0,
w = 10,
h = 11,
texture_name = "[combine:16x16^[noalpha"
},
{
type = "textarea",
x = 0,
y = 0,
w = 10,
h = 10,
name = "nano_editor",
--read_only = 1,
--label = "test",
default = file,
close_on_enter = false,
--this breaks the scrollbar
--[[ props = {
border = false,
} ]]
},
{
type = "box",
x = 0,
y = 10,
w = 10,
h = 1,
color = "#ffffff"
},
{
type = "field",
x = 0,
y = 10,
w = 10,
h = 1,
name = "nano_commands",
close_on_enter = false,
pwd = "",
props = {
border = false,
},
on_event = function(form, player, element, value, fields)
if value == "save" and fields.nano_editor then
--minetest.chat_send_all(fields.nano_editor)
if #fields.nano_editor < 12000 then --12000 is luacheck line length of 120 * 100 lines
minetest.safe_file_write(path .. "/" .. input:split(" ")[1], fields.nano_editor)
else
computers.api.chat_send_player(player, minetest.colorize("red", "[Nano]: file is to long"))
end
elseif value == "exit" then
local btn = computers.formspec.get_index_by_name(form, "nano_btn")
local ctn = computers.formspec.get_index_by_name(form, "nano_ctn")
form[ctn].state = 1
table.remove(form, btn)
--table.remove(form, ctn) cant actually remove it from within itself, therefore we hide it
local tindex = 0
for index, tab in pairs(form.tabs) do
if tab == "nano" then tindex = index end
end
table.remove(form.tabs, tindex)
tindex = computers.formspec.get_index_by_name(form, "terminal_ctn")
form[tindex].state = 0
else
computers.api.chat_send_player(player, minetest.colorize("red", "[Nano]: invalid command"))
end
return form
end,
},
})
return form
end
return nano

View File

@ -0,0 +1,7 @@
{
"name": "net",
"license": "MIT",
"version": 0.1,
"engine": 0.43,
"help": "configuration related to networking"
}

View File

@ -0,0 +1,64 @@
function net(pos, input, data)
input = input or ""
local lookup = {
list = function(param)
if param == "-ids" then
return table.concat(computers.networks.get_networks_in_area(pos), " ")
elseif not param or param == "" then
return table.concat(computers.networks.get_net_names_in_area(pos), " ")
else
return "invalid sub command"
end
end,
join = function(param)
local id = computers.networks.get_id_by_net_name(data.player, param)
if not id then
return "invalid network name"
elseif minetest.get_meta(pos):get("net_id") then
return "already joined to a network"
else
local _, networks = computers.networks.get_net_names_in_area(pos)
if not networks[param] then return "network not in range" end
minetest.get_meta(pos):set_string("net_id", id)
local status = computers.networks.add_device(id, pos)
if status then return "joined network " .. param else return "network join failed" end
end
end,
leave = function(param)
local id = minetest.get_meta(pos):get("net_id")
if id then
computers.networks.remove_device(id, pos)
return "removed device from network " .. computers.networks.get_net_name(id)
else
return "not currently connected to any network"
end
end,
status = function(param)
local id = minetest.get_meta(pos):get("net_id")
if id then
return "connected to network " .. computers.networks.get_net_name(id)
else
return "not connected to any network"
end
end,
dns = function(param)
if minetest.get_item_group(minetest.get_node(pos).name, "computers_server") == 0 then
return "command only available to servers"
end
if not param or param == "" then return "invalid or missing input" end
if param:match("%W") then return "only alphanumerics allowed" end
local id = minetest.get_meta(pos):get("net_id")
if id then
computers.networks.set_dns(id, pos, param)
return "created dns record"
else
return "not connected to network"
end
end
}
if not lookup[input:split(" ")[1]] then return "invalid sub command" end
return lookup[input:split(" ")[1]](input:split(" ", 1)[2])
end
return net

View File

@ -0,0 +1,7 @@
{
"name": "pwd",
"license": "MIT",
"version": 0.1,
"engine": 0.4,
"help": "list the current path"
}

View File

@ -0,0 +1,7 @@
function pwd(pos, input, data)
local output = data.element.pwd
if output == "" then output = "/" end
return output
end
return pwd

View File

@ -0,0 +1,7 @@
{
"name": "test",
"license": "MIT",
"version": 0.1,
"engine": 100000000,
"help": "literally worthless"
}

View File

@ -0,0 +1,6 @@
function test(pos, input)
--minetest.chat_send_all("test")
return 0
end
return test

View File

@ -0,0 +1,7 @@
{
"name": "touch",
"license": "MIT",
"version": 0.3,
"engine": 0.42,
"help": "creates a file in the current path"
}

View File

@ -0,0 +1,22 @@
function touch(pos, input, data)
local path = computers.devicepath .. "/" .. minetest.hash_node_position(pos) .. data.element.pwd
--make dir to be safe
minetest.mkdir(path)
if #minetest.get_dir_list(path, false) > 10
and not minetest.check_player_privs(data.player, "computers_filesystem") then
return "ERROR: you have reached your max file limit"
end
if input and input ~= "" and not input:find("/") then
if computers.api.get_dir_keyed_list(path, nil)[input] then
return "ERROR: trying to create already existing file/folder"
end
minetest.safe_file_write(path .. "/" .. input, "")
return "file " .. input .. " created"
else
return "invalid or missing input"
end
end
return touch

142
computers/core/api.lua Normal file
View File

@ -0,0 +1,142 @@
--[[
computers.sandbox code is from https://github.com/kikito/lua-sandbox
License MIT 2013 Enrique García Cota
additionally modified by wsor to work with lua 5.1/luajit
modifications include:
* additional protections
* tweaking of structure
* modifications to the default env
]]
computers.sandbox = {}
computers.api = {}
--default sandbox enviroment used if none is provided
computers.sandbox.default_env = {}
([[
_VERSION assert error ipairs next pairs
select tonumber tostring type unpack
math.abs math.acos math.asin math.atan math.atan2 math.ceil
math.cos math.cosh math.deg math.exp math.fmod math.floor
math.frexp math.huge math.ldexp math.log math.log10 math.max
math.min math.modf math.pi math.pow math.rad math.random
math.sin math.sinh math.sqrt math.tan math.tanh
os.clock os.difftime os.time
string.byte string.char
string.len string.lower string.reverse
string.sub string.upper
table.insert table.maxn table.remove table.sort table.concat
]]):gsub('%S+', function(id)
local module, method = id:match('([^%.]+)%.([^%.]+)')
if module then
computers.sandbox.default_env[module] = computers.sandbox.default_env[module] or {}
computers.sandbox.default_env[module][method] = _G[module][method]
else
computers.sandbox.default_env[id] = _G[id]
end
end)
--takes a code string, returns a sandboxed function to exicute
function computers.sandbox.loadstring(code, options)
local defaults = {
env = table.copy(computers.sandbox.default_env),
quota = 5000
}
options = options or {}
for k, v in pairs(defaults) do
if not options[k] then options[k] = v end
end
assert(type(code) == "string", "[computers.sandbox]: passed is not a string")
local env = options.env
env._G = env
if code:byte(1) == 27 then
minetest.log("warning", "[computers.sandbox]: attempted bytecode execution termminated")
return nil, "bytecode disallowed"
end
local f, err = loadstring(code)
if not f then return nil, err end
setfenv(f, env)
if jit then jit.off(f, true) end
local function timeout()
debug.sethook()
error("quota exceeded: " .. tostring(options.quota))
end
return function(...)
debug.sethook(timeout, "", options.quota)
local string_metatable = getmetatable("")
assert(string_metatable.__index == string, "[computers.sandbox]: error with the string metatable")
string_metatable.__index = env.string
local status, ret = pcall(f, ...)
debug.sethook()
string_metatable.__index = string
if not status then error(ret) end
return ret
end
end
--supports string input or table env input with a default env of the base
function computers.sandbox.merge_env(nenv, denv)
local base_env = table.copy(denv or computers.sandbox.default_env)
if type(nenv) == "table" then
for k, v in pairs(nenv) do
base_env[k] = base_env[k] or {}
for key, value in pairs(v) do
base_env[k][key] = value
end
end
elseif type(nenv) == "string" then
nenv:gsub('%S+', function(id)
local module, method = id:match('([^%.]+)%.([^%.]+)')
if module then
base_env[module] = base_env[module] or {}
base_env[module][method] = _G[module][method]
else
base_env[id] = _G[id]
end
end)
end
return base_env
end
function computers.api.get_dir_keyed_list(path, is_dir)
local files = minetest.get_dir_list(path, is_dir)
local keyed = {}
for _, file in pairs(files) do
keyed[file] = true
end
return keyed
end
function computers.api.chat_send_player(player, msg)
local name = player
if type(name) == "userdata" then name = player:get_player_name() end
minetest.chat_send_player(name, msg)
end
--basically for dev usage only
function computers.api.benchmark(func, ...)
local start_time = minetest.get_us_time()
for i=1, 1000 do
func(...)
end
minetest.chat_send_all(minetest.get_us_time()-start_time)
end

View File

@ -0,0 +1,26 @@
computers.registered_commands = {}
computers.registered_confs = {}
minetest.register_privilege("computers_filesystem", {
description = "advanced use of computers filesystem",
give_to_singleplayer = false,
give_to_admin = false,
})
function computers.register_command(modpath)
local func = dofile(modpath .. "/init.lua")
local f = io.open(modpath .. "/conf.json")
local conf = minetest.parse_json(f:read("*all"))
f:close()
if func and computers.os.version >= conf.engine then
computers.registered_commands[conf.name] = func
computers.registered_confs[conf.name] = conf
end
end
--load default commands
local dirs = minetest.get_dir_list(computers.modpath .. "/commands", true)
for _, dir in pairs(dirs) do
computers.register_command(computers.modpath .. "/commands/" .. dir)
end

173
computers/core/formspec.lua Normal file
View File

@ -0,0 +1,173 @@
computers.formspec = {}
computers.formspec.registered_kast = {}
computers.formspec.get_element_by_name = formspec_ast.get_element_by_name
function computers.formspec.get_index_by_name(tree, name)
--this doesnt support containers, use this to get container index and then pass container as tree
if type(tree) ~= "table" then return end
for key, element in pairs(tree) do
if type(element) == "table" and element.name and element.name == name then
return key
end
end
end
--note this is terrible hard coded
local function insert_styles(form, styles)
local headers = {size = true, position = true, anchor = true, no_prepend = true, real_cordinates = true}
local cindex = 0
local fs = {}
for key, val in pairs(form) do
if type(val) == "number" and not tonumber(key) then
fs[key] = val
elseif type(val) == "table" and val.type and headers[val.type] then
table.insert(fs, val)
cindex = key
end
end
for _, val in pairs(styles) do
table.insert(fs, val)
end
cindex = cindex+1
for i=cindex, #form do
table.insert(fs, form[i])
end
return fs
end
function computers.formspec.convert_to_ast(form)
local styles = {}
local function rfind(fs)
for key, val in pairs(fs) do
if type(val) == "table" then
if val.type and val.type:find("container") then
if val.state and val.state == 1 then
--cant use nil so swaping in thing that will never render
fs[key] = {type = "label",x = 100,y = 100,label = "nil",}
else
rfind(val)
end
elseif val.props then
table.insert(styles, {type = "style", selectors = val.selectors or {val.name}, props = val.props})
elseif val.read_only == 1 then
val.name = nil
end
if val.type == "field" then
table.insert(
styles,
{type = "field_close_on_enter", name = val.name, close_on_enter = val.close_on_enter}
)
end
end
end
end
rfind(form)
local fs = insert_styles(form, styles)
return fs
end
local forms = {}
function computers.formspec.show_formspec(player, formname, fs)
local playername = player
local formspec = fs
if type(player) == "userdata" then
playername = player:get_player_name()
end
if type(fs) == "table" then
computers.formspec.registered_kast[playername] = table.copy(fs)
formspec = formspec_ast.unparse(computers.formspec.convert_to_ast(fs))
end
forms[formname] = true
minetest.show_formspec(playername, formname, formspec)
end
function computers.formspec.close_formspec(player, formname)
local name = player
if type(name) == "userdata" then name = player:get_player_name() end
minetest.close_formspec(name, formname or "")
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
--if formname ~= "computers:gui" then return end
if not forms[formname] then return end
local pname = player:get_player_name()
if fields.quit then computers.formspec.registered_kast[pname] = nil return end
--[[
trying to figure out what a player actually did can be a mess
input can validly be nil for a text field sometimes, othertimes it can come in first
when a user has actual selected a button. buttons only come in when selected,
so we override whatever the first key is if there a button since we are sure it was pressed
since we cant get types from fields, we rely on the button being named name_btn with _btn being a suffix
]]
local keys = {}
local btn_override
for key, val in pairs(fields) do
table.insert(keys, key)
local split = key:split("_")
if #split >= 2 and split[2] == "btn" then btn_override = key end
end
local element = computers.formspec.get_element_by_name(
computers.formspec.registered_kast[pname],
btn_override or keys[1]
)
--minetest.chat_send_all(btn_override or keys[1])
--minetest.chat_send_all(fields[keys[1]])
if element and element.on_event then
--on_event(form, player, element)
local form = element.on_event(
computers.formspec.registered_kast[pname],
player,
element,
fields[btn_override or keys[1]],
fields
)
if form then computers.formspec.show_formspec(player, formname, form) end
end
end)
--[[
yes, i know this isnt perfect
requires a name field in the subtags
returns a table keyed by the name field with sub tables containing the other sub tags
]]
function computers.formspec.get_hypertext_subtags(hypertext, tag)
local adata = {}
for a in string.gmatch(hypertext, "<"..tag..".->.-</"..tag..">") do
local len = #tag+1
local tags = string.split(string.sub(a:split(">")[1], len, -1), " ")
local name
local storage = {}
for _, tag_string in pairs(tags) do
local split = tag_string:split("=")
if split[1] == "name" then
name = split[2]
else
storage[split[1]] = split[2]
end
end
adata[name] = storage
end
--minetest.chat_send_all(dump(adata))
return adata
end

330
computers/core/gui.lua Normal file
View File

@ -0,0 +1,330 @@
computers.gui = {}
local futil = computers.formspec
local f = io.open(computers.modpath .. "/default_page.page")
local default_page = f:read("*all")
f:close()
f = io.open(computers.modpath .. "/demo_page.page")
local demo_page = f:read("*all")
f:close()
local function select_btn(form, btn)
--to hardcoded
for _, obtn in pairs(form.tabs) do
local cindex = futil.get_index_by_name(form, obtn .. "_btn")
form[cindex].props.bgimg = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff70"
form[cindex].props.bgimg_hovered = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff90"
cindex = futil.get_index_by_name(form, obtn .. "_ctn")
form[cindex].state = 1
end
local cindex = futil.get_index_by_name(form, btn .. "_btn")
form[cindex].props.bgimg = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff20"
form[cindex].props.bgimg_hovered = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff40"
local aindex = futil.get_index_by_name(form, btn .. "_ctn")
form[aindex].state = 0
end
function computers.gui.load(pos, node, clicker)
local formspec = {
formspec_version = 4,
tabs = {"terminal", "browser"},
{
type = "size",
w = 10,
h = 12,
},
{
type = "no_prepend"
},
{
type = "bgcolor",
bgcolor = "black",
fullscreen = "neither"
},
{
type = "button",
x = 0,
y = 0,
w = 2,
h = 1,
name = "terminal_btn",
label = "Terminal",
on_event = function(form, player, element)
select_btn(form, "terminal")
return form
end,
props = {
border = false,
bgimg = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff70",
bgimg_hovered = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff90",
bgimg_middle = "4,4",
}
},
{
type = "button",
x = 2,
y = 0,
w = 2,
h = 1,
name = "browser_btn",
label = "Browser",
on_event = function(form, player, element)
select_btn(form, "browser")
return form
end,
props = {
border = false,
bgimg = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff70",
bgimg_hovered = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff90",
bgimg_middle = "4,4",
}
},
{
type = "container",
name = "terminal_ctn",
state = 0,
x = 0,
y = 1,
{
type = "background",
x = 0,
y = 0,
w = 10,
h = 11,
texture_name = "[combine:16x16^[noalpha"
},
{
type = "textarea",
x = 0,
y = 0,
w = 10,
h = 10,
name = "terminal_output",
read_only = 1,
--label = "test",
default = "welcome to kuto\nversion " .. computers.os.version .. "\n\nuser:~$ ",
},
{
type = "box",
x = 0,
y = 10,
w = 10,
h = 1,
color = "#ffffff"
},
{
type = "field",
x = 0,
y = 10,
w = 10,
h = 1,
name = "terminal_input",
close_on_enter = false,
pwd = "",
props = {
border = false,
},
on_event = function(form, player, element, value)
local cindex = futil.get_index_by_name(form, "terminal_ctn")
local eindex = futil.get_index_by_name(form[cindex], "terminal_output")
local text = form[cindex][eindex].default
local pass_table = {
element = element,
player = player
}
if value == "clear" then
form[cindex][eindex].default = "user:~" .. element.pwd .."$" .."\n"
end
local cdata = value:split(" ", false, 1)
if value == "clear" then
form[cindex][eindex].default = "user:~$ "
elseif value == "" then
form[cindex][eindex].default = text .. "user:~" .. element.pwd .."$" .. "\n"
elseif computers.registered_commands[cdata[1]] and cdata[2] == "-v" then
form[cindex][eindex].default = text .. value .. "\n" ..
computers.registered_confs[cdata[1]].version .. "\nuser:~" .. element.pwd .."$" .. "\n"
elseif computers.registered_commands[cdata[1]] then
form[cindex][eindex].default = text .. value .. "\n"
text = form[cindex][eindex].default
local output = computers.registered_commands[cdata[1]](pos, cdata[2], pass_table)
if output and type(output) == "string" then
form[cindex][eindex].default = text .. output .. "\n" .. "user:~" .. element.pwd .."$" .." "
elseif output and type(output) == "table" then
form = output
end
else
form[cindex][eindex].default = text .. value ..
"\nERROR: command not found\n" .. "user:~" .. element.pwd .."$" .. " "
end
return form
end,
},
},
{
type = "container",
name = "browser_ctn",
state = 1,
x = 0,
y = 1,
--[[
hardcoded background for now, need to build in custom element support
into hypertext to map to formspec elements
]]
{
type = "background",
x = 0,
y = 0,
w = 10,
h = 10,
texture_name = "[combine:16x16^[noalpha^[colorize:#ffffff70"
},
{
type = "hypertext",
name = "browser_content",
x = 0,
y = 0,
w = 10,
h = 10,
text = default_page,
on_event = function(form, player, element, value, fields)
--minetest.chat_send_all("reached")
--hard coding some network stuff for now
local name = value:split(":")[2]
local tags = futil.get_hypertext_subtags(element.text, "action")
if tags[name] and tags[name]._href and tags[name]._href == "demo_page" then
--minetest.chat_send_all(tags[name]._href)
element.text = demo_page
elseif tags[name] and tags[name]._href and tags[name]._href == "default_page" then
element.text = default_page
end
return form
end
},
{
type = "background",
x = 0,
y = 10,
w = 10,
h = 1,
texture_name = "[combine:16x16^[noalpha"
},
{
type = "box",
x = 0,
y = 10,
w = 10,
h = 1,
color = "#ffffff"
},
{
type = "field",
x = 0,
y = 10,
w = 10,
h = 1,
name = "browser_url",
close_on_enter = false,
pwd = "",
props = {
border = false,
},
on_event = function(form, player, element, value, fields)
local id = minetest.get_meta(pos):get("net_id")
if id then
local status, data = computers.networks.resolve_url(id, pos, value)
if status and data then
local cindex = futil.get_index_by_name(form, "browser_ctn")
local eindex = futil.get_index_by_name(form[cindex], "browser_content")
form[cindex][eindex].text = data
end
else
computers.api.chat_send_player(player, "[computers]: not attached to a network")
end
return form
end,
},
},
}
futil.show_formspec(clicker, "computers:gui", formspec)
end
--legacy compat
computers.load_gui = computers.gui.load
--note you can create to many pages thuse overflowing the formspec, need to be fixed
function computers.gui.add_tab(player, tname, tab)
local name = player
if type(player) == "userdata" then name = player:get_player_name() end
assert(tab, "[computers.sandbox]: new tab for " .. name .. " not found")
assert(tab.type == "container", "[computers.sandbox]: invalid new tab format for " .. name)
assert(tab.name:split("_")[2] == "ctn", "[computers.sandbox]: invalid tab name for " .. name)
assert(tab.x == 0 and tab.y == 1, "[computers.sandbox]: invalid tab name for " .. name)
local formspec = table.copy(computers.formspec.registered_kast[name])
local fs = {}
local btn
for key, val in pairs(formspec) do
if type(key) == "string" then
fs[key] = val
elseif type(val) == "table" then
if val.name and #val.name:split("_") >= 2 and val.name:split("_")[2] == "btn" then
btn = 1
elseif btn and btn == 1 then
table.insert(fs, {
type = "button",
x = #formspec.tabs*2,
y = 0,
w = 2,
h = 1,
name = tname:lower() .. "_btn",
label = tname,
on_event = function(form, _, element)
select_btn(form, tname:lower())
return form
end,
props = {
border = false,
bgimg = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff70",
bgimg_hovered = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff90",
bgimg_middle = "4,4",
}
})
btn = nil
end
table.insert(fs, val)
end
end
table.insert(fs, tab)
table.insert(fs.tabs, tname:lower())
return fs
end
--[[ minetest.register_on_player_receive_fields(function(player, formname, fields)
minetest.chat_send_all(dump(fields))
end) ]]

7
computers/core/init.lua Normal file
View File

@ -0,0 +1,7 @@
local path = computers.modpath .. "/core"
dofile(path .. "/api.lua")
dofile(path .. "/networks.lua")
dofile(path .. "/formspec.lua")
dofile(path .. "/commands.lua")
dofile(path .. "/gui.lua")

152
computers/core/networks.lua Normal file
View File

@ -0,0 +1,152 @@
local networks = {}
local network_lookup = {}
computers.networks = {}
local function init_networks()
local path = computers.networkpath
local files = minetest.get_dir_list(computers.networkpath, false)
for _, file in pairs(files) do
local id = file:sub(1,-6)
local f = io.open(path .. "/" .. file)
networks[id] = minetest.parse_json(f:read("*all"))
f:close()
if not network_lookup[networks[id].pname] then network_lookup[networks[id].pname] = {} end
network_lookup[networks[id].pname][networks[id].net_name] = id
end
end
init_networks()
local function update_file(id)
local data = networks[id]
local path = computers.networkpath .. "/" .. id .. ".json"
minetest.safe_file_write(path, minetest.write_json(data))
end
function computers.networks.create(player, net_name)
local pname = player
if type(player) == "userdata" then pname = player:get_player_name() end
local id = pname .. "_" .. minetest.get_us_time()
if net_name:match("%W") then return false end --pnly accept alphanumerics
if not network_lookup[pname] then network_lookup[pname] = {} end
if network_lookup[pname][net_name] then return false end
if networks[id] then return false end
--create storage on disk
local path = computers.networkpath .. "/" .. id .. ".json"
local data = {
pname = pname,
net_name = net_name,
devices = {},
dns = {
}
}
minetest.safe_file_write(path, minetest.write_json(data))
--store data in memory
networks[id] = data
network_lookup[pname][net_name] = id
return true, id
end
function computers.networks.verify_network(id)
if networks[id] then return true else return false end
end
function computers.networks.get_net_name(id)
return networks[id].net_name
end
function computers.networks.get_network_devices(id)
return table.copy(networks[id].devices)
end
function computers.networks.get_network_dns(id)
return table.copy(networks[id].dns)
end
function computers.networks.get_id_by_net_name(player, net_name)
local pname = player
if type(player) == "userdata" then pname = player:get_player_name() end
if not network_lookup[pname] then network_lookup[pname] = {} end
return network_lookup[pname][net_name]
end
function computers.networks.get_networks_in_area(pos, rad)
rad = rad or 10
local locations = {}
local keyed_locations = {}
local meta_nodes = minetest.find_nodes_with_meta(
vector.new(pos.x+rad, pos.y+rad, pos.z+rad),
vector.new(pos.x-rad, pos.y-rad, pos.z-rad)
)
for _, location in pairs(meta_nodes) do
local status = minetest.get_meta(location):get("net_id")
if status and networks[status] then
table.insert(locations, status)
keyed_locations[status] = true
end
end
return locations, keyed_locations
end
function computers.networks.get_net_names_in_area(pos, rad)
rad = rad or 10
local locations = {}
local keyed_locations = {}
local meta_nodes = minetest.find_nodes_with_meta(
vector.new(pos.x+rad, pos.y+rad, pos.z+rad),
vector.new(pos.x-rad, pos.y-rad, pos.z-rad)
)
for _, location in pairs(meta_nodes) do
local status = minetest.get_meta(location):get("net_id")
if status and networks[status] and not keyed_locations[networks[status].net_name] then
table.insert(locations, networks[status].net_name)
keyed_locations[networks[status].net_name] = true
end
end
return locations, keyed_locations
end
function computers.networks.add_device(id, pos)
if type(pos) ~= "table" or not networks[id] then return false end
networks[id].devices[minetest.pos_to_string(pos)] = minetest.get_node(pos).name
minetest.get_meta(pos):set_string("net_id", id)
update_file(id)
return true
end
function computers.networks.remove_device(id, pos)
if type(pos) ~= "table" or not networks[id] then return false end
networks[id].devices[minetest.pos_to_string(pos)] = nil
minetest.get_meta(pos):set_string("net_id", "")
update_file(id)
return true
end
function computers.networks.set_dns(id, pos, url)
if type(pos) ~= "table" or not networks[id] then return false end
if url:match("%W") then return false end
networks[id].dns = networks[id].dns or {}
networks[id].dns[url] = minetest.hash_node_position(pos) .. "/public_pages"
update_file(id)
return true
end
function computers.networks.resolve_url(id, pos, url)
if type(pos) ~= "table" or not networks[id] then return false end
if networks[id].dns[url:split("/")[1]] then
local path = computers.devicepath .. "/" .. networks[id].dns[url:split("/")[1]].."/index.page"
local f = io.open(path)
if not f then return false end
local data = f:read("*all")
f:close()
if data then return true, data else return false end
else
return false
end
end

View File

@ -0,0 +1,18 @@
<global margin=20>
<normal></normal>
<center><bigger>Welcome to ARPANET</bigger></center>
<big>How to use it</big>
<normal>on the bottom of this pane is field input which allows you to enter site urls</normal>
<normal>example: <mono><style color=blue>domain</style></mono></normal>
<normal>example: <mono><style color=blue>domain/demo_page.page</style></mono></normal>
<normal></normal>
<big>Try it out</big>
<action name=demo_link _href=demo_page>test url</action>
<normal></normal>
<big>How can I host my own sites?</big>
<normal>you will need to set up the server node</normal>
<normal>put your webfiles in there in hypertext format in the public_html folder</normal>
<normal>domainname/ and domainname/folder/ will connect to the indexpage file found in the DIR</normal>
<normal></normal>

23
computers/demo.lua Normal file
View File

@ -0,0 +1,23 @@
local old_node = minetest.registered_nodes["computers:shefriendSOO"]
old_node.groups.not_in_creative_inventory = 1
minetest.override_item("computers:shefriendSOO", {
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
computers.load_gui(pos, node, clicker)
end,
groups = old_node.groups
})
old_node = minetest.registered_nodes["computers:shefriendSOO_off"]
old_node.groups.not_in_creative_inventory = nil
minetest.override_item("computers:shefriendSOO_off", {
groups = old_node.groups
})
old_node = minetest.registered_nodes["computers:server_on"]
old_node.groups.computers_server = 1
minetest.override_item("computers:server_on", {
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
computers.load_gui(pos, node, clicker)
end,
groups = old_node.groups
})

7
computers/demo_page.page Normal file
View File

@ -0,0 +1,7 @@
<global margin=20>
<normal></normal>
<center><bigger>Welcome to Demo Page</bigger></center>
<normal></normal>
<action name=default_link _href=default_page>go back</action>
<normal></normal>

View File

@ -1,353 +0,0 @@
local S = minetest.get_translator("computers")
-- Sony PlayStation lookalike
computers.register("computers:slaystation", {
description = S("Pony SlayStation"),
inventory_image = "computers_ps1_inv.png",
tiles_off = { top=true },
node_box = computers.pixelnodebox(32, {
-- X Y Z W H L
{ 0, 0, 11, 32, 6, 21 }, -- Console
{ 1, 0, 1, 4, 2, 9 }, -- Controller 1 L Grip
{ 10, 0, 1, 4, 2, 9 }, -- Controller 1 R Grip
{ 5, 0, 4, 5, 2, 5 }, -- Controller 1 Center
{ 18, 0, 1, 4, 2, 9 }, -- Controller 2 L Grip
{ 27, 0, 1, 4, 2, 9 }, -- Controller 2 R Grip
{ 22, 0, 4, 5, 2, 5 } -- Controller 2 Center
})
})
-- Sony PlayStation 2 lookalike
computers.register("computers:slaystation2", {
description = S("Pony SlayStation 2"),
inventory_image = "computers_ps2_inv.png",
tiles_off = { front=true },
node_box = computers.pixelnodebox(32, {
-- X Y Z W H L
{ 2, 2, 11, 28, 3, 19 }, -- Console (Upper part)
{ 2, 0, 11, 26, 2, 19 }, -- Console (Lower part)
{ 1, 0, 1, 4, 2, 9 }, -- Controller 1 L Grip
{ 10, 0, 1, 4, 2, 9 }, -- Controller 1 R Grip
{ 5, 0, 1, 5, 2, 8 }, -- Controller 1 Center
{ 18, 0, 1, 4, 2, 9 }, -- Controller 2 L Grip
{ 27, 0, 1, 4, 2, 9 }, -- Controller 2 R Grip
{ 22, 0, 1, 5, 2, 8 } -- Controller 2 Center
})
})
-- Nintendo Wii lookalike
computers.register("computers:wee", {
description = S("Nientiendo Wee"),
inventory_image = "computers_wii_inv.png",
tiles_off = { front=true },
node_box = computers.pixelnodebox(32, {
-- X Y Z W H L
{ 11, 0, 3, 10, 6, 26 }, -- Base
{ 12, 6, 4, 8, 22, 24 } -- Top
})
})
-- XBox lookalike
computers.register("computers:hueg_box", {
description = S("HUEG Box"),
tiles_off = { },
node_box = computers.pixelnodebox(16, {
-- X Y Z W H L
{ 0, 0, 7, 16, 6, 9 }, -- Console
{ 2, 0, 1, 11, 3, 6 }, -- Controller
{ 2, 0, 0, 2, 3, 1 },
{ 11, 0, 0, 2, 3, 1 },
})
})
-- Tetris arcade machine
local shapes = {
{ { x = {0, 1, 0, 1}, y = {0, 0, 1, 1} } },
{ { x = {1, 1, 1, 1}, y = {0, 1, 2, 3} },
{ x = {0, 1, 2, 3}, y = {1, 1, 1, 1} } },
{ { x = {0, 0, 1, 1}, y = {0, 1, 1, 2} },
{ x = {1, 2, 0, 1}, y = {0, 0, 1, 1} } },
{ { x = {1, 0, 1, 0}, y = {0, 1, 1, 2} },
{ x = {0, 1, 1, 2}, y = {0, 0, 1, 1} } },
{ { x = {1, 2, 1, 1}, y = {0, 0, 1, 2} },
{ x = {0, 1, 2, 2}, y = {1, 1, 1, 2} },
{ x = {1, 1, 0, 1}, y = {0, 1, 2, 2} },
{ x = {0, 0, 1, 2}, y = {0, 1, 1, 1} } },
{ { x = {1, 1, 1, 2}, y = {0, 1, 2, 2} },
{ x = {0, 1, 2, 0}, y = {1, 1, 1, 2} },
{ x = {0, 1, 1, 1}, y = {0, 0, 1, 2} },
{ x = {0, 1, 2, 2}, y = {1, 1, 1, 0} } },
{ { x = {1, 0, 1, 2}, y = {0, 1, 1, 1} },
{ x = {1, 1, 1, 2}, y = {0, 1, 2, 1} },
{ x = {0, 1, 2, 1}, y = {1, 1, 1, 2} },
{ x = {0, 1, 1, 1}, y = {1, 0, 1, 2} } } }
local colors = { "computers_cyan.png", "computers_magenta.png", "computers_red.png",
"computers_blue.png", "computers_green.png", "computers_orange.png", "computers_yellow.png" }
local background = "image[0,0;3.55,6.66;computers_black.png]"
local buttons = "button[3,4.5;0.6,0.6;left;<]"
.."button[3.6,4.5;0.6,0.6;rotateleft;"..minetest.formspec_escape(S("L")).."]"
.."button[4.2,4.5;0.6,0.6;down;v]"
.."button[4.2,5.3;0.6,0.6;drop;V]"
.."button[4.8,4.5;0.6,0.6;rotateright;"..minetest.formspec_escape(S("R")).."]"
.."button[5.4,4.5;0.6,0.6;right;>]"
.."button[3.5,3;2,2;new;"..minetest.formspec_escape(S("New Game")).."]"
local formsize = "size[5.9,5.7]"
local boardx, boardy = 0, 0
local sizex, sizey, size = 0.29, 0.29, 0.31
local comma = ","
local semi = ";"
local close = "]"
local concat = table.concat
local insert = table.insert
local draw_shape = function(id, x, y, rot, posx, posy)
local d = shapes[id][rot]
local scr = {}
local ins = #scr
for i=1,4 do
local tmp = { "image[",
(d.x[i]+x)*sizex+posx, comma,
(d.y[i]+y)*sizey+posy, semi,
size, comma, size, semi,
colors[id], close }
ins = ins + 1
scr[ins] = concat(tmp)
end
return concat(scr)
end
local function step(pos, fields)
local meta = minetest.get_meta(pos)
local t = minetest.deserialize(meta:get_string("tetris"))
local function new_game(p)
local nex = math.random(7)
t = {
board = {},
boardstring = "",
previewstring = draw_shape(nex, 0, 0, 1, 4, 1),
score = 0,
cur = math.random(7),
nex = nex,
x=4, y=0, rot=1
}
local timer = minetest.get_node_timer(p)
timer:set(0.3, 0)
end
local function update_boardstring()
local scr = {}
local ins = #scr
for i, line in pairs(t.board) do
for _, tile in pairs(line) do
local tmp = { "image[",
tile[1]*sizex+boardx, comma,
i*sizey+boardy, semi,
size, comma, size, semi,
colors[tile[2]], close }
ins = ins + 1
scr[ins] = concat(tmp)
end
end
t.boardstring = concat(scr)
end
local function add()
local d = shapes[t.cur][t.rot]
for i=1,4 do
local l = d.y[i] + t.y
if not t.board[l] then t.board[l] = {} end
insert(t.board[l], {d.x[i] + t.x, t.cur})
end
end
local function scroll(l)
for i=l, 1, -1 do
t.board[i] = t.board[i-1] or {}
end
end
local function check_lines()
for i, line in pairs(t.board) do
if #line >= 10 then
scroll(i)
t.score = t.score + 20
end
end
end
local function check_position(x, y, rot)
local d = shapes[t.cur][rot]
for i=1,4 do
local cx, cy = d.x[i]+x, d.y[i]+y
if cx < 0 or cx > 9 or cy < 0 or cy > 19 then
return false
end
for _, tile in pairs(t.board[ cy ] or {}) do
if tile[1] == cx then return false end
end
end
return true
end
local function stuck()
if check_position(t.x, t.y+1, t.rot) then return false end
return true
end
local function tick()
if stuck() then
if t.y <= 0 then
return false end
add()
check_lines()
update_boardstring()
t.cur, t.nex = t.nex, math.random(7)
t.x, t.y, t.rot = 4, 0, 1
t.previewstring = draw_shape(t.nex, 0, 0, 1, 4.1, 0.6)
else
t.y = t.y + 1
end
return true
end
local function move(dx, dy)
local newx, newy = t.x+dx, t.y+dy
if not check_position(newx, newy, t.rot) then return end
t.x, t.y = newx, newy
end
local function rotate(dr)
local no = #(shapes[t.cur])
local newrot = (t.rot+dr) % no
if newrot<1 then newrot = newrot+no end
if not check_position(t.x, t.y, newrot) then return end
t.rot = newrot
end
local function key()
if fields.left then
move(-1, 0)
end
if fields.rotateleft then
rotate(-1)
end
if fields.down then
t.score = t.score + 1
move(0, 1)
end
if fields.drop then
while not stuck() do
t.score = t.score + 2
move(0, 1)
end
end
if fields.rotateright then
rotate(1)
end
if fields.right then
move(1, 0)
end
end
local run = true
if fields then
if fields.new then
new_game(pos)
elseif t then
key(fields)
end
elseif t then
run = tick()
end
if t then
local scr = { formsize, background,
t.boardstring, t.previewstring,
draw_shape(t.cur, t.x, t.y, t.rot, boardx, boardy),
"label[3.8,0.1;"..S("Next...").."]label[3.8,2.7;"..S("Score: "),
t.score, close, buttons }
meta:set_string("formspec", concat(scr))
meta:set_string("tetris", minetest.serialize(t))
end
return run
end
minetest.register_node("computers:tetris_arcade", {
description=S("Tetris Arcade"),
drawtype = "mesh",
mesh = "computers_tetris_arcade.obj",
tiles = {"computers_tetris_arcade.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy=3},
is_ground_content = false,
on_rotate = minetest.get_modpath("screwdriver") and screwdriver.rotate_simple or nil,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5}
},
collision_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5}
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", formsize
.."button[2,2.5;2,2;new;"..minetest.formspec_escape(S("New Game")).."]")
end,
on_timer = function(pos)
return step(pos, nil)
end,
on_receive_fields = function(pos, formanme, fields, sender)
step(pos, fields)
end,
on_place = function(itemstack, placer, pointed_thing)
local pos = pointed_thing.above
if minetest.is_protected(pos, placer:get_player_name()) or
minetest.is_protected({x=pos.x, y=pos.y+1, z=pos.z}, placer:get_player_name()) then
return itemstack
end
if minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name ~= "air" then
minetest.chat_send_player(placer:get_player_name(), S("No room for place the Arcade!"))
return itemstack
end
local dir = placer:get_look_dir()
local node = {name="computers:tetris_arcade", param1=0, param2 = minetest.dir_to_facedir(dir)}
minetest.set_node(pos, node)
itemstack:take_item()
return itemstack
end
})

View File

@ -1,105 +1,20 @@
computers = {}
computers.modpath = minetest.get_modpath("computers")
computers.storagepath = minetest.get_worldpath() .. "/computers"
computers.devicepath = computers.storagepath .. "/devices"
computers.networkpath = computers.storagepath .. "/networks"
minetest.mkdir(computers.storagepath) --make sure it exists
minetest.mkdir(computers.devicepath) --make sure it exists
minetest.mkdir(computers.networkpath) --make sure it exists
computers.register = function (name, def)
if (name:sub(1, 1) == ":") then name = name:sub(2) end
local modname, basename = name:match("^([^:]+):(.*)")
local TEXPFX = modname.."_"..basename.."_"
local ONSTATE = modname..":"..basename
local OFFSTATE = modname..":"..basename.."_off"
local cdef = table.copy(def)
minetest.register_node(ONSTATE, {
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = "clip",
description = cdef.description,
inventory_image = cdef.inventory_image,
groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
is_ground_content = false,
tiles = {
TEXPFX.."tp.png",
TEXPFX.."bt.png",
TEXPFX.."rt.png",
TEXPFX.."lt.png",
TEXPFX.."bk.png",
TEXPFX.."ft.png"
},
node_box = cdef.node_box,
selection_box = cdef.node_box,
on_rightclick = function (pos, node, clicker, itemstack)
if cdef.on_turn_off and cdef.on_turn_off(pos, node, clicker, itemstack) then
return itemstack
end
node.name = OFFSTATE
minetest.set_node(pos, node)
return itemstack
end
})
minetest.register_node(OFFSTATE, {
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = "clip",
groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1},
is_ground_content = false,
tiles = {
(TEXPFX.."tp"..(cdef.tiles_off.top and "_off" or "")..".png"),
(TEXPFX.."bt"..(cdef.tiles_off.bottom and "_off" or "")..".png"),
(TEXPFX.."rt"..(cdef.tiles_off.right and "_off" or "")..".png"),
(TEXPFX.."lt"..(cdef.tiles_off.left and "_off" or "")..".png"),
(TEXPFX.."bk"..(cdef.tiles_off.back and "_off" or "")..".png"),
(TEXPFX.."ft"..(cdef.tiles_off.front and "_off" or "")..".png")
},
node_box = cdef.node_box_off or cdef.node_box,
selection_box = cdef.node_box_off or cdef.node_box,
on_rightclick = function (pos, node, clicker, itemstack)
if cdef.on_turn_on and cdef.on_turn_on(pos, node, clicker, itemstack) then
return itemstack
end
node.name = ONSTATE
minetest.set_node(pos, node)
return itemstack
end,
drop = ONSTATE
})
end
computers.os = {
version = 0.44,
name = "kuto",
authors = {"wsor", "luk3yx"},
license = "MIT",
}
computers.register_handheld = function (name, def)
if (name:sub(1, 1) == ":") then name = name:sub(2) end
local modname, basename = name:match("^([^:]+):(.*)")
local TEXPFX = modname.."_"..basename.."_inv"
local ONSTATE = modname..":"..basename
minetest.register_craftitem(ONSTATE, {
description = def.description,
inventory_image = TEXPFX..".png",
wield_image = TEXPFX..".png"
})
end
dofile(computers.modpath .. "/core/init.lua")
dofile(computers.modpath .. "/nodes/init.lua")
computers.pixelnodebox = function (size, boxes)
local fixed = { }
for _, box in ipairs(boxes) do
local x, y, z, w, h, l = unpack(box)
fixed[#fixed + 1] = {
(x / size) - 0.5,
(y / size) - 0.5,
(z / size) - 0.5,
((x + w) / size) - 0.5,
((y + h) / size) - 0.5,
((z + l) / size) - 0.5
}
end
return {
type = "fixed",
fixed = fixed
}
end
local MODPATH = minetest.get_modpath("computers")
dofile(MODPATH.."/computers.lua")
dofile(MODPATH.."/gaming.lua")
dofile(MODPATH.."/aliases.lua")
if minetest.get_modpath("basic_materials") then
dofile(MODPATH.."/recipes.lua")
end
dofile(computers.modpath .. "/demo.lua")

View File

@ -1,24 +1,31 @@
# textdomain: computers
SheFriendSOO=Freundin S00
Pony Vanio=Pony Oiva
SX Specter=Z Inspektor
Snapple Piepad=Apfel-Ei-Pat
Admiral64=Admiral 64
### computers.lua ###
Admiral128=Admiral 128
Monitor and keyboard=Bildschirm und Tastatur
WIFI Router=WiFi-Router
Admiral64=Admiral 64
Computer Tower=Computerturm
Rack Server=Serverschrank
HUEG Box=YBOX
Monitor and keyboard=Bildschirm und Tastatur
Nientiendo Wee=Tinnendo iiW
Not enough vertical space to place a server!=Es gibt nicht genug vertikalen Platz, um einen Server zu platzieren!
Printer-Scanner Combo=Multifunktionsdrucker
Pony SlayStation=Pony Slaystation
Pony SlayStation 2=Pony Slaystation 2
Nientiendo Wee=Tinnendo iiW
HUEG Box=YBOX
Pony Vanio=Pony Oiva
Rack Server=Serverschrank
SX Specter=Z Inspektor
SheFriendSOO=Freundin S00
Snapple Piepad=Apfel-Ei-Pat
WIFI Router=WiFi-Router
Printer-Scanner Combo=Multifunktionsdrucker
### tetris.lua ###
L=L
R=R
New Game=Neues Spiel
Next...=Nächster…
No room for place the Arcade!=Kein Platz, um den Arkadeautomaten zu platzieren!
R=R
Score: =Punktzahl:
Tetris Arcade=Tetris-Arkadeautomat
No room for place the Arcade!=Kein Platz, um den Arkadeautomaten zu platzieren!

View File

@ -1,24 +1,31 @@
# textdomain: computers
SheFriendSOO=
Pony Vanio=
SX Specter=
Snapple Piepad=
Admiral64=
### computers.lua ###
Admiral128=
Monitor and keyboard=Monitor y teclado
WIFI Router=Enrutador WIFI
Admiral64=
Computer Tower=Torre de ordenador
Rack Server=Servidor en rack
HUEG Box=
Monitor and keyboard=Monitor y teclado
Nientiendo Wee=
Not enough vertical space to place a server!=¡No hay suficiente espacio para colocar un servidor!
Printer-Scanner Combo=Impresora y escáner combinados
Pony SlayStation=
Pony SlayStation 2=
Nientiendo Wee=
HUEG Box=
Pony Vanio=
Rack Server=Servidor en rack
SX Specter=
SheFriendSOO=
Snapple Piepad=
WIFI Router=Enrutador WIFI
Printer-Scanner Combo=Impresora y escáner combinados
### tetris.lua ###
L=
R=
New Game=Juego Nuevo
Next...=
No room for place the Arcade!=¡No hay lugar para colocar el arcade!
R=
Score: =
Tetris Arcade=Arcade Tetris
No room for place the Arcade!=¡No hay lugar para colocar el arcade!

View File

@ -1,24 +1,31 @@
# textdomain: computers
SheFriendSOO=
Pony Vanio=
SX Specter=
Snapple Piepad=
Admiral64=
### computers.lua ###
Admiral128=
Monitor and keyboard=Écran et clavier
WIFI Router=Routeur WiFi
Admiral64=
Computer Tower=Ordinateur (tour)
Rack Server=Serveur en rack
HUEG Box=
Monitor and keyboard=Écran et clavier
Nientiendo Wee=
Not enough vertical space to place a server!=Pas assez d'espace vertical pour placer un serveur !
Printer-Scanner Combo=Imprimante multi-fonction
Pony SlayStation=
Pony SlayStation 2=
Nientiendo Wee=
HUEG Box=
Pony Vanio=
Rack Server=Serveur en rack
SX Specter=
SheFriendSOO=
Snapple Piepad=
WIFI Router=Routeur WiFi
Printer-Scanner Combo=Imprimante multi-fonction
### tetris.lua ###
L=G
R=D
New Game=Nouveau Jeu
Next...=Suivant…
No room for place the Arcade!=Pas assez de place pour placer la borne d'arcade !
R=D
Score: =Score :
Tetris Arcade=Borne Tetris
No room for place the Arcade!=Pas assez de place pour placer la borne d'arcade !

View File

@ -1,24 +1,31 @@
# textdomain: computers
SheFriendSOO=
Pony Vanio=
SX Specter=
Snapple Piepad=
Admiral64=
### computers.lua ###
Admiral128=
Monitor and keyboard=
WIFI Router=
Admiral64=
Computer Tower=
Rack Server=
HUEG Box=
Monitor and keyboard=
Nientiendo Wee=
Not enough vertical space to place a server!=Non c'è abbastanza spazio verticale per mettere un frigorifero!
Printer-Scanner Combo=
Pony SlayStation=
Pony SlayStation 2=
Nientiendo Wee=
HUEG Box=
Pony Vanio=
Rack Server=
SX Specter=
SheFriendSOO=
Snapple Piepad=
WIFI Router=
Printer-Scanner Combo=
### tetris.lua ###
L=
R=
New Game=
Next...=
No room for place the Arcade!=
R=
Score: =
Tetris Arcade=
No room for place the Arcade!=

View File

@ -1,24 +1,31 @@
# textdomain: computers
SheFriendSOO=
Pony Vanio=
SX Specter=
Snapple Piepad=
Admiral64=
### computers.lua ###
Admiral128=
Monitor and keyboard=Monitor dan Papan Kekunci
WIFI Router=Penghala WIFI
Admiral64=
Computer Tower=Sistem Unit
Rack Server=Rak Pelayan
HUEG Box=
Monitor and keyboard=Monitor dan Papan Kekunci
Nientiendo Wee=
Not enough vertical space to place a server!=Tidak cukup ruang menegak untuk letak rak pelayan!
Printer-Scanner Combo=Pencetak Semua Dalam Satu
Pony SlayStation=
Pony SlayStation 2=
Nientiendo Wee=
HUEG Box=
Pony Vanio=
Rack Server=Rak Pelayan
SX Specter=
SheFriendSOO=
Snapple Piepad=
WIFI Router=Penghala WIFI
Printer-Scanner Combo=Pencetak Semua Dalam Satu
### tetris.lua ###
L=
R=
New Game=Main Baru
Next...=Seterusnya...
No room for place the Arcade!=Tiada ruang untuk letak Arked!
R=
Score: =Markah:
Tetris Arcade=Arked Tetris
No room for place the Arcade!=Tiada ruang untuk letak Arked!

View File

@ -1,24 +1,31 @@
# textdomain: computers
SheFriendSOO=
Pony Vanio=
SX Specter=
Snapple Piepad=
Admiral64=
### computers.lua ###
Admiral128=
Monitor and keyboard=Tela e teclado
WIFI Router=Roteador WIFI
Admiral64=
Computer Tower=Gabinete do Computador
Rack Server=Rack para Servidor
HUEG Box=
Monitor and keyboard=Tela e teclado
Nientiendo Wee=
Not enough vertical space to place a server!=Sem espaço vertical suficiente para colocar um servidor.
Printer-Scanner Combo=Tudo em Um Impressora-Scaner
Pony SlayStation=
Pony SlayStation 2=
Nientiendo Wee=
HUEG Box=
Pony Vanio=
Rack Server=Rack para Servidor
SX Specter=
SheFriendSOO=
Snapple Piepad=
WIFI Router=Roteador WIFI
Printer-Scanner Combo=Tudo em Um Impressora-Scaner
### tetris.lua ###
L=
R=
New Game=Novo Jogo
Next...=
No room for place the Arcade!=Sem espaço para colocar o Fliperama!
R=
Score: =
Tetris Arcade=Fliperama Tetris
No room for place the Arcade!=Sem espaço para colocar o Fliperama!

View File

@ -1,24 +1,31 @@
# textdomain: computers
SheFriendSOO=
Pony Vanio=
SX Specter=
Snapple Piepad=
Admiral64=
### computers.lua ###
Admiral128=
Monitor and keyboard=Tela e teclado
WIFI Router=Roteador WIFI
Admiral64=
Computer Tower=Gabinete do Computador
Rack Server=Rack para Servidor
HUEG Box=
Monitor and keyboard=Tela e teclado
Nientiendo Wee=
Not enough vertical space to place a server!=Sem espaço vertical suficiente para colocar um servidor.
Printer-Scanner Combo=Tudo em Um Impressora-Scaner
Pony SlayStation=
Pony SlayStation 2=
Nientiendo Wee=
HUEG Box=
Pony Vanio=
Rack Server=Rack para Servidor
SX Specter=
SheFriendSOO=
Snapple Piepad=
WIFI Router=Roteador WIFI
Printer-Scanner Combo=Tudo em Um Impressora-Scaner
### tetris.lua ###
L=
R=
New Game=Novo Jogo
Next...=
No room for place the Arcade!=Sem espaço para colocar o Fliperama!
R=
Score: =
Tetris Arcade=Fliperama Tetris
No room for place the Arcade!=Sem espaço para colocar o Fliperama!

View File

@ -1,24 +1,31 @@
# textdomain: computers
SheFriendSOO=
Pony Vanio=
SX Specter=
Snapple Piepad=
Admiral64=
### computers.lua ###
Admiral128=
Monitor and keyboard=Монитор и клавиатура
WIFI Router=WIFI-роутер
Admiral64=
Computer Tower=Системный блок
Rack Server=Стоечный сервер
HUEG Box=
Monitor and keyboard=Монитор и клавиатура
Nientiendo Wee=
Not enough vertical space to place a server!=Недостаточно вертикального пространства для размещения сервера!
Printer-Scanner Combo=МФУ
Pony SlayStation=
Pony SlayStation 2=
Nientiendo Wee=
HUEG Box=
Pony Vanio=
Rack Server=Стоечный сервер
SX Specter=
SheFriendSOO=
Snapple Piepad=
WIFI Router=WIFI-роутер
Printer-Scanner Combo=МФУ
### tetris.lua ###
L=
R=
New Game=Новая игра
Next...=Далее...
No room for place the Arcade!=Недостаточно места для размещения игрового автомата!
R=
Score: =Счёт:
Tetris Arcade=Игровой автомат Тетрис
No room for place the Arcade!=Недостаточно места для размещения игрового автомата!

View File

@ -1,24 +1,31 @@
# textdomain: computers
SheFriendSOO=
Pony Vanio=
SX Specter=
Snapple Piepad=
Admiral64=
### computers.lua ###
Admiral128=
Monitor and keyboard=显示器和键盘
WIFI Router=无线路由器
Admiral64=
Computer Tower=计算机箱
Rack Server=机架式服务器
HUEG Box=
Monitor and keyboard=显示器和键盘
Nientiendo Wee=
Not enough vertical space to place a server!=高度不足,无法放置服务器!
Printer-Scanner Combo=打印扫描一体机
Pony SlayStation=
Pony SlayStation 2=
Nientiendo Wee=
HUEG Box=
Pony Vanio=
Rack Server=机架式服务器
SX Specter=
SheFriendSOO=
Snapple Piepad=
WIFI Router=无线路由器
Printer-Scanner Combo=打印扫描一体机
### tetris.lua ###
L=
R=
New Game=新游戏
Next...=下一个。。。
No room for place the Arcade!=没有地方放游戏机!
R=
Score: =分数:
Tetris Arcade=俄罗斯方块游戏机
No room for place the Arcade!=没有地方放游戏机!

View File

@ -1,24 +1,31 @@
# textdomain: computers
SheFriendSOO=
Pony Vanio=
SX Specter=
Snapple Piepad=
Admiral64=
### computers.lua ###
Admiral128=
Monitor and keyboard=
WIFI Router=
Admiral64=
Computer Tower=
Rack Server=
HUEG Box=
Monitor and keyboard=
Nientiendo Wee=
Not enough vertical space to place a server!=
Printer-Scanner Combo=
Pony SlayStation=
Pony SlayStation 2=
Nientiendo Wee=
HUEG Box=
Pony Vanio=
Rack Server=
SX Specter=
SheFriendSOO=
Snapple Piepad=
WIFI Router=
Printer-Scanner Combo=
### tetris.lua ###
L=
R=
New Game=
Next...=
No room for place the Arcade!=
R=
Score: =
Tetris Arcade=
No room for place the Arcade!=

View File

@ -1,3 +1,3 @@
name = computers
depends = xcompat
depends = formspec_ast
optional_depends = screwdriver, default, basic_materials

11
computers/nodes/init.lua Normal file
View File

@ -0,0 +1,11 @@
local path = computers.modpath .. "/nodes"
dofile(path .. "/node_api.lua")
dofile(path .. "/nodes.lua")
dofile(path .. "/router.lua")
dofile(path .. "/tetris.lua")
dofile(path .. "/aliases.lua")
if minetest.get_modpath("default") and minetest.get_modpath("basic_materials") then
dofile(path .. "/recipes.lua")
end

View File

@ -0,0 +1,78 @@
computers.register = function (name, def)
if (name:sub(1, 1) == ":") then name = name:sub(2) end
local modname, basename = name:match("^([^:]+):(.*)")
local TEXPFX = modname.."_"..basename.."_"
local ONSTATE = modname..":"..basename
local OFFSTATE = modname..":"..basename.."_off"
local cdef = table.copy(def)
minetest.register_node(ONSTATE, {
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
description = cdef.description,
inventory_image = cdef.inventory_image,
groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
tiles = {
TEXPFX.."tp.png",
TEXPFX.."bt.png",
TEXPFX.."rt.png",
TEXPFX.."lt.png",
TEXPFX.."bk.png",
TEXPFX.."ft.png"
},
node_box = cdef.node_box,
selection_box = cdef.node_box,
on_rightclick = function (pos, node, clicker, itemstack)
if cdef.on_turn_off and cdef.on_turn_off(pos, node, clicker, itemstack) then
return itemstack
end
node.name = OFFSTATE
minetest.set_node(pos, node)
return itemstack
end
})
minetest.register_node(OFFSTATE, {
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1},
tiles = {
(TEXPFX.."tp"..(cdef.tiles_off.top and "_off" or "")..".png"),
(TEXPFX.."bt"..(cdef.tiles_off.bottom and "_off" or "")..".png"),
(TEXPFX.."rt"..(cdef.tiles_off.right and "_off" or "")..".png"),
(TEXPFX.."lt"..(cdef.tiles_off.left and "_off" or "")..".png"),
(TEXPFX.."bk"..(cdef.tiles_off.back and "_off" or "")..".png"),
(TEXPFX.."ft"..(cdef.tiles_off.front and "_off" or "")..".png")
},
node_box = cdef.node_box_off or cdef.node_box,
selection_box = cdef.node_box_off or cdef.node_box,
on_rightclick = function (pos, node, clicker, itemstack)
if cdef.on_turn_on and cdef.on_turn_on(pos, node, clicker, itemstack) then
return itemstack
end
node.name = ONSTATE
minetest.set_node(pos, node)
return itemstack
end,
drop = ONSTATE
})
end
computers.pixelnodebox = function (size, boxes)
local fixed = { }
for _, box in ipairs(boxes) do
local x, y, z, w, h, l = unpack(box)
fixed[#fixed + 1] = {
(x / size) - 0.5,
(y / size) - 0.5,
(z / size) - 0.5,
((x + w) / size) - 0.5,
((y + h) / size) - 0.5,
((z + l) / size) - 0.5
}
end
return {
type = "fixed",
fixed = fixed
}
end

View File

@ -21,10 +21,8 @@ minetest.register_node("computers:vanio", {
tiles = {"computers_laptop.png"},
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = "clip",
light_source = 4,
groups = {snappy=3},
is_ground_content = false,
walkable = false,
selection_box = {
type = "fixed",
@ -43,9 +41,7 @@ minetest.register_node("computers:vanio_off", {
tiles = {"computers_laptop.png"},
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = "clip",
groups = {snappy=3, not_in_creative_inventory=1},
is_ground_content = false,
walkable = false,
selection_box = {
type = "fixed",
@ -83,9 +79,8 @@ minetest.register_node("computers:piepad", {
light_source = 8,
walkable = false,
groups = {oddly_breakable_by_hand=2},
is_ground_content = false,
selection_box = {type = "wallmounted"},
sounds = xcompat.sounds.node_sound_wood_defaults()
sounds = default and default.node_sound_wood_defaults() or nil
})
-- Commodore 64 lookalike
@ -128,7 +123,6 @@ minetest.register_node("computers:monitor", {
paramtype2 = "facedir",
walkable = false,
groups = {snappy=3},
is_ground_content = false,
selection_box = mo_sbox,
on_rightclick = function(pos, node, clicker, itemstack)
node.name = "computers:monitor_on"
@ -151,7 +145,6 @@ minetest.register_node("computers:monitor_on", {
light_source = 9,
walkable = false,
groups = {snappy=3, not_in_creative_inventory=1},
is_ground_content = false,
selection_box = mo_sbox,
drop = "computers:monitor",
on_rightclick = function(pos, node, clicker, itemstack)
@ -161,40 +154,6 @@ minetest.register_node("computers:monitor_on", {
end
})
--WIFI Router (linksys look-a-like)
minetest.register_node("computers:router", {
description = S("WIFI Router"),
inventory_image = "computers_router_inv.png",
tiles = {
"computers_router_t.png",
"computers_router_bt.png",
"computers_router_l.png",
"computers_router_r.png",
"computers_router_b.png",
{
name = "computers_router_f_animated.png",
animation = {type="vertical_frames", aspect_w=32, aspect_h=32, length=1.0}
},
}, --"computers_router_f.png"},
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = "clip",
walkable = false,
groups = {snappy=3},
is_ground_content = false,
sound = xcompat.sounds.node_sound_wood_defaults(),
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.25, -0.5, -0.0625, 0.25, -0.375, 0.3125},
{-0.1875, -0.4375, 0.3125, -0.125, -0.1875, 0.375},
{0.125, -0.4375, 0.3125, 0.1875, -0.1875, 0.375},
{-0.0625, -0.4375, 0.3125, 0.0625, -0.25, 0.375}
}
}
})
local pct_cbox = {
type = "fixed",
fixed = { -0.1875, -0.5, -0.36, 0.1875, 0.34, 0.46 }
@ -210,8 +169,7 @@ minetest.register_node("computers:tower", {
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy=3},
is_ground_content = false,
sound = xcompat.sounds.node_sound_wood_defaults(),
sound = default and default.node_sound_wood_defaults() or nil,
selection_box = pct_cbox,
collision_box = pct_cbox
})
@ -231,9 +189,7 @@ minetest.register_node("computers:server", {
inventory_image = "computers_server_inv.png",
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = "clip",
groups = {snappy=3},
is_ground_content = false,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.25, 0.5, 1.125, 0.4375}
@ -242,7 +198,7 @@ minetest.register_node("computers:server", {
type = "fixed",
fixed = {-0.5, -0.5, -0.25, 0.5, 1.125, 0.4375}
},
sounds = xcompat.sounds.node_sound_wood_defaults(),
sounds = default and default.node_sound_wood_defaults() or nil,
on_rightclick = function(pos, node, clicker, itemstack)
node.name = "computers:server_on"
minetest.set_node(pos, node)
@ -272,9 +228,7 @@ minetest.register_node("computers:server_on", {
inventory_image = "computers_server_inv.png",
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = "clip",
groups = {snappy=3,not_in_creative_inventory=1},
is_ground_content = false,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.25, 0.5, 1.125, 0.4375}
@ -283,7 +237,7 @@ minetest.register_node("computers:server_on", {
type = "fixed",
fixed = {-0.5, -0.5, -0.25, 0.5, 1.125, 0.4375}
},
sounds = xcompat.sounds.node_sound_wood_defaults(),
sounds = default and default.node_sound_wood_defaults() or nil,
drop = 'computers:server',
on_rightclick = function(pos, node, clicker, itemstack)
node.name = "computers:server"
@ -301,11 +255,9 @@ minetest.register_node("computers:printer", {
"computers_printer_r.png","computers_printer_b.png","computers_printer_f.png"},
paramtype = "light",
paramtype2 = "facedir",
use_texture_alpha = "clip",
walkable = true,
groups = {snappy=3},
is_ground_content = false,
sound = xcompat.sounds.node_sound_wood_defaults(),
sound = default and default.node_sound_wood_defaults() or nil,
drawtype = "nodebox",
node_box = {
type = "fixed",
@ -321,3 +273,63 @@ minetest.register_node("computers:printer", {
},
},
})
-- Sony PlayStation lookalike
computers.register("computers:slaystation", {
description = S("Pony SlayStation"),
inventory_image = "computers_ps1_inv.png",
tiles_off = { top=true },
node_box = computers.pixelnodebox(32, {
-- X Y Z W H L
{ 0, 0, 11, 32, 6, 21 }, -- Console
{ 1, 0, 1, 4, 2, 9 }, -- Controller 1 L Grip
{ 10, 0, 1, 4, 2, 9 }, -- Controller 1 R Grip
{ 5, 0, 4, 5, 2, 5 }, -- Controller 1 Center
{ 18, 0, 1, 4, 2, 9 }, -- Controller 2 L Grip
{ 27, 0, 1, 4, 2, 9 }, -- Controller 2 R Grip
{ 22, 0, 4, 5, 2, 5 } -- Controller 2 Center
})
})
-- Sony PlayStation 2 lookalike
computers.register("computers:slaystation2", {
description = S("Pony SlayStation 2"),
inventory_image = "computers_ps2_inv.png",
tiles_off = { front=true },
node_box = computers.pixelnodebox(32, {
-- X Y Z W H L
{ 2, 2, 11, 28, 3, 19 }, -- Console (Upper part)
{ 2, 0, 11, 26, 2, 19 }, -- Console (Lower part)
{ 1, 0, 1, 4, 2, 9 }, -- Controller 1 L Grip
{ 10, 0, 1, 4, 2, 9 }, -- Controller 1 R Grip
{ 5, 0, 1, 5, 2, 8 }, -- Controller 1 Center
{ 18, 0, 1, 4, 2, 9 }, -- Controller 2 L Grip
{ 27, 0, 1, 4, 2, 9 }, -- Controller 2 R Grip
{ 22, 0, 1, 5, 2, 8 } -- Controller 2 Center
})
})
-- Nintendo Wii lookalike
computers.register("computers:wee", {
description = S("Nientiendo Wee"),
inventory_image = "computers_wii_inv.png",
tiles_off = { front=true },
node_box = computers.pixelnodebox(32, {
-- X Y Z W H L
{ 11, 0, 3, 10, 6, 26 }, -- Base
{ 12, 6, 4, 8, 22, 24 } -- Top
})
})
-- XBox lookalike
computers.register("computers:hueg_box", {
description = S("HUEG Box"),
tiles_off = { },
node_box = computers.pixelnodebox(16, {
-- X Y Z W H L
{ 0, 0, 7, 16, 6, 9 }, -- Console
{ 2, 0, 1, 11, 3, 6 }, -- Controller
{ 2, 0, 0, 2, 3, 1 },
{ 11, 0, 0, 2, 3, 1 },
})
})

View File

@ -1,11 +1,8 @@
-- Copyright (C) 2012-2013 Diego Martínez <kaeza@users.sf.net>
local materials = xcompat.materials
minetest.register_craft({
output = "computers:shefriendSOO",
recipe = {
{ "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", materials.glass, "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", "default:glass", "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", "group:wood", "basic_materials:plastic_sheet" }
}
})
@ -22,7 +19,7 @@ minetest.register_craft({
output = "computers:vanio",
recipe = {
{ "basic_materials:plastic_sheet", "", "" },
{ materials.glass, "", "" },
{ "default:glass", "", "" },
{ "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" }
}
})
@ -40,7 +37,7 @@ minetest.register_craft({
output = "computers:slaystation2",
recipe = {
{ "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", materials.steel_ingot, "basic_materials:plastic_sheet" }
{ "basic_materials:plastic_sheet", "default:steel_ingot", "basic_materials:plastic_sheet" }
}
})
@ -56,7 +53,7 @@ minetest.register_craft({
output = "computers:admiral128",
recipe = {
{ "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" },
{ materials.steel_ingot, materials.steel_ingot, materials.steel_ingot }
{ "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
}
})
@ -64,7 +61,7 @@ minetest.register_craft({
output = "computers:wee",
recipe = {
{ "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", materials.copper_ingot, "basic_materials:plastic_sheet" }
{ "basic_materials:plastic_sheet", "default:copper_ingot", "basic_materials:plastic_sheet" }
}
})
@ -72,7 +69,7 @@ minetest.register_craft({
output = "computers:piepad",
recipe = {
{ "basic_materials:plastic_sheet", "basic_materials:plastic_sheet", "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", materials.glass, "basic_materials:plastic_sheet" }
{ "basic_materials:plastic_sheet", "default:glass", "basic_materials:plastic_sheet" }
}
})
@ -81,45 +78,45 @@ minetest.register_craft({
minetest.register_craft({
output = "computers:monitor",
recipe = {
{ "basic_materials:plastic_sheet", materials.glass,"" },
{ "basic_materials:plastic_sheet", materials.glass,"" },
{ "basic_materials:plastic_sheet", materials.mese_crystal_fragment, "basic_materials:plastic_sheet" }
{ "basic_materials:plastic_sheet", "default:glass","" },
{ "basic_materials:plastic_sheet", "default:glass","" },
{ "basic_materials:plastic_sheet", "default:mese_crystal_fragment", "basic_materials:plastic_sheet" }
}
})
minetest.register_craft({
output = "computers:router",
recipe = {
{ materials.steel_ingot,"","" },
{ materials.steel_ingot ,"basic_materials:plastic_sheet", "basic_materials:plastic_sheet" },
{ materials.mese_crystal_fragment,"basic_materials:plastic_sheet", "basic_materials:plastic_sheet" }
{ "default:steel_ingot","","" },
{ "default:steel_ingot" ,"basic_materials:plastic_sheet", "basic_materials:plastic_sheet" },
{ "default:mese_crystal_fragment","basic_materials:plastic_sheet", "basic_materials:plastic_sheet" }
}
})
minetest.register_craft({
output = "computers:tower",
recipe = {
{ "basic_materials:plastic_sheet", materials.steel_ingot, "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", materials.mese_crystal, "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", materials.steel_ingot, "basic_materials:plastic_sheet" }
{ "basic_materials:plastic_sheet", "default:steel_ingot", "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", "default:mese_crystal", "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", "default:steel_ingot", "basic_materials:plastic_sheet" }
}
})
minetest.register_craft({
output = "computers:printer",
recipe = {
{ "basic_materials:plastic_sheet", materials.steel_ingot,"" },
{ "basic_materials:plastic_sheet", materials.mese_crystal, "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", materials.coal_lump, "basic_materials:plastic_sheet" }
{ "basic_materials:plastic_sheet", "default:steel_ingot","" },
{ "basic_materials:plastic_sheet", "default:mese_crystal", "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", "default:coal_lump", "basic_materials:plastic_sheet" }
}
})
minetest.register_craft({
output = "computers:printer",
recipe = {
{ "basic_materials:plastic_sheet", materials.steel_ingot,"" },
{ "basic_materials:plastic_sheet", materials.mese_crystal, "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", materials.dye_black, "basic_materials:plastic_sheet", }
{ "basic_materials:plastic_sheet", "default:steel_ingot","" },
{ "basic_materials:plastic_sheet", "default:mese_crystal", "basic_materials:plastic_sheet" },
{ "basic_materials:plastic_sheet", "dye:black", "basic_materials:plastic_sheet", }
}
})
@ -136,7 +133,7 @@ minetest.register_craft({
output = "computers:tetris_arcade",
recipe = {
{ "basic_materials:plastic_sheet", "basic_materials:energy_crystal_simple", "basic_materials:plastic_sheet", },
{ materials.dye_black, materials.glass, materials.dye_black },
{ "dye:black", "default:glass", "dye:black" },
{ "basic_materials:plastic_sheet", "basic_materials:energy_crystal_simple", "basic_materials:plastic_sheet" }
}
})

227
computers/nodes/router.lua Normal file
View File

@ -0,0 +1,227 @@
local S = minetest.get_translator("computers")
minetest.register_node("computers:router", {
description = S("WIFI Router"),
inventory_image = "computers_router_inv.png",
tiles = {
"computers_router_t.png",
"computers_router_bt.png",
"computers_router_l.png",
"computers_router_r.png",
"computers_router_b.png",
{
name = "computers_router_f_animated.png",
animation = {type="vertical_frames", aspect_w=32, aspect_h=32, length=1.0}
},
}, --"computers_router_f.png"},
paramtype = "light",
paramtype2 = "facedir",
walkable = false,
groups = {snappy=3},
sound = default and default.node_sound_wood_defaults() or nil,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.25, -0.5, -0.0625, 0.25, -0.375, 0.3125},
{-0.1875, -0.4375, 0.3125, -0.125, -0.1875, 0.375},
{0.125, -0.4375, 0.3125, 0.1875, -0.1875, 0.375},
{-0.0625, -0.4375, 0.3125, 0.0625, -0.25, 0.375}
}
},
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local formspec = {
formspec_version = 4,
{
type = "size",
w = 10,
h = 5,
},
{
type = "no_prepend"
},
{
type = "bgcolor",
bgcolor = "black",
fullscreen = "neither"
},
{
type = "background9",
x = 0,
y = 0,
w = 10,
h = 5,
texture_name = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff70",
auto_clip = false,
middle_x = 4,
middle_y = 4,
},
{
type = "hypertext",
name = "label",
x = 0,
y = 0,
w = 10,
h = 2,
text = "<global valign=middle><center><big>Choose Option Below</big></center>",
},
{
type = "button",
x = 0.5,
y = 3.5,
w = 4,
h = 1,
name = "newnetwork_btn",
label = "New Network",
on_event = function(form, player, element, value, fields)
if element.label == "New Network" then
element.label = "Submit"
table.remove(form, computers.formspec.get_index_by_name(form, "existingnetwork_btn"))
form[computers.formspec.get_index_by_name(form, "label")].text = [[
<global valign=middle><center><big>Enter New Network Name</big></center>
]]
table.insert(
form,
{
type = "box",
x = 3,
y = 1.75,
w = 4,
h = 1,
color = "#ffffff"
}
)
table.insert(
form,
{
type = "field",
x = 3,
y = 1.75,
w = 4,
h = 1,
name = "id_field",
close_on_enter = false,
props = {
border = false,
},
}
)
else
if fields.id_field == "" and not computers.formspec.get_index_by_name(form, "warning") then
table.insert(
form,
{
type = "hypertext",
name = "warning",
x = 5.5,
y = 3.5,
w = 4,
h = 1,
text = [[
<global valign=middle>
<center><style color=red>empty or invalid network name</style></center>
]]
}
)
elseif fields.id_field ~= "" then
local status, id = computers.networks.create(player, fields.id_field)
if status then
form = nil
minetest.get_meta(pos):set_string("net_id", id)
computers.networks.add_device(id, pos)
computers.api.chat_send_player(player, "network " .. fields.id_field .. " created")
computers.formspec.close_formspec(player)
elseif not computers.formspec.get_index_by_name(form, "warning") then
table.insert(
form,
{
type = "hypertext",
name = "warning",
x = 5.5,
y = 3.5,
w = 4,
h = 1,
text = [[
<global valign=middle>
<center><style color=red>empty or invalid network name</style></center>
]]
}
)
end
end
end
--minetest.chat_send_all("test")
if form then return form end
end,
props = {
border = false,
bgimg = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff70",
bgimg_hovered = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff90",
bgimg_middle = "4,4",
}
},
{
type = "button",
x = 5.5,
y = 3.5,
w = 4,
h = 1,
name = "existingnetwork_btn",
label = "Existing Network",
on_event = function(form, player, element, value, fields)
if element.label == "Existing Network" then
element.label = "Submit"
table.remove(form, computers.formspec.get_index_by_name(form, "newnetwork_btn"))
form[computers.formspec.get_index_by_name(form, "label")].text = [[
<global valign=middle><center>Enter Network</center>
]]
table.insert(
form,
{
type = "box",
x = 3,
y = 1.75,
w = 4,
h = 1,
color = "#ffffff"
}
)
table.insert(
form,
{
type = "field",
x = 3,
y = 1.75,
w = 4,
h = 1,
name = "id_field",
close_on_enter = false,
props = {
border = false,
},
}
)
else
minetest.chat_send_all("submitted")
end
return form
end,
props = {
border = false,
bgimg = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff70",
bgimg_hovered = "kuto_button.png^[combine:16x16^[noalpha^[colorize:#ffffff90",
bgimg_middle = "4,4",
}
},
}
if minetest.get_meta(pos):get("net_id") then
local net_name = computers.networks.get_net_name(minetest.get_meta(pos):get("net_id"))
computers.api.chat_send_player(clicker, "router attached to network: " .. net_name)
else
computers.formspec.show_formspec(clicker, "computers:router", formspec)
end
end
})

289
computers/nodes/tetris.lua Normal file
View File

@ -0,0 +1,289 @@
-- Tetris arcade machine
local S = minetest.get_translator("computers")
local shapes = {
{ { x = {0, 1, 0, 1}, y = {0, 0, 1, 1} } },
{ { x = {1, 1, 1, 1}, y = {0, 1, 2, 3} },
{ x = {0, 1, 2, 3}, y = {1, 1, 1, 1} } },
{ { x = {0, 0, 1, 1}, y = {0, 1, 1, 2} },
{ x = {1, 2, 0, 1}, y = {0, 0, 1, 1} } },
{ { x = {1, 0, 1, 0}, y = {0, 1, 1, 2} },
{ x = {0, 1, 1, 2}, y = {0, 0, 1, 1} } },
{ { x = {1, 2, 1, 1}, y = {0, 0, 1, 2} },
{ x = {0, 1, 2, 2}, y = {1, 1, 1, 2} },
{ x = {1, 1, 0, 1}, y = {0, 1, 2, 2} },
{ x = {0, 0, 1, 2}, y = {0, 1, 1, 1} } },
{ { x = {1, 1, 1, 2}, y = {0, 1, 2, 2} },
{ x = {0, 1, 2, 0}, y = {1, 1, 1, 2} },
{ x = {0, 1, 1, 1}, y = {0, 0, 1, 2} },
{ x = {0, 1, 2, 2}, y = {1, 1, 1, 0} } },
{ { x = {1, 0, 1, 2}, y = {0, 1, 1, 1} },
{ x = {1, 1, 1, 2}, y = {0, 1, 2, 1} },
{ x = {0, 1, 2, 1}, y = {1, 1, 1, 2} },
{ x = {0, 1, 1, 1}, y = {1, 0, 1, 2} } } }
local colors = { "computers_cyan.png", "computers_magenta.png", "computers_red.png",
"computers_blue.png", "computers_green.png", "computers_orange.png", "computers_yellow.png" }
local background = "image[0,0;3.55,6.66;computers_black.png]"
local buttons = "button[3,4.5;0.6,0.6;left;<]"
.."button[3.6,4.5;0.6,0.6;rotateleft;"..minetest.formspec_escape(S("L")).."]"
.."button[4.2,4.5;0.6,0.6;down;v]"
.."button[4.2,5.3;0.6,0.6;drop;V]"
.."button[4.8,4.5;0.6,0.6;rotateright;"..minetest.formspec_escape(S("R")).."]"
.."button[5.4,4.5;0.6,0.6;right;>]"
.."button[3.5,3;2,2;new;"..minetest.formspec_escape(S("New Game")).."]"
local formsize = "size[5.9,5.7]"
local boardx, boardy = 0, 0
local sizex, sizey, size = 0.29, 0.29, 0.31
local comma = ","
local semi = ";"
local close = "]"
local concat = table.concat
local insert = table.insert
local draw_shape = function(id, x, y, rot, posx, posy)
local d = shapes[id][rot]
local scr = {}
local ins = #scr
for i=1,4 do
local tmp = { "image[",
(d.x[i]+x)*sizex+posx, comma,
(d.y[i]+y)*sizey+posy, semi,
size, comma, size, semi,
colors[id], close }
ins = ins + 1
scr[ins] = concat(tmp)
end
return concat(scr)
end
local function step(pos, fields)
local meta = minetest.get_meta(pos)
local t = minetest.deserialize(meta:get_string("tetris"))
local function new_game(p)
local nex = math.random(7)
t = {
board = {},
boardstring = "",
previewstring = draw_shape(nex, 0, 0, 1, 4, 1),
score = 0,
cur = math.random(7),
nex = nex,
x=4, y=0, rot=1
}
local timer = minetest.get_node_timer(p)
timer:set(0.3, 0)
end
local function update_boardstring()
local scr = {}
local ins = #scr
for i, line in pairs(t.board) do
for _, tile in pairs(line) do
local tmp = { "image[",
tile[1]*sizex+boardx, comma,
i*sizey+boardy, semi,
size, comma, size, semi,
colors[tile[2]], close }
ins = ins + 1
scr[ins] = concat(tmp)
end
end
t.boardstring = concat(scr)
end
local function add()
local d = shapes[t.cur][t.rot]
for i=1,4 do
local l = d.y[i] + t.y
if not t.board[l] then t.board[l] = {} end
insert(t.board[l], {d.x[i] + t.x, t.cur})
end
end
local function scroll(l)
for i=l, 1, -1 do
t.board[i] = t.board[i-1] or {}
end
end
local function check_lines()
for i, line in pairs(t.board) do
if #line >= 10 then
scroll(i)
t.score = t.score + 20
end
end
end
local function check_position(x, y, rot)
local d = shapes[t.cur][rot]
for i=1,4 do
local cx, cy = d.x[i]+x, d.y[i]+y
if cx < 0 or cx > 9 or cy < 0 or cy > 19 then
return false
end
for _, tile in pairs(t.board[ cy ] or {}) do
if tile[1] == cx then return false end
end
end
return true
end
local function stuck()
if check_position(t.x, t.y+1, t.rot) then return false end
return true
end
local function tick()
if stuck() then
if t.y <= 0 then
return false end
add()
check_lines()
update_boardstring()
t.cur, t.nex = t.nex, math.random(7)
t.x, t.y, t.rot = 4, 0, 1
t.previewstring = draw_shape(t.nex, 0, 0, 1, 4.1, 0.6)
else
t.y = t.y + 1
end
return true
end
local function move(dx, dy)
local newx, newy = t.x+dx, t.y+dy
if not check_position(newx, newy, t.rot) then return end
t.x, t.y = newx, newy
end
local function rotate(dr)
local no = #(shapes[t.cur])
local newrot = (t.rot+dr) % no
if newrot<1 then newrot = newrot+no end
if not check_position(t.x, t.y, newrot) then return end
t.rot = newrot
end
local function key()
if fields.left then
move(-1, 0)
end
if fields.rotateleft then
rotate(-1)
end
if fields.down then
t.score = t.score + 1
move(0, 1)
end
if fields.drop then
while not stuck() do
t.score = t.score + 2
move(0, 1)
end
end
if fields.rotateright then
rotate(1)
end
if fields.right then
move(1, 0)
end
end
local run = true
if fields then
if fields.new then
new_game(pos)
elseif t then
key(fields)
end
elseif t then
run = tick()
end
if t then
local scr = { formsize, background,
t.boardstring, t.previewstring,
draw_shape(t.cur, t.x, t.y, t.rot, boardx, boardy),
"label[3.8,0.1;"..S("Next...").."]label[3.8,2.7;"..S("Score: "),
t.score, close, buttons }
meta:set_string("formspec", concat(scr))
meta:set_string("tetris", minetest.serialize(t))
end
return run
end
minetest.register_node("computers:tetris_arcade", {
description=S("Tetris Arcade"),
drawtype = "mesh",
mesh = "computers_tetris_arcade.obj",
tiles = {"computers_tetris_arcade.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy=3},
on_rotate = minetest.get_modpath("screwdriver") and screwdriver.rotate_simple or nil,
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5}
},
collision_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5}
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", formsize
.."button[2,2.5;2,2;new;"..minetest.formspec_escape(S("New Game")).."]")
end,
on_timer = function(pos)
return step(pos, nil)
end,
on_receive_fields = function(pos, formanme, fields, sender)
step(pos, fields)
end,
on_place = function(itemstack, placer, pointed_thing)
local pos = pointed_thing.above
if minetest.is_protected(pos, placer:get_player_name()) or
minetest.is_protected({x=pos.x, y=pos.y+1, z=pos.z}, placer:get_player_name()) then
return itemstack
end
if minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z}).name ~= "air" then
minetest.chat_send_player(placer:get_player_name(), S("No room for place the Arcade!"))
return itemstack
end
local dir = placer:get_look_dir()
local node = {name="computers:tetris_arcade", param1=0, param2 = minetest.dir_to_facedir(dir)}
minetest.set_node(pos, node)
itemstack:take_item()
return itemstack
end
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

View File

@ -12,8 +12,7 @@ local function reg_simple(name, def)
tiles = def.tiles,
paramtype = "light",
paramtype2 = "facedir",
groups = def.groups or {snappy=3, dig_tree=2},
is_ground_content = false,
groups = def.groups or {snappy=3},
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5}
@ -29,7 +28,6 @@ local function reg_simple(name, def)
end
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if not itemstack then return end
local pname = clicker:get_player_name()
local iname = itemstack:get_name()
local dpos = vector.add((vector.multiply(minetest.facedir_to_dir(node.param2), -1)), pos)
@ -58,4 +56,4 @@ function home_vending_machines.register_machine(type, name, def)
reg_simple(name, def)
end
--TODO: add more complex machine type with formspec and selections
end
end

View File

@ -1,26 +1,32 @@
local materials = xcompat.materials
minetest.register_craft({
output = "home_workshop_misc:soda_machine",
recipe = {
{materials.steel_ingot, materials.steel_ingot, materials.steel_ingot},
{materials.steel_ingot, materials.dye_red, materials.steel_ingot},
{materials.steel_ingot, materials.copper_block, materials.steel_ingot},
},
})
minetest.register_craft({
output = "home_vending_machines:drink_machine",
recipe = {
{materials.steel_ingot, "group:vessel", materials.steel_ingot},
{materials.steel_ingot, materials.steel_ingot, materials.steel_ingot},
{materials.steel_ingot, materials.copper_block, materials.steel_ingot},
},
})
minetest.register_craft({
output = "home_vending_machines:sweet_machine",
recipe = {
{materials.steel_ingot, "group:food_sugar", materials.steel_ingot},
{materials.steel_ingot, materials.steel_ingot, materials.steel_ingot},
{materials.steel_ingot, materials.copper_block, materials.steel_ingot},
},
})
if minetest.get_modpath("default") then
if minetest.get_modpath("dye") then
minetest.register_craft({
output = "home_workshop_misc:soda_machine",
recipe = {
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
{"default:steel_ingot", "dye:red", "default:steel_ingot"},
{"default:steel_ingot", "default:copperblock", "default:steel_ingot"},
},
})
end
if minetest.get_modpath("vessel") then
minetest.register_craft({
output = "home_vending_machines:drink_machine",
recipe = {
{"default:steel_ingot", "group:vessel", "default:steel_ingot"},
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
{"default:steel_ingot", "default:copperblock", "default:steel_ingot"},
},
})
end
if minetest.get_modpath("farming") then
minetest.register_craft({
output = "home_vending_machines:sweet_machine",
recipe = {
{"default:steel_ingot", "group:food_sugar", "default:steel_ingot"},
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
{"default:steel_ingot", "default:copperblock", "default:steel_ingot"},
},
})
end
end

View File

@ -1,3 +1 @@
name = home_vending_machines
depends = xcompat
optional_depends = screwdriver, default, dye, vessels, farming
optional_depends = screwdriver

View File

@ -1,5 +1,4 @@
local S = minetest.get_translator("home_workshop_machines")
local materials = xcompat.materials
-- "bedflinger" style 3D Printer (Prusa i3 or equivalent)
@ -17,9 +16,8 @@ minetest.register_node("home_workshop_machines:3dprinter_bedflinger", {
},
paramtype = "light",
walkable = true,
groups = {snappy=3, ud_param2_colorable = 1, dig_tree=2},
is_ground_content = false,
sound = xcompat.sounds.node_sound_wood_defaults(),
groups = {snappy=3, ud_param2_colorable = 1},
sound = default and default.node_sound_wood_defaults() or nil,
drawtype = "mesh",
mesh = "home_workshop_machines_3dprinter_bedflinger.obj",
paramtype2 = "colorwallmounted",
@ -48,9 +46,8 @@ minetest.register_node("home_workshop_machines:3dprinter_corexy", {
},
paramtype = "light",
walkable = true,
groups = {snappy=3, ud_param2_colorable = 1, dig_tree=2},
is_ground_content = false,
sound = xcompat.sounds.node_sound_wood_defaults(),
groups = {snappy=3, ud_param2_colorable = 1},
sound = default and default.node_sound_wood_defaults() or nil,
drawtype = "mesh",
mesh = "home_workshop_machines_3dprinter_corexy.obj",
paramtype2 = "colorwallmounted",
@ -64,26 +61,6 @@ minetest.register_node("home_workshop_machines:3dprinter_corexy", {
on_rotate = unifieddyes.fix_after_screwdriver_nsew,
})
if minetest.get_modpath("basic_materials") then
minetest.register_craft({
output = "home_workshop_machines:3dprinter_bedflinger",
recipe = {
{"basic_materials:plastic_sheet", materials.dye_white, "basic_materials:plastic_sheet"},
{"basic_materials:motor", "basic_materials:heating_element", "basic_materials:motor"},
{materials.steel_ingot, materials.steel_ingot, materials.steel_ingot},
},
})
minetest.register_craft({
output = "home_workshop_machines:3dprinter_corexy",
recipe = {
{materials.steel_ingot, "basic_materials:motor", "basic_materials:plastic_sheet"},
{materials.glass, "basic_materials:heating_element", materials.glass},
{materials.steel_ingot, "basic_materials:motor", materials.steel_ingot},
},
})
end
minetest.register_alias("computer:3dprinter_bedflinger", "home_workshop_machines:3dprinter_bedflinger")
minetest.register_alias("computers:3dprinter_bedflinger", "home_workshop_machines:3dprinter_bedflinger")
minetest.register_alias("computer:3dprinter_corexy", "home_workshop_machines:3dprinter_corexy")

View File

@ -1,3 +1,6 @@
# textdomain: home_workshop_machines
### init.lua ###
3D Printer ("bedflinger" design)=3D Drucker ("Bettschubser")
3D Printer (CoreXY design)=

View File

@ -1,3 +1,6 @@
# textdomain: home_workshop_machines
### init.lua ###
3D Printer ("bedflinger" design)=
3D Printer (CoreXY design)=

View File

@ -1,3 +1,4 @@
name = home_workshop_machines
depends = unifieddyes, xcompat
optional_depends = default, screwdriver, dye, basic_materials
depends = unifieddyes
optional_depends = default
optional_depends = screwdriver

View File

@ -1,19 +1,17 @@
local materials = xcompat.materials
minetest.register_craft({
output = "home_workshop_misc:tool_cabinet",
recipe = {
{ "basic_materials:motor", materials.axe_steel, materials.pick_steel },
{ materials.steel_ingot, "home_workshop_misc:drawer_small", materials.steel_ingot },
{ materials.steel_ingot, "home_workshop_misc:drawer_small", materials.steel_ingot }
{ "basic_materials:motor", "default:axe_steel", "default:pick_steel" },
{ "default:steel_ingot", "home_workshop_misc:drawer_small", "default:steel_ingot" },
{ "default:steel_ingot", "home_workshop_misc:drawer_small", "default:steel_ingot" }
},
})
minetest.register_craft({
output = "home_workshop_misc:beer_tap",
recipe = {
{ "group:stick", materials.steel_ingot, "group:stick" },
{ "basic_materials:steel_bar", materials.steel_ingot, "basic_materials:steel_bar" },
{ materials.steel_ingot, materials.steel_ingot, materials.steel_ingot }
{ "group:stick", "default:steel_ingot", "group:stick" },
{ "basic_materials:steel_bar", "default:steel_ingot", "basic_materials:steel_bar" },
{ "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
},
})

View File

@ -18,8 +18,7 @@ minetest.register_node("home_workshop_misc:tool_cabinet", {
paramtype2="facedir",
inventory_image = "home_workshop_misc_tool_cabinet_inv.png",
on_rotate = minetest.get_modpath("screwdriver") and screwdriver.rotate_simple or nil,
groups = { snappy=3, dig_tree=2 },
is_ground_content = false,
groups = { snappy=3 },
expand = { top="placeholder" },
inventory = {
size=24,
@ -37,8 +36,7 @@ minetest.register_node("home_workshop_misc:beer_tap", {
inventory_image = "home_workshop_misc_beertap_inv.png",
paramtype = "light",
paramtype2 = "facedir",
groups = { snappy=3, dig_tree=2 },
is_ground_content = false,
groups = { snappy=3 },
walkable = false,
selection_box = {
type = "fixed",
@ -46,7 +44,6 @@ minetest.register_node("home_workshop_misc:beer_tap", {
},
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local inv = clicker:get_inventory()
if not itemstack then return end
local wieldname = itemstack:get_name()
if wieldname == "vessels:drinking_glass" then
@ -78,9 +75,8 @@ minetest.register_node("home_workshop_misc:beer_mug", {
paramtype = "light",
paramtype2 = "facedir",
groups = { snappy=3, oddly_breakable_by_hand=3 },
is_ground_content = false,
walkable = false,
sounds = xcompat.sounds.node_sound_glass_defaults(),
sounds = default and default.node_sound_glass_defaults() or nil,
selection_box = beer_cbox,
on_use = function(itemstack, user, pointed_thing)
if not minetest.is_creative_enabled(user:get_player_name()) then
@ -100,7 +96,7 @@ else
end
local MODPATH = minetest.get_modpath("home_workshop_misc")
if minetest.get_modpath("basic_materials") then
if minetest.get_modpath("default") and minetest.get_modpath("basic_materials") then
dofile(MODPATH.."/crafts.lua")
end

View File

@ -1,7 +1,12 @@
# textdomain: home_workshop_misc
### init.lua ###
Metal tool cabinet and work table=Metallwerkzeugschrank und Arbeitstisch
Beer tap=Bierzapfhahn
Ahh, a frosty cold beer - look in your inventory for it!=Ahh ein kühles Bier sehen Sie in Ihrem Inventar nach!
No room in your inventory to add a beer mug!=Kein Platz im Inventar für einen Bierkrug!
Beer mug=Bierkrug
Small Wooden Drawer=
Beer tap=Bierzapfhahn
Soda Can=Limodose
Soda vending machine=Limoautomat
No room in your inventory to add a beer mug!=Kein Platz im Inventar für einen Bierkrug!
Please insert a 25 Mg cent coin in the machine.=Bitte Münze in Automaten einwerfen.

View File

@ -1,7 +1,11 @@
# textdomain: home_workshop_misc
### init.lua ###
Metal tool cabinet and work table=Mesa de trabajo y gabinete en hierro
Beer tap=Grifo de cerveza
Ahh, a frosty cold beer - look in your inventory for it!=¡Ah, una cerveza fría! La encontrarás en tu inventario.
No room in your inventory to add a beer mug!=¡No hay lugar para tomar una jarra de cerveza!
Beer mug=Jarra de cerveza
Small Wooden Drawer=
Beer tap=Grifo de cerveza
Soda Can=Lata de refresco
Soda vending machine=Máquina expendedora de refrescos
No room in your inventory to add a beer mug!=¡No hay lugar para tomar una jarra de cerveza!
Please insert a 25 Mg cent coin in the machine.=Por favor introduzca una moneda en la máquina.

View File

@ -1,7 +1,11 @@
# textdomain: home_workshop_misc
### init.lua ###
Metal tool cabinet and work table=Établi pour le travail du métal
Beer tap=Pompe à bière
Ahh, a frosty cold beer - look in your inventory for it!=Ahh, une bière bien fraîche - regardez dans votre inventaire !
No room in your inventory to add a beer mug!=Pas de place dans votre inventaire pour ajouter une pinte de bière !
Beer mug=Pinte de bière
Small Wooden Drawer=
Beer tap=Pompe à bière
No room in your inventory to add a beer mug!=Pas de place dans votre inventaire pour ajouter une pinte de bière !
Please insert a 25 Mg cent coin in the machine.=Veuillez insérer une pièce dans la machine.
Soda Can=Canette de soda
Soda vending machine=Distributeur de boissons

View File

@ -1,7 +1,11 @@
# textdomain: home_workshop_misc
### init.lua ###
Metal tool cabinet and work table=Kabinet Alatan Logam dan Meja Kerja
Beer tap=Paip Bir
Ahh, a frosty cold beer - look in your inventory for it!=Ahh, bir sejuk dingin - cari dalam inventori anda!
No room in your inventory to add a beer mug!=Tiada ruang dalam inventori anda untuk menambah kole bir!
Beer mug=Kole Bir
Small Wooden Drawer=
Beer tap=Paip Bir
No room in your inventory to add a beer mug!=Tiada ruang dalam inventori anda untuk menambah kole bir!
Please insert a 25 Mg cent coin in the machine.=Sila masukkan duit syiling ke dalam mesin.
Soda Can=Tin Soda
Soda vending machine=Mesin Soda Layan Diri

View File

@ -1,7 +1,11 @@
# textdomain: home_workshop_misc
### init.lua ###
Metal tool cabinet and work table=Gabinete de ferramentas metálicas e mesa de trabalho
Beer tap=Torneira de cerveja
Ahh, a frosty cold beer - look in your inventory for it!=Ahh, uma cerveja bem gelada - procure por ela em seu inventário!
No room in your inventory to add a beer mug!=Sem espaço no inventário para colocar uma caneca de cerveja
Beer mug=Caneca de cerveja
Small Wooden Drawer=
Beer tap=Torneira de cerveja
No room in your inventory to add a beer mug!=Sem espaço no inventário para colocar uma caneca de cerveja
Please insert a 25 Mg cent coin in the machine.=Por favor insira uma moeda na máquina.
Soda Can=Lata de Refrigerante
Soda vending machine=Máquina de refrigerante

View File

@ -1,7 +1,11 @@
# textdomain: home_workshop_misc
### init.lua ###
Metal tool cabinet and work table=Gabinete de ferramentas metálicas e mesa de trabalho
Beer tap=Torneira de cerveja
Ahh, a frosty cold beer - look in your inventory for it!=Ahh, uma cerveja bem gelada - procure por ela em seu inventário!
No room in your inventory to add a beer mug!=Sem espaço no inventário para colocar uma caneca de cerveja
Beer mug=Caneca de cerveja
Small Wooden Drawer=
Beer tap=Torneira de cerveja
No room in your inventory to add a beer mug!=Sem espaço no inventário para colocar uma caneca de cerveja
Please insert a 25 Mg cent coin in the machine.=Por favor insira uma moeda na máquina.
Soda Can=Lata de Refrigerante
Soda vending machine=Máquina de refrigerante

View File

@ -1,7 +1,11 @@
# textdomain: home_workshop_misc
### init.lua ###
Metal tool cabinet and work table=Шкаф с металлическим инструментом и рабочий стол
Beer tap=Пивной кран
Ahh, a frosty cold beer - look in your inventory for it!=О, холодное пиво! Ищи его в инвентаре!
No room in your inventory to add a beer mug!=В инвентаре нет места для пивной кружки!
Beer mug=Пивная кружка
Small Wooden Drawer=
Beer tap=Пивной кран
No room in your inventory to add a beer mug!=В инвентаре нет места для пивной кружки!
Please insert a 25 Mg cent coin in the machine.=Вставьте монету в автомат.
Soda Can=Банка газировки
Soda vending machine=Автомат с газировкой

View File

@ -1,7 +1,12 @@
# textdomain: home_workshop_misc
### init.lua ###
Metal tool cabinet and work table=金属工具柜及工作台
Beer tap=啤酒龙头
Ahh, a frosty cold beer - look in your inventory for it!=啊,一杯冰凉的啤酒-看看你的库存吧!
No room in your inventory to add a beer mug!=你的库存里没有地方放啤酒杯!
Beer mug=啤酒杯
Small Wooden Drawer=
Beer tap=啤酒龙头
No room in your inventory to add a beer mug!=你的库存里没有地方放啤酒杯!
Please insert a 25 Mg cent coin in the machine.=请在机器里放一枚硬币。
Soda Can=易拉罐
Soda vending machine=汽水自动售货机

View File

@ -1,7 +1,12 @@
# textdomain: home_workshop_misc
### init.lua ###
Metal tool cabinet and work table=
Beer tap=
Ahh, a frosty cold beer - look in your inventory for it!=
No room in your inventory to add a beer mug!=
Beer mug=
Small Wooden Drawer=
Beer tap=
No room in your inventory to add a beer mug!=
Please insert a 25 Mg cent coin in the machine.=
Soda Can=
Soda vending machine=

View File

@ -1,3 +1,2 @@
name = home_workshop_misc
depends = xcompat
optional_depends = currency, screwdriver, homedecor_common, default

View File

@ -1,2 +0,0 @@
name = home_workshop_modpack
min_minetest_version = 5.4.0