Add digilines support.
This commit is contained in:
parent
b0dbd68921
commit
6e0aab6bb7
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
*~
|
*~
|
||||||
|
bit32.so
|
||||||
|
4
README
4
README
@ -1,3 +1,7 @@
|
|||||||
How to build
|
How to build
|
||||||
|
|
||||||
|
Linux:
|
||||||
gcc bit32.c -shared -fpic -I../../src/lua/src -o bit32.so
|
gcc bit32.c -shared -fpic -I../../src/lua/src -o bit32.so
|
||||||
|
|
||||||
|
Windows:
|
||||||
|
I don't know, sorry. I need someone to explain me that!
|
||||||
|
9004
computer_memory.lua
9004
computer_memory.lua
File diff suppressed because it is too large
Load Diff
1
depends.txt
Normal file
1
depends.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
digilines
|
21
f.py
21
f.py
@ -215,6 +215,27 @@ def compile_def(name, l, immed=False):
|
|||||||
elif word == "QUIT":
|
elif word == "QUIT":
|
||||||
squit.append(here)
|
squit.append(here)
|
||||||
here += 2
|
here += 2
|
||||||
|
elif word == 'S"':
|
||||||
|
nw = l[i][:-1] #Remove trailing "
|
||||||
|
i += 1
|
||||||
|
setmemory(here, df["(branch)"])
|
||||||
|
here += 2
|
||||||
|
stack.append(here)
|
||||||
|
here += 2
|
||||||
|
stack.append(here)
|
||||||
|
for c in nw:
|
||||||
|
memory[here] = ord(c)
|
||||||
|
here += 1
|
||||||
|
k = stack.pop()
|
||||||
|
setmemory(stack.pop(), here)
|
||||||
|
setmemory(here, df["(lit)"])
|
||||||
|
here += 2
|
||||||
|
setmemory(here, k)
|
||||||
|
here += 2
|
||||||
|
setmemory(here, df["(lit)"])
|
||||||
|
here += 2
|
||||||
|
setmemory(here, len(nw))
|
||||||
|
here += 2
|
||||||
else:
|
else:
|
||||||
setmemory(here, df[word])
|
setmemory(here, df[word])
|
||||||
here += 2
|
here += 2
|
||||||
|
10
forth.fth
10
forth.fth
@ -80,6 +80,9 @@ ASSEMBLER
|
|||||||
: WAIT 0x00 0x29 ;
|
: WAIT 0x00 0x29 ;
|
||||||
: WAIT-INPUT 0x50 0x29 ;
|
: WAIT-INPUT 0x50 0x29 ;
|
||||||
: LEAVE 0x11 0x11 0x11 0x1b 0x29 ;
|
: LEAVE 0x11 0x11 0x11 0x1b 0x29 ;
|
||||||
|
: RECEIVE-AT 0x33 0x32 0x30 0x52 0x20 0x29 ;
|
||||||
|
: SET-CHANNEL 0x32 0x31 0x54 0x29 ;
|
||||||
|
: SEND 0x32 0x31 0x53 0x29 ;
|
||||||
|
|
||||||
|
|
||||||
FORTH
|
FORTH
|
||||||
@ -106,6 +109,7 @@ FORTH
|
|||||||
: CELL- 2 - ;
|
: CELL- 2 - ;
|
||||||
: CHAR+ 1+ ;
|
: CHAR+ 1+ ;
|
||||||
: CELLS 2* ;
|
: CELLS 2* ;
|
||||||
|
: RECEIVE 0x80 RECEIVE-AT ;
|
||||||
: 2! SWAP OVER ! CELL+ ! ;
|
: 2! SWAP OVER ! CELL+ ! ;
|
||||||
: 2@ DUP CELL+ @ SWAP @ ;
|
: 2@ DUP CELL+ @ SWAP @ ;
|
||||||
: SOURCE (source) 2@ ;
|
: SOURCE (source) 2@ ;
|
||||||
@ -119,7 +123,7 @@ FORTH
|
|||||||
: NIP SWAP DROP ;
|
: NIP SWAP DROP ;
|
||||||
: ABS DUP 0< IF NEGATE THEN ;
|
: ABS DUP 0< IF NEGATE THEN ;
|
||||||
: (marker) LATEST ! (here) ! ;
|
: (marker) LATEST ! (here) ! ;
|
||||||
: TYPE DUP 0> IF OVER + SWAP DO I C@ EMIT LOOP ELSE 2DROP THEN ;
|
: TYPE DUP 0> IF OVER + SWAP ?DO I C@ EMIT LOOP ELSE 2DROP THEN ;
|
||||||
: RSTR 1+ DUP 2 + C@ 127 AND TUCK - SWAP ;
|
: RSTR 1+ DUP 2 + C@ 127 AND TUCK - SWAP ;
|
||||||
: CR 10 EMIT ;
|
: CR 10 EMIT ;
|
||||||
: SPACE 32 EMIT ;
|
: SPACE 32 EMIT ;
|
||||||
@ -218,7 +222,7 @@ FORTH
|
|||||||
: ?DO ['] (?do) , HERE 0 , HERE ; IMMEDIATE
|
: ?DO ['] (?do) , HERE 0 , HERE ; IMMEDIATE
|
||||||
: LOOP ['] (loop) , , HERE SWAP ! ; IMMEDIATE
|
: LOOP ['] (loop) , , HERE SWAP ! ; IMMEDIATE
|
||||||
: +LOOP ['] (+loop) , , HERE SWAP ! ; IMMEDIATE
|
: +LOOP ['] (+loop) , , HERE SWAP ! ; IMMEDIATE
|
||||||
: ACCEPT WAIT-INPUT 0 @ MIN 16 -ROT MOVE ;
|
: ACCEPT WAIT-INPUT 0 @ MIN TUCK 16 -ROT MOVE ;
|
||||||
: EXPECT ACCEPT SPAN ! ;
|
: EXPECT ACCEPT SPAN ! ;
|
||||||
: QUERY 0 >IN ! 0 SOURCE-ID ! TIB DUP 80 ACCEPT SPACE (source) 2! ;
|
: 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 ;
|
: REFILL SOURCE-ID @ IF FALSE ELSE 0 >IN ! TIB DUP 80 ACCEPT SPACE (source) 2! TRUE THEN ;
|
||||||
@ -230,4 +234,6 @@ FORTH
|
|||||||
: DABS DUP 0< IF OVER NEGATE ROT IF SWAP INVERT ELSE SWAP NEGATE THEN THEN ;
|
: 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 ;
|
: 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 ;
|
\ : 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 ;
|
||||||
: COLD 82 EMIT 101 EMIT 97 EMIT 100 EMIT 121 EMIT QUIT ;
|
: COLD 82 EMIT 101 EMIT 97 EMIT 100 EMIT 121 EMIT QUIT ;
|
||||||
|
141
init.lua
141
init.lua
@ -1,5 +1,6 @@
|
|||||||
CYCLES_PER_STEP = 1000
|
local CYCLES_PER_STEP = 1000
|
||||||
MAX_CYCLES = 100000
|
local MAX_CYCLES = 100000
|
||||||
|
local MAX_LINE_LENGHT = 42
|
||||||
|
|
||||||
local modpath = minetest.get_modpath("forth_computer")
|
local modpath = minetest.get_modpath("forth_computer")
|
||||||
package.cpath = modpath.."/?.so;"..modpath.."/?.dll;"..package.cpath;
|
package.cpath = modpath.."/?.so;"..modpath.."/?.dll;"..package.cpath;
|
||||||
@ -37,6 +38,15 @@ function lines(str)
|
|||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function hashpos(pos)
|
||||||
|
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
|
||||||
|
|
||||||
function newline(text, toadd)
|
function newline(text, toadd)
|
||||||
local f = lines(text)
|
local f = lines(text)
|
||||||
table.insert(f, toadd)
|
table.insert(f, toadd)
|
||||||
@ -90,7 +100,7 @@ local function emit(pos, c, cptr)
|
|||||||
local ll = ls[#ls]
|
local ll = ls[#ls]
|
||||||
if s=="\n" or s=="\r" then
|
if s=="\n" or s=="\r" then
|
||||||
meta:set_string("text", newline(text,""))
|
meta:set_string("text", newline(text,""))
|
||||||
elseif string.len(ll)>=52 then
|
elseif string.len(ll)>=MAX_LINE_LENGHT then
|
||||||
meta:set_string("text", newline(text, s))
|
meta:set_string("text", newline(text, s))
|
||||||
else
|
else
|
||||||
meta:set_string("text", text..s)
|
meta:set_string("text", text..s)
|
||||||
@ -98,14 +108,52 @@ local function emit(pos, c, cptr)
|
|||||||
cptr.fmodif = true
|
cptr.fmodif = true
|
||||||
end
|
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 = 0
|
||||||
|
end
|
||||||
|
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 function run_computer(pos,cptr)
|
||||||
cptr.cycles = math.max(MAX_CYCLES,cptr.cycles+CYCLES_PER_STEP)
|
cptr.cycles = math.max(MAX_CYCLES,cptr.cycles+CYCLES_PER_STEP)
|
||||||
while 1 do
|
while 1 do
|
||||||
instr = cptr[cptr.PC]
|
instr = cptr[cptr.PC]
|
||||||
|
local f = ITABLE[instr]
|
||||||
|
if f == nil then return end
|
||||||
--print("Instr: "..tostring(instr).." PC: "..tostring(cptr.PC).." SP: "..tostring(cptr.SP).." RP: "..tostring(cptr.RP).." X: "..tostring(cptr.X).." Y: "..tostring(cptr.Y).." Z: "..tostring(cptr.Z).." I: "..tostring(cptr.I))
|
--print("Instr: "..tostring(instr).." PC: "..tostring(cptr.PC).." SP: "..tostring(cptr.SP).." RP: "..tostring(cptr.RP).." X: "..tostring(cptr.X).." Y: "..tostring(cptr.Y).." Z: "..tostring(cptr.Z).." I: "..tostring(cptr.I))
|
||||||
cptr.PC = bit32.band(cptr.PC+1, 0xffff)
|
cptr.PC = bit32.band(cptr.PC+1, 0xffff)
|
||||||
local f = ITABLE[instr]
|
setfenv(f, {cptr = cptr, pos=pos, emit=emit, receive=receive, 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})
|
||||||
setfenv(f, {cptr = cptr, pos=pos, emit=emit, 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()
|
f()
|
||||||
cptr.cycles = cptr.cycles - 1
|
cptr.cycles = cptr.cycles - 1
|
||||||
if cptr.paused or cptr.cycles == 0 then
|
if cptr.paused or cptr.cycles == 0 then
|
||||||
@ -126,6 +174,8 @@ local function create_cptr()
|
|||||||
cptr.SP = 0x200
|
cptr.SP = 0x200
|
||||||
cptr.paused = false
|
cptr.paused = false
|
||||||
cptr.has_input = false
|
cptr.has_input = false
|
||||||
|
cptr.digiline_events = {}
|
||||||
|
cptr.channel = ""
|
||||||
cptr.cycles = 0
|
cptr.cycles = 0
|
||||||
return cptr
|
return cptr
|
||||||
end
|
end
|
||||||
@ -222,10 +272,46 @@ ITABLE_RAW = {
|
|||||||
|
|
||||||
[0x50] = "if cptr.has_input then\ncptr.has_input = false\nelse\ncptr.paused = true\ncptr.PC = u16(cptr.PC-1)\nend",
|
[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)",
|
[0x51] = "emit(pos, cptr.X, cptr)",
|
||||||
|
[0x52] = "receive(cptr, cptr.X, cptr.Y, cptr.Z)", -- Digiline receive
|
||||||
|
[0x53] = "send_message(pos, cptr, cptr.X, cptr.Y)", -- Digiline send
|
||||||
|
[0x54] = "set_channel(cptr, cptr.X, cptr.Y)", -- Digiline set channel
|
||||||
}
|
}
|
||||||
|
|
||||||
ITABLE = {}
|
ITABLE = {}
|
||||||
|
|
||||||
|
local formspec_close_table = {}
|
||||||
|
local function on_formspec_close(name, func)
|
||||||
|
formspec_close_table[name] = {func=func}
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
for name, t in pairs(formspec_close_table) do
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if player == nil then
|
||||||
|
t.func()
|
||||||
|
formspec_close_table[name] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local pitch = player:get_look_pitch()
|
||||||
|
local yaw = player:get_look_yaw()
|
||||||
|
local pos = player:getpos()
|
||||||
|
if t.pitch ~= nil then
|
||||||
|
if pitch~=t.pitch or yaw~=t.yaw or pos.x~=t.x or pos.y~=t.y or pos.z~=t.z then
|
||||||
|
t.func()
|
||||||
|
formspec_close_table[name] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
t.pitch = pitch
|
||||||
|
t.yaw = yaw
|
||||||
|
t.x = pos.x
|
||||||
|
t.y = pos.y
|
||||||
|
t.z = pos.z
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
for i, v in pairs(ITABLE_RAW) do
|
for i, v in pairs(ITABLE_RAW) do
|
||||||
ITABLE[i] = loadstring(v)
|
ITABLE[i] = loadstring(v)
|
||||||
end
|
end
|
||||||
@ -248,24 +334,42 @@ end
|
|||||||
|
|
||||||
local cptrs = read_file(wpath.."/forth_computers")
|
local cptrs = read_file(wpath.."/forth_computers")
|
||||||
|
|
||||||
|
local on_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",{
|
minetest.register_node("forth_computer:computer",{
|
||||||
description = "Computer",
|
description = "Computer",
|
||||||
tiles = {"computer.png"},
|
tiles = {"computer.png"},
|
||||||
groups = {cracky=3},
|
groups = {cracky=3},
|
||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
|
digiline =
|
||||||
|
{
|
||||||
|
receptor = {},
|
||||||
|
effector = {action = on_digiline_receive},
|
||||||
|
},
|
||||||
on_construct = function(pos)
|
on_construct = function(pos)
|
||||||
local meta=minetest.get_meta(pos)
|
local meta=minetest.get_meta(pos)
|
||||||
meta:set_string("text","\n\n\n\n\n\n\n\n\n\n")
|
meta:set_string("text","\n\n\n\n\n\n\n\n\n\n")
|
||||||
cptrs[minetest.serialize(pos)] = {pos=pos, cptr=create_cptr(), fmodif=false}
|
cptrs[hashpos(pos)] = {pos=pos, cptr=create_cptr(), fmodif=false}
|
||||||
end,
|
end,
|
||||||
on_destruct = function(pos)
|
on_destruct = function(pos)
|
||||||
cptrs[minetest.serialize(pos)] = nil
|
cptrs[hashpos(pos)] = nil
|
||||||
end,
|
end,
|
||||||
on_rightclick = function(pos, node, clicker)
|
on_rightclick = function(pos, node, clicker)
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
local name = clicker:get_player_name()
|
local name = clicker:get_player_name()
|
||||||
cptrs[minetest.serialize(pos)].cptr.pname = name
|
if cptrs[hashpos(pos)] == nil then
|
||||||
minetest.show_formspec(name,"computer"..minetest.serialize(pos),create_formspec(meta:get_string("text")))
|
cptrs[hashpos(pos)] = {pos=pos, cptr=create_cptr(), fmodif=false}
|
||||||
|
end
|
||||||
|
cptrs[hashpos(pos)].cptr.pname = name
|
||||||
|
on_formspec_close(name, function()
|
||||||
|
local c = cptrs[hashpos(pos)]
|
||||||
|
if c~= nil then c.cptr.pname = nil end
|
||||||
|
end)
|
||||||
|
minetest.show_formspec(name,"computer"..hashpos(pos),create_formspec(meta:get_string("text")))
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -276,7 +380,7 @@ minetest.register_globalstep(function(dtime)
|
|||||||
i.cptr.fmodif=false
|
i.cptr.fmodif=false
|
||||||
if i.cptr.pname~=nil then
|
if i.cptr.pname~=nil then
|
||||||
local meta = minetest.get_meta(i.pos)
|
local meta = minetest.get_meta(i.pos)
|
||||||
minetest.show_formspec(i.cptr.pname,"computer"..minetest.serialize(i.pos),create_formspec(meta:get_string("text")))
|
minetest.show_formspec(i.cptr.pname,"computer"..hashpos(i.pos),create_formspec(meta:get_string("text")))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -290,12 +394,16 @@ minetest.register_on_shutdown(function()
|
|||||||
write_file(wpath.."/forth_computers",cptrs)
|
write_file(wpath.."/forth_computers",cptrs)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
function escape(x)
|
||||||
|
return string.gsub(string.gsub(string.gsub(x,";","\\;"), "%]", "\\]"), "%[", "\\[")
|
||||||
|
end
|
||||||
|
|
||||||
function create_formspec(text)
|
function create_formspec(text)
|
||||||
local f = lines(text)
|
local f = lines(text)
|
||||||
s = "size[5,4.5;"
|
s = "size[5,4.5;"
|
||||||
i = -0.25
|
i = -0.25
|
||||||
for _,x in ipairs(f) do
|
for _,x in ipairs(f) do
|
||||||
s = s.."]label[0,"..tostring(i)..";"..minetest.formspec_escape(x)
|
s = s.."]label[0,"..tostring(i)..";"..escape(x)--minetest.formspec_escape(x)
|
||||||
i = i+0.3
|
i = i+0.3
|
||||||
end
|
end
|
||||||
s = s.."]field[0.3,"..tostring(i+0.4)..";4.4,1;f;;]"
|
s = s.."]field[0.3,"..tostring(i+0.4)..";4.4,1;f;;]"
|
||||||
@ -305,20 +413,21 @@ end
|
|||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
if formname:sub(1,8)~="computer" then return end
|
if formname:sub(1,8)~="computer" then return end
|
||||||
if fields["f"]==nil or fields["f"]=="" then return end
|
if fields["f"]==nil or fields["f"]=="" then return end
|
||||||
local pos = minetest.deserialize(formname:sub(9,-1))
|
local pos = dehashpos(formname:sub(9,-1))
|
||||||
local c = cptrs[minetest.serialize(pos)]
|
local c = cptrs[hashpos(pos)]
|
||||||
if c==nil then return end
|
if c==nil then return end
|
||||||
local cptr=c.cptr
|
local cptr=c.cptr
|
||||||
cptr.has_input = true
|
cptr.has_input = true
|
||||||
if string.len(fields["f"])>52 then
|
if string.len(fields["f"])>MAX_LINE_LENGHT then
|
||||||
fields["f"] = string.sub(fields["f"],1,52)
|
fields["f"] = string.sub(fields["f"],1,MAX_LINE_LENGHT)
|
||||||
end
|
end
|
||||||
for i=1,string.len(fields["f"]) do
|
for i=1,string.len(fields["f"]) do
|
||||||
cptr[15+i] = string.byte(fields["f"],i)
|
cptr[15+i] = string.byte(fields["f"],i)
|
||||||
end
|
end
|
||||||
write(cptr, 0, string.len(fields["f"]))
|
write(cptr, 0, string.len(fields["f"]))
|
||||||
local meta = minetest.get_meta(pos)
|
local meta = minetest.get_meta(pos)
|
||||||
local ntext = newline(meta:get_string("text"),fields["f"])
|
--local ntext = newline(meta:get_string("text"),fields["f"])
|
||||||
|
local ntext = meta:get_string("text")..fields["f"]
|
||||||
meta:set_string("text",ntext)
|
meta:set_string("text",ntext)
|
||||||
minetest.show_formspec(player:get_player_name(),formname,create_formspec(ntext))
|
minetest.show_formspec(player:get_player_name(),formname,create_formspec(ntext))
|
||||||
end)
|
end)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user