Merge forth_computer: part I

This includes screen and disk drive, but not the computer yet
This commit is contained in:
Novatux 2015-02-13 12:36:20 +01:00
parent b50ad6e748
commit 9b83e2586a
20 changed files with 331 additions and 121 deletions

View File

@ -1,5 +1,6 @@
License of textures
All textures are by kaeza, licensed under the CC-BY-SA license
License of textures and models
Textures and nodebox of screen are by kaeza, modified by Nore, under the WTFPL license
All other textures are by kaeza, licensed under the CC-BY-SA license
------------------------------
License of code

View File

@ -5,4 +5,4 @@ or placing nodes.
--------------------
Depends on:
pipeworks
digilines (optional)
digilines

View File

@ -1,5 +1,5 @@
local MOVE_COST = 100
local FUEL_EFFICIENCY = 10000
local FUEL_EFFICIENCY = 1000
tl = {}
local function delay(x)

View File

@ -1,2 +1,2 @@
pipeworks
digilines

162
floppy.lua Normal file
View File

@ -0,0 +1,162 @@
floppy = {}
local floppies = db.read_file("floppies")
minetest.register_on_shutdown(function()
db.write_file("floppies", floppies)
end)
local function create_floppy_id()
return #floppies + 1
end
local function handle_floppy_meta(stack)
if stack.metadata == "" or stack.metadata == nil then
local id = create_floppy_id()
stack.metadata = tostring(id)
floppies[id] = string.rep(string.char(0), 16384)
return floppies[id], true
elseif string.len(stack.metadata) >= 1000 then
local id = create_floppy_id()
floppies[id] = stack.metadata
stack.metadata = tostring(id)
return floppies[id], true
else
if floppies[tonumber(stack.metadata)] == nil then
floppies[tonumber(stack.metadata)] = string.rep(string.char(0), 16384)
end
return floppies[tonumber(stack.metadata)], false
end
end
local function set_floppy_contents(name, contents)
floppies[tonumber(name)] = contents
end
minetest.register_craftitem("turtle:floppy", {
description = "Floppy disk",
inventory_image = "floppy.png",
stack_max = 1,
})
local progs = {
["Empty"] = string.rep(string.char(0), 16536),
["Forth Boot Disk"] = create_forth_floppy(),
}
minetest.register_node("turtle:floppy_programmator",{
description = "Floppy disk programmator",
tiles = {"floppy_programmator_top.png", "floppy_programmator_bottom.png", "floppy_programmator_right.png",
"floppy_programmator_left.png", "floppy_programmator_back.png", "floppy_programmator_front.png"},
groups = {cracky = 3},
sounds = default.node_sound_stone_defaults(),
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size("floppy", 1)
meta:set_int("selected", 1)
local s = "size[8,5.5;]" ..
"dropdown[0,0;5;pselector;"
for key, _ in pairs(progs) do
s = s .. key .. ","
end
s = string.sub(s, 1, -2)
s = s .. ";1]" ..
"button[5,0;2,1;prog;Program]" ..
"list[current_name;floppy;7,0;1,1;]" ..
"list[current_player;main;0,1.5;8,4;]"
meta:set_string("formspec", s)
end,
can_dig = function(pos, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:is_empty("floppy")
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if stack:get_name() == "turtle:floppy" then return 1 end
return 0
end,
on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
if fields.prog then
local inv = meta:get_inventory()
local prog = progs[fields.pselector]
local stack = inv:get_stack("floppy", 1):to_table()
if stack == nil then return end
if stack.name ~= "turtle:floppy" or stack:is_empty() then return end
local contents, update = handle_floppy_meta(stack)
set_floppy_contents(stack.metadata, prog)
if update then
inv:set_stack("floppy", 1, ItemStack(stack))
end
end
end,
})
function floppy.disk_digiline_receive(inv, channel, msg, disk_channel, send_func)
if channel == disk_channel then
if string.len(msg) ~= 1 and string.len(msg) ~= 65 then return end -- Invalid message, it comes probably from the disk itself
local page = string.byte(msg, 1)
if page == nil then return end
local stack = inv:get_stack("floppy", 1):to_table()
if stack == nil then return end
if stack.name ~= "turtle:floppy" then return end
local floppy_contents, update = handle_floppy_meta(stack)
if update then
inv:set_stack("floppy", 1, ItemStack(stack))
end
msg = string.sub(msg, 2, -1)
if string.len(msg) == 0 then -- read
send_func(string.sub(floppy_contents, page * 64 + 1, page * 64 + 64))
else -- write
floppy_contents = string.sub(floppy_contents, 1, page * 64) ..
msg ..
string.sub(floppy_contents, page * 64 + 65, -1)
set_floppy_contents(stack.metadata, floppy_contents)
end
end
end
minetest.register_node("turtle:disk",{
description = "Disk drive",
paramtype2 = "facedir",
tiles = {"floppy_drive_top.png", "floppy_drive_bottom.png", "floppy_drive_right.png", "floppy_drive_left.png", "floppy_drive_back.png", "floppy_drive_front.png"},
groups = {cracky = 3},
sounds = default.node_sound_stone_defaults(),
digiline =
{
receptor = {},
effector = {action = function(pos, node, channel, msg)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local disk_channel = meta:get_string("channel")
floppy.disk_digiline_receive(inv, channel, msg, disk_channel, function(msg)
digiline:receptor_send(pos, digiline.rules.default, disk_channel, msg)
end)
end},
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size("floppy", 1)
meta:set_string("channel", "")
meta:set_string("formspec", "size[9,5.5;]"..
"field[0,0.5;7,1;channel;Channel:;${channel}]"..
"list[current_name;floppy;8,0;1,1;]"..
"list[current_player;main;0,1.5;8,4;]")
end,
can_dig = function(pos, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:is_empty("floppy")
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if stack:get_name() == "turtle:floppy" then return 1 end
return 0
end,
on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
fields.channel = fields.channel or meta:get_string("channel")
meta:set_string("channel", fields.channel)
end,
})

View File

@ -1,10 +1,24 @@
turtles = {}
local modpath = minetest.get_modpath("turtle")
--dofile(modpath.."/turtle.lua")
-- Database handler (for turtles and floppies)
dofile(modpath .. "/db.lua")
-- Initial computer state: bootloader
dofile(modpath .. "/computer_memory.lua")
-- Data for the forth floppy, created from forth.fth file by f.py
dofile(modpath .. "/forth_floppy.lua")
-- Computer simulation code
dofile(modpath .. "/cptr.lua")
-- Screen handler for formspec
dofile(modpath .. "/screen.lua")
-- Floppy, floppy programmator, and disk
dofile(modpath .. "/floppy.lua")
-- Turtle code
dofile(modpath .. "/t2.lua")

View File

@ -58,3 +58,125 @@ function screen.create_text_formspec(text, basex, basey)
return s:sub(2, -1)
end
------------------
-- Screen nodes --
------------------
local screens = {}
local function hashpos(pos)
if pos.x == 0 then pos.x = 0 end -- Fix for signed 0
if pos.y == 0 then pos.y = 0 end -- Fix for signed 0
if pos.z == 0 then pos.z = 0 end -- Fix for signed 0
return tostring(pos.x).."\n"..tostring(pos.y).."\n"..tostring(pos.z)
end
local function dehashpos(str)
local l = lines(str)
return {x = tonumber(l[1]), y = tonumber(l[2]), z = tonumber(l[3])}
end
local function screen_digiline_receive(pos, node, channel, msg)
local meta = minetest.get_meta(pos)
if channel == meta:get_string("channel") then
local ntext = screen.add_text(meta:get_string("text"), msg)
meta:set_string("text", ntext)
local hash = hashpos(pos)
if not screens[hash] then
screens[hash] = {pos = vector.new(pos), fmodif = true, playernames = {}}
else
screens[hashpos(pos)].fmodif = true
end
end
end
local function create_screen_formspec(text)
return "size[5,4.5;]" .. screen.create_text_formspec(text, 0, 0)
end
minetest.register_globalstep(function(dtime)
for screenhash, i in pairs(screens) do
if i.fmodif then
i.fmodif = false
local meta = minetest.get_meta(i.pos)
for pname, _ in pairs(i.playernames) do
minetest.show_formspec(pname, "screen" .. screenhash,
create_screen_formspec(meta:get_string("text")))
end
end
end
end)
local MAX_TEXT_SEND = 80
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname:sub(1,6) ~= "screen" then return end
local hash = formname:sub(7, -1)
local s = screens[hash]
if s == nil then return end
local pos = s.pos
if fields["f"] == nil or fields["f"] == "" then
if fields["quit"] ~= nil then
s.playernames[player:get_player_name()] = nil
end
return
end
if string.len(fields["f"]) > MAX_TEXT_SEND then
fields["f"] = string.sub(fields["f"], 1, MAX_TEXT_SEND)
end
digiline:receptor_send(pos, digiline.rules.default, "screen", fields["f"])
local meta = minetest.get_meta(pos)
local ntext = screen.add_text(meta:get_string("text"), fields["f"])
meta:set_string("text", ntext)
minetest.show_formspec(player:get_player_name(), formname, create_screen_formspec(ntext))
end)
minetest.register_node("turtle:screen", {
description = "Screen",
tiles = {"screen_top.png", "screen_bottom.png", "screen_right.png", "screen_left.png", "screen_back.png", "screen_front.png"},
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
node_box = {
type = "fixed",
fixed = {
{ -16/32, -16/32, 1/32, 16/32, 16/32, 13/32 }, -- Monitor Screen
{ -13/32, -13/32, 13/32, 13/32, 13/32, 16/32 }, -- Monitor Tube
{ -16/32, -16/32, -16/32, 16/32, -12/32, 1/32 }, -- Keyboard
}
},
groups = {cracky = 3},
sounds = default.node_sound_stone_defaults(),
digiline =
{
receptor = {},
effector = {action = screen_digiline_receive},
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("text", "\n\n\n\n\n\n\n\n\n\n\n\n")
screens[hashpos(pos)] = {pos = pos, fmodif = false, playernames = {}}
meta:set_string("channel", "")
meta:set_string("formspec", "field[channel;Channel;${channel}]")
end,
on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
fields.channel = fields.channel or ""
meta:set_string("channel", fields.channel)
meta:set_string("formspec", "")
end,
on_destruct = function(pos)
screens[hashpos(pos)] = nil
end,
on_rightclick = function(pos, node, clicker)
local name = clicker:get_player_name()
local meta = minetest.get_meta(pos)
local hash = hashpos(pos)
if screens[hash] == nil then
screens[hash] = {pos = pos, fmodif = false, playernames = {}}
end
screens[hash].playernames[name] = true
minetest.show_formspec(name, "screen" .. hash,
create_screen_formspec(meta:get_string("text")))
end,
})

141
t2.lua
View File

@ -5,7 +5,6 @@ local DEBUG = true
-------------------------
local turtle_infos = db.read_file("turtle_infos")
local floppies = db.read_file("floppies")
minetest.register_on_shutdown(function()
for id, info in pairs(turtle_infos) do
@ -13,9 +12,12 @@ minetest.register_on_shutdown(function()
info.playernames = {}
end
db.write_file("turtle_infos", turtle_infos)
db.write_file("floppies", floppies)
end)
------------------
-- Some helpers --
------------------
function turtles.get_turtle_info(turtle_id)
if turtle_infos[turtle_id] == nil then
turtle_infos[turtle_id] = {}
@ -32,17 +34,13 @@ function turtles.create_turtle_id()
return #turtle_infos + 1
end
function turtles.create_floppy_id()
return #floppies + 1
end
function turtles.update_formspec(turtle_id)
local info = turtles.get_turtle_info(turtle_id)
local pos = info.spos
local formspec = "size[13,9]"..
screen.create_text_formspec(info.screen, 0, 0)..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;4.8,0;8,4;]"..
"image_button[1,7.6;2.5,1;turtle_execute.png;reboot;]"..
"image_button[1,7.6;2.5,1;turtle_reboot.png;reboot;]"..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";floppy;0,7.6;1,1;]"..
"list[current_player;main;4.8,4.6;8,4;]"
if info.formspec ~= formspec then
@ -59,120 +57,24 @@ local function on_screen_digiline_receive(turtle, channel, msg)
end
end
local function handle_floppy_meta(stack)
if stack.metadata == "" or stack.metadata == nil then
local id = turtles.create_floppy_id()
stack.metadata = tostring(id)
floppies[id] = string.rep(string.char(0), 16384)
return floppies[id], true
elseif string.len(stack.metadata) >= 1000 then
local id = turtles.create_floppy_id()
floppies[id] = stack.metadata
stack.metadata = tostring(id)
return floppies[id], true
else
if floppies[tonumber(stack.metadata)] == nil then
floppies[tonumber(stack.metadata)] = string.rep(string.char(0), 16384)
local function on_disk_digiline_receive(turtle, channel, msg)
local inv = turtles.get_turtle_inventory(turtle)
floppy.disk_digiline_receive(inv, channel, msg, "boot",
function(msg) turtle_receptor_send(turtle, "boot", msg) end)
end
return floppies[tonumber(stack.metadata)], false
end
end
local function set_floppy_contents(name, contents)
floppies[tonumber(name)] = contents
end
function on_disk_digiline_receive(turtle_id, channel, msg)
if channel == "boot" then
if string.len(msg) ~= 1 and string.len(msg) ~= 65 then return end -- Invalid message, it comes probably from the disk itself
local page = string.byte(msg, 1)
if page == nil then return end
local inv = turtles.get_turtle_inventory(turtle_id)
local stack = inv:get_stack("floppy", 1):to_table()
if stack == nil then return end
if stack.name ~= "turtle:floppy" then return end
local floppy_contents, update = handle_floppy_meta(stack)
if update then
inv:set_stack("floppy", 1, ItemStack(stack))
end
msg = string.sub(msg, 2, -1)
if string.len(msg) == 0 then -- read
turtle_receptor_send(turtle_id, channel,
string.sub(floppy_contents, page * 64 + 1, page * 64 + 64))
else -- write
floppy_contents = string.sub(floppy_contents, 1, page * 64) ..
msg ..
string.sub(floppy_contents, page * 64 + 65, -1)
set_floppy_contents(stack.metadata, floppy_contents)
end
end
end
minetest.register_craftitem("turtle:floppy", {
description = "Floppy disk",
inventory_image = "floppy.png",
stack_max = 1,
})
local progs = {
["Empty"] = string.rep(string.char(0), 16536),
["Forth Boot Disk"] = create_forth_floppy(),
}
minetest.register_node("turtle:floppy_programmator",{
description = "Floppy disk programmator",
tiles = {"floppy_programmator_top.png", "floppy_programmator_bottom.png", "floppy_programmator_right.png",
"floppy_programmator_left.png", "floppy_programmator_back.png", "floppy_programmator_front.png"},
groups = {cracky = 3},
sounds = default.node_sound_stone_defaults(),
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size("floppy", 1)
meta:set_int("selected", 1)
local s = "size[8,5.5;]" ..
"dropdown[0,0;5;pselector;"
for key, _ in pairs(progs) do
s = s .. key .. ","
end
s = string.sub(s, 1, -2)
s = s .. ";1]" ..
"button[5,0;2,1;prog;Program]" ..
"list[current_name;floppy;7,0;1,1;]" ..
"list[current_player;main;0,1.5;8,4;]"
meta:set_string("formspec", s)
end,
can_dig = function(pos, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:is_empty("floppy")
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if stack:get_name() == "turtle:floppy" then return 1 end
return 0
end,
on_receive_fields = function(pos, formname, fields, sender)
local meta = minetest.get_meta(pos)
if fields.prog then
local inv = meta:get_inventory()
local prog = progs[fields.pselector]
local stack = inv:get_stack("floppy", 1):to_table()
if stack == nil then return end
if stack.name ~= "turtle:floppy" then return end
local contents, update = handle_floppy_meta(stack)
set_floppy_contents(stack.metadata, prog)
if update then
inv:set_stack("floppy", 1, ItemStack(stack))
end
end
end,
})
function turtle_receptor_send(turtle, channel, msg)
on_screen_digiline_receive(turtle, channel, msg)
on_computer_digiline_receive(turtle, channel, msg)
on_disk_digiline_receive(turtle, channel, msg)
--on_turtle_command_receive(turtle, channel, msg)
local info = turtles.get_turtle_info(turtle)
digiline:receptor_send(info.spos, digiline.rules.default, channel, msg)
end
local function turtle_receive(turtle, channel, msg)
on_screen_digiline_receive(turtle, channel, msg)
on_computer_digiline_receive(turtle, channel, msg)
on_disk_digiline_receive(turtle, channel, msg)
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
@ -218,6 +120,15 @@ minetest.register_node("turtle:turtle", {
sunlight_propagates = true,
walkable = false,
pointable = false,
digiline =
{
receptor = {},
effector = {action = function(pos, node, channel, msg)
local meta = minetest.get_meta(pos)
local turtle = meta:get_int("turtle_id")
turtle_receive(turtle, channel, msg)
end},
},
after_place_node = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

BIN
textures/screen_back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
textures/screen_bottom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

BIN
textures/screen_front.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 B

BIN
textures/screen_left.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

BIN
textures/screen_right.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

BIN
textures/screen_top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B