Huge update
This commit is contained in:
parent
893fb0ebb2
commit
8968e5d875
97
bit32.lua
Normal file
97
bit32.lua
Normal file
@ -0,0 +1,97 @@
|
||||
bit32 = {}
|
||||
|
||||
local N = 32
|
||||
local P = 2^N
|
||||
|
||||
bit32.bnot = function(x)
|
||||
x = x%P
|
||||
return P-1-x
|
||||
end
|
||||
|
||||
bit32.band = function(x, y)
|
||||
-- Common usecases, they deserve to be optimized
|
||||
if y == 0xff then return x%0x100 end
|
||||
if y == 0xffff then return x%0x10000 end
|
||||
if y == 0xffffffff then return x%0x100000000 end
|
||||
|
||||
x, y = x%P, y%P
|
||||
local r = 0
|
||||
local p = 1
|
||||
for i = 1, N do
|
||||
a, b = x%2, y%2
|
||||
x, y = math.floor(x/2), math.floor(y/2)
|
||||
if a+b == 2 then
|
||||
r = r + p
|
||||
end
|
||||
p = 2*p
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
bit32.bor = function(x, y)
|
||||
-- Common usecases, they deserve to be optimized
|
||||
if y == 0xff then return x%0x100 end
|
||||
if y == 0xffff then return x%0x10000 end
|
||||
|
||||
x, y = x%P, y%P
|
||||
local r = 0
|
||||
local p = 1
|
||||
for i = 1, N do
|
||||
a, b = x%2, y%2
|
||||
x, y = math.floor(x/2), math.floor(y/2)
|
||||
if a+b >= 1 then
|
||||
r = r + p
|
||||
end
|
||||
p = 2*p
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
bit32.bxor = function(x, y)
|
||||
x, y = x%P, y%P
|
||||
local r = 0
|
||||
local p = 1
|
||||
for i = 1, N do
|
||||
a, b = x%2, y%2
|
||||
x, y = math.floor(x/2), math.floor(y/2)
|
||||
if a+b == 1 then
|
||||
r = r + p
|
||||
end
|
||||
p = 2*p
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
bit32.lshift = function(x, s_amount)
|
||||
if math.abs(s_amount) >= N then return 0 end
|
||||
x = x%P
|
||||
if s_amount < 0 then
|
||||
return math.floor(x*(2^s_amount))
|
||||
else
|
||||
return (x*(2^s_amount))%P
|
||||
end
|
||||
end
|
||||
|
||||
bit32.rshift = function(x, s_amount)
|
||||
if math.abs(s_amount) >= N then return 0 end
|
||||
x = x%P
|
||||
if s_amount > 0 then
|
||||
return math.floor(x*(2^-s_amount))
|
||||
else
|
||||
return (x*(2^-s_amount))%P
|
||||
end
|
||||
end
|
||||
|
||||
bit32.arshift = function(x, s_amount)
|
||||
if math.abs(s_amount) >= N then return 0 end
|
||||
x = x%P
|
||||
if s_amount > 0 then
|
||||
local add = 0
|
||||
if x >= P/2 then
|
||||
add = P - 2^(N-s_amount)
|
||||
end
|
||||
return math.floor(x*(2^-s_amount))+add
|
||||
else
|
||||
return (x*(2^-s_amount))%P
|
||||
end
|
||||
end
|
741
computer.lua
Normal file
741
computer.lua
Normal file
@ -0,0 +1,741 @@
|
||||
local CYCLES_PER_STEP = 1000
|
||||
local MAX_CYCLES = 100000
|
||||
local MAX_LINE_LENGHT = 42
|
||||
|
||||
local function file_exists(name)
|
||||
local f = io.open(name, "r")
|
||||
if f then
|
||||
f:close()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function loadpkg(na)
|
||||
local modpath = minetest.get_modpath("forth_computer")
|
||||
local ol = package.cpath
|
||||
local sp
|
||||
if file_exists(modpath.."/INIT.LUA") then
|
||||
-- On windows, if we try to open the others we get a crash
|
||||
-- even with pcall
|
||||
sp = {modpath.."/?.dll"}
|
||||
else
|
||||
sp = {modpath.."/?.so.32", modpath.."/?.so.64"}
|
||||
end
|
||||
for i=1,#sp do
|
||||
package.cpath = sp[i]
|
||||
e, lib = pcall(require, na)
|
||||
package.cpath = ol
|
||||
if e then
|
||||
return lib
|
||||
end
|
||||
end
|
||||
package.cpath = ol
|
||||
return nil
|
||||
end
|
||||
|
||||
local modpath = minetest.get_modpath("forth_computer")
|
||||
|
||||
if bit32 == nil and jit == nil then
|
||||
-- No need to use the library if LuaJIT is there, the Lua one is more efficient
|
||||
bit32 = loadpkg("bit32")
|
||||
end
|
||||
if bit32 == nil then
|
||||
-- bit32 has not been loaded, using a Lua implementation of what we need
|
||||
dofile(modpath.."/bit32.lua")
|
||||
if jit == nil then
|
||||
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "..
|
||||
"WARNING: bit32 could not loaded, you should fix"..
|
||||
" that or use LuaJIT for better performance"..
|
||||
" <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<")
|
||||
end
|
||||
end
|
||||
|
||||
dofile(modpath.."/computer_memory.lua")
|
||||
dofile(modpath.."/forth_floppy.lua")
|
||||
|
||||
local wpath = minetest.get_worldpath()
|
||||
local function read_file(fn)
|
||||
local f = io.open(fn, "r")
|
||||
if f==nil then return {} end
|
||||
local t = f:read("*all")
|
||||
f:close()
|
||||
if t=="" or t==nil then return {} end
|
||||
return minetest.deserialize(t)
|
||||
end
|
||||
|
||||
local function write_file(fn, tbl)
|
||||
local f = io.open(fn, "w")
|
||||
f:write(minetest.serialize(tbl))
|
||||
f:close()
|
||||
end
|
||||
|
||||
local cptrs = read_file(wpath.."/forth_computers")
|
||||
local oldcptrs = read_file(wpath.."/forth_computers")
|
||||
local screens = read_file(wpath.."/screens")
|
||||
|
||||
function hacky_swap_node(pos,name)
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name ~= name then
|
||||
local meta = minetest.get_meta(pos)
|
||||
local meta0 = meta:to_table()
|
||||
node.name = name
|
||||
minetest.set_node(pos,node)
|
||||
meta = minetest.get_meta(pos)
|
||||
meta:from_table(meta0)
|
||||
end
|
||||
return node.name
|
||||
end
|
||||
|
||||
local function s16(x)
|
||||
if bit32.band(x, 0x8000)~=0 then
|
||||
return bit32.band(x, 0xffff)-0x10000
|
||||
end
|
||||
return bit32.band(x, 0xffff)
|
||||
end
|
||||
|
||||
local function u16(x)
|
||||
return bit32.band(x, 0xffff)
|
||||
end
|
||||
|
||||
local function s32(x)
|
||||
if bit32.band(x, 0x80000000)~=0 then
|
||||
return bit32.band(x, 0xffffffff)-0x100000000
|
||||
end
|
||||
return bit32.band(x, 0xffffffff)
|
||||
end
|
||||
|
||||
local function u32(x)
|
||||
return bit32.band(x, 0xffffffff)
|
||||
end
|
||||
|
||||
function lines(str)
|
||||
local t = {}
|
||||
local function helper(line) table.insert(t, line) return "" end
|
||||
helper((str:gsub("(.-)\r?\n", helper)))
|
||||
return t
|
||||
end
|
||||
|
||||
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 newline(text, toadd)
|
||||
local f = lines(text)
|
||||
table.insert(f, toadd)
|
||||
return table.concat(f, "\n", 2)
|
||||
end
|
||||
|
||||
local function add_char(text, char)
|
||||
local ls = lines(text)
|
||||
local ll = ls[#ls]
|
||||
if char=="\n" or char=="\r" then
|
||||
return newline(text,"")
|
||||
elseif string.len(ll)>=MAX_LINE_LENGHT then
|
||||
return newline(text, char)
|
||||
else
|
||||
return text..char
|
||||
end
|
||||
end
|
||||
|
||||
local function add_text(text, toadd)
|
||||
for i=1, string.len(toadd) do
|
||||
text = add_char(text, string.sub(toadd, i, i))
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
local function readC(cptr, addr)
|
||||
return cptr[addr]
|
||||
end
|
||||
|
||||
local function writeC(cptr, addr, value)
|
||||
cptr[addr] = bit32.band(value, 0xff)
|
||||
end
|
||||
|
||||
local function read(cptr, addr)
|
||||
return cptr[addr] + 256*cptr[u16(addr+1)]
|
||||
end
|
||||
|
||||
local function write(cptr, addr, value)
|
||||
cptr[addr] = bit32.band(value, 0xff)
|
||||
cptr[addr+1] = bit32.band(math.floor(value/256), 0xff)
|
||||
end
|
||||
|
||||
local function push(cptr, value)
|
||||
cptr.SP = u16(cptr.SP+2)
|
||||
write(cptr, cptr.SP, value)
|
||||
end
|
||||
|
||||
local function pop(cptr, value)
|
||||
local n = read(cptr, cptr.SP)
|
||||
cptr.SP = u16(cptr.SP-2)
|
||||
return n
|
||||
end
|
||||
|
||||
local function rpush(cptr, value)
|
||||
cptr.RP = u16(cptr.RP+2)
|
||||
write(cptr, cptr.RP, value)
|
||||
end
|
||||
|
||||
local function rpop(cptr, value)
|
||||
local n = read(cptr, cptr.RP)
|
||||
cptr.RP = u16(cptr.RP-2)
|
||||
return n
|
||||
end
|
||||
|
||||
local function emit(pos, c, cptr)
|
||||
local s = string.char(bit32.band(c, 0xff))
|
||||
local meta = minetest.get_meta(pos)
|
||||
local text = meta:get_string("text")
|
||||
local ls = lines(text)
|
||||
local ll = ls[#ls]
|
||||
if s=="\n" or s=="\r" then
|
||||
meta:set_string("text", newline(text,""))
|
||||
elseif string.len(ll)>=MAX_LINE_LENGHT then
|
||||
meta:set_string("text", newline(text, s))
|
||||
else
|
||||
meta:set_string("text", text..s)
|
||||
end
|
||||
cptr.fmodif = true
|
||||
end
|
||||
|
||||
local function string_at(cptr, addr, len)
|
||||
local l = {}
|
||||
for k=1, len do
|
||||
local i = u16(addr+k-1)
|
||||
local s = cptr[i]
|
||||
l[k] = string.char(s)
|
||||
end
|
||||
return table.concat(l, "")
|
||||
end
|
||||
|
||||
local function receive(cptr, caddr, clen, raddr)
|
||||
local channel = string_at(cptr, caddr, clen)
|
||||
local event = cptr.digiline_events[channel]
|
||||
if event and type(event)=="string" then
|
||||
if string.len(event)>80 then
|
||||
event = string.sub(event,1,80)
|
||||
end
|
||||
for i=1,string.len(event) do
|
||||
cptr[u16(raddr-1+i)] = string.byte(event,i)
|
||||
end
|
||||
cptr.X = string.len(event)
|
||||
else
|
||||
cptr.X = u16(-1)
|
||||
end
|
||||
end
|
||||
|
||||
local function delete_message(cptr, caddr, clen)
|
||||
local channel = string_at(cptr, caddr, clen)
|
||||
cptr.digiline_events[channel] = nil
|
||||
end
|
||||
|
||||
local function set_channel(cptr, caddr, clen)
|
||||
local channel = string_at(cptr, caddr, clen)
|
||||
cptr.channel = channel
|
||||
end
|
||||
|
||||
local function send_message(pos, cptr, maddr, mlen)
|
||||
local msg = string_at(cptr, maddr, mlen)
|
||||
cptr.digiline_events[cptr.channel] = msg
|
||||
digiline:receptor_send(pos, digiline.rules.default, cptr.channel, msg)
|
||||
end
|
||||
|
||||
local function run_computer(pos,cptr)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local oldpos = meta:get_string("pos")
|
||||
if oldpos == "" then
|
||||
return
|
||||
end
|
||||
oldpos = minetest.deserialize(oldpos)
|
||||
if oldpos.x ~= pos.x or oldpos.y ~= pos.y or oldpos.z ~= pos.z then
|
||||
local old_cptr = oldcptrs[hashpos(oldpos)]
|
||||
for key, _ in pairs(oldcptrs) do
|
||||
print(key)
|
||||
end
|
||||
meta:set_string("pos", minetest.serialize(pos))
|
||||
print(hashpos(oldpos))
|
||||
if old_cptr ~= nil then
|
||||
cptrs[hashpos(pos)].cptr = old_cptr.cptr
|
||||
end
|
||||
end
|
||||
if cptr.stopped then return end
|
||||
cptr.cycles = math.max(MAX_CYCLES,cptr.cycles+CYCLES_PER_STEP)
|
||||
while 1 do
|
||||
instr = cptr[cptr.PC]
|
||||
local f = ITABLE[instr]
|
||||
if f == nil then return end
|
||||
cptr.PC = bit32.band(cptr.PC+1, 0xffff)
|
||||
setfenv(f, {cptr = cptr, pos=pos, emit=emit, receive=receive, delete_message=delete_message, set_channel=set_channel, send_message=send_message, u16=u16, u32=u32, s16=s16, s32=s32, read=read, write=write, readC=readC, writeC=writeC, push=push, pop=pop, rpush=rpush, rpop=rpop, bit32=bit32, math=math})
|
||||
f()
|
||||
cptr.cycles = cptr.cycles - 1
|
||||
if cptr.paused or cptr.cycles == 0 then
|
||||
cptr.paused = false
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function create_cptr()
|
||||
local cptr = create_cptr_memory()
|
||||
cptr.X = 0
|
||||
cptr.Y = 0
|
||||
cptr.Z = 0
|
||||
cptr.I = 0
|
||||
cptr.PC = 0xff00
|
||||
cptr.RP = 0
|
||||
cptr.SP = 0
|
||||
cptr.paused = false
|
||||
cptr.stopped = true
|
||||
cptr.has_input = false
|
||||
cptr.digiline_events = {}
|
||||
cptr.channel = ""
|
||||
cptr.cycles = 0
|
||||
return cptr
|
||||
end
|
||||
|
||||
ITABLE_RAW = {
|
||||
[0x28] = "cptr.I = rpop(cptr)",
|
||||
[0x29] = "cptr.PC = read(cptr, cptr.I); cptr.I = u16(cptr.I+2)",
|
||||
[0x2a] = "rpush(cptr, cptr.I); cptr.I = u16(cptr.PC+2); cptr.PC=read(cptr, cptr.PC)",
|
||||
[0x2b] = "cptr.X = read(cptr, cptr.I); cptr.I = u16(cptr.I+2)",
|
||||
|
||||
[0x08] = "cptr.X = cptr.SP",
|
||||
[0x09] = "cptr.X = cptr.RP",
|
||||
[0x0a] = "cptr.X = cptr.PC",
|
||||
[0x0b] = "cptr.X = cptr.I",
|
||||
|
||||
[0x00] = "cptr.paused = true",
|
||||
|
||||
[0x01] = "rpush(cptr, cptr.X)",
|
||||
[0x02] = "rpush(cptr, cptr.Y)",
|
||||
[0x03] = "rpush(cptr, cptr.Z)",
|
||||
[0x10] = "cptr.X = read(cptr, cptr.RP)",
|
||||
[0x11] = "cptr.X = rpop(cptr)",
|
||||
[0x12] = "cptr.Y = rpop(cptr)",
|
||||
[0x13] = "cptr.Z = rpop(cptr)",
|
||||
|
||||
[0x20] = "write(cptr, cptr.SP, cptr.X)",
|
||||
[0x21] = "push(cptr, cptr.X)",
|
||||
[0x22] = "push(cptr, cptr.Y)",
|
||||
[0x23] = "push(cptr, cptr.Z)",
|
||||
[0x30] = "cptr.X = read(cptr, cptr.SP)",
|
||||
[0x31] = "cptr.X = pop(cptr)",
|
||||
[0x32] = "cptr.Y = pop(cptr)",
|
||||
[0x33] = "cptr.Z = pop(cptr)",
|
||||
|
||||
[0x04] = "cptr.X = read(cptr, cptr.X)",
|
||||
[0x05] = "cptr.X = read(cptr, cptr.Y)",
|
||||
[0x06] = "cptr.Y = read(cptr, cptr.X)",
|
||||
[0x07] = "cptr.Y = read(cptr, cptr.Y)",
|
||||
|
||||
[0x14] = "cptr.X = readC(cptr, cptr.X)",
|
||||
[0x15] = "cptr.X = readC(cptr, cptr.Y)",
|
||||
[0x16] = "cptr.Y = readC(cptr, cptr.X)",
|
||||
[0x17] = "cptr.Y = readC(cptr, cptr.Y)",
|
||||
|
||||
[0x25] = "write(cptr, cptr.X, cptr.Y)",
|
||||
[0x26] = "write(cptr, cptr.Y, cptr.X)",
|
||||
|
||||
[0x35] = "writeC(cptr, cptr.X, cptr.Y)",
|
||||
[0x36] = "writeC(cptr, cptr.Y, cptr.X)",
|
||||
|
||||
[0x0c] = "n=cptr.X+cptr.Y; cptr.Y = u16(n); cptr.X = u16(math.floor(n/0x10000))",
|
||||
[0x0d] = "n=cptr.X-cptr.Y; cptr.Y = u16(n); cptr.X = u16(math.floor(n/0x10000))",
|
||||
[0x0e] = "n=cptr.X*cptr.Y; cptr.Y = u16(n); cptr.X = u16(math.floor(n/0x10000))",
|
||||
[0x0f] = "n=s16(cptr.X)*s16(cptr.Y); cptr.Y = u16(n); cptr.X = u16(math.floor(n/0x10000))",
|
||||
[0x1e] = "if cptr.Z~=0 then n = cptr.X*0x10000+cptr.Y; cptr.Y = u16(math.floor(n/cptr.Z)); cptr.X = u16(math.floor((n/cptr.Z)/0x10000)); cptr.Z = u16(n%cptr.Z) end",
|
||||
[0x1f] = "if cptr.Z~=0 then n = s32(cptr.X*0x10000+cptr.Y); cptr.Y = u16(math.floor(n/s16(cptr.Z))); cptr.X = u16(math.floor((n/s16(cptr.Z))/0x10000)); cptr.Z = u16(n%s16(cptr.Z)) end",
|
||||
[0x2c] = "cptr.X = u16(bit32.band(cptr.X, cptr.Y))",
|
||||
[0x2d] = "cptr.X = u16(bit32.bor(cptr.X, cptr.Y))",
|
||||
[0x2e] = "cptr.X = u16(bit32.bxor(cptr.X, cptr.Y))",
|
||||
[0x2f] = "cptr.X = u16(bit32.bnot(cptr.X))",
|
||||
[0x3c] = "cptr.X = bit32.rshift(cptr.X, cptr.Y)",
|
||||
[0x3d] = "cptr.X = u16(bit32.arshift(s16(cptr.X), cptr.Y))",
|
||||
[0x3e] = "n = cptr.X; cptr.X = u16(bit32.lshift(n, cptr.Y)); cptr.Y = u16(bit32.lshift(n, cptr.Y-16))",
|
||||
[0x3f] = "if s16(cptr.Y)<0 then cptr.X = u16(-1) else cptr.X = 0 end",
|
||||
|
||||
[0x38] = "cptr.PC = u16(cptr.PC+read(cptr, cptr.PC)+2)",
|
||||
[0x39] = "if cptr.X~=0 then cptr.PC = u16(cptr.PC+read(cptr, cptr.PC)) end; cptr.PC = u16(cptr.PC+2)",
|
||||
[0x3a] = "if cptr.Y~=0 then cptr.PC = u16(cptr.PC+read(cptr, cptr.PC)) end; cptr.PC = u16(cptr.PC+2)",
|
||||
[0x3b] = "if cptr.Z~=0 then cptr.PC = u16(cptr.PC+read(cptr, cptr.PC)) end; cptr.PC = u16(cptr.PC+2)",
|
||||
|
||||
[0x18] = "cptr.SP = cptr.X",
|
||||
[0x19] = "cptr.RP = cptr.X",
|
||||
[0x1a] = "cptr.PC = cptr.X",
|
||||
[0x1b] = "cptr.I = cptr.X",
|
||||
|
||||
[0x40] = "cptr.Z = cptr.X",
|
||||
[0x41] = "cptr.Z = cptr.Y",
|
||||
[0x42] = "cptr.X = cptr.Z",
|
||||
[0x43] = "cptr.Y = cptr.Z",
|
||||
[0x44] = "cptr.X = cptr.Y",
|
||||
[0x45] = "cptr.Y = cptr.X",
|
||||
|
||||
[0x46] = "cptr.X = u16(cptr.X-1)",
|
||||
[0x47] = "cptr.Y = u16(cptr.Y-1)",
|
||||
[0x48] = "cptr.Z = u16(cptr.Z-1)",
|
||||
|
||||
[0x49] = "cptr.X = u16(cptr.X+1)",
|
||||
[0x4a] = "cptr.Y = u16(cptr.Y+1)",
|
||||
[0x4b] = "cptr.Z = u16(cptr.Z+1)",
|
||||
|
||||
[0x4d] = "cptr.X = read(cptr, cptr.PC); cptr.PC = u16(cptr.PC+2)",
|
||||
[0x4e] = "cptr.Y = read(cptr, cptr.PC); cptr.PC = u16(cptr.PC+2)",
|
||||
[0x4f] = "cptr.Z = read(cptr, cptr.PC); cptr.PC = u16(cptr.PC+2)",
|
||||
|
||||
-- [0x50] = "if cptr.has_input then\ncptr.has_input = false\nelse\ncptr.paused = true\ncptr.PC = u16(cptr.PC-1)\nend",
|
||||
-- [0x51] = "emit(pos, cptr.X, cptr)",
|
||||
[0x52] = "receive(cptr, cptr.X, cptr.Y, cptr.Z)", -- Digiline receive
|
||||
[0x53] = "delete_message(cptr, cptr.X, cptr.Y)",
|
||||
[0x54] = "send_message(pos, cptr, cptr.X, cptr.Y)", -- Digiline send
|
||||
[0x55] = "set_channel(cptr, cptr.X, cptr.Y)", -- Digiline set channel
|
||||
}
|
||||
|
||||
ITABLE = {}
|
||||
|
||||
for i, v in pairs(ITABLE_RAW) do
|
||||
ITABLE[i] = loadstring(v) -- Parse everything at the beginning, way faster
|
||||
end
|
||||
|
||||
local on_computer_digiline_receive = function (pos, node, channel, msg)
|
||||
local cptr = cptrs[hashpos(pos)].cptr
|
||||
if cptr == nil then return end
|
||||
cptr.digiline_events[channel] = msg
|
||||
end
|
||||
|
||||
minetest.register_node("forth_computer:computer",{
|
||||
description = "Computer on (you hacker you)",
|
||||
paramtype2 = "facedir",
|
||||
tiles = {"cpu_top.png", "cpu_bottom.png", "cpu_right.png", "cpu_left.png", "cpu_back.png", "cpu_front.png"},
|
||||
groups = {cracky=3, not_in_creative_inventory=1},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
digiline =
|
||||
{
|
||||
receptor = {},
|
||||
effector = {action = on_computer_digiline_receive},
|
||||
},
|
||||
on_construct = function(pos)
|
||||
if cptrs[hashpos(pos)] then return end
|
||||
cptrs[hashpos(pos)] = {pos=pos, cptr=create_cptr()}
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("pos", minetest.serialize(pos))
|
||||
end,
|
||||
on_destruct = function(pos)
|
||||
if cptrs[hashpos(pos)] == nil then return end
|
||||
if cptrs[hashpos(pos)].swapping then
|
||||
cptrs[hashpos(pos)].swapping = nil
|
||||
return
|
||||
end
|
||||
oldcptrs[hashpos(pos)] = cptrs[hashpos(pos)]
|
||||
cptrs[hashpos(pos)] = nil
|
||||
end,
|
||||
on_punch = function(pos, node, puncher)
|
||||
if cptrs[hashpos(pos)] == nil then return end
|
||||
local cptr = cptrs[hashpos(pos)].cptr
|
||||
cptr.stopped = true
|
||||
cptrs[hashpos(pos)].swapping = true
|
||||
hacky_swap_node(pos, "forth_computer:computer_off")
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("forth_computer:computer_off",{
|
||||
description = "Computer",
|
||||
paramtype2 = "facedir",
|
||||
tiles = {"cpu_top.png", "cpu_bottom.png", "cpu_right.png", "cpu_left.png", "cpu_back.png", "cpu_front_off.png"},
|
||||
groups = {cracky=3},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
digiline =
|
||||
{
|
||||
receptor = {},
|
||||
effector = {action = on_computer_digiline_receive},
|
||||
},
|
||||
on_construct = function(pos)
|
||||
if cptrs[hashpos(pos)] then return end
|
||||
cptrs[hashpos(pos)] = {pos=pos, cptr=create_cptr()}
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("pos", minetest.serialize(pos))
|
||||
end,
|
||||
on_destruct = function(pos)
|
||||
if cptrs[hashpos(pos)] == nil then return end
|
||||
if cptrs[hashpos(pos)].swapping then
|
||||
cptrs[hashpos(pos)].swapping = nil
|
||||
return
|
||||
end
|
||||
oldcptrs[hashpos(pos)] = cptrs[hashpos(pos)]
|
||||
cptrs[hashpos(pos)] = nil
|
||||
end,
|
||||
on_punch = function(pos, node, puncher)
|
||||
if cptrs[hashpos(pos)] == nil then return end
|
||||
local cptr = cptrs[hashpos(pos)].cptr
|
||||
cptr.stopped = false
|
||||
cptrs[hashpos(pos)].swapping = true
|
||||
hacky_swap_node(pos, "forth_computer:computer")
|
||||
end,
|
||||
})
|
||||
|
||||
local on_screen_digiline_receive = function (pos, node, channel, msg)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if channel == meta:get_string("channel") then
|
||||
local ntext = add_text(meta:get_string("text"), msg)
|
||||
meta:set_string("text",ntext)
|
||||
screens[hashpos(pos)].fmodif = true
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("forth_computer: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 = {
|
||||
-- X Y Z W H L
|
||||
{ -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 = on_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}
|
||||
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)
|
||||
if screens[hashpos(pos)] == nil then
|
||||
screens[hashpos(pos)] = {pos=pos, fmodif=false}
|
||||
end
|
||||
screens[hashpos(pos)].pname = name
|
||||
minetest.show_formspec(name,"screen"..hashpos(pos),create_formspec(meta:get_string("text")))
|
||||
end,
|
||||
})
|
||||
|
||||
local on_disk_digiline_receive = function (pos, node, channel, msg)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if channel == meta:get_string("channel") then
|
||||
local page = string.byte(msg, 1)
|
||||
if page==nil then return end
|
||||
local inv = meta:get_inventory()
|
||||
local stack = inv:get_stack("floppy", 1):to_table()
|
||||
if stack == nil then return end
|
||||
if stack.name ~= "forth_computer:floppy" then return end
|
||||
if stack.metadata == "" then stack.metadata = string.rep(string.char(0), 16384) end
|
||||
msg = string.sub(msg, 2, -1)
|
||||
if string.len(msg) == 0 then -- read
|
||||
local ret = string.sub(stack.metadata, page*64+1, page*64+64)
|
||||
digiline:receptor_send(pos, digiline.rules.default, channel, ret)
|
||||
else -- write
|
||||
if string.len(msg) ~= 64 then return end
|
||||
stack.metadata = string.sub(stack.metadata, 1, page*64)..msg..string.sub(stack.metadata, page*64+65, -1)
|
||||
end
|
||||
inv:set_stack("floppy", 1, ItemStack(stack))
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("forth_computer: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 = on_disk_digiline_receive},
|
||||
},
|
||||
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() == "forth_computer: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:set_string("channel", fields.channel)
|
||||
end,
|
||||
})
|
||||
|
||||
local function create_from_file(filename)
|
||||
local f = io.open(filename, "r")
|
||||
if f==nil then return {} end
|
||||
local t = f:read("*all")
|
||||
f:close()
|
||||
local l = lines(t)
|
||||
for key, i in ipairs(l) do
|
||||
l[key] = i..string.rep(string.char(0), 64-string.len(i))
|
||||
end
|
||||
t = table.concat(l, "")
|
||||
return t..string.rep(string.char(0), 16536-string.len(t))
|
||||
end
|
||||
|
||||
local progs = {["Empty"] = string.rep(string.char(0), 16536),
|
||||
["Forth Boot Disk"] = create_forth_floppy(),
|
||||
["Double number library"] = create_from_file(modpath.."/double.fth"),
|
||||
--["Floating point number library"] = create_from_file(modpath.."/float.fth"),
|
||||
["Decompiler"] = create_from_file(modpath.."/see.fth")}
|
||||
minetest.register_node("forth_computer: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() == "forth_computer: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 ~= "forth_computer:floppy" then return end
|
||||
stack.metadata = prog
|
||||
inv:set_stack("floppy", 1, ItemStack(stack))
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craftitem("forth_computer:floppy",{
|
||||
description = "Floppy disk",
|
||||
inventory_image = "floppy.png",
|
||||
stack_max = 1,
|
||||
})
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
for _,i in pairs(cptrs) do
|
||||
run_computer(i.pos, i.cptr)
|
||||
end
|
||||
oldcptrs = {}
|
||||
for _,i in pairs(screens) do
|
||||
if i.fmodif then
|
||||
i.fmodif=false
|
||||
if i.pname~=nil then
|
||||
local meta = minetest.get_meta(i.pos)
|
||||
minetest.show_formspec(i.pname,"screen"..hashpos(i.pos),create_formspec(meta:get_string("text")))
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
for _,i in pairs(screens) do
|
||||
i.fmodif = false
|
||||
i.pname = nil
|
||||
end
|
||||
write_file(wpath.."/forth_computers",cptrs)
|
||||
write_file(wpath.."/old_forth_computers",oldcptrs)
|
||||
write_file(wpath.."/screens",screens)
|
||||
end)
|
||||
|
||||
function escape(text)
|
||||
-- Remove all \0's in the string, that cannot be done using string.gsub as there can't be \0's in a pattern
|
||||
text2 = ""
|
||||
for i=1, string.len(text) do
|
||||
if string.byte(text, i)~=0 then text2 = text2..string.sub(text, i, i) end
|
||||
end
|
||||
return minetest.formspec_escape(text2)
|
||||
end
|
||||
|
||||
function create_formspec(text)
|
||||
local f = lines(text)
|
||||
s = "size[5,4.5;"
|
||||
i = -0.25
|
||||
for _,x in ipairs(f) do
|
||||
s = s.."]label[0,"..tostring(i)..";"..escape(x)
|
||||
i = i+0.3
|
||||
end
|
||||
s = s.."]field[0.3,"..tostring(i+0.4)..";4.4,1;f;;]"
|
||||
return s
|
||||
--return "size[5,4.5;]textarea[0.3,0;4.4,4.1;;"..escape(text)..";]field[0.3,3.6;4.4,1;f;;]"
|
||||
end
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname:sub(1,6)~="screen" then return end
|
||||
local pos = dehashpos(formname:sub(7,-1))
|
||||
local s = screens[hashpos(pos)]
|
||||
if s==nil then return end
|
||||
if fields["f"]==nil or fields["f"]=="" then
|
||||
if fields["quit"] ~= nil then
|
||||
s.pname = nil
|
||||
end
|
||||
return
|
||||
end
|
||||
if string.len(fields["f"])>MAX_LINE_LENGHT then
|
||||
fields["f"] = string.sub(fields["f"],1,MAX_LINE_LENGHT)
|
||||
end
|
||||
digiline:receptor_send(pos, digiline.rules.default, "screen", fields["f"])
|
||||
local meta = minetest.get_meta(pos)
|
||||
local ntext = add_text(meta:get_string("text"), fields["f"])
|
||||
meta:set_string("text",ntext)
|
||||
minetest.show_formspec(player:get_player_name(),formname,create_formspec(ntext))
|
||||
end)
|
||||
|
51
computer_memory.lua
Normal file
51
computer_memory.lua
Normal file
@ -0,0 +1,51 @@
|
||||
function create_cptr_memory()
|
||||
tbl = {}
|
||||
for i=0, 65535 do tbl[i] = 0 end
|
||||
tbl[0xff00] = 0x4d
|
||||
tbl[0xff01] = 0x2a
|
||||
tbl[0xff02] = 0xff
|
||||
tbl[0xff03] = 0x4e
|
||||
tbl[0xff04] = 0x04
|
||||
tbl[0xff05] = 0x00
|
||||
tbl[0xff06] = 0x55
|
||||
tbl[0xff07] = 0x4d
|
||||
tbl[0xff08] = 0x29
|
||||
tbl[0xff09] = 0xff
|
||||
tbl[0xff0a] = 0x4e
|
||||
tbl[0xff0b] = 0x01
|
||||
tbl[0xff0c] = 0x00
|
||||
tbl[0xff0d] = 0x54
|
||||
tbl[0xff0e] = 0x4d
|
||||
tbl[0xff0f] = 0x2a
|
||||
tbl[0xff10] = 0xff
|
||||
tbl[0xff11] = 0x4e
|
||||
tbl[0xff12] = 0x04
|
||||
tbl[0xff13] = 0x00
|
||||
tbl[0xff14] = 0x52
|
||||
tbl[0xff15] = 0x4d
|
||||
tbl[0xff16] = 0x40
|
||||
tbl[0xff17] = 0x00
|
||||
tbl[0xff18] = 0x43
|
||||
tbl[0xff19] = 0x0c
|
||||
tbl[0xff1a] = 0x41
|
||||
tbl[0xff1b] = 0x4d
|
||||
tbl[0xff1c] = 0x29
|
||||
tbl[0xff1d] = 0xff
|
||||
tbl[0xff1e] = 0x16
|
||||
tbl[0xff1f] = 0x4a
|
||||
tbl[0xff20] = 0x35
|
||||
tbl[0xff21] = 0x16
|
||||
tbl[0xff22] = 0x3a
|
||||
tbl[0xff23] = 0xe2
|
||||
tbl[0xff24] = 0xff
|
||||
tbl[0xff25] = 0x4d
|
||||
tbl[0xff26] = 0x00
|
||||
tbl[0xff27] = 0x04
|
||||
tbl[0xff28] = 0x1a
|
||||
tbl[0xff29] = 0x00
|
||||
tbl[0xff2a] = 0x62
|
||||
tbl[0xff2b] = 0x6f
|
||||
tbl[0xff2c] = 0x6f
|
||||
tbl[0xff2d] = 0x74
|
||||
return tbl
|
||||
end
|
456
cptr.lua
Normal file
456
cptr.lua
Normal file
@ -0,0 +1,456 @@
|
||||
local CYCLES_PER_STEP = 1000
|
||||
local MAX_CYCLES = 100000
|
||||
local FUEL_EFFICIENCY = 3 -- How many moves can the turtle do with a second fuel
|
||||
|
||||
local function file_exists(name)
|
||||
local f = io.open(name, "r")
|
||||
if f then
|
||||
f:close()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function loadpkg(na)
|
||||
local modpath = minetest.get_modpath("forth_computer")
|
||||
local ol = package.cpath
|
||||
local sp
|
||||
if file_exists(modpath.."/INIT.LUA") then
|
||||
-- On windows, if we try to open the others we get a crash
|
||||
-- even with pcall
|
||||
sp = {modpath.."/?.dll"}
|
||||
else
|
||||
sp = {modpath.."/?.so.32", modpath.."/?.so.64"}
|
||||
end
|
||||
for i=1,#sp do
|
||||
package.cpath = sp[i]
|
||||
e, lib = pcall(require, na)
|
||||
package.cpath = ol
|
||||
if e then
|
||||
return lib
|
||||
end
|
||||
end
|
||||
package.cpath = ol
|
||||
return nil
|
||||
end
|
||||
|
||||
local modpath = minetest.get_modpath("turtle")
|
||||
|
||||
if bit32 == nil and jit == nil then
|
||||
-- No need to use the library if LuaJIT is there, the Lua one is more efficient
|
||||
bit32 = loadpkg("bit32")
|
||||
end
|
||||
if bit32 == nil then
|
||||
-- bit32 has not been loaded, using a Lua implementation of what we need
|
||||
dofile(modpath.."/bit32.lua")
|
||||
if jit == nil then
|
||||
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "..
|
||||
"WARNING: bit32 could not loaded, you should fix"..
|
||||
" that or use LuaJIT for better performance"..
|
||||
" <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<")
|
||||
end
|
||||
end
|
||||
|
||||
local function s16(x)
|
||||
if bit32.band(x, 0x8000)~=0 then
|
||||
return bit32.band(x, 0xffff)-0x10000
|
||||
end
|
||||
return bit32.band(x, 0xffff)
|
||||
end
|
||||
|
||||
local function u16(x)
|
||||
return bit32.band(x, 0xffff)
|
||||
end
|
||||
|
||||
local function s32(x)
|
||||
if bit32.band(x, 0x80000000)~=0 then
|
||||
return bit32.band(x, 0xffffffff)-0x100000000
|
||||
end
|
||||
return bit32.band(x, 0xffffffff)
|
||||
end
|
||||
|
||||
local function u32(x)
|
||||
return bit32.band(x, 0xffffffff)
|
||||
end
|
||||
|
||||
local function readC(cptr, addr)
|
||||
return cptr[addr]
|
||||
end
|
||||
|
||||
local function writeC(cptr, addr, value)
|
||||
cptr[addr] = bit32.band(value, 0xff)
|
||||
end
|
||||
|
||||
local function read(cptr, addr)
|
||||
return cptr[addr] + 256*cptr[u16(addr+1)]
|
||||
end
|
||||
|
||||
local function write(cptr, addr, value)
|
||||
cptr[addr] = bit32.band(value, 0xff)
|
||||
cptr[addr+1] = bit32.band(math.floor(value/256), 0xff)
|
||||
end
|
||||
|
||||
local function push(cptr, value)
|
||||
cptr.SP = u16(cptr.SP+2)
|
||||
write(cptr, cptr.SP, value)
|
||||
end
|
||||
|
||||
local function pop(cptr, value)
|
||||
local n = read(cptr, cptr.SP)
|
||||
cptr.SP = u16(cptr.SP-2)
|
||||
return n
|
||||
end
|
||||
|
||||
local function rpush(cptr, value)
|
||||
cptr.RP = u16(cptr.RP+2)
|
||||
write(cptr, cptr.RP, value)
|
||||
end
|
||||
|
||||
local function rpop(cptr, value)
|
||||
local n = read(cptr, cptr.RP)
|
||||
cptr.RP = u16(cptr.RP-2)
|
||||
return n
|
||||
end
|
||||
|
||||
local function string_at(cptr, addr, len)
|
||||
local l = {}
|
||||
for k=1, len do
|
||||
local i = u16(addr+k-1)
|
||||
local s = cptr[i]
|
||||
l[k] = string.char(s)
|
||||
end
|
||||
return table.concat(l, "")
|
||||
end
|
||||
|
||||
local function receive(cptr, caddr, clen, raddr)
|
||||
local channel = string_at(cptr, caddr, clen)
|
||||
local event = cptr.digiline_events[channel]
|
||||
if event and type(event)=="string" then
|
||||
if string.len(event)>80 then
|
||||
event = string.sub(event,1,80)
|
||||
end
|
||||
for i=1,string.len(event) do
|
||||
cptr[u16(raddr-1+i)] = string.byte(event,i)
|
||||
end
|
||||
cptr.X = string.len(event)
|
||||
else
|
||||
cptr.X = u16(-1)
|
||||
end
|
||||
end
|
||||
|
||||
local function delete_message(cptr, caddr, clen)
|
||||
local channel = string_at(cptr, caddr, clen)
|
||||
cptr.digiline_events[channel] = nil
|
||||
end
|
||||
|
||||
local function set_channel(cptr, caddr, clen)
|
||||
local channel = string_at(cptr, caddr, clen)
|
||||
cptr.channel = channel
|
||||
end
|
||||
|
||||
local function send_message(turtle, cptr, maddr, mlen)
|
||||
local msg = string_at(cptr, maddr, mlen)
|
||||
cptr.digiline_events[cptr.channel] = msg
|
||||
turtle_receptor_send(turtle, cptr.channel, msg)
|
||||
end
|
||||
|
||||
local function getv(dir)
|
||||
if dir==0 then return {x=0,y=0,z=1}
|
||||
elseif dir==1 then return {x=1,y=0,z=0}
|
||||
elseif dir==2 then return {x=0,y=0,z=-1}
|
||||
elseif dir==3 then return {x=-1,y=0,z=0} end
|
||||
end
|
||||
|
||||
local function turtle_can_go(nname)
|
||||
return nname=="air" or minetest.registered_nodes[nname].liquidtype~="none"
|
||||
end
|
||||
|
||||
local tl = {}
|
||||
|
||||
function tl.forward(turtle, cptr)
|
||||
local info = get_turtle_info(turtle)
|
||||
if info.fuel == 0 then
|
||||
cptr.X = 0
|
||||
return
|
||||
end
|
||||
local spos = info.spos
|
||||
local dir = info.dir
|
||||
local npos = vector.add(spos, getv(dir))
|
||||
if turtle_can_go(minetest.get_node(npos).name) then
|
||||
info.npos = npos
|
||||
info.moving = true
|
||||
info.fuel = info.fuel - 1
|
||||
cptr.X = u16(-1)
|
||||
cptr.paused = true
|
||||
else
|
||||
cptr.X = 0
|
||||
end
|
||||
end
|
||||
|
||||
function tl.backward(turtle, cptr)
|
||||
local info = get_turtle_info(turtle)
|
||||
if info.fuel == 0 then
|
||||
cptr.X = 0
|
||||
return
|
||||
end
|
||||
local spos = info.spos
|
||||
local dir = info.dir
|
||||
local npos = vector.add(spos, getv((dir+2)%4))
|
||||
if turtle_can_go(minetest.get_node(npos).name) then
|
||||
info.npos = npos
|
||||
info.moving = true
|
||||
info.fuel = info.fuel - 1
|
||||
cptr.X = u16(-1)
|
||||
cptr.paused = true
|
||||
else
|
||||
cptr.X = 0
|
||||
end
|
||||
end
|
||||
|
||||
function tl.up(turtle, cptr)
|
||||
local info = get_turtle_info(turtle)
|
||||
if info.fuel == 0 then
|
||||
cptr.X = 0
|
||||
return
|
||||
end
|
||||
local spos = info.spos
|
||||
local npos = vector.add(spos, {x=0, y=1, z=0})
|
||||
if turtle_can_go(minetest.get_node(npos).name) then
|
||||
info.npos = npos
|
||||
info.moving = true
|
||||
info.fuel = info.fuel - 1
|
||||
cptr.X = u16(-1)
|
||||
cptr.paused = true
|
||||
else
|
||||
cptr.X = 0
|
||||
end
|
||||
end
|
||||
|
||||
function tl.down(turtle, cptr)
|
||||
local info = get_turtle_info(turtle)
|
||||
if info.fuel == 0 then
|
||||
cptr.X = 0
|
||||
return
|
||||
end
|
||||
local spos = info.spos
|
||||
local npos = vector.add(spos, {x=0, y=-1, z=0})
|
||||
if turtle_can_go(minetest.get_node(npos).name) then
|
||||
info.npos = npos
|
||||
info.moving = true
|
||||
info.fuel = info.fuel - 1
|
||||
cptr.X = u16(-1)
|
||||
cptr.paused = true
|
||||
else
|
||||
cptr.X = 0
|
||||
end
|
||||
end
|
||||
|
||||
function tl.turnleft(turtle, cptr)
|
||||
local info = get_turtle_info(turtle)
|
||||
info.ndir = (info.dir+3)%4
|
||||
info.rotate = math.pi/2
|
||||
info.moving = true
|
||||
cptr.paused = true
|
||||
end
|
||||
|
||||
function tl.turnright(turtle, cptr)
|
||||
local info = get_turtle_info(turtle)
|
||||
info.ndir = (info.dir+1)%4
|
||||
info.rotate = -math.pi/2
|
||||
info.moving = true
|
||||
cptr.paused = true
|
||||
end
|
||||
|
||||
local function stack_set_count(stack, count)
|
||||
stack = stack:to_table()
|
||||
if stack==nil then return nil end
|
||||
stack.count=count
|
||||
return ItemStack(stack)
|
||||
end
|
||||
|
||||
function tl.refuel(turtle, cptr, slot, nmax)
|
||||
local info = get_turtle_info(turtle)
|
||||
local stack = turtle_invs:get_stack(turtle, slot)
|
||||
local fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = {stack}})
|
||||
if fuel.time <= 0 then
|
||||
cptr.X = 0
|
||||
return
|
||||
end
|
||||
local count = math.min(stack:get_count(), nmax)
|
||||
local fs = stack:to_table()
|
||||
fs.count = 1
|
||||
local fstack = ItemStack(fs)
|
||||
local fuel, afterfuel
|
||||
fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = {fstack}})
|
||||
stack:take_item(count)
|
||||
if afterfuel ~= nil then
|
||||
afterfuel = afterfuel.items[1]
|
||||
end
|
||||
if afterfuel ~= nil then
|
||||
afterfuel = stack_set_count(afterfuel, afterfuel:get_count()*count)
|
||||
end
|
||||
if afterfuel ~= nil then
|
||||
local leftover = stack:add_item(ItemStack(afterfuel))
|
||||
turtle_invs:set_stack(turtle, slot, stack)
|
||||
local leftover2 = turtle_invs:add_item(turtle, leftover)
|
||||
minetest.add_item(info.spos,leftover2)
|
||||
else
|
||||
turtle_invs:set_stack(turtle, slot, stack)
|
||||
end
|
||||
info.fuel = info.fuel+FUEL_EFFICIENCY*count*fuel.time
|
||||
cptr.X = u16(FUEL_EFFICIENCY*count*fuel.time)
|
||||
end
|
||||
|
||||
function run_computer(turtle, cptr)
|
||||
if cptr.stopped then return end
|
||||
cptr.cycles = math.max(MAX_CYCLES,cptr.cycles+CYCLES_PER_STEP)
|
||||
while 1 do
|
||||
instr = cptr[cptr.PC]
|
||||
local f = ITABLE[instr]
|
||||
if f == nil then return end
|
||||
cptr.PC = bit32.band(cptr.PC+1, 0xffff)
|
||||
setfenv(f, {cptr = cptr, turtle=turtle, receive=receive, delete_message=delete_message, set_channel=set_channel, send_message=send_message, u16=u16, u32=u32, s16=s16, s32=s32, read=read, write=write, readC=readC, writeC=writeC, push=push, pop=pop, rpush=rpush, rpop=rpop, bit32=bit32, math=math, tl=tl})
|
||||
f()
|
||||
cptr.cycles = cptr.cycles - 1
|
||||
if cptr.paused or cptr.cycles <= 0 then
|
||||
cptr.paused = false
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function create_cptr()
|
||||
local cptr = create_cptr_memory()
|
||||
cptr.X = 0
|
||||
cptr.Y = 0
|
||||
cptr.Z = 0
|
||||
cptr.I = 0
|
||||
cptr.PC = 0xff00
|
||||
cptr.RP = 0
|
||||
cptr.SP = 0
|
||||
cptr.paused = false
|
||||
cptr.stopped = false
|
||||
cptr.has_input = false
|
||||
cptr.digiline_events = {}
|
||||
cptr.channel = ""
|
||||
cptr.cycles = 0
|
||||
return cptr
|
||||
end
|
||||
|
||||
ITABLE_RAW = {
|
||||
[0x28] = "cptr.I = rpop(cptr)",
|
||||
[0x29] = "cptr.PC = read(cptr, cptr.I); cptr.I = u16(cptr.I+2)",
|
||||
[0x2a] = "rpush(cptr, cptr.I); cptr.I = u16(cptr.PC+2); cptr.PC=read(cptr, cptr.PC)",
|
||||
[0x2b] = "cptr.X = read(cptr, cptr.I); cptr.I = u16(cptr.I+2)",
|
||||
|
||||
[0x08] = "cptr.X = cptr.SP",
|
||||
[0x09] = "cptr.X = cptr.RP",
|
||||
[0x0a] = "cptr.X = cptr.PC",
|
||||
[0x0b] = "cptr.X = cptr.I",
|
||||
|
||||
[0x00] = "cptr.paused = true",
|
||||
|
||||
[0x01] = "rpush(cptr, cptr.X)",
|
||||
[0x02] = "rpush(cptr, cptr.Y)",
|
||||
[0x03] = "rpush(cptr, cptr.Z)",
|
||||
[0x10] = "cptr.X = read(cptr, cptr.RP)",
|
||||
[0x11] = "cptr.X = rpop(cptr)",
|
||||
[0x12] = "cptr.Y = rpop(cptr)",
|
||||
[0x13] = "cptr.Z = rpop(cptr)",
|
||||
|
||||
[0x20] = "write(cptr, cptr.SP, cptr.X)",
|
||||
[0x21] = "push(cptr, cptr.X)",
|
||||
[0x22] = "push(cptr, cptr.Y)",
|
||||
[0x23] = "push(cptr, cptr.Z)",
|
||||
[0x30] = "cptr.X = read(cptr, cptr.SP)",
|
||||
[0x31] = "cptr.X = pop(cptr)",
|
||||
[0x32] = "cptr.Y = pop(cptr)",
|
||||
[0x33] = "cptr.Z = pop(cptr)",
|
||||
|
||||
[0x04] = "cptr.X = read(cptr, cptr.X)",
|
||||
[0x05] = "cptr.X = read(cptr, cptr.Y)",
|
||||
[0x06] = "cptr.Y = read(cptr, cptr.X)",
|
||||
[0x07] = "cptr.Y = read(cptr, cptr.Y)",
|
||||
|
||||
[0x14] = "cptr.X = readC(cptr, cptr.X)",
|
||||
[0x15] = "cptr.X = readC(cptr, cptr.Y)",
|
||||
[0x16] = "cptr.Y = readC(cptr, cptr.X)",
|
||||
[0x17] = "cptr.Y = readC(cptr, cptr.Y)",
|
||||
|
||||
[0x25] = "write(cptr, cptr.X, cptr.Y)",
|
||||
[0x26] = "write(cptr, cptr.Y, cptr.X)",
|
||||
|
||||
[0x35] = "writeC(cptr, cptr.X, cptr.Y)",
|
||||
[0x36] = "writeC(cptr, cptr.Y, cptr.X)",
|
||||
|
||||
[0x0c] = "n=cptr.X+cptr.Y; cptr.Y = u16(n); cptr.X = u16(math.floor(n/0x10000))",
|
||||
[0x0d] = "n=cptr.X-cptr.Y; cptr.Y = u16(n); cptr.X = u16(math.floor(n/0x10000))",
|
||||
[0x0e] = "n=cptr.X*cptr.Y; cptr.Y = u16(n); cptr.X = u16(math.floor(n/0x10000))",
|
||||
[0x0f] = "n=s16(cptr.X)*s16(cptr.Y); cptr.Y = u16(n); cptr.X = u16(math.floor(n/0x10000))",
|
||||
[0x1e] = "if cptr.Z~=0 then n = cptr.X*0x10000+cptr.Y; cptr.Y = u16(math.floor(n/cptr.Z)); cptr.X = u16(math.floor((n/cptr.Z)/0x10000)); cptr.Z = u16(n%cptr.Z) end",
|
||||
[0x1f] = "if cptr.Z~=0 then n = s32(cptr.X*0x10000+cptr.Y); cptr.Y = u16(math.floor(n/s16(cptr.Z))); cptr.X = u16(math.floor((n/s16(cptr.Z))/0x10000)); cptr.Z = u16(n%s16(cptr.Z)) end",
|
||||
[0x2c] = "cptr.X = u16(bit32.band(cptr.X, cptr.Y))",
|
||||
[0x2d] = "cptr.X = u16(bit32.bor(cptr.X, cptr.Y))",
|
||||
[0x2e] = "cptr.X = u16(bit32.bxor(cptr.X, cptr.Y))",
|
||||
[0x2f] = "cptr.X = u16(bit32.bnot(cptr.X))",
|
||||
[0x3c] = "cptr.X = bit32.rshift(cptr.X, cptr.Y)",
|
||||
[0x3d] = "cptr.X = u16(bit32.arshift(s16(cptr.X), cptr.Y))",
|
||||
[0x3e] = "n = cptr.X; cptr.X = u16(bit32.lshift(n, cptr.Y)); cptr.Y = u16(bit32.lshift(n, cptr.Y-16))",
|
||||
[0x3f] = "if s16(cptr.Y)<0 then cptr.X = u16(-1) else cptr.X = 0 end",
|
||||
|
||||
[0x38] = "cptr.PC = u16(cptr.PC+read(cptr, cptr.PC)+2)",
|
||||
[0x39] = "if cptr.X~=0 then cptr.PC = u16(cptr.PC+read(cptr, cptr.PC)) end; cptr.PC = u16(cptr.PC+2)",
|
||||
[0x3a] = "if cptr.Y~=0 then cptr.PC = u16(cptr.PC+read(cptr, cptr.PC)) end; cptr.PC = u16(cptr.PC+2)",
|
||||
[0x3b] = "if cptr.Z~=0 then cptr.PC = u16(cptr.PC+read(cptr, cptr.PC)) end; cptr.PC = u16(cptr.PC+2)",
|
||||
|
||||
[0x18] = "cptr.SP = cptr.X",
|
||||
[0x19] = "cptr.RP = cptr.X",
|
||||
[0x1a] = "cptr.PC = cptr.X",
|
||||
[0x1b] = "cptr.I = cptr.X",
|
||||
|
||||
[0x40] = "cptr.Z = cptr.X",
|
||||
[0x41] = "cptr.Z = cptr.Y",
|
||||
[0x42] = "cptr.X = cptr.Z",
|
||||
[0x43] = "cptr.Y = cptr.Z",
|
||||
[0x44] = "cptr.X = cptr.Y",
|
||||
[0x45] = "cptr.Y = cptr.X",
|
||||
|
||||
[0x46] = "cptr.X = u16(cptr.X-1)",
|
||||
[0x47] = "cptr.Y = u16(cptr.Y-1)",
|
||||
[0x48] = "cptr.Z = u16(cptr.Z-1)",
|
||||
|
||||
[0x49] = "cptr.X = u16(cptr.X+1)",
|
||||
[0x4a] = "cptr.Y = u16(cptr.Y+1)",
|
||||
[0x4b] = "cptr.Z = u16(cptr.Z+1)",
|
||||
|
||||
[0x4d] = "cptr.X = read(cptr, cptr.PC); cptr.PC = u16(cptr.PC+2)",
|
||||
[0x4e] = "cptr.Y = read(cptr, cptr.PC); cptr.PC = u16(cptr.PC+2)",
|
||||
[0x4f] = "cptr.Z = read(cptr, cptr.PC); cptr.PC = u16(cptr.PC+2)",
|
||||
|
||||
[0x52] = "receive(cptr, cptr.X, cptr.Y, cptr.Z)", -- Digiline receive
|
||||
[0x53] = "delete_message(cptr, cptr.X, cptr.Y)",
|
||||
[0x54] = "send_message(turtle, cptr, cptr.X, cptr.Y)", -- Digiline send
|
||||
[0x55] = "set_channel(cptr, cptr.X, cptr.Y)", -- Digiline set channel
|
||||
|
||||
-- Turtle commands
|
||||
[0x60] = "tl.forward(turtle, cptr)",
|
||||
[0x61] = "tl.backward(turtle, cptr)",
|
||||
[0x62] = "tl.up(turtle, cptr)",
|
||||
[0x63] = "tl.down(turtle, cptr)",
|
||||
[0x64] = "tl.turnleft(turtle, cptr)",
|
||||
[0x65] = "tl.turnright(turtle, cptr)",
|
||||
|
||||
[0x70] = "tl.refuel(turtle, cptr, cptr.X, cptr.Y)",
|
||||
}
|
||||
|
||||
ITABLE = {}
|
||||
|
||||
for i, v in pairs(ITABLE_RAW) do
|
||||
ITABLE[i] = loadstring(v) -- Parse everything at the beginning, way faster
|
||||
end
|
||||
|
||||
function on_computer_digiline_receive(turtle, channel, msg)
|
||||
local info = get_turtle_info(turtle)
|
||||
local cptr = info.cptr
|
||||
cptr.digiline_events[channel] = msg
|
||||
end
|
287
forth.fth
Normal file
287
forth.fth
Normal file
@ -0,0 +1,287 @@
|
||||
ASSEMBLER
|
||||
: EXIT IPOP NXT ;
|
||||
: (lit) CRX PHX NXT ;
|
||||
: (slit) CRX TXY TIX PHX PHY ADD TYX TXI NXT ;
|
||||
: (dodoes) CRX PHX CRX TXI NXT ;
|
||||
: DUP SPX PHX NXT ;
|
||||
: SWAP PLX PLY PHX PHY NXT ;
|
||||
: ROT PLX PLY PLZ PHY PHX PHZ NXT ;
|
||||
: -ROT PLX PLY PLZ PHX PHZ PHY NXT ;
|
||||
: OVER PLY SPX PHY PHX NXT ;
|
||||
: PICK PLY TYX ADD TSX SUB RYY PHY NXT ;
|
||||
: DROP PLX NXT ;
|
||||
: 2DROP PLX PLX NXT ;
|
||||
: 2DUP PLY SPX PHY PHX PHY NXT ;
|
||||
: 2SWAP PLX PLY PLZ RPHZ PLZ PHY PHX PHZ RPLZ PHZ NXT ;
|
||||
: 2OVER PLZ RPHZ PLZ PLY SPX PHY PHZ RPLZ PHZ PHX PHY NXT ;
|
||||
: NIP PLX PSX NXT ;
|
||||
: TUCK PLX PLY PHX PHY PHX NXT ;
|
||||
: ?DUP SPX XJMP 1 0 NXT PHX NXT ;
|
||||
: >R PLX RPHX NXT ;
|
||||
: R> RPLX PHX NXT ;
|
||||
: R@ RPX PHX NXT ;
|
||||
: ! PLY PLX WYX NXT ;
|
||||
: C! PLY PLX CWYX NXT ;
|
||||
: @ SPX RXX PSX NXT ;
|
||||
: C@ SPX CRXX PSX NXT ;
|
||||
: AND PLY SPX AND PSX NXT ;
|
||||
: OR PLY SPX OR PSX NXT ;
|
||||
: XOR PLY SPX XOR PSX NXT ;
|
||||
: INVERT SPX NOT PSX NXT ;
|
||||
: (branch) CRX TXI NXT ;
|
||||
: (0branch) PLY CRX YJMP 1 0 TXI NXT ;
|
||||
: ROLL PLY TYZ INCZ TYX ADD TSX SUB RXY PHX PLX TYX INCY INCY RYY WXY INCX INCX TXY DECZ ZJMP -11 -1 NXT ;
|
||||
: + PLY PLX ADD PHY NXT ;
|
||||
: - PLY PLX SUB PHY NXT ;
|
||||
: +! PLY TYZ RYY PLX ADD TZX WXY NXT ;
|
||||
: * PLY PLX MUL PHY NXT ;
|
||||
: U< PLY SPX SUB PSX NXT ;
|
||||
: U> PLX PLY SUB PHX NXT ;
|
||||
: M* PLY PLX SMUL PHY PHX NXT ;
|
||||
: UM* PLY PLX MUL PHY PHX NXT ;
|
||||
: 0= SPX XJMP 3 0 NOT PSX NXT ENTX 0 0 PSX NXT ;
|
||||
: 0<> SPX XJMP 1 0 NXT ENTX -1 -1 PSX NXT ;
|
||||
: 0< PLY SIGN PHX NXT ;
|
||||
: 0> PLY YJMP 2 0 PHY NXT SIGN NOT PHX NXT ;
|
||||
: <> PLY SPX SUB YJMP 2 0 PSX NXT ENTX -1 -1 PSX NXT ;
|
||||
: = PLY SPX SUB YJMP 5 0 ENTX -1 -1 PSX NXT ENTX 0 0 PSX NXT ;
|
||||
: EMPTYR ENTX 0 3 TXR NXT ;
|
||||
: EMPTYS ENTX 0 2 TXS NXT ;
|
||||
: DEPTH TSX ENTY 0 2 SUB TYX ENTY 1 0 ASH PHX NXT ;
|
||||
: 2* ENTY 1 0 SPX LSH PSX NXT ;
|
||||
: 2/ ENTY 1 0 SPX ASH PSX NXT ;
|
||||
: RSHIFT PLY SPX RSH PSX NXT ;
|
||||
: LSHIFT PLY SPX LSH PSX NXT ;
|
||||
: 2>R PLY PLX RPHX RPHY NXT ;
|
||||
: 2R> RPLY RPLX PHX PHY NXT ;
|
||||
: 2R@ RPLY RPX RPHY PHX PHY NXT ;
|
||||
: 1+ SPX INCX PSX NXT ;
|
||||
: 1- SPX DECX PSX NXT ;
|
||||
: EXECUTE PLX TXP ;
|
||||
: */MOD PLZ PLY PLX SMUL SDIV PHZ PHY NXT ;
|
||||
: */ PLZ PLY PLX SMUL SDIV PHY NXT ;
|
||||
: /MOD PLZ PLY SIGN SDIV PHZ PHY NXT ;
|
||||
: / PLZ PLY SIGN SDIV PHY NXT ;
|
||||
: MOD PLZ PLY SIGN SDIV PHZ NXT ;
|
||||
: UM/MOD PLZ PLX PLY DIV PHZ PHY NXT ;
|
||||
: FM/MOD PLZ PLX PLY SDIV PHZ PHY NXT ;
|
||||
: O+ PLY PLX ADD PHY PHX NXT ;
|
||||
: UDM/MOD PLZ PLX PLY DIV PHZ PHY PHX NXT ;
|
||||
: < PLY SIGN TYZ PLY PHY XOR TXY SIGN NOT XJMP 4 0 PLY SIGN PHX NXT PLX TZY SUB PHX NXT ;
|
||||
: > PLX PLY PHX SIGN TYZ PLY PHY XOR TXY SIGN NOT XJMP 4 0 PLY SIGN PHX NXT PLX TZY SUB PHX NXT ;
|
||||
: NEGATE SPX NOT INCX PSX NXT ;
|
||||
: (do) CRX RPHX PLY PLZ RPHZ RPHY NXT ;
|
||||
: (?do) CRX RPHX PLY PLX RPHX RPHY SUB YJMP 4 0 RPLY RPLY RPLX TXI NXT ;
|
||||
: I RPX PHX NXT ;
|
||||
: J RPLZ RPLY PHY RPLY RPX RPHY PLY RPHY RPHZ PHX NXT ;
|
||||
: UNLOOP RPLY RPLY RPLY NXT ;
|
||||
: (loop) RPLY INCY RPX RPHY SUB CRX YJMP 4 0 RPLY RPLY RPLY NXT TXI NXT ;
|
||||
: (+loop) RPLY TYZ PLX ADD RPX DECX RPHY TZY TXZ SUB SIGN PHX TZX RPLY RPHY SUB SIGN PLY XOR TXY CRX YJMP 2 0 TXI NXT RPLY RPLY RPLY NXT ;
|
||||
: WAIT BRK NXT ;
|
||||
: LEAVE RPLX RPLX RPLX TXI NXT ;
|
||||
: RECEIVE-AT PLZ PLY SPX RCV PSX NXT ;
|
||||
: DELETE-MSG PLY PLX DMSG NXT ;
|
||||
: SET-CHANNEL PLY PLX CHAN NXT ;
|
||||
: SEND PLY PLX SEND NXT ;
|
||||
|
||||
ENVIRONMENT
|
||||
256 CONSTANT /COUNTED-STRING
|
||||
34 CONSTANT /HOLD
|
||||
84 CONSTANT /PAD
|
||||
8 CONSTANT ADRESS-UNIT-BITS
|
||||
-1 CONSTANT CORE
|
||||
-1 CONSTANT CORE-EXT
|
||||
-1 CONSTANT FLOORED
|
||||
255 CONSTANT MAX-CHAR
|
||||
32767 CONSTANT MAX-N
|
||||
-1 CONSTANT MAX-U
|
||||
128 CONSTANT RETURN-STACK-CELLS
|
||||
128 CONSTANT STACK-CELLS
|
||||
0xffffffff 2CONSTANT MAX-UD
|
||||
0x7fffffff 2CONSTANT MAX-D
|
||||
-1 CONSTANT SEARCH-ORDER
|
||||
-1 CONSTANT SEARCH-ORDER-EXT
|
||||
8 CONSTANT WORDLISTS
|
||||
|
||||
FORTH
|
||||
32 CONSTANT BL
|
||||
0 CONSTANT FALSE
|
||||
-1 CONSTANT TRUE
|
||||
0x100 CONSTANT (source)
|
||||
0x104 CONSTANT >IN
|
||||
0x106 CONSTANT SOURCE-ID
|
||||
0x108 CONSTANT BASE
|
||||
0x10a CONSTANT STATE
|
||||
0x10c CONSTANT LATEST
|
||||
0x110 CONSTANT SPAN
|
||||
0x112 CONSTANT (here)
|
||||
0x114 CONSTANT LT
|
||||
0x116 CONSTANT #TIB
|
||||
0x118 CONSTANT TIB
|
||||
0x1a0 CONSTANT 'NUMBER
|
||||
0x1a2 CONSTANT NEW-WORDLIST
|
||||
0x1a4 CONSTANT CW
|
||||
0x1a6 CONSTANT NWORDER
|
||||
0x1b0 CONSTANT WORDLISTS
|
||||
0x1b0 CONSTANT FORTH-WORDLIST
|
||||
0x1b2 CONSTANT ENVDICO
|
||||
0x1d0 CONSTANT WORDER
|
||||
|
||||
: CHARS ; IMMEDIATE
|
||||
: ALIGN ; IMMEDIATE
|
||||
: ALIGNED ; IMMEDIATE
|
||||
: CELL+ 2 + ;
|
||||
: CELL- 2 - ;
|
||||
: CHAR+ 1+ ;
|
||||
: CELLS 2* ;
|
||||
: EMIT S" screen" SET-CHANNEL 2 ! 2 1 SEND ;
|
||||
: RECEIVE 0x80 RECEIVE-AT ;
|
||||
: 2! SWAP OVER ! CELL+ ! ;
|
||||
: 2@ DUP CELL+ @ SWAP @ ;
|
||||
: SOURCE (source) 2@ ;
|
||||
: S>D DUP 0< ;
|
||||
: MAX 2DUP > IF DROP ELSE NIP THEN ;
|
||||
: MIN 2DUP > IF NIP ELSE DROP THEN ;
|
||||
: D+ ROT + -ROT O+ ROT + ;
|
||||
: HEX 16 BASE ! ;
|
||||
: DECIMAL 10 BASE ! ;
|
||||
: TUCK SWAP OVER ;
|
||||
: NIP SWAP DROP ;
|
||||
: ABS DUP 0< IF NEGATE THEN ;
|
||||
: (marker) LATEST ! (here) ! ;
|
||||
: TYPE DUP 0> IF OVER + SWAP ?DO I C@ EMIT LOOP ELSE 2DROP THEN ;
|
||||
: RSTR 1+ DUP 2 + C@ 127 AND TUCK - SWAP ;
|
||||
: CR 10 EMIT ;
|
||||
: SPACE 32 EMIT ;
|
||||
: SPACES DUP 0> IF 0 DO SPACE LOOP ELSE DROP THEN ;
|
||||
: STR= 0 DO OVER C@ OVER C@ <> IF UNLOOP 2DROP FALSE EXIT THEN SWAP 1+ SWAP 1+ LOOP 2DROP TRUE ;
|
||||
: IMMEDIATE LATEST @ 1- DUP C@ 128 OR SWAP C! ;
|
||||
: HERE (here) @ ;
|
||||
: [ FALSE STATE ! ; IMMEDIATE
|
||||
: ] TRUE STATE ! ;
|
||||
: ALLOT (here) +! ;
|
||||
: , HERE ! 2 ALLOT ;
|
||||
: C, HERE C! 1 ALLOT ;
|
||||
: SKIP-WHITE BEGIN DUP C@ 33 < WHILE 1+ 2DUP = IF EXIT THEN REPEAT ;
|
||||
: EXIT-IF-END SOURCE NIP >IN @ = IF SOURCE + 0 R> DROP THEN ;
|
||||
: PARSE-LIMITS SOURCE OVER + SWAP >IN @ + ;
|
||||
: >IN-END SOURCE NIP >IN ! ;
|
||||
: COUNTED-STRING DUP HERE C! HERE 1+ -ROT OVER + SWAP DO I C@ OVER C! 1+ LOOP DROP HERE ;
|
||||
: PARSE-WORD EXIT-IF-END PARSE-LIMITS SKIP-WHITE 2DUP = IF >IN-END DROP 0 EXIT THEN DUP >R BEGIN DUP C@ 32 > WHILE 1+ 2DUP = IF >IN-END DROP R@ - R> SWAP EXIT THEN REPEAT NIP DUP SOURCE DROP - 1+ >IN ! R@ - R> SWAP ;
|
||||
: PARSE SOURCE NIP >IN @ = IF DROP SOURCE + 0 EXIT THEN PARSE-LIMITS DUP >R ROT >R BEGIN DUP C@ R@ <> WHILE 1+ 2DUP = IF R> DROP >IN-END DROP R@ - R> SWAP EXIT THEN REPEAT R> DROP NIP DUP SOURCE DROP - 1+ >IN ! R@ - R> SWAP ;
|
||||
|
||||
\ TODO: Fix WORD not skipping leading delimiters
|
||||
: WORD SOURCE NIP >IN @ = IF DROP 0 HERE C! HERE EXIT THEN PARSE-LIMITS DUP >R ROT >R BEGIN DUP C@ R@ <> WHILE 1+ 2DUP = IF R> DROP >IN-END DROP R@ - R> SWAP EXIT THEN REPEAT R> DROP NIP DUP SOURCE DROP - 1+ >IN ! R@ - R> SWAP COUNTED-STRING ;
|
||||
|
||||
: HEADER PARSE-WORD TUCK 0 C, OVER + SWAP DO I C@ C, LOOP LATEST @ , C, ;
|
||||
: : HEADER HERE DUP LT ! 42 C, ] ;
|
||||
: :CODE HEADER HERE DUP LT ! ;
|
||||
: UNUSED HERE NEGATE ;
|
||||
: NCHAR DUP C@ DUP 58 < IF 48 - ELSE DUP 97 < IF 55 - ELSE 87 - THEN THEN ;
|
||||
: >NUMBER DUP >R 0 DO NCHAR DUP BASE @ < OVER 0< INVERT AND IF 2SWAP BASE @ * 0 SWAP ROT BASE @ UM* D+ ROT 0 D+ ROT 1+ ELSE DROP I UNLOOP R> SWAP - EXIT THEN LOOP R> DROP 0 ;
|
||||
:NONAME 0 0 2SWAP OVER C@ 45 = IF SWAP 1+ SWAP 1- >NUMBER 2SWAP DROP NEGATE 1 2SWAP ELSE >NUMBER ROT DROP 1 -ROT THEN ; 'NUMBER !
|
||||
: NUMBER 'NUMBER @ EXECUTE ;
|
||||
: SAVE-INPUT >IN @ 1 ;
|
||||
: RESTORE-INPUT DUP 1 = IF DROP >IN ! FALSE ELSE 0 ?DO DROP LOOP TRUE THEN ;
|
||||
: COUNT DUP 1+ SWAP C@ ;
|
||||
: CHAR PARSE-WORD DROP C@ ;
|
||||
: FILL -ROT DUP 0> IF OVER + SWAP DO DUP I C! LOOP ELSE 2DROP THEN DROP ;
|
||||
: ERASE 0 FILL ;
|
||||
: ( 41 PARSE 2DROP ; IMMEDIATE
|
||||
: .( 41 PARSE TYPE ; IMMEDIATE
|
||||
: \ 10 PARSE 2DROP ; IMMEDIATE
|
||||
: THEN HERE SWAP ! ; IMMEDIATE
|
||||
: BEGIN HERE ; IMMEDIATE
|
||||
: FIND-WORD-DICO SWAP >R BEGIN DUP 4 - RSTR R@ = IF 2 PICK R@ STR= IF NIP R> DROP EXIT THEN ELSE DROP THEN 3 - @ DUP 0= UNTIL NIP R> DROP ;
|
||||
: GET-WL-LATEST DUP CW @ = IF DROP LATEST @ ELSE @ THEN ;
|
||||
: FIND-WORD WORDER NWORDER @ 2* + WORDER DO I @ GET-WL-LATEST FIND-WORD-DICO ?DUP IF UNLOOP EXIT THEN 2 +LOOP 0 ;
|
||||
: ' PARSE-WORD FIND-WORD ;
|
||||
: POSTPONE ' DUP 1- C@ 128 AND IF , ELSE ['] (lit) , , ['] , , THEN ; IMMEDIATE
|
||||
: LITERAL ['] (lit) , , ; IMMEDIATE
|
||||
: NLITERAL DUP >R 0 DO ['] (lit) , 0 , LOOP R> 0 DO HERE 2 - I 4 * - ! LOOP ; IMMEDIATE
|
||||
: DOES> ['] (dodoes) LATEST @ 1+ ! R> LATEST @ 5 + ! ;
|
||||
: ['] ' POSTPONE LITERAL ; IMMEDIATE
|
||||
: [COMPILE] ' , ; IMMEDIATE
|
||||
: ; ['] EXIT , LATEST ! POSTPONE [ ; IMMEDIATE
|
||||
: CODE; 41 C, LATEST ! ;
|
||||
: [CHAR] CHAR POSTPONE LITERAL ; IMMEDIATE
|
||||
: CREATE HEADER HERE LATEST ! 42 C, HERE 6 + POSTPONE LITERAL ['] EXIT , ;
|
||||
: VARIABLE CREATE 2 ALLOT ;
|
||||
: CONSTANT HEADER HERE LATEST ! 77 C, , 33 C, 41 C, ;
|
||||
: MARKER HERE HEADER HERE SWAP 42 C, POSTPONE LITERAL LATEST @ POSTPONE LITERAL ['] (marker) , ['] EXIT , LATEST ! ;
|
||||
: IF ['] (0branch) , HERE 0 , ; IMMEDIATE
|
||||
: ELSE ['] (branch) , HERE SWAP 0 , HERE SWAP ! ; IMMEDIATE
|
||||
: UNTIL ['] (0branch) , , ; IMMEDIATE
|
||||
: REPEAT ['] (branch) , , HERE SWAP ! ; IMMEDIATE
|
||||
: WHILE ['] (0branch) , HERE SWAP 0 , ; IMMEDIATE
|
||||
: CASE 0 ; IMMEDIATE
|
||||
: ENDCASE ['] DROP , BEGIN DUP 0<> WHILE HERE SWAP ! REPEAT DROP ; IMMEDIATE
|
||||
: OF ['] OVER , ['] = , ['] (0branch) , HERE 0 , ['] DROP , ; IMMEDIATE
|
||||
: ENDOF ['] (branch) , HERE 0 , HERE ROT ! ; IMMEDIATE
|
||||
\ : S" 34 PARSE ['] (branch) , HERE 0 , -ROT 2DUP OVER + SWAP ?DO I C@ C, LOOP NIP SWAP DUP HERE SWAP ! 2 + POSTPONE LITERAL POSTPONE LITERAL ; IMMEDIATE
|
||||
: SLITERAL ['] (slit) , DUP , OVER + SWAP ?DO I C@ C, LOOP ; IMMEDIATE
|
||||
: S" 34 PARSE POSTPONE SLITERAL ; IMMEDIATE
|
||||
: PAD HERE 36 + ;
|
||||
: VALUE HEADER HERE LATEST ! 77 C, , 33 C, 41 C, ;
|
||||
: TO PARSE-WORD FIND-WORD 1+ STATE @ IF POSTPONE LITERAL ['] ! , ELSE ! THEN ; IMMEDIATE
|
||||
: COMPILE, , ;
|
||||
: AGAIN ['] (branch) , , ; IMMEDIATE
|
||||
: ABORT EMPTYS QUIT ;
|
||||
: COMPILE-WORD 2DUP 2>R FIND-WORD ?DUP IF 2R> 2DROP DUP 1- C@ 128 AND IF EXECUTE ELSE , THEN ELSE 2R@ NUMBER 0= IF DROP 2R> 2DROP POSTPONE NLITERAL ELSE DROP 0 ?DO DROP LOOP 2R> TYPE SPACE 63 EMIT ABORT THEN THEN ;
|
||||
: COUNT DUP 1+ SWAP C@ ;
|
||||
: RECURSE LT @ , ; IMMEDIATE
|
||||
: :NONAME HERE DUP LT ! 42 C, LATEST @ ] ;
|
||||
: >BODY 7 + ;
|
||||
: ENVIRONMENT? ENVDICO @ FIND-WORD-DICO DUP IF EXECUTE TRUE THEN ;
|
||||
: D0= OR 0= ;
|
||||
: HOLD HERE @ 1- DUP HERE ! C! ;
|
||||
: # BASE @ UDM/MOD ROT DUP 9 > IF 55 + ELSE 48 + THEN HOLD ;
|
||||
: #S BEGIN # 2DUP D0= UNTIL ;
|
||||
: ." POSTPONE S" ['] TYPE , ; IMMEDIATE
|
||||
: C" 34 PARSE ['] (branch) , HERE 0 , -ROT HERE -ROT DUP C, OVER + SWAP ?DO I C@ C, LOOP SWAP HERE SWAP ! POSTPONE LITERAL ; IMMEDIATE
|
||||
: <# PAD HERE ! ;
|
||||
: #> 2DROP HERE @ PAD OVER - ;
|
||||
: SIGN 0< IF 45 HOLD THEN ;
|
||||
: CONVERT -1 >NUMBER DROP ;
|
||||
: MOVE DUP 0= IF DROP 2DROP EXIT THEN -ROT 2DUP U> IF ROT 0 DO OVER C@ OVER C! 1+ SWAP 1+ SWAP LOOP ELSE 2 PICK TUCK + -ROT + SWAP ROT 0 DO 1- SWAP 1- SWAP OVER C@ OVER C! LOOP THEN 2DROP ;
|
||||
: . DUP >R ABS 0 <# BL HOLD #S R> SIGN #> TYPE ;
|
||||
: U. 0 <# BL HOLD #S #> TYPE ;
|
||||
: .R >R DUP >R ABS 0 <# BL HOLD #S R> SIGN #> R> OVER - SPACES TYPE ;
|
||||
: U.R >R 0 <# BL HOLD #S #> R> OVER - SPACES TYPE ;
|
||||
: WITHIN OVER - >R - R> U< ;
|
||||
: DO ['] (do) , HERE 0 , HERE ; IMMEDIATE
|
||||
: ?DO ['] (?do) , HERE 0 , HERE ; IMMEDIATE
|
||||
: LOOP ['] (loop) , , HERE SWAP ! ; IMMEDIATE
|
||||
: +LOOP ['] (+loop) , , HERE SWAP ! ; IMMEDIATE
|
||||
: ACCEPT S" screen" DELETE-MSG BEGIN S" screen" 16 RECEIVE-AT DUP 0< WHILE DROP WAIT REPEAT MIN TUCK 16 -ROT MOVE ;
|
||||
: EXPECT ACCEPT SPAN ! ;
|
||||
: QUERY 0 >IN ! 0 SOURCE-ID ! TIB DUP 80 ACCEPT SPACE (source) 2! ;
|
||||
: REFILL SOURCE-ID @ IF FALSE ELSE 0 >IN ! TIB DUP 80 ACCEPT SPACE (source) 2! TRUE THEN ;
|
||||
: INTERPRET-WORD 2DUP 2>R FIND-WORD ?DUP IF 2R> 2DROP EXECUTE ELSE 2R@ NUMBER 0= IF 2DROP 2R> 2DROP ELSE DROP 0 ?DO DROP LOOP 2R> TYPE SPACE 63 EMIT ABORT THEN THEN ;
|
||||
: EVALUATE SOURCE 2>R >IN @ >R SOURCE-ID @ >R -1 SOURCE-ID ! 0 >IN ! (source) 2! BEGIN PARSE-WORD ?DUP WHILE STATE @ IF COMPILE-WORD ELSE INTERPRET-WORD THEN REPEAT DROP R> SOURCE-ID ! R> >IN ! 2R> (source) 2! ;
|
||||
: QUIT EMPTYR CR BEGIN REFILL WHILE BEGIN PARSE-WORD ?DUP WHILE STATE @ IF COMPILE-WORD ELSE INTERPRET-WORD THEN REPEAT DROP SPACE 79 EMIT 75 EMIT CR REPEAT ;
|
||||
: (abort") ROT IF TYPE ABORT THEN 2DROP ;
|
||||
: ABORT" POSTPONE S" ['] (abort") , ; IMMEDIATE
|
||||
: DABS DUP 0< IF OVER NEGATE ROT IF SWAP INVERT ELSE SWAP NEGATE THEN THEN ;
|
||||
: SM/REM OVER >R 2DUP XOR >R ABS >R DABS R> UM/MOD R> 0< IF NEGATE THEN SWAP R> 0< IF NEGATE THEN SWAP ;
|
||||
\ : KEY BEGIN RAWKEY DUP 31 > OVER 127 < AND IF EXIT THEN DROP AGAIN ;
|
||||
: ON SET-CHANNEL S" on" SEND ;
|
||||
: OFF SET-CHANNEL S" off" SEND ;
|
||||
: IO@ RECEIVE 3 < ;
|
||||
: LOADPKG 0 0x11e C! PARSE-WORD 0x11a 2! BEGIN 0x11a 2@ SET-CHANNEL 0x11e 1 SEND 0x11e C@ 1+ 0x11e C! 0x11a 2@ 16 RECEIVE-AT 16 C@ WHILE 16 SWAP EVALUATE REPEAT DROP ;
|
||||
: GET-CURRENT CW @ ;
|
||||
: SET-CURRENT LATEST @ CW @ ! DUP CW ! @ LATEST ! ;
|
||||
: WORDLIST NEW-WORDLIST @ DUP CELL+ NEW-WORDLIST ! ;
|
||||
: DEFINITIONS WORDER @ SET-CURRENT ;
|
||||
: GET-ORDER WORDER NWORDER @ 1- 2* + ?DO I @ -2 +LOOP NWORDER @ ;
|
||||
: SET-ORDER DUP NWORDER ! WORDER 0 ?DO TUCK ! CELL+ LOOP DROP ;
|
||||
: ALSO WORDER DUP CELL+ NWORDER @ 2* MOVE NWORDER 2 +! ;
|
||||
: FORTH FORTH-WORDLIST WORDER ! ;
|
||||
: ONLY FORTH 1 NWORDER ! ;
|
||||
: ORDER WORDER NWORDER @ 2* + WORDER DO I @ . 2 +LOOP CR CW @ ;
|
||||
: PREVIOUS WORDER CELL+ WORDER NWORDER @ 1- 2* MOVE NWORDER -2 +! ;
|
||||
: SEARCH-WORDLIST GET-WL-LATEST FIND-WORD-DICO DUP IF DUP 1- C@ 128 AND IF 1 ELSE -1 THEN THEN ;
|
||||
: FIND DUP COUNT WORDER NWORDER @ 2* + WORDER DO 2DUP I @ SEARCH-WORDLIST ?DUP IF 2>R 2DROP DROP 2R> UNLOOP EXIT THEN 2 +LOOP 2DROP 0 ;
|
||||
: DUMP SET-CHANNEL 256 0 DO I 64 * PAD 1+ 64 MOVE I PAD C! PAD 65 SEND LOOP ;
|
||||
: SAVE-STATE S" boot" DUMP ;
|
||||
: COLD S" Computer is ready (" TYPE UNUSED U. S" bytes free)" TYPE QUIT ;
|
3
forth_floppy.lua
Normal file
3
forth_floppy.lua
Normal file
File diff suppressed because one or more lines are too long
147
helpers.lua
Normal file
147
helpers.lua
Normal file
@ -0,0 +1,147 @@
|
||||
luahelpers={}
|
||||
|
||||
function long_string(s,i)
|
||||
local ii=i
|
||||
local ls=string.len(s)
|
||||
local depth=0
|
||||
while i<=ls do
|
||||
i=i+1
|
||||
c=string.sub(s,i,i)
|
||||
if c=='[' then
|
||||
i=i+1
|
||||
break
|
||||
else
|
||||
depth=depth+1
|
||||
end
|
||||
end
|
||||
while i<=ls-depth-1 do
|
||||
i=i+1
|
||||
c=string.sub(s,i,i+depth+1)
|
||||
if c==']'..string.rep("=",depth).."]" then
|
||||
i=i+depth+2
|
||||
break
|
||||
end
|
||||
end
|
||||
return i,string.sub(s,ii,i-1)
|
||||
end
|
||||
|
||||
function countb(s,i)
|
||||
local x=0
|
||||
while string.sub(s,i,i)=="\\" do
|
||||
i=i-1
|
||||
x=x+1
|
||||
end
|
||||
return x
|
||||
end
|
||||
|
||||
function luahelpers.remove_comments(s)
|
||||
local i=1
|
||||
local ls=string.len(s)
|
||||
local l2=""
|
||||
while i<=ls do
|
||||
local c=string.sub(s,i,i)
|
||||
if c=="-" then
|
||||
if i==ls then
|
||||
l2=l2.."-"
|
||||
break
|
||||
end
|
||||
local c2=string.sub(s,i+1,i+1)
|
||||
if c2=="-" then
|
||||
--comment
|
||||
if i==ls-1 then break end
|
||||
local c3=string.sub(s,i+2,i+2)
|
||||
if c3=="[" then --long comment
|
||||
local k=""
|
||||
i,k=long_string(s,i+2)
|
||||
print(k)
|
||||
else --short comment
|
||||
i=i+2
|
||||
c=string.sub(s,i,i)
|
||||
while i<=ls and c~="\n" do
|
||||
c=string.sub(s,i,i)
|
||||
i=i+1
|
||||
end
|
||||
l2=l2.."\n"
|
||||
end
|
||||
else
|
||||
i=i+1
|
||||
l2=l2.."-"
|
||||
end
|
||||
elseif c=='"' then
|
||||
c=string.sub(s,i,i)
|
||||
while i<=ls do
|
||||
l2=l2..c
|
||||
i=i+1
|
||||
c=string.sub(s,i,i)
|
||||
if c=='"' then
|
||||
local c2=countb(s,i-1)
|
||||
if c2%2==0 then
|
||||
i=i+1
|
||||
l2=l2..'"'
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif c=="'" then
|
||||
c=string.sub(s,i,i)
|
||||
while i<=ls do
|
||||
l2=l2..c
|
||||
i=i+1
|
||||
c=string.sub(s,i,i)
|
||||
if c=="'" then
|
||||
local c2=countb(s,i-1)
|
||||
if c2%2==0 then
|
||||
i=i+1
|
||||
l2=l2.."'"
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif c=="[" then
|
||||
if i==ls then
|
||||
l2=l2.."["
|
||||
break
|
||||
end
|
||||
local c2=string.sub(s,i+1,i+1)
|
||||
if c2=="[" or c2=="=" then
|
||||
local k=""
|
||||
i,k=long_string(s,i)
|
||||
l2=l2..k
|
||||
else
|
||||
i=i+1
|
||||
l2=l2.."["
|
||||
end
|
||||
else
|
||||
l2=l2..c
|
||||
i=i+1
|
||||
end
|
||||
end
|
||||
return l2
|
||||
end
|
||||
|
||||
function luahelpers.add_yields(s)
|
||||
s=luahelpers.remove_comments(s)
|
||||
s="\n"..s.."\n"
|
||||
s=string.gsub(s, "[^_%w]while[^_%w].-[^_%w]do[^_%w]", "%1 coroutine.yield(0);")
|
||||
s=string.gsub(s, "[^_%w]for[^_%w].-[^_%w]do[^_%w]", "%1 coroutine.yield(0);")
|
||||
s=string.gsub(s, "[^_%w]repeat[^_%w]", "%1 coroutine.yield(0);")
|
||||
s=string.gsub(s, "[^_%w]function[^_%w].-%)", "%1 coroutine.yield(0);")
|
||||
return s
|
||||
end
|
||||
|
||||
--[======[ DEBUG CODE
|
||||
print(luahelpers.remove_comments([====[
|
||||
gzvsvs--gsv
|
||||
fsd"--hkj"fvd
|
||||
[=[--[[]=]
|
||||
--[[fzffs]]
|
||||
]====]))
|
||||
print(luahelpers.remove_comments([====[
|
||||
--[[fzffs]]
|
||||
]====]))
|
||||
--]======]
|
||||
|
||||
print(luahelpers.add_yields([[
|
||||
while true do
|
||||
turtle.forward()
|
||||
end]]))
|
6
init.lua
6
init.lua
@ -1,2 +1,6 @@
|
||||
local modpath = minetest.get_modpath("turtle")
|
||||
dofile(modpath.."/turtle.lua")
|
||||
--dofile(modpath.."/turtle.lua")
|
||||
dofile(modpath.."/computer_memory.lua")
|
||||
dofile(modpath.."/forth_floppy.lua")
|
||||
dofile(modpath.."/cptr.lua")
|
||||
dofile(modpath.."/t.lua")
|
||||
|
567
progs/replicate.lua
Normal file
567
progs/replicate.lua
Normal file
@ -0,0 +1,567 @@
|
||||
DOWN=-300
|
||||
|
||||
function v3add(v1,v2)
|
||||
return {x=v1.x+v2.x, y=v1.y+v2.y, z=v1.z+v2.z}
|
||||
end
|
||||
function v3sub(v1,v2)
|
||||
return {x=v1.x-v2.x, y=v1.y-v2.y, z=v1.z-v2.z}
|
||||
end
|
||||
|
||||
function forward(iid)
|
||||
mem.pos = v3add(mem.pos, mem.dir)
|
||||
turtle.forward(iid)
|
||||
end
|
||||
|
||||
function back(iid)
|
||||
mem.pos = v3sub(mem.pos, mem.dir)
|
||||
turtle.back(iid)
|
||||
end
|
||||
|
||||
function up(iid)
|
||||
mem.pos.y=mem.pos.y+1
|
||||
turtle.up(iid)
|
||||
end
|
||||
|
||||
function down(iid)
|
||||
mem.pos.y=mem.pos.y-1
|
||||
turtle.down(iid)
|
||||
end
|
||||
|
||||
function turnleft(iid)
|
||||
mem.dir={x=mem.dir.z, y=mem.dir.y, z=-mem.dir.x}
|
||||
turtle.turnleft(iid)
|
||||
end
|
||||
|
||||
function turnright(iid)
|
||||
mem.dir={x=-mem.dir.z, y=mem.dir.y, z=mem.dir.x}
|
||||
turtle.turnright(iid)
|
||||
end
|
||||
|
||||
function gotoface(iid, dir)
|
||||
if dir.x==0 then
|
||||
if mem.dir.x==-dir.z then
|
||||
turnleft(iid)
|
||||
elseif mem.dir.x==dir.z then
|
||||
turnright(iid)
|
||||
elseif mem.dir.z==dir.z then
|
||||
interrupt(0, iid)
|
||||
else
|
||||
mem.gotofaceiid=iid
|
||||
turnleft("gotoface")
|
||||
end
|
||||
else
|
||||
if mem.dir.z==dir.x then
|
||||
turnleft(iid)
|
||||
elseif mem.dir.z==-dir.x then
|
||||
turnright(iid)
|
||||
elseif mem.dir.x==dir.x then
|
||||
interrupt(0, iid)
|
||||
else
|
||||
mem.gotofaceiid=iid
|
||||
turnleft("gotoface")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function nface(iid)
|
||||
gotoface(iid, {x=0,y=0,z=1})
|
||||
end
|
||||
|
||||
function put_all_except(name)
|
||||
if turtle.getstack(1).name~=name then
|
||||
turtle.drop(1)
|
||||
end
|
||||
if turtle.getstack(2).name~=name then
|
||||
turtle.drop(2)
|
||||
end
|
||||
if turtle.getstack(3).name~=name then
|
||||
turtle.drop(3)
|
||||
end
|
||||
if turtle.getstack(4).name~=name then
|
||||
turtle.drop(4)
|
||||
end
|
||||
if turtle.getstack(5).name~=name then
|
||||
turtle.drop(5)
|
||||
end
|
||||
if turtle.getstack(6).name~=name then
|
||||
turtle.drop(6)
|
||||
end
|
||||
if turtle.getstack(7).name~=name then
|
||||
turtle.drop(7)
|
||||
end
|
||||
if turtle.getstack(8).name~=name then
|
||||
turtle.drop(8)
|
||||
end
|
||||
if turtle.getstack(9).name~=name then
|
||||
turtle.drop(9)
|
||||
end
|
||||
if turtle.getstack(10).name~=name then
|
||||
turtle.drop(10)
|
||||
end
|
||||
if turtle.getstack(11).name~=name then
|
||||
turtle.drop(11)
|
||||
end
|
||||
if turtle.getstack(12).name~=name then
|
||||
turtle.drop(12)
|
||||
end
|
||||
if turtle.getstack(13).name~=name then
|
||||
turtle.drop(13)
|
||||
end
|
||||
if turtle.getstack(14).name~=name then
|
||||
turtle.drop(14)
|
||||
end
|
||||
if turtle.getstack(15).name~=name then
|
||||
turtle.drop(15)
|
||||
end
|
||||
if turtle.getstack(16).name~=name then
|
||||
turtle.drop(16)
|
||||
end
|
||||
end
|
||||
|
||||
function put_all(name)
|
||||
if turtle.getstack(1).name==name then
|
||||
turtle.drop(1)
|
||||
end
|
||||
if turtle.getstack(2).name==name then
|
||||
turtle.drop(2)
|
||||
end
|
||||
if turtle.getstack(3).name==name then
|
||||
turtle.drop(3)
|
||||
end
|
||||
if turtle.getstack(4).name==name then
|
||||
turtle.drop(4)
|
||||
end
|
||||
if turtle.getstack(5).name==name then
|
||||
turtle.drop(5)
|
||||
end
|
||||
if turtle.getstack(6).name==name then
|
||||
turtle.drop(6)
|
||||
end
|
||||
if turtle.getstack(7).name==name then
|
||||
turtle.drop(7)
|
||||
end
|
||||
if turtle.getstack(8).name==name then
|
||||
turtle.drop(8)
|
||||
end
|
||||
if turtle.getstack(9).name==name then
|
||||
turtle.drop(9)
|
||||
end
|
||||
if turtle.getstack(10).name==name then
|
||||
turtle.drop(10)
|
||||
end
|
||||
if turtle.getstack(11).name==name then
|
||||
turtle.drop(11)
|
||||
end
|
||||
if turtle.getstack(12).name==name then
|
||||
turtle.drop(12)
|
||||
end
|
||||
if turtle.getstack(13).name==name then
|
||||
turtle.drop(13)
|
||||
end
|
||||
if turtle.getstack(14).name==name then
|
||||
turtle.drop(14)
|
||||
end
|
||||
if turtle.getstack(15).name==name then
|
||||
turtle.drop(15)
|
||||
end
|
||||
if turtle.getstack(16).name==name then
|
||||
turtle.drop(16)
|
||||
end
|
||||
end
|
||||
|
||||
function find_stack(name)
|
||||
if turtle.getstack(1).name==name then
|
||||
return 1
|
||||
elseif turtle.getstack(2).name==name then
|
||||
return 2
|
||||
elseif turtle.getstack(3).name==name then
|
||||
return 3
|
||||
elseif turtle.getstack(4).name==name then
|
||||
return 4
|
||||
elseif turtle.getstack(5).name==name then
|
||||
return 5
|
||||
elseif turtle.getstack(6).name==name then
|
||||
return 6
|
||||
elseif turtle.getstack(7).name==name then
|
||||
return 7
|
||||
elseif turtle.getstack(8).name==name then
|
||||
return 8
|
||||
elseif turtle.getstack(9).name==name then
|
||||
return 9
|
||||
elseif turtle.getstack(10).name==name then
|
||||
return 10
|
||||
elseif turtle.getstack(11).name==name then
|
||||
return 11
|
||||
elseif turtle.getstack(12).name==name then
|
||||
return 12
|
||||
elseif turtle.getstack(13).name==name then
|
||||
return 13
|
||||
elseif turtle.getstack(14).name==name then
|
||||
return 14
|
||||
elseif turtle.getstack(15).name==name then
|
||||
return 15
|
||||
elseif turtle.getstack(16).name==name then
|
||||
return 16
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--print(event)
|
||||
if event.type=="program" then
|
||||
mem.spx=1
|
||||
mem.spy=1
|
||||
mem.pos = {x=0,y=0,z=0}
|
||||
mem.dir = {x=0,y=0,z=1}
|
||||
turtle.dig()
|
||||
turtle.refuel(1)
|
||||
forward("cuttree")
|
||||
mem.return_to="firsttree"
|
||||
elseif event.type=="endmove" or event.type=="interrupt" then
|
||||
if event.iid=="gotoface" then
|
||||
turnleft(mem.gotofaceiid)
|
||||
elseif event.iid=="cuttree" then
|
||||
turtle.dig()
|
||||
mem.origface={x=mem.dir.x,y=mem.dir.y,z=mem.dir.z}
|
||||
name = turtle.detectup()
|
||||
if name=="air" then
|
||||
down("endcuttree")
|
||||
else
|
||||
turtle.digup()
|
||||
up("cuttree2")
|
||||
end
|
||||
elseif event.iid=="cuttree2" then
|
||||
turtle.dig()
|
||||
turnleft("cuttree3")
|
||||
elseif event.iid=="cuttree3" then
|
||||
turtle.dig()
|
||||
turnleft("cuttree4")
|
||||
elseif event.iid=="cuttree4" then
|
||||
turtle.dig()
|
||||
turnleft("cuttree5")
|
||||
elseif event.iid=="cuttree5" then
|
||||
turtle.dig()
|
||||
name = turtle.detectup()
|
||||
if name=="air" then
|
||||
down("endcuttree")
|
||||
else
|
||||
turtle.digup()
|
||||
up("cuttree2")
|
||||
end
|
||||
elseif event.iid=="endcuttree" then
|
||||
name = turtle.detectdown()
|
||||
turtle.suckdown()
|
||||
if name=="air" then
|
||||
down("endcuttree")
|
||||
else
|
||||
gotoface(mem.return_to, mem.origface)
|
||||
end
|
||||
elseif event.iid=="firsttree" then
|
||||
nface("firsttree1")
|
||||
elseif event.iid=="firsttree1" then
|
||||
turtle.dropup(2)
|
||||
turtle.dropup(3)
|
||||
turtle.craft(3)
|
||||
turtle.dropup(1)
|
||||
turtle.moveto(2,1,1)
|
||||
turtle.moveto(2,3,5)
|
||||
turtle.moveto(2,5,1)
|
||||
turtle.moveto(2,7,1)
|
||||
turtle.moveto(2,9,1)
|
||||
turtle.moveto(2,10,1)
|
||||
turtle.moveto(2,11,1)
|
||||
turtle.craft(1)
|
||||
turtle.place(1)
|
||||
turtle.craft(4)
|
||||
turtle.drop(1)
|
||||
interrupt(5,"firsttree2")
|
||||
elseif event.iid=="firsttree2" then
|
||||
turtle.suckup()
|
||||
turtle.suckup()
|
||||
turtle.suckup()
|
||||
turtle.suckup() -- Excess suckups are whenever saplings fell
|
||||
turtle.suckup()
|
||||
turtle.suckup()
|
||||
turtle.suckup()
|
||||
turtle.suckup()
|
||||
turnleft("firsttree3")
|
||||
elseif event.iid=="firsttree3" then
|
||||
local s=nil
|
||||
s=find_stack("default:leaves")
|
||||
if s==nil then --we don't have leaves, only spalings
|
||||
interrupt(0.1,"plant_sapling")
|
||||
else
|
||||
mem.leaves_stack=s
|
||||
turtle.place(s)
|
||||
mem.return_to="plant_sapling"
|
||||
interrupt(0.1,"leaves_dig")
|
||||
end
|
||||
elseif event.iid=="leaves_dig" then
|
||||
turtle.dig()
|
||||
interrupt(0.1, "leaves_place")
|
||||
elseif event.iid=="leaves_place" then
|
||||
if turtle.getstack(mem.leaves_stack).name=="default:leaves" then
|
||||
turtle.place(mem.leaves_stack)
|
||||
interrupt(0.1,"leaves_dig")
|
||||
else --no more leaves
|
||||
interrupt(0.1,mem.return_to)
|
||||
end
|
||||
elseif event.iid=="plant_sapling" then
|
||||
local s
|
||||
local w
|
||||
s=find_stack("default:sapling")
|
||||
w=find_stack("default:tree")
|
||||
mem.sapstack=s
|
||||
turtle.place(s)
|
||||
turtle.refuel(w, 1)
|
||||
mem.ddown = math.floor(turtle.get_fuel_time()/2)-10
|
||||
turnleft("plant_sapling2")
|
||||
elseif event.iid=="plant_sapling2" then
|
||||
turtle.place(mem.sapstack)
|
||||
turnleft("plant_sapling3")
|
||||
elseif event.iid=="plant_sapling3" then
|
||||
turtle.place(mem.sapstack)
|
||||
turnright("dig1")
|
||||
elseif event.iid=="dig" then
|
||||
m=find_stack("default:mese_crystal")
|
||||
d=find_stack("default:diamond")
|
||||
if m~=nil and d~=nil and turtle.getstack(m).count>=30 and turtle.getstack(d).count>=7 then
|
||||
nface("craft")
|
||||
else
|
||||
w=find_stack("default:tree")
|
||||
if w~=nil then
|
||||
turtle.refuel(w)
|
||||
end
|
||||
c=find_stack("default:coal_lump")
|
||||
if c~=nil then
|
||||
turtle.refuel(c)
|
||||
end
|
||||
ddown = math.floor(turtle.get_fuel_time()/2)-30
|
||||
if ddown>mem.ddown+30 then
|
||||
mem.ddown=ddown
|
||||
interrupt(0,"dig1")
|
||||
else
|
||||
turnright("checktree")
|
||||
end
|
||||
end
|
||||
elseif event.iid=="dig1" then
|
||||
if mem.pos.y==-mem.ddown then
|
||||
turtle.dig()
|
||||
forward("dig2")
|
||||
elseif mem.pos.y==DOWN then
|
||||
mem.mmove=(mem.ddown+DOWN)*2
|
||||
mem.spx=mem.spx-1
|
||||
mem.spy=mem.spy-1
|
||||
interrupt(0,"dig5")
|
||||
mem.sx=0
|
||||
mem.sy=0
|
||||
else
|
||||
turtle.digdown()
|
||||
down("dig1")
|
||||
end
|
||||
elseif event.iid=="dig2" then
|
||||
if mem.pos.y==-2 then
|
||||
back("dig3")
|
||||
else
|
||||
turtle.digup()
|
||||
up("dig2")
|
||||
end
|
||||
elseif event.iid=="dig3" then
|
||||
up("dig4")
|
||||
elseif event.iid=="dig4" then
|
||||
if mem.pos.y==0 then
|
||||
turnright("checktree")
|
||||
else
|
||||
turtle.digup()
|
||||
up("dig4")
|
||||
end
|
||||
elseif event.iid=="dig5" then
|
||||
mem.mmove=mem.mmove-1
|
||||
turtle.digup()
|
||||
turtle.digdown()
|
||||
if mem.mmove%100==0 then put_all("default:cobble") end
|
||||
if mem.sx==mem.spx then
|
||||
mem.spx=mem.spx+1
|
||||
turnleft("dig6")
|
||||
elseif mem.mmove<=0 and mem.sx==0 then
|
||||
if mem.sy==0 then
|
||||
gotoface("dig4",{x=0,y=0,z=-1})
|
||||
else
|
||||
turnleft("dig6")
|
||||
end
|
||||
else
|
||||
turtle.dig()
|
||||
mem.sx=mem.sx+1
|
||||
forward("dig5")
|
||||
end
|
||||
elseif event.iid=="dig6" then
|
||||
mem.mmove=mem.mmove-1
|
||||
turtle.digup()
|
||||
turtle.digdown()
|
||||
if mem.mmove%100==0 then put_all("default:cobble") end
|
||||
if mem.sy==mem.spy then
|
||||
mem.spy=mem.spy+1
|
||||
turnleft("dig7")
|
||||
elseif mem.mmove<=0 and mem.sy==0 then
|
||||
if mem.sx==0 then
|
||||
gotoface("dig4",{x=0,y=0,z=-1})
|
||||
else
|
||||
turnleft("dig7")
|
||||
end
|
||||
else
|
||||
turtle.dig()
|
||||
mem.sy=mem.sy+1
|
||||
forward("dig6")
|
||||
end
|
||||
elseif event.iid=="dig7" then
|
||||
mem.mmove=mem.mmove-1
|
||||
turtle.digup()
|
||||
turtle.digdown()
|
||||
if mem.mmove%100==0 then put_all("default:cobble") end
|
||||
if mem.sx==-mem.spx then
|
||||
turnleft("dig8")
|
||||
elseif mem.mmove<=0 and mem.sx==0 then
|
||||
if mem.sy==0 then
|
||||
gotoface("dig4",{x=0,y=0,z=-1})
|
||||
else
|
||||
turnleft("dig8")
|
||||
end
|
||||
else
|
||||
turtle.dig()
|
||||
mem.sx=mem.sx-1
|
||||
forward("dig7")
|
||||
end
|
||||
elseif event.iid=="dig8" then
|
||||
mem.mmove=mem.mmove-1
|
||||
turtle.digup()
|
||||
turtle.digdown()
|
||||
if mem.mmove%100==0 then put_all("default:cobble") end
|
||||
if mem.sy==-mem.spy then
|
||||
turnleft("dig5")
|
||||
elseif mem.mmove<=0 and mem.sy==0 then
|
||||
if mem.sx==0 then
|
||||
gotoface("dig4",{x=0,y=0,z=-1})
|
||||
else
|
||||
turnleft("dig5")
|
||||
end
|
||||
else
|
||||
turtle.dig()
|
||||
mem.sy=mem.sy-1
|
||||
forward("dig8")
|
||||
end
|
||||
elseif event.iid=="checktree" then
|
||||
put_all("default:cobble")
|
||||
local name=turtle.detect()
|
||||
if name=="default:tree" then
|
||||
mem.return_to="endchecktree"
|
||||
turtle.dig()
|
||||
forward("cuttree")
|
||||
elseif name=="air" then
|
||||
sapstack = find_stack("default:sapling")
|
||||
if sapstack==nil then
|
||||
s=find_stack("default:leaves")
|
||||
mem.leaves_stack=s
|
||||
turtle.place(s)
|
||||
mem.return_to="checktree"
|
||||
interrupt(0.1,"leaves_dig")
|
||||
else
|
||||
turtle.place(sapstack)
|
||||
interrupt(0, "checktree")
|
||||
end
|
||||
else
|
||||
turnleft("checktree2")
|
||||
end
|
||||
elseif event.iid=="endchecktree" then
|
||||
back("checktree")
|
||||
elseif event.iid=="checktree2" then
|
||||
local name=turtle.detect()
|
||||
if name=="default:tree" then
|
||||
mem.return_to="endchecktree2"
|
||||
turtle.dig()
|
||||
forward("cuttree")
|
||||
elseif name=="air" then
|
||||
sapstack = find_stack("default:sapling")
|
||||
if sapstack==nil then
|
||||
s=find_stack("default:leaves")
|
||||
mem.leaves_stack=s
|
||||
turtle.place(s)
|
||||
mem.return_to="checktree2"
|
||||
interrupt(0.1,"leaves_dig")
|
||||
else
|
||||
turtle.place(sapstack)
|
||||
interrupt(0, "checktree2")
|
||||
end
|
||||
else
|
||||
turnleft("checktree3")
|
||||
end
|
||||
elseif event.iid=="endchecktree2" then
|
||||
back("checktree2")
|
||||
elseif event.iid=="checktree3" then
|
||||
local name=turtle.detect()
|
||||
if name=="default:tree" then
|
||||
mem.return_to="endchecktree3"
|
||||
turtle.dig()
|
||||
forward("cuttree")
|
||||
elseif name=="air" then
|
||||
sapstack = find_stack("default:sapling")
|
||||
if sapstack==nil then
|
||||
s=find_stack("default:leaves")
|
||||
mem.leaves_stack=s
|
||||
turtle.place(s)
|
||||
mem.return_to="checktree3"
|
||||
interrupt(0.1,"leaves_dig")
|
||||
else
|
||||
turtle.place(sapstack)
|
||||
interrupt(0, "checktree3")
|
||||
end
|
||||
else
|
||||
turnright("dig")
|
||||
end
|
||||
elseif event.iid=="endchecktree3" then
|
||||
back("checktree3")
|
||||
elseif event.iid=="craft" then
|
||||
d=find_stack("default:diamond")
|
||||
turtle.drop(d)
|
||||
interrupt(5,"craft2")
|
||||
elseif event.iid=="craft2" then
|
||||
put_all_except("default:mese_crystal")
|
||||
m=find_stack("default:mese_crystal")
|
||||
turtle.moveto(m,16,99)
|
||||
turtle.moveto(16,1,4)
|
||||
turtle.moveto(16,2,4)
|
||||
turtle.moveto(16,3,4)
|
||||
turtle.moveto(16,5,3)
|
||||
turtle.moveto(16,6,3)
|
||||
turtle.moveto(16,7,3)
|
||||
turtle.moveto(16,9,3)
|
||||
turtle.moveto(16,10,3)
|
||||
turtle.moveto(16,11,3)
|
||||
turtle.dropup(16)
|
||||
turtle.craft(3)
|
||||
turtle.suck()
|
||||
turtle.drop(4)
|
||||
turtle.moveto(5,6,1)
|
||||
turtle.moveto(5,10,15)
|
||||
turtle.craft(1)
|
||||
turtle.dropup(10)
|
||||
turtle.moveto(1,2,1)
|
||||
interrupt(5,"craft3")
|
||||
elseif event.iid=="craft3" then
|
||||
turtle.suck()
|
||||
turtle.moveto(1,6,1)
|
||||
turtle.moveto(1,9,1)
|
||||
turtle.moveto(1,11,1)
|
||||
turtle.suck()
|
||||
turtle.moveto(1,3,1)
|
||||
turtle.moveto(1,5,1)
|
||||
turtle.moveto(1,7,1)
|
||||
turtle.moveto(1,10,1)
|
||||
turtle.craft(1)
|
||||
turtle.suckup()
|
||||
turtle.suckup()
|
||||
turtle.suckup()
|
||||
turtle.suckup()
|
||||
turtle.suckup()
|
||||
put_all_except()
|
||||
end
|
||||
end
|
4
progs/test.lua
Normal file
4
progs/test.lua
Normal file
@ -0,0 +1,4 @@
|
||||
while true do
|
||||
turtle.forward()
|
||||
delay(2)
|
||||
end
|
418
t.lua
Normal file
418
t.lua
Normal file
@ -0,0 +1,418 @@
|
||||
local MAX_LINE_LENGHT = 28
|
||||
|
||||
|
||||
local serialize_inv = function(l)
|
||||
local l2={}
|
||||
for _,i in pairs(l or {}) do
|
||||
l2[_]=i:to_table()
|
||||
end
|
||||
return l2
|
||||
end
|
||||
|
||||
local deserialize_inv = function(l)
|
||||
local l2={}
|
||||
for _,i in pairs(l or {}) do
|
||||
l2[_]=ItemStack(i)
|
||||
end
|
||||
return l2
|
||||
end
|
||||
|
||||
local wpath = minetest.get_worldpath()
|
||||
local function read_file(fn)
|
||||
local f = io.open(fn, "r")
|
||||
if f==nil then return {} end
|
||||
local t = f:read("*all")
|
||||
f:close()
|
||||
if t=="" or t==nil then return {} end
|
||||
return minetest.deserialize(t)
|
||||
end
|
||||
|
||||
local function write_file(fn, tbl)
|
||||
local f = io.open(fn, "w")
|
||||
f:write(minetest.serialize(tbl))
|
||||
f:close()
|
||||
end
|
||||
|
||||
local function newline(text, toadd)
|
||||
local f = lines(text)
|
||||
table.insert(f, toadd)
|
||||
return table.concat(f, "\n", 2)
|
||||
end
|
||||
|
||||
local function add_char(text, char)
|
||||
local ls = lines(text)
|
||||
local ll = ls[#ls]
|
||||
if char=="\n" or char=="\r" then
|
||||
return newline(text,"")
|
||||
elseif string.len(ll)>=MAX_LINE_LENGHT then
|
||||
return newline(text, char)
|
||||
else
|
||||
return text..char
|
||||
end
|
||||
end
|
||||
|
||||
local function add_text(text, toadd)
|
||||
for i=1, string.len(toadd) do
|
||||
text = add_char(text, string.sub(toadd, i, i))
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
turtle_infos = read_file(wpath.."/turtle_infos")
|
||||
floppies = read_file(wpath.."/floppies")
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
for turtle,i in pairs(turtle_infos) do
|
||||
i.turtle = nil
|
||||
i.playernames = nil
|
||||
i.inventory = serialize_inv(turtle_invs:get_list(turtle))
|
||||
i.floppy = serialize_inv(turtle_floppy:get_list(turtle))
|
||||
end
|
||||
write_file(wpath.."/turtle_infos",turtle_infos)
|
||||
write_file(wpath.."/floppies", floppies)
|
||||
end)
|
||||
|
||||
function get_turtle_info(turtle)
|
||||
if turtle_infos[turtle]==nil then turtle_infos[turtle]={} end
|
||||
return turtle_infos[turtle]
|
||||
end
|
||||
|
||||
local function get_turtle_id()
|
||||
i=0
|
||||
while true do
|
||||
if turtle_infos["turtle"..tostring(i)]==nil then return "turtle"..tostring(i) end
|
||||
i=i+1
|
||||
end
|
||||
end
|
||||
|
||||
local function get_floppy_id()
|
||||
return #floppies + 1
|
||||
end
|
||||
|
||||
local function round_pos(p)
|
||||
return {x=math.floor(p.x+0.5),
|
||||
y=math.floor(p.y+0.5),
|
||||
z=math.floor(p.z+0.5)}
|
||||
end
|
||||
|
||||
function lines(str)
|
||||
local t = {}
|
||||
local function helper(line) table.insert(t, line) return "" end
|
||||
helper((str:gsub("(.-)\r?\n", helper)))
|
||||
return t
|
||||
end
|
||||
|
||||
function escape(text)
|
||||
-- Remove all \0's in the string, that cannot be done using string.gsub as there can't be \0's in a pattern
|
||||
text2 = ""
|
||||
for i=1, string.len(text) do
|
||||
if string.byte(text, i)~=0 then text2 = text2..string.sub(text, i, i) end
|
||||
end
|
||||
return minetest.formspec_escape(text2)
|
||||
end
|
||||
|
||||
function create_text_formspec(text)
|
||||
local f = lines(text)
|
||||
s = ""
|
||||
i = -0.25
|
||||
for _,x in ipairs(f) do
|
||||
s = s.."]label[0,"..tostring(i)..";"..escape(x)
|
||||
i = i+0.3
|
||||
end
|
||||
s = s.."]field[0.3,"..tostring(i+0.4)..";4.4,1;f;;]"
|
||||
return s:sub(2, -1)
|
||||
--return "textarea[0.3,0;4.4,4.1;;"..escape(text)..";]field[0.3,3.6;4.4,1;f;;]"
|
||||
end
|
||||
|
||||
local update_formspec = function(turtle)
|
||||
local info = get_turtle_info(turtle)
|
||||
local formspec = "size[9,10]"..
|
||||
create_text_formspec(info.text)..
|
||||
"list[detached:turtle:invs;"..turtle..";4.8,0;4,4;]"..
|
||||
"image_button[1,4.6;2.5,1;turtle_execute.png;reboot;]"..
|
||||
"list[detached:turtle:floppy;"..turtle..";0,4.6;1,1;]"..
|
||||
"list[current_player;main;0.5,6;8,4;]"
|
||||
if info.formspec ~= formspec then
|
||||
info.formspec = formspec
|
||||
info.formspec_changed = true
|
||||
end
|
||||
end
|
||||
|
||||
local function on_screen_digiline_receive(turtle, channel, msg)
|
||||
if channel == "screen" then
|
||||
local info = get_turtle_info(turtle)
|
||||
info.text = add_text(info.text, msg)
|
||||
update_formspec(turtle)
|
||||
end
|
||||
end
|
||||
|
||||
local function handle_floppy_meta(stack)
|
||||
if stack.metadata == "" or stack.metadata == nil then
|
||||
local id = get_floppy_id()
|
||||
stack.metadata = tostring(id)
|
||||
floppies[stack.metadata] = string.rep(string.char(0), 16384)
|
||||
return floppies[id], true
|
||||
elseif string.len(stack.metadata) >= 1000 then
|
||||
local id = get_floppy_id()
|
||||
floppies[id] = stack.metadata
|
||||
stack.metadata = tostring(id)
|
||||
return floppies[id], true
|
||||
else
|
||||
return floppies[tonumber(stack.metadata)], false
|
||||
end
|
||||
end
|
||||
|
||||
local function set_floppy_contents(name, contents)
|
||||
floppies[tonumber(name)] = contents
|
||||
end
|
||||
|
||||
local on_disk_digiline_receive = function (turtle, 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 stack = turtle_floppy:get_stack(turtle, 1):to_table()
|
||||
if stack == nil then return end
|
||||
if stack.name ~= "turtle:floppy" then return end
|
||||
--if stack.metadata == "" then stack.metadata = string.rep(string.char(0), 16384) end
|
||||
local floppy_contents, update = handle_floppy_meta(stack)
|
||||
if update then
|
||||
turtle_floppy:set_stack(turtle, 1, ItemStack(stack))
|
||||
end
|
||||
msg = string.sub(msg, 2, -1)
|
||||
if string.len(msg) == 0 then -- read
|
||||
local ret = string.sub(floppy_contents, page*64+1, page*64+64)
|
||||
turtle_receptor_send(turtle, channel, ret)
|
||||
else -- write
|
||||
floppy_contents = string.sub(floppy_contents, 1, page*64)..msg..string.sub(floppy_contents, page*64+65, -1)
|
||||
--turtle_floppy:set_stack(turtle, 1, ItemStack(stack))
|
||||
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)
|
||||
--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)
|
||||
end
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname:sub(1,6) ~= "turtle" then return end
|
||||
if fields.f ~= nil and fields.f ~= "" then
|
||||
if string.len(fields.f) > 80 then
|
||||
fields.f = string.sub(fields.f, 1, 80)
|
||||
end
|
||||
turtle_receptor_send(formname, "screen", fields.f)
|
||||
update_formspec(formname)
|
||||
return
|
||||
end
|
||||
if fields.reboot then
|
||||
local info = get_turtle_info(formname)
|
||||
info.cptr = create_cptr()
|
||||
return
|
||||
end
|
||||
if fields.quit then
|
||||
local info = get_turtle_info(formname)
|
||||
info.playernames[player:get_player_name()] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_craftitem("turtle:turtle",{
|
||||
description = "Turtle",
|
||||
image = "turtle_turtle_inv.png",
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then return end
|
||||
local obj = minetest.add_entity(pointed_thing.above, "turtle:turtle")
|
||||
itemstack:take_item()
|
||||
--return itemstack
|
||||
end
|
||||
})
|
||||
|
||||
turtle_invs = minetest.create_detached_inventory("turtle:invs")
|
||||
turtle_floppy = minetest.create_detached_inventory("turtle:floppy")
|
||||
for turtle,i in pairs(turtle_infos) do
|
||||
turtle_invs:set_size(turtle, 16)
|
||||
for l,stack in pairs(deserialize_inv(i.inventory)) do
|
||||
turtle_invs:set_stack(turtle, l, stack)
|
||||
end
|
||||
turtle_floppy:set_size(turtle, 1)
|
||||
for l,stack in pairs(deserialize_inv(i.floppy)) do
|
||||
turtle_floppy:set_stack(turtle, l, stack)
|
||||
end
|
||||
end
|
||||
|
||||
local function dot(v1, v2)
|
||||
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z
|
||||
end
|
||||
|
||||
local function done_move(pos, spos, npos)
|
||||
local dir = vector.subtract(npos, spos)
|
||||
local move = vector.subtract(npos, pos)
|
||||
return dot(dir, move) <= 0
|
||||
end
|
||||
|
||||
local function done_rotation(yaw, nyaw, rotate_speed)
|
||||
return (nyaw - yaw + rotate_speed - math.pi/2)%(2*math.pi) < math.pi
|
||||
end
|
||||
|
||||
minetest.register_entity("turtle:turtle", {
|
||||
physical = true,
|
||||
force_load = TURTLES_FORCE_LOAD,
|
||||
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||
visual = "wielditem",
|
||||
visual_size = {x = 2/3, y = 2/3},
|
||||
textures = {"default:wood"},
|
||||
on_activate = function(self, staticdata)
|
||||
local info
|
||||
if staticdata == nil or staticdata == "" then
|
||||
self.n = get_turtle_id()
|
||||
info = get_turtle_info(self.n)
|
||||
turtle_invs:set_size(self.n, 16)
|
||||
turtle_floppy:set_size(self.n, 1)
|
||||
info.turtle = self
|
||||
info.spos = round_pos(self.object:getpos())
|
||||
info.dir = 0
|
||||
info.fuel = 0
|
||||
info.text = "\n\n\n\n\n\n\n\n\n\n"
|
||||
info.cptr = create_cptr()
|
||||
info.playernames = {}
|
||||
-- Build formspec
|
||||
update_formspec(self.n)
|
||||
else
|
||||
self.n = staticdata
|
||||
info = get_turtle_info(self.n)
|
||||
info.turtle = self
|
||||
info.playernames = {}
|
||||
end
|
||||
end,
|
||||
on_step = function(self, dtime)
|
||||
local info = get_turtle_info(self.n)
|
||||
if info.rotate then
|
||||
self.object:setyaw(self.object:getyaw()+info.rotate*dtime)
|
||||
end
|
||||
if info.moving then
|
||||
if info.npos ~= nil then
|
||||
local pos = self.object:getpos()
|
||||
local npos = info.npos
|
||||
local spos = info.spos
|
||||
if done_move(pos, spos, npos) then
|
||||
self.object:setpos(npos)
|
||||
self.object:setvelocity({x=0, y=0, z=0})
|
||||
info.spos = npos
|
||||
info.npos = nil
|
||||
info.moving = nil
|
||||
else
|
||||
self.object:setvelocity(vector.subtract(npos, spos))
|
||||
end
|
||||
elseif info.ndir ~= nil then
|
||||
local yaw = self.object:getyaw()
|
||||
local rotate_speed = info.rotate
|
||||
local nyaw = info.ndir*math.pi/2
|
||||
if done_rotation(yaw, nyaw, rotate_speed) then
|
||||
self.object:setyaw(nyaw)
|
||||
info.dir = info.ndir
|
||||
info.ndir = nil
|
||||
info.rotate = nil
|
||||
info.moving = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if not info.moving then
|
||||
run_computer(self.n, info.cptr)
|
||||
end
|
||||
if info.formspec_changed then
|
||||
for playername, _ in pairs(info.playernames) do
|
||||
print(info.text)
|
||||
print("------------------------------------")
|
||||
minetest.show_formspec(playername, self.n, info.formspec)
|
||||
end
|
||||
info.formspec_changed = nil
|
||||
end
|
||||
end,
|
||||
on_rightclick = function(self, clicker)
|
||||
local info = get_turtle_info(self.n)
|
||||
local name = clicker:get_player_name()
|
||||
info.playernames[name] = true
|
||||
minetest.show_formspec(name, self.n, info.formspec)
|
||||
end,
|
||||
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
|
||||
self.object:remove()
|
||||
minetest.add_item(turtle_infos[self.n].spos, "turtle:turtle")
|
||||
|
||||
for i=1,16 do
|
||||
local stack = turtle_invs:get_stack(self.n, i)
|
||||
minetest.add_item(turtle_infos[self.n].spos, stack)
|
||||
turtle_invs:set_stack(self.n, i, ItemStack(""))
|
||||
end
|
||||
|
||||
local stack = turtle_floppy:get_stack(self.n, 1)
|
||||
minetest.add_item(turtle_infos[self.n].spos, stack)
|
||||
turtle_floppy:set_stack(self.n, 1, ItemStack(""))
|
||||
|
||||
turtle_infos[self.n] = nil
|
||||
end,
|
||||
get_staticdata = function(self)
|
||||
return self.n
|
||||
end,
|
||||
})
|
1003
turtle-old.lua
Normal file
1003
turtle-old.lua
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,3 @@
|
||||
-- Turtle mod for Minetest
|
||||
-- License: LGPL
|
||||
|
||||
local FUEL_EFFICIENCY = 3 -- How many moves can the turtle do with a second fuel
|
||||
local TURTLES_FORCE_LOAD = true -- Useless for now, has to wait until force_load is merged
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user