diff --git a/.gitignore b/.gitignore index 3847865..0bd19f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ test.lua +*.ogg diff --git a/DMS.xml b/DMS.xml index 651e031..ac2db17 100644 --- a/DMS.xml +++ b/DMS.xml @@ -24,10 +24,10 @@ /* */ - ENABLE DISABLE LOAD ENTRY USING VERSION as + ENABLE DISABLE LOADFILE ENTRY USING VERSION as if then return and or True False for while - leaking debugging warnings - ceil tan CSIM log10 sinh GOTOE lshift deg MUL QUIT cosh exp rad GOTO SUB log ADD JUMP error POW randomseed floor tanh max atan SKIP acos DIV abs rshif COMPARE print atan2 asin cos sin mod sqrt function getInput sleep getVar setVar newThread setGlobalVar getGlobalVar + leaking debugging warnings statesave hostmsg + ceil tan CSIM log10 sinh GOTOE lshift deg MUL QUIT cosh exp rad GOTO SUB log ADD JUMP error POW randomseed floor tanh max atan SKIP acos DIV abs rshif COMPARE print atan2 asin cos sin mod sqrt function getInput sleep getVar setVar newThread setGlobalVar getGlobalVar SAVE LOAD WATCH _VERSION filesystem extendedDefine diff --git a/Story/bedroom.dms b/Story/bedroom.dms new file mode 100644 index 0000000..966062d --- /dev/null +++ b/Story/bedroom.dms @@ -0,0 +1,3 @@ +[BEDROOM]{ + +} \ No newline at end of file diff --git a/parseManager/audio.lua b/parseManager/audio.lua new file mode 100644 index 0000000..1b4ef06 --- /dev/null +++ b/parseManager/audio.lua @@ -0,0 +1,29 @@ +require("proAudioRt") +proAudio.create() +local audio = {} +audio.__index = audio +function audio:new(path) + local c = {} + c.path = path + c.handle = proAudio.sampleFromFile(path) + setmetatable(c,audio) + return c +end +function audio:play(volume,loop) + local volume = volume or 1 + if loop then + proAudio.soundLoop(self.handle, volume, volume, 0, 1) + else + proAudio.soundPlay(self.handle, volume, volume, 0, 1) + end +end +function audio:stop() + if not self then proAudio.soundStop() return end + proAudio.soundStop(self.handle) +end +function audio:setVolume(volume) + proAudio.soundUpdate(self.handle,volume,volume) +end +function parseManager:audio() + return audio +end \ No newline at end of file diff --git a/parseManager/extendedDefine.lua b/parseManager/extendedDefine.lua index be4a456..2396000 100644 --- a/parseManager/extendedDefine.lua +++ b/parseManager/extendedDefine.lua @@ -1,4 +1,4 @@ -local multi,bin,GLOBAL,sThread +local multi, bin, GLOBAL,sThread local loaded, err = pcall(function() multi = require("multi") local plat = multi:getPlatform() @@ -7,18 +7,17 @@ local loaded, err = pcall(function() elseif plat == "love2d" then GLOBAL, sThread = require("multi.integration.loveManager").init() end - GLOBAL["TEST"]=true bin = require("bin") end) function parseManager:extendedDefine() if not loaded then self:pushWarning("Could not load the extendedDefine module!") print(err) end local tc = 1 + self.mainENV=GLOBAL + self.currentENV=GLOBAL self:define{ - setVar = function(self,name,val) - GLOBAL[name]=val - end, - getVar = function(self,name) - return sThread.waitFor(name) + WATCH=function(self,...) + if self.watchvars then return end + self.watchvars = {...} end, newThread = function(self,block,name) multi:newSystemThread(name or "NewThread"..tc,function(blck,path,name) @@ -30,22 +29,18 @@ function parseManager:extendedDefine() sThread=_G.sThread end local test=parseManager:load(path) - t=test:next(blck) + test.mainENV = GLOBAL + test.currentENV = GLOBAL test:define{ sleep = function(self,n) thread.sleep(n) end, - setVar = function(self,name,val) - GLOBAL[name]=val - end, - getVar = function(self,name) - return sThread.waitFor(name) - end, - test = function(self,text) - os.execute("title "..text.."") + title = function(self,t) + os.execute("title "..t) end } - multi:newThread("Runner",function() + t=test:next(blck) + multi:newThread(name,function() while true do thread.skip(0) if not t then error("Thread ended!") end @@ -78,7 +73,9 @@ function parseManager:extendedDefine() multi:mainloop() end,block,self.currentChunk.path,name or "NewThread"..tc) tc=tc+1 - end, } end +multi.OnError(function(...) + print(...) +end) diff --git a/parseManager/init.lua b/parseManager/init.lua index 8fccf2e..fc40f97 100644 --- a/parseManager/init.lua +++ b/parseManager/init.lua @@ -1,3 +1,10 @@ +_print = print +local noprint +function print(...) + if not noprint then + _print(...) + end +end require("bin") parseManager={} parseManager.VERSION = 5 @@ -33,9 +40,9 @@ function parseManager:mainRunner(block) elseif t.Type=="method" then t=self:next() elseif t.Type=="choice" then - print(t.text) + _print(t.text) for i=1,#t.choices do - print(i..". "..t.choices[i]) + _print(i..". "..t.choices[i]) end io.write("Choose#: ") cm=tonumber(io.read()) @@ -99,9 +106,15 @@ function factorial(n) end end function parseManager:ENABLE(fn) + if fn == "hostmsg" then + noprint = false + end self.stats[string.lower(fn)]=true end function parseManager:DISABLE(fn) + if fn == "hostmsg" then + noprint = true + end self.stats[string.lower(fn)]=false end function parseManager:USING(fn,name) @@ -168,6 +181,9 @@ function parseManager:load(path,c) c = {} setmetatable(c,parseManager) end + if not c.path then + c.path = path + end local file if type(path)=="table" then if path.Type=="bin" then @@ -203,7 +219,7 @@ function parseManager:load(path,c) self:debug("E",fn) c:ENABLE(fn) end - for fn in header:gmatch("LOAD (.-)\n") do + for fn in header:gmatch("LOADFILE (.-)\n") do self:debug("L",fn) c:load(fn,c) end @@ -412,6 +428,7 @@ function parseManager:dump() return str end function table.print(tbl, indent) + if type(tbl)~="table" then return end if not indent then indent = 0 end for k, v in pairs(tbl) do formatting = string.rep(' ', indent) .. k .. ': ' @@ -469,7 +486,6 @@ local function pieceList(list,self,name) else local sym = getSymbol("`") self:compileFWR("__PUSHPARSE",sym,'"$'..list[i]..'$"',name) - cc=cc+1 L[#L+1]="\1"..sym end elseif list[i]:sub(1,1)=="\"" and list[i]:sub(-1,-1)=="\"" then @@ -871,18 +887,32 @@ end local function trim1(s) return (s:gsub("^%s*(.-)%s*$", "%1")) end +local function extract(dat,name) + if type(dat)=="string" and dat:sub(1,1)=="\1" then + return dat:sub(2,-1) + elseif tonumber(dat)~=nil then + return tonumber(dat) + else + return dat + end +end function parseManager:compile(name,ctype,data) local isFBlock,FBArgs=ctype:match("(f)unction%((.*)%)") --Check if we are dealing with a FBlock if isFBlock=="f" then + if not self.isInternal then + self.isInternal = {} + end self.cFuncs[name]=true -- if self.methods[name] then -- self:pushError("You cannot create a method with the same name as a standard method or duplicate method names!",name) -- end self.methods[name]=function(...) - self:Invoke(name,...) + --self:Invoke(name,...) + return self:Call(name,...) end - self.__INTERNAL[name] = true + self.isInternal[name]=self.methods[name] + -- self.__INTERNAL[name] = true -- if not self.variables.__internal then -- self.variables.__internal = {} -- end @@ -902,10 +932,10 @@ function parseManager:compile(name,ctype,data) for i=1,#data do data[i]=trim1(data[i]) if data[i]~="" then - if data[i]:match("for[%s%w=%-]-[%d%-,%s]-<") then + if data[i]:match("for[%s%w=%-]-[%d%-%w%(%),%s]-<") then choiceBlockFor=true local sym = getSymbol("FOR") - local var,a,b,c = data[i]:match("for%s*([%w_]+)%s*=%s*(%-*[%d]+),%s*(%-*[%d]+)%s*,*%s*(%-*[%d]*)") + local var,a,b,c = data[i]:match("for%s*([%w_]+)%s*=%s*(%-*[%d%w%(%)]+),%s*(%-*[%d%w%(%)]+)%s*,*%s*(%-*[%d%w%(%)]*)") local s = getSymbol(getSymbol("LOOPEND")) push(stack,{sym,var,a,b,s,1,c}) -- 1 for loop, 2 while loop data[i] = "::"..sym.."::" @@ -930,7 +960,12 @@ function parseManager:compile(name,ctype,data) local s = dat[5] local cmd = dat[6] if cmd==1 then - self:compileAssign(dat[2],dat[2] .. (tonumber(dat[7]) or "+1"),name) + local t = extract(dat[7],name) + if type(t)=="string" then + t="+"..t + end + -- print(dat[2] .. (t or "+1")) + self:compileAssign(dat[2],dat[2] .. (t or "+1"),name) self:compileCondition(dat[2].."=="..tonumber(dat[4])+(tonumber(dat[7]) or 1),"GOTO(\""..s.."\")","GOTO(\""..dat[1].."\")",name) data[i] = "::"..s.."::" elseif cmd == 2 then @@ -1050,6 +1085,15 @@ function parseManager:testDict(dict) return end end +function parseManager:dataToEnv(values) + local env = {} + if values then + for i,v in pairs(values) do + env[#env+1] = test:dataToValue(v) + end + end + return env +end function parseManager:dataToValue(name,envF,b) -- includes \1\ envF=envF or self.currentENV local tab=name @@ -1076,7 +1120,11 @@ function parseManager:dataToValue(name,envF,b) -- includes \1\ end end end - return tab or {} + if tab~= nil then + return tab + else + return {} + end end function parseManager:define(t) for i,v in pairs(t) do @@ -1086,80 +1134,6 @@ end function parseManager:handleChoice(func) self.choiceManager = func end -function parseManager:Invoke(func,vars,...) - if not self.isrunning then - self.isrunning = true - local t=self:next() - local name=func - local func=self.chunks[func] - if func then - if func.type:sub(1,1)=="f" then - local returndata={} - self.fArgs={...} - if #self.fArgs==0 then - self.fArgs={self.lastCall} - end - push(self.stack,{chunk=self.currentChunk,pos=self.currentChunk.pos,env=self.currentENV,vars=vars}) - self.currentENV = self:newENV() - self.methods.JUMP(self,name) - -- return - else - self:pushError("Attempt to call a non function block!",name) - end - else - self:pushError("Attempt to call a non existing function!",name) - end - while t do - if t.Type=="text" then - io.write(t.text) - io.read() - t=self:next() - elseif t.Type=="condition" then - t=self:next() - elseif t.Type=="assignment" then - t=self:next() - elseif t.Type=="label" then - t=self:next() - elseif t.Type=="method" then - t=self:next() - elseif t.Type=="choice" then - if self.choiceManager then - t=self:choiceManager(t) - else - t=self:next(nil,math.random(1,#t[1])) - end - elseif t.Type=="end" then - if t.text=="leaking" then - t=self:next() - end - elseif t.Type=="error" then - error(t.text) - else - t=self:next() - end - end - return - end - local name=func - local func=self.chunks[func] - if func then - if func.type:sub(1,1)=="f" then - local returndata={} - self.fArgs={...} - if #self.fArgs==0 then - self.fArgs={self.lastCall} - end - push(self.stack,{chunk=self.currentChunk,pos=self.currentChunk.pos,env=self.currentENV,vars=vars}) - self.currentENV = self:newENV() - self.methods.JUMP(self,name) - return - else - self:pushError("Attempt to call a non function block!",name) - end - else - self:pushError("Attempt to call a non existing function!",name) - end -end function round(num, numDecimalPlaces) local mult = 10^(numDecimalPlaces or 0) return math.floor(num * mult + 0.5) / mult @@ -1370,51 +1344,30 @@ function parseManager:next(block,choice) self.lastCall=nil return {Type="text",text=self:parseHeader(data.text)} elseif data.Type=="funcblock" then - local env=self.currentENV - self.currentENV=self:newENV() - self:pairAssign(data.args,self.fArgs,env) + -- self:pairAssign(data.args,self.fArgs) return {Type="FBLOCK"} elseif data.Type=="return" then - local obj=pop(self.stack) - local chunk=obj.chunk - local pos=obj.pos - local env=obj.env - local vars=obj.vars - local name=chunk.name - local env=self.currentENV - chunk.pos=pos - self.currentENV=env - self:pairAssign(vars,data.RETArgs,env) - self.currentChunk=chunk - return {Type="method"} + return {Type="method",Vars = vars, RetArgs = data.RETArgs} elseif data.Type=="fwr" then local args=self:dataToValue(data.args,nil,data.Func == "__PUSHPARSE") local rets={} local Func - local Ext=false if type(data.Func)=="table" then Ext=true Func=self.currentENV[data.Func[1]][data.Func[2]] else Func=self.methods[data.Func] end - if Ext then + if self.isInternal[data.Func] then rets={Func(unpack(args))} - elseif self.__INTERNAL[data.Func] then - self:Invoke(data.Func,data.vars,unpack(args)) else - if type(Func)~="function" then - rets={self:Invoke(data.Func,data.vars,unpack(args))} - return {Type="method"} - else - rets={Func(self,unpack(args))} - end + rets={Func(self,unpack(args))} end if #rets~=0 then self:pairAssign(data.vars,rets) end self.lastCall=nil - return {Type="method"} + return {Type="method",name=data.Func,args = args} elseif data.Type=="fwor" then local args=self:dataToValue(data.args) local Func @@ -1428,14 +1381,9 @@ function parseManager:next(block,choice) if Ext then self.lastCall=Func(unpack(args)) else - if type(Func)~="function" then - self.lastCall=self:Invoke(data.Func,"lastCall",unpack(args)) - return {Type="method"} - else - self.lastCall=Func(self,unpack(args)) - end + self.lastCall=Func(self,unpack(args)) end - return {Type="method"} + return {Type="method",name=data.Func,args = args} elseif data.Type=="choice" then self.choiceData=data local CList={} diff --git a/parseManager/standardDefine.lua b/parseManager/standardDefine.lua index d6f09b8..cc1438f 100644 --- a/parseManager/standardDefine.lua +++ b/parseManager/standardDefine.lua @@ -1,3 +1,4 @@ +local bin = require("bin") local clock = os.clock parseManager:define{ __PUSHPARSE = function(self,dat) @@ -10,7 +11,39 @@ parseManager:define{ return io.read() end, print=function(self,...) - print(...) + _print(...) + end, + WATCH=function(self,...) + if self.watchvars then return end + self.watchvars = {...} + end, + SAVE=function(self,fn) + local file = bin.new() + local data = {} + for i=1,#self.watchvars do + data[self.watchvars[i]] = self.currentENV[self.watchvars[i]] + end + data["__CHUNK"] = self.methods.getCurrentChunk(self) + data["__POSITION"] = self.methods.getCurrentPosition(self) + file:addBlock(data) + file:tofile(fn or "save.dat") + end, + LOAD=function(self,fn) + if not bin.fileExists(fn or "save.dat") then return false end + local file = bin.load(fn or "save.dat") + t = file:getBlock("t") + local c,p = t.__CHUNK,t.__POSITION + t.__CHUNK,t.__POSITION = nil,nil + for i,v in pairs(t) do + self.mainENV[i] = v + end + if self.stats.statesave then + self.methods.JUMP(self,c, p) + end + return true,c,p + end, + EXECUTE = function(self,cmd) + os.execute(cmd) end, error=function(self,msg) self:pushError(msg,"\2") @@ -21,16 +54,29 @@ parseManager:define{ getGlobalVar=function(self,var,val) self.mainENV[var]=val end, + len=function(self,t) + return #t + end, QUIT=function() os.exit() end, + getCurrentChunk = function(self) + for i,v in pairs(self.chunks) do + if self.currentChunk == v then + return i + end + end + end, + getCurrentPosition = function(self) + return self.currentChunk.pos-1 + end, sleep=function(self,n) local t0 = clock() while clock() - t0 <= n do end end, - JUMP=function(self,block) + JUMP=function(self,block,pos) if self.chunks[block] then - self.chunks[block].pos=1 + self.chunks[block].pos=pos or 1 self.currentChunk=self.chunks[block] else self:pushError("Attempt to jump to a non existing block:","\2") @@ -342,7 +388,4 @@ parseManager:define{ self.methods.SKIP(self,1) end end, - print=function(self,...) - print(...) - end } diff --git a/proAudioRt.dll b/proAudioRt.dll new file mode 100644 index 0000000..f24fcb9 Binary files /dev/null and b/proAudioRt.dll differ diff --git a/rps.dmsc b/rps.dmsc new file mode 100644 index 0000000..40c8dc6 Binary files /dev/null and b/rps.dmsc differ diff --git a/save.dat b/save.dat new file mode 100644 index 0000000..e7b995f Binary files /dev/null and b/save.dat differ diff --git a/test.dms b/test.dms index 0feadef..977b3b1 100644 --- a/test.dms +++ b/test.dms @@ -1,43 +1,61 @@ -ENTRY MAIN +ENTRY INIT2 +LOADFILE Story/bedroom.dms USING extendedDefine -VERSION 4.1 -[MAIN]{ - // test = [1,2,3,4,5,6,7,8,9,10] - // t=0 - // test2 = "Hello" - // str = $test2[1:-1]$ - // print("$test2[-1:1]$") - // print(str) - // t=testfunc(1,2) - // print(t) - // for i = 1,10 < - // "Choice Test: $test[1]$" < - // "A" setGlobalVar("t",1) - // "B" continue() - // "C" setGlobalVar("t",3) - // > - // > - // ::leave:: - // print("t = $t$ i = $i$") - val = 0 +DISABLE warnings +USING audio as audio +// DISABLE hostmsg +[INIT2]{ multi = external() - multi:newTLoop(testfunc,1) - // multi:newTLoop(testfunc2) - // alarm = multi:newAlarm(3) - // alarm:OnRing(testfunc) - print("Hooked function!") + multi:newTLoop(DoMe,1) } -[testfunc:function()]{ - val = val + 1 - print("Called $val$ times!") - return True +[DoMe:function(a)]{ + print("Hi",a) } -[testfunc2:function()]{ - "Test"< - "1" print("A") - "2" print("B") - "3" print("C") - > - // print("Yo whats up!") - return True -} \ No newline at end of file +/* +[INIT]{ + // The LOAD function will load variables and jump to the saved location. Be sure to setup runtime variables before the LOAD function is called! + WATCH("money","name","day","chapter","passive") + loaded,c,p = LOAD() + if loaded==false then JUMP("SETUP")|SKIP(0) + newThread("UPDATER","Thread_DisplayStats") + JUMP(c,p) + QUIT() +} +[SETUP]{ + money = 100 + name = getInput("Enter name: ") + day = 1 + chapter = 1 + passive = 1 + newThread("UPDATER","Thread_DisplayStats") + SAVE() + JUMP("START") +} +[UPDATER]{ + maintheme=audio:new("Audio/Nadia.ogg") + maintheme:play(.5) + ::loop:: + EXECUTE("title $name$ $$money$ Day: $day$ Chap: $chapter$") + sleep(.1) + money = money + passive + GOTO("loop") +} +[stop:function()]{ + "hmm" + return 1,2 +} +[Fade:function(obj)]{ + // for x = 100, 0, -1 < + // sleep(.1) + // obj:setVolume(x/100) + // > +} +[START]{ + "HI!" + maintheme:setVolume(1) + sleep(1) + Fade(maintheme) + "Yo" + // JUMP("BEDROOM") +} +*/ diff --git a/test.dmsc b/test.dmsc index e8567f7..ba0e4ea 100644 Binary files a/test.dmsc and b/test.dmsc differ diff --git a/test.lua b/test.lua index a059c82..86d4e15 100644 --- a/test.lua +++ b/test.lua @@ -1,16 +1,52 @@ package.path="?/init.lua;lua/?/init.lua;lua/?.lua;"..package.path +package.cpath="?.dll;"..package.cpath local bin = require("bin") local multi = require("multi") require("parseManager") require("multi") -test=parseManager:compileToFile("test.dms","test.dmsc")--load("StoryTest/init.dms") ---~ test = parseManager:loadCompiled("test.dmsc") -print(test:dump()) +test=parseManager:load("test.dms")--parseManager:compileToFile("test.dms","test.dmsc")-- test:define{ - external=function(self) + external = function() return multi end } +--~ test = parseManager:loadCompiled("test.dmsc") +function parseManager:Call(func,...) + local env = {} + local temp = parseManager:load(self.path) +--~ local temp = {} +--~ setmetatable(temp,{__index = self}) + temp.fArgs = {...} + local t = temp:next(func) + while t do + if t.Type=="text" then + io.write(t.text.."\n") + t=temp:next() + elseif t.Type=="condition" then + t=temp:next() + elseif t.Type=="assignment" then + t=temp:next() + elseif t.Type=="label" then + t=temp:next() + elseif t.Type=="method" then + env = temp:dataToEnv(t.RetArgs) + t=temp:next() + elseif t.Type=="choice" then + _print(t.prompt) + io.write("Choose#: ") + cm=tonumber(1,#t[1]) + t=temp:next(nil,cm) + elseif t.Type=="end" then + print("Something went wrong!") + elseif t.Type=="error" then + error(t.text) + else + t=temp:next() + end + end + return unpack(env) +end +--~ print(test.methods.DoMe(test,1,2)) t=test:next() while t do if t.Type=="text" then @@ -26,7 +62,7 @@ while t do elseif t.Type=="method" then t=test:next() elseif t.Type=="choice" then - print(t.prompt) + _print(t.prompt) for i=1,#t[1] do print(i..". "..t[1][i]) end @@ -45,4 +81,6 @@ while t do t=test:next() end end -multi:mainloop() +multi:mainloop{ + protect = true +}