Compare commits
	
		
			39 Commits
		
	
	
		
			2021-03-04
			...
			computers
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 59a217ceb9 | ||
|  | 0dbc57cbbe | ||
|  | ee4cbef811 | ||
|  | fc7c0ff095 | ||
|  | 1f28124569 | ||
|  | 1ea698a1e1 | ||
|  | c46ec76c63 | ||
|  | aca2f138a8 | ||
|  | 8267c4d71f | ||
|  | fa1f4894af | ||
|  | 2593c55ee3 | ||
|  | 3e4e65e01b | ||
|  | 2060c59920 | ||
|  | 4cfacb1abc | ||
|  | ef2ceed755 | ||
|  | d0a4ace94e | ||
|  | 1397b08bcb | ||
|  | a844c7ec5e | ||
|  | f57b1642b9 | ||
|  | eacbe80fae | ||
|  | b3ca88e58d | ||
|  | b5ec85d037 | ||
|  | 0af4ae2eb2 | ||
|  | 2058c58738 | ||
|  | 1ce0533672 | ||
|  | 6f9a27ff05 | ||
|  | c350f40405 | ||
|  | 35a3be337d | ||
|  | 0664552799 | ||
|  | 7043a7d15d | ||
|  | 2e2d904261 | ||
|  | daf04bd400 | ||
|  | 427b6b1f3f | ||
|  | 92ee7e419e | ||
|  | 0a43ffe46a | ||
|  | eca7c55028 | ||
|  | 7e517d8386 | ||
|  | 03325e886a | ||
|  | d37bc20673 | 
							
								
								
									
										18
									
								
								.github/workflows/luacheck.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,18 @@ | ||||
|  | ||||
| name: luacheck | ||||
|  | ||||
| on: [push, pull_request] | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v1 | ||||
|     - name: apt | ||||
|       run: sudo apt-get install -y luarocks | ||||
|     - name: luacheck install | ||||
|       run: luarocks install --local luacheck | ||||
|     - name: luacheck run | ||||
|       run: $HOME/.luarocks/bin/luacheck ./ | ||||
							
								
								
									
										25
									
								
								.luacheckrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,25 @@ | ||||
| unused_args = false | ||||
| allow_defined_top = true | ||||
|  | ||||
| exclude_files = {".luacheckrc"} | ||||
|  | ||||
| globals = { | ||||
|     "minetest", "core", | ||||
|  | ||||
|     --mod provided | ||||
|     "home_vending_machines", "computers", | ||||
| } | ||||
|  | ||||
| read_globals = { | ||||
|     string = {fields = {"split"}}, | ||||
|     table = {fields = {"copy", "getn"}}, | ||||
|  | ||||
|     --luac | ||||
|     "math", "table", | ||||
|  | ||||
|     -- Builtin | ||||
|     "vector", "ItemStack", "dump", "DIR_DELIM", "VoxelArea", "Settings", "PcgRandom", "VoxelManip", "PseudoRandom", | ||||
|  | ||||
|     --mod produced | ||||
|     "default", "screwdriver", "unifieddyes", "formspec_ast",  | ||||
| } | ||||
| @@ -1,21 +0,0 @@ | ||||
| unused_args = false | ||||
| allow_defined_top = true | ||||
| max_comment_line_length = 999 | ||||
|  | ||||
| read_globals = { | ||||
| 	"DIR_DELIM", | ||||
| 	"minetest", "core", | ||||
| 	"unpack", | ||||
| 	"dump", | ||||
| 	table = { fields = { "copy", "getn" } }, | ||||
| 	"vector", "nodeupdate", | ||||
| 	"VoxelManip", "VoxelArea", | ||||
| 	"PseudoRandom", "ItemStack", | ||||
| 	"default", | ||||
| 	"unifieddyes", | ||||
| 	"screwdriver", | ||||
| } | ||||
|  | ||||
| globals = { | ||||
| } | ||||
|  | ||||
| @@ -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
									
								
							
							
						
						| @@ -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 | ||||
| @@ -1,49 +0,0 @@ | ||||
|  | ||||
| Decorative Computers Mod for Minetest | ||||
| by Diego Martínez <kaeza@users.sf.net> | ||||
|  | ||||
| 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/ | ||||
| @@ -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 :) | ||||
							
								
								
									
										7
									
								
								computers/commands/cat/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "cat", | ||||
|     "license": "MIT", | ||||
|     "version": 0.1, | ||||
|     "engine": 0.44, | ||||
|     "help": "output file to the terminal" | ||||
| } | ||||
							
								
								
									
										15
									
								
								computers/commands/cat/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										7
									
								
								computers/commands/cd/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "cd", | ||||
|     "license": "MIT", | ||||
|     "version": 0.11, | ||||
|     "engine": 0.41, | ||||
|     "help": "move in and out of folders" | ||||
| } | ||||
							
								
								
									
										28
									
								
								computers/commands/cd/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										7
									
								
								computers/commands/echo/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "echo", | ||||
|     "license": "MIT", | ||||
|     "version": 0.1, | ||||
|     "engine": 0.3, | ||||
|     "help": "prints out input to the terminal" | ||||
| } | ||||
							
								
								
									
										5
									
								
								computers/commands/echo/init.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,5 @@ | ||||
| function echo(pos, input, data) | ||||
|     return input | ||||
| end | ||||
|  | ||||
| return echo | ||||
							
								
								
									
										7
									
								
								computers/commands/exit/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "exit", | ||||
|     "license": "MIT", | ||||
|     "version": 0.1, | ||||
|     "engine": 0.42, | ||||
|     "help": "exits the computer" | ||||
| } | ||||
							
								
								
									
										7
									
								
								computers/commands/exit/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										7
									
								
								computers/commands/expr/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "expr", | ||||
|     "license": "MIT", | ||||
|     "version": 0.1, | ||||
|     "engine": 0.42, | ||||
|     "help": "exicutes mathmatical expresions" | ||||
| } | ||||
							
								
								
									
										14
									
								
								computers/commands/expr/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										7
									
								
								computers/commands/help/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "help", | ||||
|     "license": "MIT", | ||||
|     "version": 0.1, | ||||
|     "engine": 0.4, | ||||
|     "help": "prints out help" | ||||
| } | ||||
							
								
								
									
										9
									
								
								computers/commands/help/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										7
									
								
								computers/commands/ls/conf.json
									
									
									
									
									
										Normal 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" | ||||
| } | ||||
							
								
								
									
										9
									
								
								computers/commands/ls/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										7
									
								
								computers/commands/mkdir/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "mkdir", | ||||
|     "license": "MIT", | ||||
|     "version": 0.11, | ||||
|     "engine": 0.41, | ||||
|     "help": "makes a dir in the current path" | ||||
| } | ||||
							
								
								
									
										15
									
								
								computers/commands/mkdir/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										7
									
								
								computers/commands/nano/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "nano", | ||||
|     "license": "MIT", | ||||
|     "version": 0.1, | ||||
|     "engine": 0.42, | ||||
|     "help": "allows editing of files" | ||||
| } | ||||
							
								
								
									
										113
									
								
								computers/commands/nano/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										7
									
								
								computers/commands/net/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "net", | ||||
|     "license": "MIT", | ||||
|     "version": 0.1, | ||||
|     "engine": 0.43, | ||||
|     "help": "configuration related to networking" | ||||
| } | ||||
							
								
								
									
										64
									
								
								computers/commands/net/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										7
									
								
								computers/commands/pwd/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "pwd", | ||||
|     "license": "MIT", | ||||
|     "version": 0.1, | ||||
|     "engine": 0.4, | ||||
|     "help": "list the current path" | ||||
| } | ||||
							
								
								
									
										7
									
								
								computers/commands/pwd/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										7
									
								
								computers/commands/test/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "test", | ||||
|     "license": "MIT", | ||||
|     "version": 0.1, | ||||
|     "engine": 100000000, | ||||
|     "help": "literally worthless" | ||||
| } | ||||
							
								
								
									
										6
									
								
								computers/commands/test/init.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| function test(pos, input) | ||||
|     --minetest.chat_send_all("test") | ||||
|     return 0 | ||||
| end | ||||
|  | ||||
| return test | ||||
							
								
								
									
										7
									
								
								computers/commands/touch/conf.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "name": "touch", | ||||
|     "license": "MIT", | ||||
|     "version": 0.3, | ||||
|     "engine": 0.42, | ||||
|     "help": "creates a file in the current path" | ||||
| } | ||||
							
								
								
									
										22
									
								
								computers/commands/touch/init.lua
									
									
									
									
									
										Normal 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
									
								
							
							
						
						| @@ -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 | ||||
							
								
								
									
										26
									
								
								computers/core/commands.lua
									
									
									
									
									
										Normal 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
									
								
							
							
						
						| @@ -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
									
								
							
							
						
						| @@ -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
									
								
							
							
						
						| @@ -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
									
								
							
							
						
						| @@ -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 | ||||
							
								
								
									
										18
									
								
								computers/default_page.page
									
									
									
									
									
										Normal 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
									
								
							
							
						
						| @@ -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
									
								
							
							
						
						| @@ -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> | ||||
| @@ -1,354 +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) | ||||
| 			..default.gui_bg..default.gui_bg_img..default.gui_slots) | ||||
| 		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")).."]" | ||||
| 			..default.gui_bg..default.gui_bg_img..default.gui_slots) | ||||
| 	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 | ||||
| }) | ||||
| @@ -1,98 +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", | ||||
| 		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.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.."/recipes.lua") | ||||
| dofile(MODPATH.."/gaming.lua") | ||||
| dofile(MODPATH.."/aliases.lua") | ||||
| dofile(computers.modpath .. "/demo.lua") | ||||
|   | ||||
| @@ -1,3 +1,3 @@ | ||||
| name = computers | ||||
| depends = default, basic_materials | ||||
| optional_depends = screwdriver | ||||
| depends = formspec_ast | ||||
| optional_depends = screwdriver, default, basic_materials | ||||
|   | ||||
| @@ -3,11 +3,13 @@ minetest.register_alias("computer:shefriendSOO_off",     "computers:shefriendSOO | ||||
| minetest.register_alias("computer:vanio",                "computers:vanio") | ||||
| minetest.register_alias("computer:vanio_off",            "computers:vanio_off") | ||||
| minetest.register_alias("computer:slaystation",          "computers:slaystation") | ||||
| minetest.register_alias("computer:slaystation_off",      "computers:slaystation_off") | ||||
| minetest.register_alias("computer:slaystation2",         "computers:slaystation2") | ||||
| minetest.register_alias("computer:slaystation2_off",     "computers:slaystation2_off") | ||||
| minetest.register_alias("computer:specter",              "computers:specter") | ||||
| minetest.register_alias("computer:specter_off",          "computers:specter_off") | ||||
| minetest.register_alias("computer:wee",                  "computers:wee") | ||||
| minetest.register_alias("computer:wee_off",              "computers:wee_off") | ||||
| minetest.register_alias("computer:piepad",               "computers:piepad") | ||||
| minetest.register_alias("computer:admiral64",            "computers:admiral64") | ||||
| minetest.register_alias("computer:admiral64_off",        "computers:admiral64_off") | ||||
							
								
								
									
										11
									
								
								computers/nodes/init.lua
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										78
									
								
								computers/nodes/node_api.lua
									
									
									
									
									
										Normal 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 | ||||
| @@ -80,7 +80,7 @@ minetest.register_node("computers:piepad", { | ||||
| 	walkable = false, | ||||
| 	groups = {oddly_breakable_by_hand=2}, | ||||
| 	selection_box = {type = "wallmounted"}, | ||||
| 	sounds = default.node_sound_wood_defaults() | ||||
| 	sounds = default and default.node_sound_wood_defaults() or nil | ||||
| }) | ||||
| 
 | ||||
| -- Commodore 64 lookalike | ||||
| @@ -116,7 +116,9 @@ minetest.register_node("computers:monitor", { | ||||
| 	inventory_image = "computers_monitor_inv.png", | ||||
| 	drawtype = "mesh", | ||||
| 	mesh = "computers_monitor.obj", | ||||
| 	tiles = {"computers_black.png", "computers_monitor_plastic.png", "computers_black.png", "computers_monitor_plastic.png"}, | ||||
| 	tiles = { | ||||
| 		"computers_black.png", "computers_monitor_plastic.png", "computers_black.png", "computers_monitor_plastic.png" | ||||
| 	}, | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	walkable = false, | ||||
| @@ -132,7 +134,12 @@ minetest.register_node("computers:monitor", { | ||||
| minetest.register_node("computers:monitor_on", { | ||||
| 	drawtype = "mesh", | ||||
| 	mesh = "computers_monitor.obj", | ||||
| 	tiles = {"computers_monitor_display.png^[transformFX", "computers_monitor_plastic.png", "computers_black.png", "computers_monitor_plastic.png"}, | ||||
| 	tiles = { | ||||
| 		"computers_monitor_display.png^[transformFX", | ||||
| 		"computers_monitor_plastic.png", | ||||
| 		"computers_black.png", | ||||
| 		"computers_monitor_plastic.png" | ||||
| 	}, | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	light_source = 9, | ||||
| @@ -147,38 +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", | ||||
| 	walkable = false, | ||||
| 	groups = {snappy=3}, | ||||
| 	sound = default.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 } | ||||
| @@ -194,7 +169,7 @@ minetest.register_node("computers:tower", { | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	groups = {snappy=3}, | ||||
| 	sound = default.node_sound_wood_defaults(), | ||||
| 	sound = default and default.node_sound_wood_defaults() or nil, | ||||
| 	selection_box = pct_cbox, | ||||
| 	collision_box = pct_cbox | ||||
| }) | ||||
| @@ -223,7 +198,7 @@ minetest.register_node("computers:server", { | ||||
| 		type = "fixed", | ||||
| 		fixed = {-0.5, -0.5, -0.25, 0.5, 1.125, 0.4375} | ||||
| 	}, | ||||
| 	sounds = default.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) | ||||
| @@ -262,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 = default.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" | ||||
| @@ -282,7 +257,7 @@ minetest.register_node("computers:printer", { | ||||
| 	paramtype2 = "facedir", | ||||
| 	walkable = true, | ||||
| 	groups = {snappy=3}, | ||||
| 	sound = default.node_sound_wood_defaults(), | ||||
| 	sound = default and default.node_sound_wood_defaults() or nil, | ||||
| 	drawtype = "nodebox", | ||||
| 	node_box = { | ||||
| 		type = "fixed", | ||||
| @@ -298,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 }, | ||||
| 	}) | ||||
| }) | ||||
| @@ -1,5 +1,3 @@ | ||||
| -- Copyright (C) 2012-2013 Diego Martínez <kaeza@users.sf.net> | ||||
| 
 | ||||
| minetest.register_craft({ | ||||
| 	output = "computers:shefriendSOO", | ||||
| 	recipe = { | ||||
							
								
								
									
										227
									
								
								computers/nodes/router.lua
									
									
									
									
									
										Normal 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
									
								
							
							
						
						| @@ -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 | ||||
| }) | ||||
							
								
								
									
										
											BIN
										
									
								
								computers/textures/kuto_button.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 504 B | 
							
								
								
									
										59
									
								
								home_vending_machines/api.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,59 @@ | ||||
| local registered_currency = {} | ||||
|  | ||||
| function home_vending_machines.register_currency(name, worth) | ||||
|     registered_currency[name] = worth | ||||
| end | ||||
|  | ||||
| local function reg_simple(name, def) | ||||
|     minetest.register_node(":" .. name, { | ||||
|         description = def.description, | ||||
|         drawtype = "mesh", | ||||
|         mesh = "home_vending_machines_machine.obj", | ||||
|         tiles = def.tiles, | ||||
|         paramtype = "light", | ||||
|         paramtype2 = "facedir", | ||||
|         groups = def.groups or {snappy=3}, | ||||
|         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} | ||||
|         }, | ||||
|         sounds = def.sounds, | ||||
|         on_rotate = function(pos, node, user, mode, new_param2) | ||||
|             if minetest.get_modpath("screwdriver") then | ||||
|                 return screwdriver.rotate_simple(pos, node, user, mode, new_param2) | ||||
|             end | ||||
|         end, | ||||
|         on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) | ||||
|             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) | ||||
|  | ||||
|             if registered_currency[iname] and registered_currency[iname] == 1 then | ||||
|                 local item = def._vmachine.item | ||||
|                 if type(item) == "table" then | ||||
|                     item = item[math.random(#item)] | ||||
|                 end | ||||
|  | ||||
|                 minetest.add_item(dpos, item) | ||||
|  | ||||
|                 if not minetest.is_creative_enabled(pname) then | ||||
|                     itemstack:take_item() | ||||
|                     return itemstack | ||||
|                 end | ||||
|             else | ||||
|                 minetest.chat_send_player(pname, "Please insert valid currency.") | ||||
|             end | ||||
|         end | ||||
|     }) | ||||
| end | ||||
|  | ||||
| function home_vending_machines.register_machine(type, name, def) | ||||
|     if type == "simple" then | ||||
|         reg_simple(name, def) | ||||
|     end | ||||
|     --TODO: add more complex machine type with formspec and selections | ||||
| end | ||||
							
								
								
									
										32
									
								
								home_vending_machines/crafts.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,32 @@ | ||||
| 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 | ||||
							
								
								
									
										9
									
								
								home_vending_machines/init.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,9 @@ | ||||
| local modpath = minetest.get_modpath("home_vending_machines") | ||||
| home_vending_machines = {} | ||||
|  | ||||
| dofile(modpath .. "/api.lua") | ||||
| dofile(modpath .. "/machines.lua") | ||||
| dofile(modpath .. "/items.lua") | ||||
| dofile(modpath .. "/crafts.lua") | ||||
|  | ||||
| home_vending_machines.init = true | ||||
							
								
								
									
										12
									
								
								home_vending_machines/items.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| local function reg_item(name, evalue) | ||||
|     minetest.register_craftitem("home_vending_machines:" .. name, { | ||||
|         description = string.gsub(name, "_", " "), | ||||
|         inventory_image = "home_vending_machines_" .. name .. ".png", | ||||
|         on_use = minetest.item_eat(evalue), | ||||
|     }) | ||||
| end | ||||
|  | ||||
| reg_item("soda_can", 2) | ||||
| minetest.register_alias("home_workshop_misc:soda_can", "home_vending_machines:soda_can") | ||||
|  | ||||
| reg_item("water_bottle", 3) | ||||
							
								
								
									
										29
									
								
								home_vending_machines/machines.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,29 @@ | ||||
| home_vending_machines.register_currency("default:gold_ingot", 1) | ||||
| home_vending_machines.register_currency("currency:minegeld_cent_25", 1) | ||||
|  | ||||
| home_vending_machines.register_machine("simple", "home_workshop_misc:soda_machine", { | ||||
|     description = "Soda vending machine", | ||||
|     tiles = {"home_vending_machines_soda_machine.png"}, | ||||
|     sounds = nil, | ||||
|     _vmachine = { | ||||
|         item = "home_vending_machines:soda_can" | ||||
|     } | ||||
| }) | ||||
|  | ||||
| home_vending_machines.register_machine("simple", "home_vending_machines:drink_machine", { | ||||
|     description = "Drinks vending machine", | ||||
|     tiles = {"home_vending_machines_drink_machine.png"}, | ||||
|     sounds = nil, | ||||
|     _vmachine = { | ||||
|         item = {"home_vending_machines:soda_can", "home_vending_machines:water_bottle"} | ||||
|     } | ||||
| }) | ||||
|  | ||||
| home_vending_machines.register_machine("simple", "home_vending_machines:sweet_machine", { | ||||
|     description = "Sweets vending machine", | ||||
|     tiles = {"home_vending_machines_sweet_machine.png"}, | ||||
|     sounds = nil, | ||||
|     _vmachine = { | ||||
|         item = "home_vending_machines:soda_can" | ||||
|     } | ||||
| }) | ||||
							
								
								
									
										1
									
								
								home_vending_machines/mod.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| optional_depends = screwdriver | ||||
							
								
								
									
										11
									
								
								home_vending_machines/readme.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,11 @@ | ||||
| code wsor MIT | ||||
|  | ||||
| VanessaE (cc-by-sa 4.0): | ||||
| home_vending_machines_machine.obj | ||||
| home_vending_machines_soda_can.png | ||||
| home_vending_machines_soda_machine.png | ||||
|  | ||||
| Andrey01 (CC BY-SA 3.0): | ||||
| home_vending_machines_drimk_machine.png | ||||
| home_vending_machines_sweet_machine.png | ||||
| home_vending_machines_water_bottle.png | ||||
| Before Width: | Height: | Size: 155 B After Width: | Height: | Size: 155 B | 
| After Width: | Height: | Size: 381 B | 
| After Width: | Height: | Size: 920 B | 
| Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB | 
| After Width: | Height: | Size: 1.3 KiB | 
| @@ -1,2 +0,0 @@ | ||||
| -- nothing to see here :P | ||||
| -- this is just a stub to provide a few textures | ||||
| @@ -17,7 +17,7 @@ minetest.register_node("home_workshop_machines:3dprinter_bedflinger", { | ||||
| 	paramtype = "light", | ||||
| 	walkable = true, | ||||
| 	groups = {snappy=3, ud_param2_colorable = 1}, | ||||
| 	sound = default.node_sound_wood_defaults(), | ||||
| 	sound = default and default.node_sound_wood_defaults() or nil, | ||||
| 	drawtype = "mesh", | ||||
| 	mesh = "home_workshop_machines_3dprinter_bedflinger.obj", | ||||
| 	paramtype2 = "colorwallmounted", | ||||
| @@ -47,7 +47,7 @@ minetest.register_node("home_workshop_machines:3dprinter_corexy", { | ||||
| 	paramtype = "light", | ||||
| 	walkable = true, | ||||
| 	groups = {snappy=3, ud_param2_colorable = 1}, | ||||
| 	sound = default.node_sound_wood_defaults(), | ||||
| 	sound = default and default.node_sound_wood_defaults() or nil, | ||||
| 	drawtype = "mesh", | ||||
| 	mesh = "home_workshop_machines_3dprinter_corexy.obj", | ||||
| 	paramtype2 = "colorwallmounted", | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| name = home_workshop_machines | ||||
| depends = default, unifieddyes | ||||
| depends = unifieddyes | ||||
| optional_depends = default | ||||
| optional_depends = screwdriver | ||||
|   | ||||
| @@ -14,13 +14,4 @@ minetest.register_craft({ | ||||
| 		{ "basic_materials:steel_bar", "default:steel_ingot", "basic_materials:steel_bar" }, | ||||
| 		{ "default:steel_ingot",       "default:steel_ingot", "default:steel_ingot" } | ||||
| 	}, | ||||
| }) | ||||
|  | ||||
| minetest.register_craft({ | ||||
| 	output = "homedecor: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"}, | ||||
| 	}, | ||||
| }) | ||||
| }) | ||||
| @@ -14,6 +14,7 @@ minetest.register_node("home_workshop_misc:tool_cabinet", { | ||||
| 		"home_workshop_common_generic_metal_bright.png", | ||||
| 		"home_workshop_misc_tool_cabinet_misc.png", | ||||
| 	}, | ||||
| 	paramtype = "light", | ||||
| 	paramtype2="facedir", | ||||
| 	inventory_image = "home_workshop_misc_tool_cabinet_inv.png", | ||||
| 	on_rotate = minetest.get_modpath("screwdriver") and screwdriver.rotate_simple or nil, | ||||
| @@ -33,6 +34,7 @@ minetest.register_node("home_workshop_misc:beer_tap", { | ||||
| 		{ name = "home_workshop_common_generic_metal.png", color = 0xff303030 } | ||||
| 	}, | ||||
| 	inventory_image = "home_workshop_misc_beertap_inv.png", | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	groups = { snappy=3 }, | ||||
| 	walkable = false, | ||||
| @@ -46,9 +48,9 @@ minetest.register_node("home_workshop_misc:beer_tap", { | ||||
| 		local wieldname = itemstack:get_name() | ||||
| 		if wieldname == "vessels:drinking_glass" then | ||||
| 			if inv:room_for_item("main", "home_workshop_misc:beer_mug 1") then | ||||
| 				inv:add_item("main", "home_workshop_misc:beer_mug 1") | ||||
| 				itemstack:take_item() | ||||
| 				clicker:set_wielded_item(itemstack) | ||||
| 				inv:add_item("main", "home_workshop_misc:beer_mug 1") | ||||
| 				minetest.chat_send_player(clicker:get_player_name(), | ||||
| 						S("Ahh, a frosty cold beer - look in your inventory for it!")) | ||||
| 			else | ||||
| @@ -70,77 +72,35 @@ minetest.register_node("home_workshop_misc:beer_mug", { | ||||
| 	mesh = "home_workshop_misc_beer_mug.obj", | ||||
| 	tiles = { "home_workshop_misc_beer_mug.png" }, | ||||
| 	inventory_image = "home_workshop_misc_beer_mug_inv.png", | ||||
| 	paramtype = "light", | ||||
| 	paramtype2 = "facedir", | ||||
| 	groups = { snappy=3, oddly_breakable_by_hand=3 }, | ||||
| 	walkable = false, | ||||
| 	sounds = default.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 creative.is_enabled_for(user:get_player_name()) then | ||||
| 		if not minetest.is_creative_enabled(user:get_player_name()) then | ||||
| 			minetest.do_item_eat(2, "vessels:drinking_glass 1", itemstack, user, pointed_thing) | ||||
| 			return itemstack | ||||
| 		end | ||||
| 	end | ||||
| }) | ||||
|  | ||||
| local svm_cbox = { | ||||
| 	type = "fixed", | ||||
| 	fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5} | ||||
| } | ||||
|  | ||||
| minetest.register_node("home_workshop_misc:soda_machine", { | ||||
| 	description = S("Soda vending machine"), | ||||
| 	drawtype = "mesh", | ||||
| 	mesh = "home_workshop_misc_soda_machine.obj", | ||||
| 	tiles = {"home_workshop_misc_soda_machine.png"}, | ||||
| 	paramtype2 = "facedir", | ||||
| 	groups = {snappy=3}, | ||||
| 	selection_box = svm_cbox, | ||||
| 	collision_box = svm_cbox, | ||||
| 	expand = { top="placeholder" }, | ||||
| 	sounds = default.node_sound_wood_defaults(), | ||||
| 	on_rotate = minetest.get_modpath("screwdriver") and screwdriver.rotate_simple or nil, | ||||
| 	on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) | ||||
| 		local playername = clicker:get_player_name() | ||||
| 		local wielditem = clicker:get_wielded_item() | ||||
| 		local wieldname = wielditem:get_name() | ||||
| 		local fdir_to_fwd = { {0, -1}, {-1, 0}, {0, 1}, {1, 0} } | ||||
| 		local fdir = node.param2 | ||||
| 		local pos_drop = { x=pos.x+fdir_to_fwd[fdir+1][1], y=pos.y, z=pos.z+fdir_to_fwd[fdir+1][2] } | ||||
| 		if wieldname == "currency:minegeld_cent_25" then | ||||
| 			minetest.spawn_item(pos_drop, "home_workshop_misc:soda_can") | ||||
| 			minetest.sound_play("insert_coin", { | ||||
| 				pos=pos, max_hear_distance = 5 | ||||
| 			}) | ||||
| 			if not creative.is_enabled_for(playername) then | ||||
| 				wielditem:take_item() | ||||
| 				clicker:set_wielded_item(wielditem) | ||||
| 				return wielditem | ||||
| 			end | ||||
| 		else | ||||
| 			minetest.chat_send_player(playername, S("Please insert a 25 Mg cent coin in the machine.")) | ||||
| 		end | ||||
| 	end | ||||
| }) | ||||
|  | ||||
| minetest.register_craftitem("home_workshop_misc:soda_can", { | ||||
| 	description = S("Soda Can"), | ||||
| 	inventory_image = "home_workshop_misc_soda_can.png", | ||||
| 	on_use = minetest.item_eat(2), | ||||
| }) | ||||
|  | ||||
| if minetest.get_modpath("homedecor_common") then | ||||
| 	minetest.register_alias("home_workshop_misc:drawer_small", "homedecor:drawer_small") | ||||
| else | ||||
| 	minetest.register_craftitem("home_workshop_misc:drawer_small", { | ||||
| 			description = S("Small Wooden Drawer"), | ||||
| 			inventory_image = "home_workshop_machines_drawer_small.png", | ||||
| 			inventory_image = "home_workshop_common_drawer_small.png", | ||||
| 	}) | ||||
| end | ||||
|  | ||||
| local MODPATH = minetest.get_modpath("home_workshop_misc") | ||||
| dofile(MODPATH.."/crafts.lua") | ||||
| if minetest.get_modpath("default") and minetest.get_modpath("basic_materials") then | ||||
| 	dofile(MODPATH.."/crafts.lua") | ||||
| end | ||||
|  | ||||
| minetest.register_alias("homedecor:tool_cabinet",        "home_workshop_misc:tool_cabinet") | ||||
| minetest.register_alias("homedecor:tool_cabinet_bottom", "home_workshop_misc:tool_cabinet") | ||||
| minetest.register_alias("homedecor:tool_cabinet_top",    "air") | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,2 @@ | ||||
| name = home_workshop_misc | ||||
| depends = default, home_workshop_common | ||||
| optional_depends = currency, screwdriver, homedecor_common | ||||
| optional_depends = currency, screwdriver, homedecor_common, default | ||||
|   | ||||
| Before Width: | Height: | Size: 225 B After Width: | Height: | Size: 225 B | 
| Before Width: | Height: | Size: 218 B After Width: | Height: | Size: 218 B | 
| Before Width: | Height: | Size: 186 B After Width: | Height: | Size: 186 B | 
							
								
								
									
										2
									
								
								license.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,2 @@ | ||||
| LGPL-3.0 for code, | ||||
| CC-BY-SA-4.0 for media. | ||||