diff --git a/game/GuiManagerDebug/Core/Clickable.int b/game/GuiManagerDebug/Core/Clickable.int new file mode 100644 index 0000000..f192d8e --- /dev/null +++ b/game/GuiManagerDebug/Core/Clickable.int @@ -0,0 +1,15 @@ +function gui:Clickable() + local x,y,w,h=love.graphics.getScissor() + local mx=love.mouse.getX() + local my=love.mouse.getY() + if _GuiPro.HasStencel then + local obj=_GuiPro.StencelHolder + if self:isDescendant(obj) then + return math.sqrt((mx-obj.x)^2+(my-obj.y)^2)<=(obj.offset.size.x or 0) + end + end + if not(x) then + return true + end + return not(mx>x+w or mxy+h or myx+w or mxy+h or my self.x and x < self.x+self.width and y > self.y and y < self.y+self.height and self:TClickable(x,y) and self:eventable()) + end + end + self.id=-1 +end +multi:newTask(function() -- A bit of post-loading haha + gui.touchpressed=multi:newConnection() + gui.touchreleased=multi:newConnection() + gui.touchmoved=multi:newConnection() + love.touchpressed=Library.convert(love.touchpressed or function() end) + love.touchreleased=Library.convert(love.touchreleased or function() end) + love.touchmoved=Library.convert(love.touchmoved or function() end) + love.touchpressed:inject(function(id, x, y, dx, dy, pressure) gui.touchpressed:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + love.touchreleased:inject(function(id, x, y, dx, dy, pressure) gui.touchreleased:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + love.touchmoved:inject(function(id, x, y, dx, dy, pressure) gui.touchmoved:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + _GuiPro.TouchReady=true + _GuiPro.TouchRegister={} + gui.touchpressed:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if #v.tid==0 then + if (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + v:addTID(id) + v.touchcount=1 + for i=1,#v.ToFuncP do + v.ToFuncP[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + elseif not(v:hasTID(id)) then + if (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + v:addTID(id) + v.touchcount=v.touchcount+1 + for i=1,#v.ToFuncP do + v.ToFuncP[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end + end) + gui.touchreleased:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if v:hasTID(id) then + v:removeTID(id) + for i=1,#v.ToFuncR do + v.ToFuncR[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end) + gui.touchmoved:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if v:hasTID(id) and (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + for i=1,#v.ToFuncM do + v.ToFuncM[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + elseif v:hasTID(id) and not((x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable())) then + v:removeTID(id) + for i=1,#v.ToFuncR do + v.ToFuncR[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end) +end) +-- now that that is done lets set up some more post loading checks +_GuiPro.int=multi:newProcess() +_GuiPro.int:Start() +_GuiPro.int:setJobSpeed(.001) +_GuiPro.EXACT=0 +_GuiPro.LAX=.01 +_GuiPro.LAZY=.05 +-- now lets define the reg function +function gui.Compare(a,b,v,tp) + if tp==">" then + if (a+v>b or a-v>b) then + return true + end + elseif tp=="<" then + if (a+v=" then + if (a+v>=b or a-v>=b) then + return true + end + elseif tp=="==" then -- this one is gonna be tricky + if (a>=b-v and a<=b+v) or (b>=a-v and b<=a+v) then + return true + end + end + return false +end +function gui:regesterTouch() + local obj=self + obj.ToFuncP={} + obj.ToFuncM={} + obj.ToFuncR={} + obj.To2Func={} + obj.ToDTFunc={} + obj.touchRendering =_GuiPro.EXACT -- exact(0), lax(), # + function obj:removeTID(id) + for i=1,#self.tid do + if self.tid[i]==id then + table.remove(self.tid,i) + self.touchcount=self.touchcount-1 + return + end + end + end + function obj:hasTID(id) + for i=1,#self.tid do + if self.tid[i]==id then + return true + end + end + return false + end + obj.txl1=0 + obj.tyl1=0 + obj.txl2=0 + obj.tyl2=0 + obj.LS=0 + obj:OnUpdate(function(self) + if self.touchcount==2 then + local x1,y1=love.touch.getPosition( self.tid[1] ) + local x2,y2=love.touch.getPosition( self.tid[2] ) + local CS=math.sqrt((x2-x1)^2+(y2-y1)^2) + if gui.Compare(CS,self.LS,self.touchRendering,">") then + for i=1,#self.To2Func do + self.To2Func[i](self,CS,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + elseif gui.Compare(CS,self.LS,self.touchRendering,"<") then + for i=1,#self.To2Func do + self.To2Func[i](self,-CS,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + elseif gui.Compare(CS,self.LS,self.touchRendering,"==") then + for i=1,#self.To2Func do + self.To2Func[i](self,0,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + end + -- if self.txl1~=x1 or self.txl2~=x2 or self.tyl1~=y1 or self.tyl2~=y2 then + -- for i=1,#self.To2Func do + -- self.To2Func[i](self,0,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + -- end + -- end + self.LS=CS + self.txl1=x1 + self.txl2=x2 + self.tyl1=y1 + self.tyl2=y2 + end + end) + function obj:OnDoubleTap(func) + table.insert(self.ToDTFunc,func) + end + function obj:On2TouchMoved(func) + table.insert(self.To2Func,func) + end + function obj:addTID(id) + table.insert(self.tid,id) + end + function obj:OnTouchPressed(func) + table.insert(self.ToFuncP,func) -- event for touches + end + function obj:OnTouchReleased(func) -- event for touches + table.insert(self.ToFuncR,func) + end + function obj:OnTouchMoved(func) -- event for touches + table.insert(self.ToFuncM,func) + end + if _GuiPro.TouchReady then -- my sneaky test + print("Registred: "..tostring(obj)) + table.insert(_GuiPro.TouchRegister,obj) + else + print("Attempting to register: "..tostring(obj)) + _GuiPro.int:newJob(function() table.insert(_GuiPro.TouchRegister,obj) end) -- a sneaky way to ensure that your object gets registered eventually, even if you call the method before the touch patch was activated. + end +end diff --git a/game/GuiManagerDebug/Drawing/AddDrawRuleB.int b/game/GuiManagerDebug/Drawing/AddDrawRuleB.int new file mode 100644 index 0000000..5510a3d --- /dev/null +++ b/game/GuiManagerDebug/Drawing/AddDrawRuleB.int @@ -0,0 +1,4 @@ +function gui:AddDrawRuleB(rule) + if not(self.DrawRulesB) then self.DrawRulesB={} end + table.insert(self.DrawRulesB,rule) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Drawing/AddDrawRuleE.int b/game/GuiManagerDebug/Drawing/AddDrawRuleE.int new file mode 100644 index 0000000..a025f89 --- /dev/null +++ b/game/GuiManagerDebug/Drawing/AddDrawRuleE.int @@ -0,0 +1,4 @@ +function gui:AddDrawRuleE(rule) + if not(self.DrawRulesE) then self.DrawRulesE={} end + table.insert(self.DrawRulesE,rule) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Drawing/draw.int b/game/GuiManagerDebug/Drawing/draw.int new file mode 100644 index 0000000..d0b2404 --- /dev/null +++ b/game/GuiManagerDebug/Drawing/draw.int @@ -0,0 +1,12 @@ +function gui:draw() + if _GuiPro.rotate~=0 then + love.graphics.rotate(math.rad(_GuiPro.rotate)) + end + if self.FormFactor:lower()=="rectangle" then + self:drawR() + elseif self.FormFactor:lower()=="circle" then + self:drawC() + else + error("Unsupported FormFactor: "..self.FormFactor.."!") + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Drawing/drawC.int b/game/GuiManagerDebug/Drawing/drawC.int new file mode 100644 index 0000000..22782ed --- /dev/null +++ b/game/GuiManagerDebug/Drawing/drawC.int @@ -0,0 +1,89 @@ +function gui:drawC() + if love.mouse.isDown("l")==false and love.mouse.isDown("m")==false and love.mouse.isDown("r")==false then + _GuiPro.DragItem={} + _GuiPro.hasDrag=false + end + if self.Visible==true and self.VIS==true then + local b=true + for i,v in pairs(_GuiPro.Clips) do + if self:isDescendant(v)==true then + b=false + end + end + if b then + love.graphics.setStencilTest( ) + _GuiPro.HasStencel=false + _GuiPro.StencelHolder=nil + end + local x,y,r,s=(self.offset.pos.x or 0)+self.Parent.x,(self.offset.pos.y or 0)+self.Parent.y,self.offset.size.x or 0,self.offset.size.y or 360 + if self.CC then + x,y=x+r,y+r + end + self.x,self.y=x,y + _GuiPro.circleStencilFunction = function() + love.graphics.circle("fill",x,y,r,s) + end + if math.sqrt((love.mouse.getX()-x)^2+(love.mouse.getY()-y)^2)<=r and self:eventable() and self:Clickable() and self.Active==true then + self.hovering=true + if love.mouse.isDown("l") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.lclicked=true + elseif love.mouse.isDown("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.rclicked=true + elseif love.mouse.isDown("m") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.mclicked=true + else + if string.find(self.Type, "Button") and _GuiPro.hasDrag==false then + love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + self.hovering=false + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + if self.ClipDescendants==true then + _GuiPro.Clips[tostring(self)]=self + _GuiPro.HasStencel=true + _GuiPro.StencelHolder=self + love.graphics.stencil(_GuiPro.circleStencilFunction) + love.graphics.setStencilTest("notequal",0) + end + love.graphics.circle("fill",x,y,r,s) + love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.BorderVisibility*254) + for b=0,self.BorderSize-1 do + love.graphics.circle("line",x,y,r+b,s) + end + if string.find(self.Type, "Text") then + if self.text~=nil then + if self.AutoScaleText then + self.FontSize=math.floor(self.height/1.45833) + end + love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility*254) + love.graphics.setFont(self.Font) + love.graphics.printf(self.text, x-(r/2)+(self.XTween), y-(r/2)+self.Tween, r, self.TextFormat) + end + end + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Drawing/drawR.int b/game/GuiManagerDebug/Drawing/drawR.int new file mode 100644 index 0000000..ad4297b --- /dev/null +++ b/game/GuiManagerDebug/Drawing/drawR.int @@ -0,0 +1,118 @@ +function gui:drawR() + if love.mouse.isDown("l")==false and love.mouse.isDown("m")==false and love.mouse.isDown("r")==false then + _GuiPro.DragItem={} + _GuiPro.hasDrag=false + end + if self.Visible==true and self.VIS==true then + local b=true + for i,v in pairs(_GuiPro.Clips) do + if self:isDescendant(v)==true then + b=false + end + end + if b==true then + love.graphics.setStencilTest() + love.graphics.setScissor() + end + self.x=(self.Parent.width*self.scale.pos.x)+self.offset.pos.x+self.Parent.x + self.y=(self.Parent.height*self.scale.pos.y)+self.offset.pos.y+self.Parent.y + self.width=(self.Parent.width*self.scale.size.x)+self.offset.size.x + self.height=(self.Parent.height*self.scale.size.y)+self.offset.size.y + if self.DrawRulesB then + for dr=1,#self.DrawRulesB do + self.DrawRulesB[dr](self) + end + end + if (love.mouse.getX() > self.x and love.mouse.getX() < self.x+self.width and love.mouse.getY() > self.y and love.mouse.getY() < self.y+self.height and self:Clickable() and self:eventable()) or self:touchable("r") and self.Active==true then + self.hovering=true + if love.mouse.isDown("l") or self:touchable("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.lclicked=true + elseif love.mouse.isDown("r") or self:touchable("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.rclicked=true + elseif love.mouse.isDown("m") or self:touchable("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.mclicked=true + else + if string.find(self.Type, "Button") or self:touchable("r") and _GuiPro.hasDrag==false then + love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + self.hovering=false + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + if self.ClipDescendants==true then + _GuiPro.Clips[tostring(self)]=self + love.graphics.setScissor(self.x, self.y, self.width, self.height) + end + if self:hasRoundness() then + love.graphics.stencil(self.stfunc, "replace", 1) + love.graphics.setStencilTest("greater", 0) + end + love.graphics.rectangle("fill", self.x, self.y, self.width, self.height,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI) + if string.find(self.Type, "Image") then + self:ImageRule() + end + if self.Type=="Video" then + self:VideoRule() + end + if self:hasRoundness() then + love.graphics.setStencilTest() + end + love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.BorderVisibility*254) + for b=0,self.BorderSize-1 do + love.graphics.rectangle("line", self.x-(b/2), self.y-(b/2), self.width+b, self.height+b,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI) + end + if string.find(self.Type, "Text") then + if self.text~=nil then + if self.AutoScaleText then + self.FontSize=math.floor(self.height/1.45833) + end + love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility*254) + if self.Font==_defaultfont then + love.graphics.setFont(self.Font) + love.graphics.printf(self.text, self.x+2+(self.XTween*self.DPI)+((self.marginL or 0)*self.DPI or self.XTween*self.DPI), self.y+(self.FontHeight/2)+self.Tween*self.DPI, self.width+(0 or (self.marginR or 0)*self.DPI), self.TextFormat) + else + if type(self.Font)=="string" then + self.Font=love.graphics.newFont(self.Font,self.FontSize) + self.FontHeight=self.Font:getHeight() + else + love.graphics.setFont(self.Font) + end + if type(self.FontSize)=="string" then + self.FontSize=tonumber(self.FontSize) + love.graphics.setNewFont(self.FontSize) + end + love.graphics.printf(self.text, self.x+2+((self.marginL or 0)*self.DPI or self.XTween*self.DPI), self.y+math.floor((self.FontHeight-self.FontSize)/2)+self.Tween*self.DPI, self.width+(0 or (self.marginR or 0)*self.DPI), self.TextFormat) + end + end + end + if self.DrawRulesE then + for dr=1,#self.DrawRulesE do + self.DrawRulesE[dr](self) + end + end + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Frame/newDropFrame.int b/game/GuiManagerDebug/Frame/newDropFrame.int new file mode 100644 index 0000000..97e4720 --- /dev/null +++ b/game/GuiManagerDebug/Frame/newDropFrame.int @@ -0,0 +1,37 @@ +function gui:newDropFrame(name,x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("DropFrame",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=false + c.funcD={} + function c:GetDroppedItems() + local t=self:getChildren() + local tab={} + for i=1,#t do + if t[i].Type=="TextImageButtonFrameDrag" then + table.insert(tab,t[i]) + end + end + return tab + end + function c:OnDropped(func) + table.insert(self.funcD,func) + end + c:OnUpdate(function(self) + if _GuiPro.DragItem then + if _GuiPro.DragItem.Type=="TextImageButtonFrameDrag" and love.mouse.isDown(_GuiPro.DragItem.dragbut or "m")==false and self:IsHovering() then + local t=_GuiPro.DragItem + _GuiPro.DragItem={} + for i=1,#t.funcD do + t.funcD[i](self,t) + end + for i=1,#self.funcD do + self.funcD[i](self,t) + end + _GuiPro.hasDrag=false + end + end + end) + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Frame/newFrame.int b/game/GuiManagerDebug/Frame/newFrame.int new file mode 100644 index 0000000..5e6b084 --- /dev/null +++ b/game/GuiManagerDebug/Frame/newFrame.int @@ -0,0 +1,8 @@ +function gui:newFrame(name,x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("Frame",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=false + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Frame/newFullFrame.int b/game/GuiManagerDebug/Frame/newFullFrame.int new file mode 100644 index 0000000..5cda200 --- /dev/null +++ b/game/GuiManagerDebug/Frame/newFullFrame.int @@ -0,0 +1,4 @@ +function gui:newFullFrame(name) + name=name or "" + return self:newFrame(name,0,0,0,0,0,0,1,1) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Frame/newTabFrame.int b/game/GuiManagerDebug/Frame/newTabFrame.int new file mode 100644 index 0000000..9f8f8fe --- /dev/null +++ b/game/GuiManagerDebug/Frame/newTabFrame.int @@ -0,0 +1,59 @@ +function gui:newTabFrame(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=gui:newFrame(name, x, y, w, h, sx ,sy ,sw ,sh) + c.tabheight=20 + c.Holder=c:newFrame("Holder",0,c.tabheight,0,0,0,0,1,1) + c.TabHolder=c:newFrame("TabHolder",0,0,0,c.tabheight,0,0,1) + function c:setTabHeight(n) + self.tabheight=n + self.Holder:SetDualDim(0,-self.tabheight,0,0,0,0,1,1) + end + function c:addTab(name,colorT,colorH) + if colorT and not(colorH) then + colorH=colorT + end + local tab=self.TabHolder:newTextButton(name,name,0,0,0,0,0,0,0,1) + tab.Tween=-3 + if colorT then + tab.Color=colorT + end + local holder=self.Holder:newFrame(name,0,0,0,0,0,0,1,1) + if colorH then + holder.Color=colorH + end + tab.frame=holder + tab:OnReleased(function(b,self) + if b=="l" then + local tt=self.Parent:getChildren() + local th=self.Parent.Parent.Holder:getChildren() + for i=1,#th do + th[i].Visible=false + end + for i=1,#tt do + tt[i].frame.Visible=false + tt[i].BorderSize=1 + end + self.BorderSize=0 + self.frame.Visible=true + end + end) + local tt=self.TabHolder:getChildren() + for i=1,#tt do + tt[i].frame.Visible=false + tt[i].BorderSize=1 + end + tab.frame.Visible=true + tab.BorderSize=0 + return tab,holder + end + c:OnUpdate(function(self) + local th=self.TabHolder:getChildren() + local l=self.width/#th + for i=1,#th do + th[i]:SetDualDim(l*(i-1),0,l) + end + if #th==0 then + self:Destroy() + end + end) + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Frame/newratioFrame.int b/game/GuiManagerDebug/Frame/newratioFrame.int new file mode 100644 index 0000000..e69de29 diff --git a/game/GuiManagerDebug/Image-Animation/SetImage.int b/game/GuiManagerDebug/Image-Animation/SetImage.int new file mode 100644 index 0000000..d0d5f78 --- /dev/null +++ b/game/GuiManagerDebug/Image-Animation/SetImage.int @@ -0,0 +1,13 @@ +function gui:SetImage(i) + if type(i)=="string" then + self.Image=love.graphics.newImage(i) + else + self.Image=i + end + if self.Image~=nil then + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) + end + return self.ImageWidth,self.ImageHeigth +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Image-Animation/UpdateImage.int b/game/GuiManagerDebug/Image-Animation/UpdateImage.int new file mode 100644 index 0000000..be4cfd7 --- /dev/null +++ b/game/GuiManagerDebug/Image-Animation/UpdateImage.int @@ -0,0 +1,5 @@ +function gui:UpdateImage() + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Image-Animation/getTile.int b/game/GuiManagerDebug/Image-Animation/getTile.int new file mode 100644 index 0000000..6b6fcae --- /dev/null +++ b/game/GuiManagerDebug/Image-Animation/getTile.int @@ -0,0 +1,20 @@ +function gui:getTile(i,x,y,w,h)-- returns imagedata + if type(i)=="string" then + i=love.graphics.newImage(i) + elseif type(i)=="userdata" then + -- do nothing + elseif string.find(self.Type,"Image",1,true) then + local i,x,y,w,h=self.Image,i,x,y,w + else + error("getTile invalid args!!! Usage: ImageElement:getTile(x,y,w,h) or gui:getTile(imagedata,x,y,w,h)") + end + local iw,ih=i:getDimensions() + local id,_id=i:getData(),love.image.newImageData(w,h) + for _x=x,w+x-1 do + for _y=y,h+y-1 do + -- + _id:setPixel(_x-x,_y-y,id:getPixel(_x,_y)) + end + end + return love.graphics.newImage(_id) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Image-Animation/newAnim.int b/game/GuiManagerDebug/Image-Animation/newAnim.int new file mode 100644 index 0000000..30850aa --- /dev/null +++ b/game/GuiManagerDebug/Image-Animation/newAnim.int @@ -0,0 +1,57 @@ +function gui:newAnim(file,delay, x, y, w, h, sx ,sy ,sw ,sh) + local x,y,w,h,sx,sy,sw,sh=filter(file, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation",file, x, y, w, h, sx ,sy ,sw ,sh) + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files={} + c.AnimStart={} + c.AnimEnd={} + local _files=alphanumsort(love.filesystem.getDirectoryItems(file)) + for i=1,#_files do + if string.sub(_files[i],-1,-1)~="b" then + table.insert(c.files,love.graphics.newImage(file.."/".._files[i])) + end + end + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(pos,step) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Image-Animation/newAnimFromData.int b/game/GuiManagerDebug/Image-Animation/newAnimFromData.int new file mode 100644 index 0000000..02c85c7 --- /dev/null +++ b/game/GuiManagerDebug/Image-Animation/newAnimFromData.int @@ -0,0 +1,52 @@ +function gui:newAnimFromData(data,delay, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation","FromFile", x, y, w, h, sx ,sy ,sw ,sh) + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files=data + c.AnimStart={} + c.AnimEnd={} + c:SetImage(c.files[1]) + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(pos,step) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Image-Animation/newAnimFromTiles.int b/game/GuiManagerDebug/Image-Animation/newAnimFromTiles.int new file mode 100644 index 0000000..70aea2c --- /dev/null +++ b/game/GuiManagerDebug/Image-Animation/newAnimFromTiles.int @@ -0,0 +1,59 @@ +function gui:newAnimFromTiles(file,xd,yd,delay, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(file, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation",file, x, y, w, h, sx ,sy ,sw ,sh) + local im=love.graphics.newImage(file) + local _x,_y=im:getDimensions() + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files={} + c.AnimStart={} + c.AnimEnd={} + for i=0,_y/yd-1 do + for j=0,_x/xd-1 do + table.insert(c.files,gui:getTile(im,j*xd,i*yd,xd,yd)) + end + end + c:SetImage(c.files[1]) + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(pos,step) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Image-Animation/newFullImageLabel.int b/game/GuiManagerDebug/Image-Animation/newFullImageLabel.int new file mode 100644 index 0000000..953f480 --- /dev/null +++ b/game/GuiManagerDebug/Image-Animation/newFullImageLabel.int @@ -0,0 +1,3 @@ +function gui:newFullImageLabel(i,name) + return self:newImageLabel(i,name,0,0,0,0,0,0,1,1) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Image-Animation/newImageButton.int b/game/GuiManagerDebug/Image-Animation/newImageButton.int new file mode 100644 index 0000000..6d0e51d --- /dev/null +++ b/game/GuiManagerDebug/Image-Animation/newImageButton.int @@ -0,0 +1,25 @@ +function gui:newImageButton(i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageButton",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + else + c.Image=i + end + c.Visibility=0 + c.ImageVisibility=1 + c.rotation=0 + if c.Image~=nil then + c.ImageHeigth=c.Image:getHeight() + c.ImageHeight=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c:OnEnter(function() + love.mouse.setCursor(_GuiPro.CursorH) + end) + c:OnExit(function() + love.mouse.setCursor(_GuiPro.CursorN) + end) + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Image-Animation/newImageLabel.int b/game/GuiManagerDebug/Image-Animation/newImageLabel.int new file mode 100644 index 0000000..47323e1 --- /dev/null +++ b/game/GuiManagerDebug/Image-Animation/newImageLabel.int @@ -0,0 +1,18 @@ +function gui:newImageLabel(i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageLabel",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + else + c.Image=i + end + c.Visibility=0 + c.ImageVisibility=1 + c.rotation=0 + if c.Image~=nil then + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Image-Animation/newVideo.int b/game/GuiManagerDebug/Image-Animation/newVideo.int new file mode 100644 index 0000000..de2c379 --- /dev/null +++ b/game/GuiManagerDebug/Image-Animation/newVideo.int @@ -0,0 +1,62 @@ +function gui:newVideo(name,i,x,y,w,h,sx,sy,sw,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("Video",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Video=love.graphics.newVideo(i) + else + c.Video=i + end + c.Visibility=0 + c.VideoVisibility=1 + c.rotation=0 + if c.Video~=nil then + c.VideoHeigth=c.Video:getHeight() + c.VideoWidth=c.Video:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.VideoWidth,c.VideoHeigth) + end + c.funcV={} + function c:Play() + self.handStart=true + self.Video:play() + end + function c:Pause() + self.Video:pause() + end + c.Resume=c.Play + function c:Stop() + self.handStart=false + self:Pause() + self:Rewind() + for i=1,# self.funcV do + self.funcV[i](self) + end + end + function c:OnVideoStopped(func) + table.insert(self.funcV,func) + end + function c:Rewind() + self.Video:rewind() + end + function c:Restart() + self:Rewind() + self:Play() + end + function c:Seek(o) + self.Video:seek(o) + end + function c:Tell() + self.Video:tell() + end + function c:SetFilter(min, mag, anisotropy) + self.Video:setFilter(min, mag, anisotropy) + end + function c:IsPlaying() + return self.Video:isPlaying() + end + c:OnUpdate(function(self) + if self.Video:isPlaying()==false and self.handStart == true then + self:Stop() + end + end) + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Item/newDragItem.int b/game/GuiManagerDebug/Item/newDragItem.int new file mode 100644 index 0000000..162341c --- /dev/null +++ b/game/GuiManagerDebug/Item/newDragItem.int @@ -0,0 +1,51 @@ +function gui:newDragItem(t,i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextImageButtonFrameDrag",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=true + c.funcD={} + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + c.ImageVisibility=1 + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + elseif type(i)=="image" then + c.Image=i + c.ImageVisibility=1 + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c:OnDragStart(function(self,x,y) + if _GuiPro.hasDrag==false then + self:setParent(_GuiPro) + self:SetDualDim(x,y) + self:TopStack() + end + end) + c.rotation=0 + c.Tween=0 + c.XTween=0 + c.text = t + c.AutoScaleText=false + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.TextVisibility=1 + c.TextColor = {0, 0, 0} + function c:OnDropped(func) + table.insert(self.funcD,func) + end + c:OnUpdate(function(self) + if love.mouse.isDown("m" or self.dragbut)==false and self==_GuiPro.DragItem and self.hovering==false then + _GuiPro.DragItem={} + for i=1,#self.func7 do + self.func7[i](self,(love.mouse.getX())-self.width/2,(love.mouse.getY())-self.height/2) + end + end + end) + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Item/newItem.int b/game/GuiManagerDebug/Item/newItem.int new file mode 100644 index 0000000..57a68d5 --- /dev/null +++ b/game/GuiManagerDebug/Item/newItem.int @@ -0,0 +1,28 @@ +function gui:newItem(t,i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextImageButtonFrame",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + else + c.Image=i + end + c.rotation=0 + c.ImageVisibility=1 + c.Draggable=false + if c.Image~=nil then + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c.Tween=0 + c.XTween=0 + c.text = t + c.AutoScaleText=false + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.TextVisibility=1 -- 0=invisible,1=solid (self.TextVisibility*254+1) + c.TextColor = {0, 0, 0} + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/AdvTextBox.int b/game/GuiManagerDebug/Misc/AdvTextBox.int new file mode 100644 index 0000000..08a3499 --- /dev/null +++ b/game/GuiManagerDebug/Misc/AdvTextBox.int @@ -0,0 +1,45 @@ +function gui:AdvTextBox(txt,x,y,w,h,sx,sy,sw,sh) + name="AdvTextBox" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("AdvTextBoxFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c.BorderSize=0 + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + --local temp = c:newTextButton("X","Close",-25,5,20,20,1) + --temp.Tween=-5 + --temp.XTween=-2 + --temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + --temp.Color=Color.Red + c.tLink=c:newTextBox("puttext","TextBox",5,h-95,-40,30,0,1,1,1) + c.tLink.Color=Color.light_gray + c.tLink.ClearOnFocus=true + c.tLink:OnFocus(function(self) self.ClearOnFocus=false end) + local temp=c:newTextButton("OK","Ok",-35,h-65,30,30,1,1) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcO do self.Parent.funcO[i](self.Parent,self.Parent.tLink.text) end end) + temp.Color=Color.Green + temp.XTween=-2 + local temp=c:newTextButton("X","Cancel",-35,h-95,30,30,1,1) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent,self.Parent.tLink.text) end end) + temp.Color=Color.Red + temp.XTween=-2 + function c:Close() + self.Visible=false + end + function c:Open() + self.Visible=true + end + function c:OnOk(func) + table.insert(self.funcO,func) + end + function c:OnX(func) + table.insert(self.funcX,func) + end + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/ApplyGradient.int b/game/GuiManagerDebug/Misc/ApplyGradient.int new file mode 100644 index 0000000..e092739 --- /dev/null +++ b/game/GuiManagerDebug/Misc/ApplyGradient.int @@ -0,0 +1,36 @@ +function _GuiPro.gradient(colors) + local direction = colors.direction or "horizontal" + colors.direction=nil + trans = colors.trans or 255 + trans=math.floor(trans) + if direction == "horizontal" then + direction = true + elseif direction == "vertical" then + direction = false + else + error("Invalid direction '" .. tostring(direction) "' for gradient. Horizontal or vertical expected.") + end + local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1) + for __i, color in ipairs(colors) do + local x, y + if direction then + x, y = 0, __i - 1 + else + x, y = __i - 1, 0 + end + result:setPixel(x, y, color[1], color[2], color[3], trans) + end + result = love.graphics.newImage(result) + result:setFilter('linear', 'linear') + return result +end +function _GuiPro.drawinrect(img, x, y, w, h, r, ox, oy, kx, ky) + love.graphics.draw(img, x, y, r, w / img:getWidth(), h / img:getHeight(), ox, oy, kx, ky) +end +function gui:ApplyGradient(rules) + self.Image=nil + self.Type=self.Type.."w/GradImage" + self.rotation=0 + self.ImageVisibility=rules.visibility or 1 + self:SetImage(_GuiPro.gradient(rules)) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/BottomStack.int b/game/GuiManagerDebug/Misc/BottomStack.int new file mode 100644 index 0000000..b339ec4 --- /dev/null +++ b/game/GuiManagerDebug/Misc/BottomStack.int @@ -0,0 +1,10 @@ +function gui:BottomStack() + childs=self.Parent:getChildren() + for i=1,#childs do + if childs[i]==self then + table.remove(self.Parent.Children,i) + table.insert(self.Parent.Children,1,self) + break + end + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/Center.int b/game/GuiManagerDebug/Misc/Center.int new file mode 100644 index 0000000..0089c93 --- /dev/null +++ b/game/GuiManagerDebug/Misc/Center.int @@ -0,0 +1,4 @@ +function gui:Center() + local x,y=self:getFullSize() + self:SetDualDim(-math.floor(x/2),-math.floor(y/2),nil,nil,.5,.5) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/Destroy.int b/game/GuiManagerDebug/Misc/Destroy.int new file mode 100644 index 0000000..9c524f1 --- /dev/null +++ b/game/GuiManagerDebug/Misc/Destroy.int @@ -0,0 +1,9 @@ +function gui:Destroy() + check=self.Parent:getChildren() + local cc=0 + for cc=1,#check do + if check[cc]==self then + table.remove(self.Parent.Children,cc) + end + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/GetAllChildren.int b/game/GuiManagerDebug/Misc/GetAllChildren.int new file mode 100644 index 0000000..b3a0ae4 --- /dev/null +++ b/game/GuiManagerDebug/Misc/GetAllChildren.int @@ -0,0 +1,25 @@ +function gui:GetAllChildren() + local Stuff = {} + function Seek(Items) + for i=1,#Items do + if Items[i].Visible==true then + table.insert(Stuff,Items[i]) + local NItems = Items[i]:getChildren() + if NItems ~= nil then + Seek(NItems) + end + end + end + end + local Objs = self:getChildren() + for i=1,#Objs do + if Objs[i].Visible==true then + table.insert(Stuff,Objs[i]) + local Items = Objs[i]:getChildren() + if Items ~= nil then + Seek(Items) + end + end + end + return Stuff +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/GetChild.int b/game/GuiManagerDebug/Misc/GetChild.int new file mode 100644 index 0000000..d434f40 --- /dev/null +++ b/game/GuiManagerDebug/Misc/GetChild.int @@ -0,0 +1,3 @@ +function gui:GetChild(name) + return self.Children[name] or self +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/InGrid.int b/game/GuiManagerDebug/Misc/InGrid.int new file mode 100644 index 0000000..4e097a7 --- /dev/null +++ b/game/GuiManagerDebug/Misc/InGrid.int @@ -0,0 +1,3 @@ +function InGrid(i,x,y,s) + return math.floor((i-1)/x)*s,(i-1)*s-(math.floor((i-1)/y)*(s*x)) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/InGridX.int b/game/GuiManagerDebug/Misc/InGridX.int new file mode 100644 index 0000000..c4aadc2 --- /dev/null +++ b/game/GuiManagerDebug/Misc/InGridX.int @@ -0,0 +1,5 @@ +function InGridX(i,w,h,xs,ys) + local xc,yc=math.floor(w/xs),math.floor(h/ys) + local xi,yi=(i-1)%xc,math.floor((i-1)/xc) + return xi*xs,yi*ys +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/InGridY.int b/game/GuiManagerDebug/Misc/InGridY.int new file mode 100644 index 0000000..555c72a --- /dev/null +++ b/game/GuiManagerDebug/Misc/InGridY.int @@ -0,0 +1,5 @@ +function InGridY(i,w,h,xs,ys) + local xc,yc=math.floor(w/xs),math.floor(h/ys) + local xi,yi=math.floor((i-1)/yc),(i-1)%yc + return xi*xs,yi*ys +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/IsHovering.int b/game/GuiManagerDebug/Misc/IsHovering.int new file mode 100644 index 0000000..072bb54 --- /dev/null +++ b/game/GuiManagerDebug/Misc/IsHovering.int @@ -0,0 +1,3 @@ +function gui:IsHovering() + return (love.mouse.getX() > self.x and love.mouse.getX() < self.x+self.width and love.mouse.getY() > self.y and love.mouse.getY() < self.y+self.height) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/Move.int b/game/GuiManagerDebug/Misc/Move.int new file mode 100644 index 0000000..6f32db9 --- /dev/null +++ b/game/GuiManagerDebug/Misc/Move.int @@ -0,0 +1,4 @@ +function gui:Move(x,y) + self.offset.pos.x=self.offset.pos.x+x + self.offset.pos.y=self.offset.pos.y+y +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/SetDualDim.int b/game/GuiManagerDebug/Misc/SetDualDim.int new file mode 100644 index 0000000..0774965 --- /dev/null +++ b/game/GuiManagerDebug/Misc/SetDualDim.int @@ -0,0 +1,46 @@ +function gui:SetDualDim(x, y, w, h, sx ,sy ,sw ,sh) + if _GuiPro.DPI_ENABLED then + if x then + x=self.DPI*x + end + if y then + y=self.DPI*y + end + if w then + w=self.DPI*w + end + if h then + h=self.DPI*h + end + end + if sx then + self.scale.pos.x=sx + end + if sy then + self.scale.pos.y=sy + end + if x then + self.offset.pos.x=x + end + if y then + self.offset.pos.y=y + end + if sw then + self.scale.size.x=sw + end + if sh then + self.scale.size.y=sh + end + if w then + self.offset.size.x=w + end + if h then + self.offset.size.y=h + end + if self.Image then + self:SetImage(self.Image) + end +end +function gui:setDualDim(...) + self:SetDualDim(...) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/SetHand.int b/game/GuiManagerDebug/Misc/SetHand.int new file mode 100644 index 0000000..8171f2c --- /dev/null +++ b/game/GuiManagerDebug/Misc/SetHand.int @@ -0,0 +1,5 @@ +_GuiPro.CursorN=love.mouse.getSystemCursor("arrow") +_GuiPro.CursorH=love.mouse.getSystemCursor("hand") +function gui:SetHand(img,x,y) + _GuiPro.CursorN=love.mouse.newCursor(img,x,y) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/SetHover.int b/game/GuiManagerDebug/Misc/SetHover.int new file mode 100644 index 0000000..956e593 --- /dev/null +++ b/game/GuiManagerDebug/Misc/SetHover.int @@ -0,0 +1,3 @@ +function gui:SetHover(img,x,y) + _GuiPro.CursorH=love.mouse.newCursor(img,x,y) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/SetName.int b/game/GuiManagerDebug/Misc/SetName.int new file mode 100644 index 0000000..1e69edd --- /dev/null +++ b/game/GuiManagerDebug/Misc/SetName.int @@ -0,0 +1,4 @@ +function gui:SetName(name) + self.Parent.Children[name]=self + self.Name=name +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/TopStack.int b/game/GuiManagerDebug/Misc/TopStack.int new file mode 100644 index 0000000..a1db016 --- /dev/null +++ b/game/GuiManagerDebug/Misc/TopStack.int @@ -0,0 +1,10 @@ +function gui:TopStack() + childs=self.Parent:getChildren() + for i=1,#childs do + if childs[i]==self then + table.remove(self.Parent.Children,i) + table.insert(self.Parent.Children,self) + break + end + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/addDominance.int b/game/GuiManagerDebug/Misc/addDominance.int new file mode 100644 index 0000000..5a55975 --- /dev/null +++ b/game/GuiManagerDebug/Misc/addDominance.int @@ -0,0 +1,3 @@ +function gui:addDominance() + _GuiPro.TopHovered=self +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/addHotKey.int b/game/GuiManagerDebug/Misc/addHotKey.int new file mode 100644 index 0000000..0ec05e0 --- /dev/null +++ b/game/GuiManagerDebug/Misc/addHotKey.int @@ -0,0 +1,6 @@ +function gui:addHotKey(key) + local temp=self:newFrame(0,0,0,0) + temp.Visible=false + temp:setHotKey(key) + return temp +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/alphanumsort.int b/game/GuiManagerDebug/Misc/alphanumsort.int new file mode 100644 index 0000000..3b36133 --- /dev/null +++ b/game/GuiManagerDebug/Misc/alphanumsort.int @@ -0,0 +1,7 @@ +function alphanumsort(o) + local function padnum(d) local dec, n = string.match(d, "(%.?)0*(.+)") + return #dec > 0 and ("%.12f"):format(d) or ("%s%03d%s"):format(dec, #n, n) + end + table.sort(o, function(a,b) return tostring(a):gsub("%.?%d+",padnum)..("%3d"):format(#b)< tostring(b):gsub("%.?%d+",padnum)..("%3d"):format(#a) end) + return o +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/anchorRight.int b/game/GuiManagerDebug/Misc/anchorRight.int new file mode 100644 index 0000000..91251ad --- /dev/null +++ b/game/GuiManagerDebug/Misc/anchorRight.int @@ -0,0 +1,3 @@ +function gui:anchorRight(n) + self:SetDualDim(-(self.width+n),nil,nil,nil,1) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/centerX.int b/game/GuiManagerDebug/Misc/centerX.int new file mode 100644 index 0000000..ea1f599 --- /dev/null +++ b/game/GuiManagerDebug/Misc/centerX.int @@ -0,0 +1,3 @@ +function gui:centerX() + self:SetDualDim(-(self.width/2),nil,nil,nil,.5) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/centerY.int b/game/GuiManagerDebug/Misc/centerY.int new file mode 100644 index 0000000..c998589 --- /dev/null +++ b/game/GuiManagerDebug/Misc/centerY.int @@ -0,0 +1,3 @@ +function gui:centerY() + self:SetDualDim(nil,-(self.height/2),nil,nil,nil,.5) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/disrespectHierarchy.int b/game/GuiManagerDebug/Misc/disrespectHierarchy.int new file mode 100644 index 0000000..d25162d --- /dev/null +++ b/game/GuiManagerDebug/Misc/disrespectHierarchy.int @@ -0,0 +1,3 @@ +function gui:disrespectHierarchy() + _GuiPro.Hierarchy=false +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/getChildren.int b/game/GuiManagerDebug/Misc/getChildren.int new file mode 100644 index 0000000..295c5fc --- /dev/null +++ b/game/GuiManagerDebug/Misc/getChildren.int @@ -0,0 +1,3 @@ +function gui:getChildren() + return self.Children +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/getColor.int b/game/GuiManagerDebug/Misc/getColor.int new file mode 100644 index 0000000..bef482e --- /dev/null +++ b/game/GuiManagerDebug/Misc/getColor.int @@ -0,0 +1,3 @@ +function gui:getColor(cindex) + return Color[cindex] +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/getFullSize.int b/game/GuiManagerDebug/Misc/getFullSize.int new file mode 100644 index 0000000..294667a --- /dev/null +++ b/game/GuiManagerDebug/Misc/getFullSize.int @@ -0,0 +1,12 @@ +function gui:getFullSize() + local maxx,maxy=-math.huge,-math.huge + local temp = self:GetAllChildren() + for i=1,#temp do + if temp[i].width>maxx then + maxx=temp[i].width+temp[i].offset.pos.x + elseif temp[i].height>maxy then + maxy=temp[i].height+temp[i].offset.pos.y + end + end + return maxx,maxy +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/getHighest.int b/game/GuiManagerDebug/Misc/getHighest.int new file mode 100644 index 0000000..df7121a --- /dev/null +++ b/game/GuiManagerDebug/Misc/getHighest.int @@ -0,0 +1,5 @@ +function gui:getHighest() + if self.Children[#self.Children]~=nil then + return self.Children[#self.Children] + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/getLowest.int b/game/GuiManagerDebug/Misc/getLowest.int new file mode 100644 index 0000000..5319544 --- /dev/null +++ b/game/GuiManagerDebug/Misc/getLowest.int @@ -0,0 +1,5 @@ +function gui:getLowest() + if self.Children[1]~=nil then + return self.Children[1] + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/isDescendant.int b/game/GuiManagerDebug/Misc/isDescendant.int new file mode 100644 index 0000000..5c9c2a5 --- /dev/null +++ b/game/GuiManagerDebug/Misc/isDescendant.int @@ -0,0 +1,9 @@ +function gui:isDescendant(obj) + local things=obj:GetAllChildren() + for i=1,#things do + if things[i]==self then + return true + end + end + return false +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/isHighest.int b/game/GuiManagerDebug/Misc/isHighest.int new file mode 100644 index 0000000..0453c16 --- /dev/null +++ b/game/GuiManagerDebug/Misc/isHighest.int @@ -0,0 +1,3 @@ +function gui:isHighest() + return (self==self.Parent:getHighest()) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/isLowest.int b/game/GuiManagerDebug/Misc/isLowest.int new file mode 100644 index 0000000..a210883 --- /dev/null +++ b/game/GuiManagerDebug/Misc/isLowest.int @@ -0,0 +1,3 @@ +function gui:isLowest() + return (self==self.Parent:getLowest()) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/massMutate.int b/game/GuiManagerDebug/Misc/massMutate.int new file mode 100644 index 0000000..1c75aee --- /dev/null +++ b/game/GuiManagerDebug/Misc/massMutate.int @@ -0,0 +1,6 @@ +function gui.massMutate(t,...) + local mut={...} + for i=1,#mut do + mut[i]:Mutate(t) + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/newCheckBox.int b/game/GuiManagerDebug/Misc/newCheckBox.int new file mode 100644 index 0000000..ccd530c --- /dev/null +++ b/game/GuiManagerDebug/Misc/newCheckBox.int @@ -0,0 +1,41 @@ +if love.filesystem.exists("CheckBoxes.png") then + _GuiPro.UC=gui:getTile("CheckBoxes.png",0,0,16,16) + _GuiPro.C=gui:getTile("CheckBoxes.png",16,0,16,16) + _GuiPro.UCH=gui:getTile("CheckBoxes.png",0,16,16,16) + _GuiPro.CH=gui:getTile("CheckBoxes.png",16,16,16,16) +end +function gui:newCheckBox(name,x,y) + if not(_GuiPro.UC) then error("CheckBoxes.png not found! Cannot currently use checkbox without the data") end + if type(name)~="String" then + x,y,name=name,x,"CheckBox" + end + local c=self:newImageLabel(_GuiPro.UC,name, x, y, 16,16) + c.Visibility=0 + c.check=false + c:OnEnter(function(self) + if self.check then + self:SetImage(_GuiPro.CH) + else + self:SetImage(_GuiPro.UCH) + end + end) + function c:isChecked() + return self.check + end + c:OnExit(function(self) + if self.check then + self:SetImage(_GuiPro.C) + else + self:SetImage(_GuiPro.UC) + end + end) + c:OnReleased(function(b,self) + self.check=not(self.check) + if self.check then + self:SetImage(_GuiPro.CH) + else + self:SetImage(_GuiPro.UCH) + end + end) + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/newMessageBox.int b/game/GuiManagerDebug/Misc/newMessageBox.int new file mode 100644 index 0000000..6b11a5a --- /dev/null +++ b/game/GuiManagerDebug/Misc/newMessageBox.int @@ -0,0 +1,36 @@ +function gui:newMessageBox(txt,x,y,w,h,sx,sy,sw,sh) + name="MessageBox" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("MessageBoxFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c.BorderSize=0 + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + local temp = c:newTextButton("X","Close",-25,5,20,20,1) + temp.Tween=-5 + temp.XTween=-2 + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + temp.Color=Color.Red + local temp=c:newTextButton("OK","Ok",0,h-65,0,30,.25,1,.5) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcO do self.Parent.funcO[i](self.Parent) end end) + temp.Color=Color.Green + function c:Close() + self.Visible=false + end + function c:Open() + self.Visible=true + end + function c:OnOk(func) + table.insert(self.funcO,func) + end + function c:OnX(func) + table.insert(self.funcX,func) + end + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/newPart.int b/game/GuiManagerDebug/Misc/newPart.int new file mode 100644 index 0000000..79bd3e5 --- /dev/null +++ b/game/GuiManagerDebug/Misc/newPart.int @@ -0,0 +1,49 @@ +function gui:newPart(x, y,w ,h , sx ,sy ,sw ,sh) + local c = {} + setmetatable(c, gui) + if self==gui then + c.Parent=_GuiPro + else + c.Parent=self + end + c.funcs={} + c.funcs2={} + c.funcs3={} + c.funcs4={} + c.funcs5={} + c.func6={} + c.func7={} + c.func8={} + c.func9={} + c.func10={} + c.form="rectangle" + c.Color = {255, 255, 255} + c.scale={} + c.scale.size={} + c.scale.size.x=sw or 0 + c.scale.size.y=sh or 0 + c.offset={} + c.offset.size={} + c.offset.size.x=w or 0 + c.offset.size.y=h or 0 + c.scale.pos={} + c.scale.pos.x=sx or 0 + c.scale.pos.y=sy or 0 + c.offset.pos={} + c.offset.pos.x=x or 0 + c.offset.pos.y=y or 0 + c.VIS=true + c.Visible=true + c.Visibility=1 + c.BorderColor={0,0,0} + c.BorderSize=0 + c.Type="Part" + c.Name="GuiPart" + _GuiPro.count=_GuiPro.count+1 + c.x=(c.Parent.width*c.scale.pos.x)+c.offset.pos.x+c.Parent.x + c.y=(c.Parent.height*c.scale.pos.y)+c.offset.pos.y+c.Parent.y + c.width=(c.Parent.width*c.scale.size.x)+c.offset.size.x + c.height=(c.Parent.height*c.scale.size.y)+c.offset.size.y + table.insert(c.Parent.Children,c) + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/newProgressBar.int b/game/GuiManagerDebug/Misc/newProgressBar.int new file mode 100644 index 0000000..2f82f9f --- /dev/null +++ b/game/GuiManagerDebug/Misc/newProgressBar.int @@ -0,0 +1,45 @@ +function gui:newProgressBar(txt,x,y,w,h,sx,sy,sw,sh) + name="newProgressBar" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("newProgressBarFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c.BorderSize=0 + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + local temp = c:newTextButton("X","Close",-25,5,20,20,1) + temp.Tween=-5 + temp.XTween=-2 + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + temp.Color=Color.Red + c.BarBG=c:newTextButton("",5,h-65,-10,30,0,1,1) + c.BarBG:ApplyGradient{Color.Red,Color.light_red} + c.Bar=c.BarBG:newTextLabel("",0,0,0,0,0,0,0,1) + c.Bar:ApplyGradient{Color.Green,Color.light_green} + c.BarDisp=c.BarBG:newTextLabel("0%","0%",0,0,0,0,0,0,1,1) + c.BarDisp.Visibility=0 + c.BarDisp.Link=c.Bar + c.BarDisp:OnUpdate(function(self) + self.text=self.Link.scale.size.x*100 .."%" + end) + c.Func1={} + function c:On100(func) + table.insert(self.Func1,func) + end + c:OnUpdate(function(self) + if self.Bar.scale.size.x*100>=100 then + for P=1,#self.Func1 do + self.Func1[P](self) + end + end + end) + function c:SetPercentage(n) + self.Bar:SetDualDim(0,0,0,0,0,0,n/100,1) + end + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/newScrollBar.int b/game/GuiManagerDebug/Misc/newScrollBar.int new file mode 100644 index 0000000..6fa810a --- /dev/null +++ b/game/GuiManagerDebug/Misc/newScrollBar.int @@ -0,0 +1,42 @@ +function gui:newScrollBar(color1,color2) + local scrollbar=self:newFrame(-20,0,20,0,1,0,0,1) + scrollbar.funcS={} + scrollbar.Color=color1 or Color.saddle_brown + scrollbar:OnClicked(function(b,self,x,y) + love.mouse.setX(self.x+10) + if y>=10 and y<=self.height-10 then + self.mover:SetDualDim(0,y-10) + end + if y<10 then + love.mouse.setY(10+self.y) + end + if y>self.height-10 then + love.mouse.setY((self.height-10)+self.y) + end + for i=1,#self.funcS do + self.funcS[i](self,self:getPosition()) + end + end) + scrollbar:OnEnter(function(self) + self:addDominance() + end) + scrollbar:OnExit(function(self) + self:removeDominance() + end) + scrollbar.mover=scrollbar:newTextButton("","",0,0,20,20) + scrollbar.mover.Color=color2 or Color.light_brown + function scrollbar:getPosition() + return ((self.mover.offset.pos.y)/(self.height-20))*100 + end + function scrollbar:setPosition(n) + print((self.height-20),n) + self.mover.offset.pos.y=((self.height-20)/(100/n)) + for i=1,#self.funcS do + self.funcS[i](self,self:getPosition()) + end + end + function scrollbar:OnScroll(func) + table.insert(self.funcS,func) + end + return scrollbar +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/newScrollMenu.int b/game/GuiManagerDebug/Misc/newScrollMenu.int new file mode 100644 index 0000000..3dbfdaf --- /dev/null +++ b/game/GuiManagerDebug/Misc/newScrollMenu.int @@ -0,0 +1,98 @@ +function gui:newScrollMenu(title,tabN,onloop,x, y, w, h, sx ,sy ,sw ,sh) + local Main = self:newFrame(x, y, w, h, sx ,sy ,sw ,sh) + local Title=Main:newTextButton(title,"Title",0,0,0,20,0,0,1) + Title.Tween=-4 + Title.FontSize=12 + Title:OnReleased(function(b,self) + self.Parent.Tick=not(self.Parent.Tick) + end) + local scroll=Main:newTextButton("","Scroll",-20,20,20,-20,1,0,0,1) + scroll:OnClicked(function(b,self,x,y) + self.Parent.Mover:SetDualDim(0,y-10,20,20) + if self.Parent.Mover.offset.pos.y<0 then + self.Parent.Mover:SetDualDim(0,0,20,20) + end + if self.Parent.Mover.offset.pos.y>self.Parent.height-40 then + self.Parent.Mover:SetDualDim(0,self.Parent.height-40,20,20) + end + local temp = #self.Parent.TList + self.Parent.pos=(math.floor((temp*self.Parent.Mover.offset.pos.y)/self.height))+1 + end) + Main:OnUpdate(function(self) + if self.Tick==false then + self.Visibility=0 + end + end) + scroll:OnUpdate(function(self) + self.Visible=self.Parent.Tick + end) + local Mover=scroll:newTextLabel("",0,0,20,20) + Main.Mover=Mover + Main.TList=tabN + Main.pos=1 + Main.Tick=true + function Main:Update(title,tabN,onloop) + ch=self:getChildren() + for i=#ch,1,-1 do + ch[i]:Destroy() + end + Title=Main:newTextButton(title,"Title",0,0,0,20,0,0,1) + Title.Tween=-4 + Title.FontSize=12 + Title:OnReleased(function(b,self) + self.Parent.Tick=not(self.Parent.Tick) + end) + scroll=Main:newTextButton("","Scroll",-20,20,20,-20,1,0,0,1) + scroll:OnClicked(function(b,self,x,y) + self.Parent.Mover:SetDualDim(0,y-10,20,20) + if self.Parent.Mover.offset.pos.y<0 then + self.Parent.Mover:SetDualDim(0,0,20,20) + end + if self.Parent.Mover.offset.pos.y>self.Parent.height-40 then + self.Parent.Mover:SetDualDim(0,self.Parent.height-40,20,20) + end + local temp = #self.Parent.TList + self.Parent.pos=(math.floor((temp*self.Parent.Mover.offset.pos.y)/self.height))+1 + end) + local Mover=scroll:newTextLabel("",0,0,20,20) + Main.Mover=Mover + Main.TList=tabN + Main.pos=1 + Main.Tick=true + scroll:OnUpdate(function(self) + self.Visible=self.Parent.Tick + end) + for i=1,math.floor(Main.height/20)-1 do + local temp=Main:newTextButton("","Item"..i,0,i*20,-20,20,0,0,1) + temp.FontSize=10 + temp.Tween=-4 + temp.pos=i + temp:OnUpdate(function(self) + self.text=self.Parent.TList[(self.Parent.pos+self.pos)-1] + self.Visible=self.Parent.Tick + end) + if onloop then + onloop(temp,i) + end + end + end + io.write(tostring(Main.height).."\n") + for i=1,math.floor(Main.height/20)-1 do + local temp=Main:newTextButton("Item"..i,0,i*20,-20,20,0,0,1) + temp.FontSize=10 + temp.Tween=-4 + temp.pos=i + temp:OnUpdate(function(self) + if self.Parent.TList[(self.Parent.pos+self.pos)-1]~=nil then + self.text=self.Parent.TList[(self.Parent.pos+self.pos)-1] + else + self.text="" + end + self.Visible=self.Parent.Tick + end) + if onloop then + onloop(temp,i) + end + end + return Main +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/removeAllChildren.int b/game/GuiManagerDebug/Misc/removeAllChildren.int new file mode 100644 index 0000000..8d0d99e --- /dev/null +++ b/game/GuiManagerDebug/Misc/removeAllChildren.int @@ -0,0 +1,6 @@ +function gui:destroyAllChildren() + local c=self.Children + for i=1,#c do + c[i]:Destroy() + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/removeDominance.int b/game/GuiManagerDebug/Misc/removeDominance.int new file mode 100644 index 0000000..c42b2e1 --- /dev/null +++ b/game/GuiManagerDebug/Misc/removeDominance.int @@ -0,0 +1,3 @@ +function gui:removeDominance() + _GuiPro.TopHovered=nil +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/respectHierarchy.int b/game/GuiManagerDebug/Misc/respectHierarchy.int new file mode 100644 index 0000000..656a992 --- /dev/null +++ b/game/GuiManagerDebug/Misc/respectHierarchy.int @@ -0,0 +1,3 @@ +function gui:respectHierarchy() + _GuiPro.Hierarchy=true +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/round.int b/game/GuiManagerDebug/Misc/round.int new file mode 100644 index 0000000..f06ad57 --- /dev/null +++ b/game/GuiManagerDebug/Misc/round.int @@ -0,0 +1,4 @@ +function gui.round(num, idp) + local mult = 10^(idp or 0) + return math.floor(num * mult + 0.5) / mult +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/setBG.int b/game/GuiManagerDebug/Misc/setBG.int new file mode 100644 index 0000000..c82f045 --- /dev/null +++ b/game/GuiManagerDebug/Misc/setBG.int @@ -0,0 +1,3 @@ +function gui.setBG(i) + gui.ff:SetImage(i) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/setColor.int b/game/GuiManagerDebug/Misc/setColor.int new file mode 100644 index 0000000..7a81a6f --- /dev/null +++ b/game/GuiManagerDebug/Misc/setColor.int @@ -0,0 +1,14 @@ +function gui:setColor(a,b,c) + if type(a)=="string" then + self.Color=Color[a] + elseif type(a)=="number" then + self.Color=Color.new(a,b,c) + end +end +function gui:setTextColor(a,b,c) + if type(a)=="string" then + self.TextColor=Color[a] + elseif type(a)=="number" then + self.TextColor=Color.new(a,b,c) + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/setDefualtFont.int b/game/GuiManagerDebug/Misc/setDefualtFont.int new file mode 100644 index 0000000..001b9f7 --- /dev/null +++ b/game/GuiManagerDebug/Misc/setDefualtFont.int @@ -0,0 +1,3 @@ +function gui:setDefualtFont(font) + _defaultfont = font +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/setHotKey.int b/game/GuiManagerDebug/Misc/setHotKey.int new file mode 100644 index 0000000..5866cfc --- /dev/null +++ b/game/GuiManagerDebug/Misc/setHotKey.int @@ -0,0 +1,24 @@ +function gui:setHotKey(key) + local tab=key:split("+") + self.hotkeys=tab + self.cooldown=false + self.Alarm=multi:newAlarm(1) + self.Alarm.parent=self + self.args={} + self.funcHK=multi:newConnection() + self.Alarm:OnRing(function(alarm) alarm.parent.cooldown=false end) + function self:OnHotKey(func) + self.funcHK:connect(func) + end + self:OnUpdate(function(self) + if self.cooldown then return end + for i=1,#self.hotkeys do + if not(love.keyboard.isDown(self.hotkeys[i])) then + return + end + end + self.cooldown=true + self.funcHK:Fire(self) + self.Alarm:Reset() + end) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/setNewFont.int b/game/GuiManagerDebug/Misc/setNewFont.int new file mode 100644 index 0000000..93d95c5 --- /dev/null +++ b/game/GuiManagerDebug/Misc/setNewFont.int @@ -0,0 +1,3 @@ +function gui:setNewFont(FontSize) + self.Font=love.graphics.setNewFont(tonumber(FontSize)) +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/setParent.int b/game/GuiManagerDebug/Misc/setParent.int new file mode 100644 index 0000000..37ddb6e --- /dev/null +++ b/game/GuiManagerDebug/Misc/setParent.int @@ -0,0 +1,14 @@ +function gui:setParent(parent,name)-- Needs fixing!!! + local temp=self.Parent:getChildren() + for i=1,#temp do + if temp[i]==self then + table.remove(self.Parent.Children,i) + break + end + end + table.insert(parent.Children,self) + self.Parent=parent + if name then + self:SetName(name) + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/setVisibility.int b/game/GuiManagerDebug/Misc/setVisibility.int new file mode 100644 index 0000000..ca6008c --- /dev/null +++ b/game/GuiManagerDebug/Misc/setVisibility.int @@ -0,0 +1,14 @@ +function gui:setVisiblity(val) + self.Visible=val + self.oV=val + doto=self:GetAllChildren() + if val==false then + for i=1,#doto do + doto[i].Visible=val + end + else + for i=1,#doto do + doto[i].Visible=doto[i].oV + end + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Misc/setgetText.int b/game/GuiManagerDebug/Misc/setgetText.int new file mode 100644 index 0000000..bb4afc6 --- /dev/null +++ b/game/GuiManagerDebug/Misc/setgetText.int @@ -0,0 +1,6 @@ +function gui:setText(txt) + self.text=txt +end +function gui:getText(txt) + return self.text +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Text/newTextBox.int b/game/GuiManagerDebug/Text/newTextBox.int new file mode 100644 index 0000000..b243ca7 --- /dev/null +++ b/game/GuiManagerDebug/Text/newTextBox.int @@ -0,0 +1,178 @@ +function string:insert(p,s) + return ("%s%s%s"):format(self:sub(1,p), s, self:sub(p+1)) +end +function string:remove(p,l) + l=l or 1 + return ("%s%s"):format(self:sub(1,p-1), self:sub(p+l)) +end +function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextBox",name, x, y, w, h, sx ,sy ,sw ,sh) + c.ClearOnFocus=false + c.LoseFocusOnEnter=true + c.Tween=0 + c.XTween=0 + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.text = t + c.ttext= t + c.AutoScaleText=false + c.TextVisibility=1 + c.Color = {220, 220, 220} + c.TextColor = {0, 0, 0} + c.Active=false + c.hidden=false + c.cursor={0,1} + c.mark=nil + c.arrowkeys=false + c.funcF={function() + love.keyboard.setTextInput(true) + end} + c.cooldown=false + c.cooldown2=false + c.funcE={function() + love.keyboard.setTextInput(false) + end} + function c:triggerEnter() + for cc=1,#self.funcE do + self.funcE[cc](self,self.ttext) + end + self.text="" + self.ttext="" + end + c.Enter=true + c.Alarm=multi:newAlarm(.1) + c.Alarm.parent=c + c.Alarm:OnRing(function(alarm) alarm.parent.cooldown=false end) + c.Alarm2=multi:newAlarm(.5) + c.Alarm2.parent=c + c.Alarm2:OnRing(function(alarm) alarm.parent.cooldown2=false end) + c.ArrowAlarm=multi:newAlarm(.1) + c.ArrowAlarm.parent=c + c.ArrowAlarm:OnRing(function(alarm) alarm.parent.arrowkeys=false end) + function c:OnFocus(func) + table.insert(self.funcF,func) + end + function c:OnEnter(func) + table.insert(self.funcE,func) + end + c:OnClicked(function(b,self) + for cc=1,#self.funcF do + self.funcF[cc](self) + end + if self.Active==false then + if self.ClearOnFocus==true then + self.text="" + self.ttext="" + end + for tb=1,#gui.TB do + if gui.TB[tb]~=nil then + gui.TB[tb].Active=false + end + end + self.Active=true + end + end) + c:OnClicked(function(b,self,x,y) + local dwidth, wrappedtext = _defaultfont:getWrap(self.text:sub(1,self.cursor[1]), self.width) + local height = _defaultfont:getHeight() + if #wrappedtext>=1 then + width= _defaultfont:getWidth(wrappedtext[#wrappedtext]) + self.cursor[2]=#wrappedtext + else + self.cursor[2]=1 + width=0 + end + yc=math.ceil(((y/self.DPI)-(self.FontHeight/2)+self.Tween-self.y)/height) + xc=math.floor(x) + end) + c:AddDrawRuleE(function(self) + if self.Active then + local dwidth, wrappedtext = _defaultfont:getWrap(self.text:sub(1,self.cursor[1]), self.width) + local height = _defaultfont:getHeight() + if #wrappedtext>=1 then + width= _defaultfont:getWidth(wrappedtext[#wrappedtext]) + self.cursor[2]=#wrappedtext + else + self.cursor[2]=1 + width=0 + end + x1=width+2+self.x+self.XTween + y1=(self.y+(height*(self.cursor[2]-1))+(self.FontHeight/2)+self.Tween)*self.DPI + x2=width+2+self.x+self.XTween + y2=(self.y+(self.FontHeight/2)+self.Tween*self.DPI)+height*self.cursor[2] + love.graphics.line(x1,y1,x2,y2) + end + end) + c:OnUpdate(function(self) + if love.keyboard.isDown("backspace") and self.Active and self.cooldown==false then + if #self.text>0 then + self.text = self.text:remove(self.cursor[1]) + self.ttext = self.ttext:remove(self.cursor[1]) + self.cursor[1]=self.cursor[1]-1 + end + self.cooldown=true + self.Alarm:Reset() + elseif love.keyboard.isDown("backspace")==false then + self.cooldown=false + end + if love.keyboard.isDown("left") and self.arrowkeys==false and self.Active then + self.arrowkeys=true + self.cursor[1]=self.cursor[1]-1 + if self.cursor[1]<0 then + self.cursor[1]=0 + end + self.ArrowAlarm:Reset() + elseif love.keyboard.isDown("right") and self.arrowkeys==false and self.Active then + self.arrowkeys=true + self.cursor[1]=self.cursor[1]+1 + if self.cursor[1]>#self.text then + self.cursor[1]=#self.text + end + self.ArrowAlarm:Reset() + end + if love.keyboard.isDown("delete") and self.Active then + if #self.text>0 then + self.text = "" + self.ttext = "" + self.cursor[1]=1 + end + elseif (love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift")) and love.keyboard.isDown("return") and self.cooldown2==false then + self.text=self.text.."\n" + self.ttext=self.ttext.."\n" + self.cooldown2=true + c.Alarm2:Reset() + elseif (love.keyboard.isDown("return") or love.keyboard.isDown("enter") or love.keyboard.isDown("kpenter")) and self.Active and self.Enter and not(love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift")) then + if self.LoseFocusOnEnter then + self.Active=false + else + self.Active=true + end + for cc=1,#self.funcE do + self.funcE[cc](self,self.ttext) + end + end + end) + table.insert(gui.TB,c) + return c +end +--TEXT BOX HELPER FUNCTION +function love.textinput(t) + for tb=1,#gui.TB do + if gui.TB[tb]~=nil then + if gui.TB[tb].Active then + if gui.TB[tb].hidden then + --gui.TB[tb].text=gui.TB[tb].text.."*" + gui.TB[tb].text=gui.TB[tb].text:insert(gui.TB[tb].cursor[1],"*") + else + --gui.TB[tb].text=gui.TB[tb].text..t + gui.TB[tb].text=gui.TB[tb].text:insert(gui.TB[tb].cursor[1],t) + end + gui.TB[tb].ttext=gui.TB[tb].ttext:insert(gui.TB[tb].cursor[1],t) + gui.TB[tb].cursor[1]=gui.TB[tb].cursor[1]+1 + end + end + end +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Text/newTextButton.int b/game/GuiManagerDebug/Text/newTextButton.int new file mode 100644 index 0000000..da2f3f6 --- /dev/null +++ b/game/GuiManagerDebug/Text/newTextButton.int @@ -0,0 +1,22 @@ +function gui:newTextButton(t,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextButton",name, x, y, w, h, sx ,sy ,sw ,sh) + c.Tween=0 + c.XTween=0 + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.text = t + c.AutoScaleText=false + c.TextVisibility=1 -- 0=invisible,1=solid (self.TextVisibility*254+1) + c.Color = {220, 220, 220} + c.TextColor = {0, 0, 0} + c:OnEnter(function() + love.mouse.setCursor(_GuiPro.CursorH) + end) + c:OnExit(function() + love.mouse.setCursor(_GuiPro.CursorN) + end) + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/Text/newTextLabel.int b/game/GuiManagerDebug/Text/newTextLabel.int new file mode 100644 index 0000000..4424d0e --- /dev/null +++ b/game/GuiManagerDebug/Text/newTextLabel.int @@ -0,0 +1,16 @@ +function gui:newTextLabel(t,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextLabel",name, x, y, w, h, sx ,sy ,sw ,sh) + c.Tween=0 + c.XTween=0 + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.text = t + c.AutoScaleText=false + c.TextVisibility=1 -- 0=invisible,1=solid (self.TextVisibility*254+1) + c.Color = {220, 220, 220} + c.TextColor = {0, 0, 0} + return c +end \ No newline at end of file diff --git a/game/GuiManagerDebug/init.lua b/game/GuiManagerDebug/init.lua new file mode 100644 index 0000000..2060ee7 --- /dev/null +++ b/game/GuiManagerDebug/init.lua @@ -0,0 +1,58 @@ +utf8 = require("utf8") +_defaultfont = love.graphics.getFont() +gui = {} +gui.__index = gui +gui.TB={} +gui.Version="VERSION" -- Is it really ready for release? +_GuiPro={GBoost=true,hasDrag=false,DragItem={},Children={},Visible=true,count=0,x=0,y=0,height=0,width=0,update=function(self) local things=GetAllChildren2(self) UpdateThings(things) end,draw=function(self) local things=GetAllChildren(self) DrawThings(things) end,getChildren=function(self) return self.Children end} +_GuiPro.Clips={} +_GuiPro.rotate=0 +setmetatable(_GuiPro, gui) +function gui:LoadInterface(file) + local add=".int" + if string.find(file,".",1,true) then add="" end + if love.filesystem.exists(file..add) then + a,b=pcall(love.filesystem.load(file..add)) + if a then + print("Loaded: "..file) + else + print("Error loading file: "..file) + print(a,b) + end + else + print("File does not exist!") + return false + end +end +function gui.LoadAll(dir) + files=love.filesystem.getDirectoryItems(dir) + for i=1,#files do + if string.sub(files[i],-4)==".int" then + gui:LoadInterface(dir.."/"..files[i]) + end + end +end +-- Start Of Load + +--gui.LoadAll("GuiManager/LibCore") +gui.LoadAll("GuiManager/Core") +gui.LoadAll("GuiManager/Image-Animation") +gui.LoadAll("GuiManager/Frame") +gui.LoadAll("GuiManager/Item") +gui.LoadAll("GuiManager/Misc") +gui.LoadAll("GuiManager/Text") +gui.LoadAll("GuiManager/Drawing") +gui.LoadAll("GuiManager/Combos") +--gui.LoadAll("GuiManager/WIP") +multi.boost=2 + +-- End of Load +gui:respectHierarchy() +_GuiPro.width,_GuiPro.height=love.graphics.getDimensions() +multi:newLoop():OnLoop(function() _GuiPro.width,_GuiPro.height=love.graphics.getDimensions() _GuiPro:update() end) +multi:onDraw(function() _GuiPro:draw() end) +gui.ff=gui:newFrame("",0,0,0,0,0,0,1,1) +gui.ff.Color={255,255,255} +gui.ff:OnUpdate(function(self) + self:BottomStack() +end) diff --git a/game/bin/compressors/lzw.lua b/game/bin/compressors/lzw.lua new file mode 100644 index 0000000..57653b3 --- /dev/null +++ b/game/bin/compressors/lzw.lua @@ -0,0 +1,73 @@ +--[[ +LZW String Compression demo for Gideros +This code is MIT licensed, see http://www.opensource.org/licenses/mit-license.php +(C) 2013 - Guava7 +]] +CLZWCompression = {} +function CLZWCompression:InitDictionary(isEncode) + self.mDictionary = {} + -- local s = " !#$%&'\"()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + local s={} + for i=1,255 do + s[#s+1]=string.char(i) + end + s=table.concat(s) + local len = #s + for i = 1, len do + if isEncode then + self.mDictionary[s:sub(i, i)] = i + else + self.mDictionary[i] = s:sub(i, i) + end + end + self.mDictionaryLen = len +end +function CLZWCompression:Encode(sInput) + self:InitDictionary(true) + local s = "" + local ch + local len = #sInput + local result = {} + local dic = self.mDictionary + local temp + for i = 1, len do + ch = sInput:sub(i, i) + temp = s..ch + if dic[temp] then + s = temp + else + result[#result + 1] = dic[s] + self.mDictionaryLen = self.mDictionaryLen + 1 + dic[temp] = self.mDictionaryLen + s = ch + end + end + result[#result + 1] = dic[s] + return result +end +function CLZWCompression:Decode(data) + self:InitDictionary(false) + local dic = self.mDictionary + local entry + local ch + local prevCode, currCode + local result = {} + prevCode = data[1] + result[#result + 1] = dic[prevCode] + for i = 2, #data do + currCode = data[i] + entry = dic[currCode] + if entry then + ch = entry:sub(1, 1) + result[#result + 1] = entry + else + ch = dic[prevCode]:sub(1, 1) + result[#result + 1] = dic[prevCode]..ch + end + dic[#dic + 1] = dic[prevCode]..ch + prevCode = currCode + end + return table.concat(result) +end + +return CLZWCompression diff --git a/game/bin/converters/base64.lua b/game/bin/converters/base64.lua new file mode 100644 index 0000000..6b134c3 --- /dev/null +++ b/game/bin/converters/base64.lua @@ -0,0 +1,30 @@ +local base64={} +local bs = { [0] = + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/', +} +local bsd=table.flip(bs) +local char=string.char +function base64.encode(s) + local byte, rep, pad = string.byte, string.rep, 2 - ((#s-1) % 3) + s = (s..rep('\0', pad)):gsub("...", function(cs) + local a, b, c = byte(cs, 1, 3) + return bs[bit.rshift(a,2)] .. bs[bit.bor(bit.lshift(bit.band(a,3),4),bit.rshift(b,4))] .. bs[bit.bor(bit.lshift(bit.band(b,15),2),bit.rshift(c,6))] .. bs[bit.band(c,63)] + end) + return s:sub(1, #s-pad) .. rep('=', pad) +end +function base64.decode(s) + local s=s:match("["..s.."=]+") + local p,cc=s:gsub("=","A") + local r="" + local n=0 + s=s:sub(1,#s-#p)..p + for c = 1,#s,4 do + n = bit.lshift(bsd[s:sub(c, c)], 18) + bit.lshift(bsd[s:sub(c+1, c+1)], 12) + bit.lshift(bsd[s:sub(c + 2, c + 2)], 6) + bsd[s:sub(c + 3, c + 3)] + r = r .. char(bit.band(bit.arshift(n, 16), 0xFF)) .. char(bit.band(bit.arshift(n, 8), 0xFF)) .. char(bit.band(n, 0xFF)) + end + return r:sub(1,-(cc+1)) +end +return base64 diff --git a/game/bin/converters/base91.lua b/game/bin/converters/base91.lua new file mode 100644 index 0000000..157f312 --- /dev/null +++ b/game/bin/converters/base91.lua @@ -0,0 +1,72 @@ +local base91={} +local b91enc={[0]= + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '#', '$', + '%', '&', '(', ')', '*', '+', ',', '.', '/', ':', ';', '<', '=', + '>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '"' +} +local b91dec=table.flip(b91enc) +function base91.decode(d) + local l,v,o,b,n = #d,-1,"",0,0 + for i in d:gmatch(".") do + local c=b91dec[i] + if not(c) then + -- Continue + else + if v < 0 then + v = c + else + v = v+c*91 + b = bit.bor(b, bit.lshift(v,n)) + if bit.band(v,8191) then + n = n + 13 + else + n = n + 14 + end + while true do + o=o..string.char(bit.band(b,255)) + b=bit.rshift(b,8) + n=n-8 + if not (n>7) then + break + end + end + v=-1 + end + end + end + if v + 1>0 then + o=o..string.char(bit.band(bit.bor(b,bit.lshift(v,n)),255)) + end + return o +end +function base91.encode(d) + local b,n,o,l=0,0,"",#d + for i in d:gmatch(".") do + b=bit.bor(b,bit.lshift(string.byte(i),n)) + n=n+8 + if n>13 then + v=bit.band(b,8191) + if v>88 then + b=bit.rshift(b,13) + n=n-13 + else + v=bit.band(b,16383) + b=bit.rshift(b,14) + n=n-14 + end + o=o..b91enc[v % 91] .. b91enc[math.floor(v / 91)] + end + end + if n>0 then + o=o..b91enc[b % 91] + if n>7 or b>90 then + o=o .. b91enc[math.floor(b / 91)] + end + end + return o +end +return base91 diff --git a/game/bin/hashes/md5.lua b/game/bin/hashes/md5.lua new file mode 100644 index 0000000..7ffa55a --- /dev/null +++ b/game/bin/hashes/md5.lua @@ -0,0 +1,377 @@ +local md5 = { + _VERSION = "md5.lua 1.1.0", + _DESCRIPTION = "MD5 computation in Lua (5.1-3, LuaJIT)", + _URL = "https://github.com/kikito/md5.lua", + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software + ]] +} + +-- bit lib implementions + +local char, byte, format, rep, sub = + string.char, string.byte, string.format, string.rep, string.sub +local bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift + +local ok, bit = pcall(require, 'bit') +if ok then + bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift = bit.bor, bit.band, bit.bnot, bit.bxor, bit.rshift, bit.lshift +else + ok, bit = pcall(require, 'bit32') + + if ok then + + bit_not = bit.bnot + + local tobit = function(n) + return n <= 0x7fffffff and n or -(bit_not(n) + 1) + end + + local normalize = function(f) + return function(a,b) return tobit(f(tobit(a), tobit(b))) end + end + + bit_or, bit_and, bit_xor = normalize(bit.bor), normalize(bit.band), normalize(bit.bxor) + bit_rshift, bit_lshift = normalize(bit.rshift), normalize(bit.lshift) + + else + + local function tbl2number(tbl) + local result = 0 + local power = 1 + for i = 1, #tbl do + result = result + tbl[i] * power + power = power * 2 + end + return result + end + + local function expand(t1, t2) + local big, small = t1, t2 + if(#big < #small) then + big, small = small, big + end + -- expand small + for i = #small + 1, #big do + small[i] = 0 + end + end + + local to_bits -- needs to be declared before bit_not + + bit_not = function(n) + local tbl = to_bits(n) + local size = math.max(#tbl, 32) + for i = 1, size do + if(tbl[i] == 1) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + return tbl2number(tbl) + end + + -- defined as local above + to_bits = function (n) + if(n < 0) then + -- negative + return to_bits(bit_not(math.abs(n)) + 1) + end + -- to bits table + local tbl = {} + local cnt = 1 + local last + while n > 0 do + last = n % 2 + tbl[cnt] = last + n = (n-last)/2 + cnt = cnt + 1 + end + + return tbl + end + + bit_or = function(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + for i = 1, #tbl_m do + if(tbl_m[i]== 0 and tbl_n[i] == 0) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + + return tbl2number(tbl) + end + + bit_and = function(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + for i = 1, #tbl_m do + if(tbl_m[i]== 0 or tbl_n[i] == 0) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + + return tbl2number(tbl) + end + + bit_xor = function(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + for i = 1, #tbl_m do + if(tbl_m[i] ~= tbl_n[i]) then + tbl[i] = 1 + else + tbl[i] = 0 + end + end + + return tbl2number(tbl) + end + + bit_rshift = function(n, bits) + local high_bit = 0 + if(n < 0) then + -- negative + n = bit_not(math.abs(n)) + 1 + high_bit = 0x80000000 + end + + local floor = math.floor + + for i=1, bits do + n = n/2 + n = bit_or(floor(n), high_bit) + end + return floor(n) + end + + bit_lshift = function(n, bits) + if(n < 0) then + -- negative + n = bit_not(math.abs(n)) + 1 + end + + for i=1, bits do + n = n*2 + end + return bit_and(n, 0xFFFFFFFF) + end + end +end + +-- convert little-endian 32-bit int to a 4-char string +local function lei2str(i) + local f=function (s) return char( bit_and( bit_rshift(i, s), 255)) end + return f(0)..f(8)..f(16)..f(24) +end + +-- convert raw string to big-endian int +local function str2bei(s) + local v=0 + for i=1, #s do + v = v * 256 + byte(s, i) + end + return v +end + +-- convert raw string to little-endian int +local function str2lei(s) + local v=0 + for i = #s,1,-1 do + v = v*256 + byte(s, i) + end + return v +end + +-- cut up a string in little-endian ints of given size +local function cut_le_str(s,...) + local o, r = 1, {} + local args = {...} + for i=1, #args do + table.insert(r, str2lei(sub(s, o, o + args[i] - 1))) + o = o + args[i] + end + return r +end + +local swap = function (w) return str2bei(lei2str(w)) end + +-- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh) +-- 10/02/2001 jcw@equi4.com + +local CONSTS = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, + 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 +} + +local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end +local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end +local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end +local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end +local z=function (ff,a,b,c,d,x,s,ac) + a=bit_and(a+ff(b,c,d)+x+ac,0xFFFFFFFF) + -- be *very* careful that left shift does not cause rounding! + return bit_or(bit_lshift(bit_and(a,bit_rshift(0xFFFFFFFF,s)),s),bit_rshift(a,32-s))+b +end + +local function transform(A,B,C,D,X) + local a,b,c,d=A,B,C,D + local t=CONSTS + + a=z(f,a,b,c,d,X[ 0], 7,t[ 1]) + d=z(f,d,a,b,c,X[ 1],12,t[ 2]) + c=z(f,c,d,a,b,X[ 2],17,t[ 3]) + b=z(f,b,c,d,a,X[ 3],22,t[ 4]) + a=z(f,a,b,c,d,X[ 4], 7,t[ 5]) + d=z(f,d,a,b,c,X[ 5],12,t[ 6]) + c=z(f,c,d,a,b,X[ 6],17,t[ 7]) + b=z(f,b,c,d,a,X[ 7],22,t[ 8]) + a=z(f,a,b,c,d,X[ 8], 7,t[ 9]) + d=z(f,d,a,b,c,X[ 9],12,t[10]) + c=z(f,c,d,a,b,X[10],17,t[11]) + b=z(f,b,c,d,a,X[11],22,t[12]) + a=z(f,a,b,c,d,X[12], 7,t[13]) + d=z(f,d,a,b,c,X[13],12,t[14]) + c=z(f,c,d,a,b,X[14],17,t[15]) + b=z(f,b,c,d,a,X[15],22,t[16]) + + a=z(g,a,b,c,d,X[ 1], 5,t[17]) + d=z(g,d,a,b,c,X[ 6], 9,t[18]) + c=z(g,c,d,a,b,X[11],14,t[19]) + b=z(g,b,c,d,a,X[ 0],20,t[20]) + a=z(g,a,b,c,d,X[ 5], 5,t[21]) + d=z(g,d,a,b,c,X[10], 9,t[22]) + c=z(g,c,d,a,b,X[15],14,t[23]) + b=z(g,b,c,d,a,X[ 4],20,t[24]) + a=z(g,a,b,c,d,X[ 9], 5,t[25]) + d=z(g,d,a,b,c,X[14], 9,t[26]) + c=z(g,c,d,a,b,X[ 3],14,t[27]) + b=z(g,b,c,d,a,X[ 8],20,t[28]) + a=z(g,a,b,c,d,X[13], 5,t[29]) + d=z(g,d,a,b,c,X[ 2], 9,t[30]) + c=z(g,c,d,a,b,X[ 7],14,t[31]) + b=z(g,b,c,d,a,X[12],20,t[32]) + + a=z(h,a,b,c,d,X[ 5], 4,t[33]) + d=z(h,d,a,b,c,X[ 8],11,t[34]) + c=z(h,c,d,a,b,X[11],16,t[35]) + b=z(h,b,c,d,a,X[14],23,t[36]) + a=z(h,a,b,c,d,X[ 1], 4,t[37]) + d=z(h,d,a,b,c,X[ 4],11,t[38]) + c=z(h,c,d,a,b,X[ 7],16,t[39]) + b=z(h,b,c,d,a,X[10],23,t[40]) + a=z(h,a,b,c,d,X[13], 4,t[41]) + d=z(h,d,a,b,c,X[ 0],11,t[42]) + c=z(h,c,d,a,b,X[ 3],16,t[43]) + b=z(h,b,c,d,a,X[ 6],23,t[44]) + a=z(h,a,b,c,d,X[ 9], 4,t[45]) + d=z(h,d,a,b,c,X[12],11,t[46]) + c=z(h,c,d,a,b,X[15],16,t[47]) + b=z(h,b,c,d,a,X[ 2],23,t[48]) + + a=z(i,a,b,c,d,X[ 0], 6,t[49]) + d=z(i,d,a,b,c,X[ 7],10,t[50]) + c=z(i,c,d,a,b,X[14],15,t[51]) + b=z(i,b,c,d,a,X[ 5],21,t[52]) + a=z(i,a,b,c,d,X[12], 6,t[53]) + d=z(i,d,a,b,c,X[ 3],10,t[54]) + c=z(i,c,d,a,b,X[10],15,t[55]) + b=z(i,b,c,d,a,X[ 1],21,t[56]) + a=z(i,a,b,c,d,X[ 8], 6,t[57]) + d=z(i,d,a,b,c,X[15],10,t[58]) + c=z(i,c,d,a,b,X[ 6],15,t[59]) + b=z(i,b,c,d,a,X[13],21,t[60]) + a=z(i,a,b,c,d,X[ 4], 6,t[61]) + d=z(i,d,a,b,c,X[11],10,t[62]) + c=z(i,c,d,a,b,X[ 2],15,t[63]) + b=z(i,b,c,d,a,X[ 9],21,t[64]) + + return bit_and(A+a,0xFFFFFFFF),bit_and(B+b,0xFFFFFFFF), + bit_and(C+c,0xFFFFFFFF),bit_and(D+d,0xFFFFFFFF) +end + +---------------------------------------------------------------- + +local function md5_update(self, s) + self.pos = self.pos + #s + s = self.buf .. s + for ii = 1, #s - 63, 64 do + local X = cut_le_str(sub(s,ii,ii+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4) + assert(#X == 16) + X[0] = table.remove(X,1) -- zero based! + self.a,self.b,self.c,self.d = transform(self.a,self.b,self.c,self.d,X) + end + self.buf = sub(s, math.floor(#s/64)*64 + 1, #s) + return self +end + +local function md5_finish(self) + local msgLen = self.pos + local padLen = 56 - msgLen % 64 + + if msgLen % 64 > 56 then padLen = padLen + 64 end + + if padLen == 0 then padLen = 64 end + + local s = char(128) .. rep(char(0),padLen-1) .. lei2str(bit_and(8*msgLen, 0xFFFFFFFF)) .. lei2str(math.floor(msgLen/0x20000000)) + md5_update(self, s) + + assert(self.pos % 64 == 0) + return lei2str(self.a) .. lei2str(self.b) .. lei2str(self.c) .. lei2str(self.d) +end + +---------------------------------------------------------------- + +function md5.new() + return { a = CONSTS[65], b = CONSTS[66], c = CONSTS[67], d = CONSTS[68], + pos = 0, + buf = '', + update = md5_update, + finish = md5_finish } +end + +function md5.tohex(s) + return format("%08x%08x%08x%08x", str2bei(sub(s, 1, 4)), str2bei(sub(s, 5, 8)), str2bei(sub(s, 9, 12)), str2bei(sub(s, 13, 16))) +end + +function md5.sum(s) + return md5.new():update(s):finish() +end + +function md5.sumhexa(s) + return md5.tohex(md5.sum(s)) +end + +return md5 diff --git a/game/bin/init.lua b/game/bin/init.lua new file mode 100644 index 0000000..3728c6f --- /dev/null +++ b/game/bin/init.lua @@ -0,0 +1,739 @@ +bin={} +bin.Version={5,1,0} +bin.stage='stable' +bin.data='' +bin.t='bin' +bin.__index = bin +bin.__tostring=function(self) return self:getData() end +bin.__len=function(self) return self:getlength() end +bin.lastBlockSize=0 +bin.streams={} +-- Helpers +function bin.getVersion() + return bin.Version[1]..'.'..bin.Version[2]..'.'..bin.Version[3] +end +require("bin.support.utils") +if jit then + bit=require("bit") +elseif bit32 then + bit=bit32 +else + bit=require("bin.numbers.no_jit_bit") +end +base64=require("bin.converters.base64") +base91=require("bin.converters.base91") +bin.lzw=require("bin.compressors.lzw") -- A WIP +bits=require("bin.numbers.bits") +infinabits=require("bin.numbers.infinabits") -- like the bits library but works past 32 bits for 32bit lua and 64 bits for 64 bit lua. +bin.md5=require("bin.hashes.md5") +randomGen=require("bin.numbers.random") +function bin.setBitsInterface(int) + bin.defualtBit=int or bits +end +bin.setBitsInterface() +function bin.normalizeData(data) -- unified function to allow for all types to string + if type(data)=="string" then return data end + if type(data)=="table" then + if data.Type=="bin" or data.Type=="streamable" or data.Type=="buffer" then + return data:getData() + elseif data.Type=="bits" or data.Type=="infinabits" then + return data:toSbytes() + elseif data.Type=="sink" then + -- LATER + else + return "" + end + elseif type(data)=="userdata" then + if tostring(data):sub(1,4)=="file" then + local cur=data:seek("cur") + data:seek("set",0) + local dat=data:read("*a") + data:seek("set",cur) + return dat + else + error("File handles are the only userdata that can be used!") + end + end +end +function bin.resolveType(tab) -- used in getblock for auto object creation. Internal method + if tab.Type then + if tab.Type=="bin" then + return bin.new(tab.data) + elseif tab.Type=="streamable" then + if bin.fileExist(tab.file) then return nil,"Cannot load the stream file, source file does not exist!" end + return bin.stream(tab.file,tab.lock) + elseif tab.Type=="buffer" then + local buf=bin.newDataBuffer(tab.size) + buf[1]=tab:getData() + return buf + elseif tab.Type=="bits" then + local b=bits.new("") + b.data=tab.data + return b + elseif tab.Type=="infinabits" then + local b=infinabits.new("") + b.data=tab.data + return b + elseif tab.Type=="sink" then + return bin.newSync(tab.data) + else -- maybe a type from another library + return tab + end + else return tab end +end +function bin.fileExist(path) + g=io.open(path or '','r') + if path =='' then + p='empty path' + return nil + end + if g~=nil and true or false then + p=(g~=nil and true or false) + end + if g~=nil then + io.close(g) + else + return false + end + return p +end +function bin.toHex(str) + local str=bin.normalizeData(str) + return (str:gsub('.', function (c) + return string.format('%02X', string.byte(c)) + end)) +end +function bin.fromHex(str) + return (str:gsub('..', function (cc) + return string.char(tonumber(cc, 16)) + end)) +end +function bin.toBase64(s) + return base64.encode(s) +end +function bin.fromBase64(s) + return base64.decode(s) +end +function bin.toBase91(s) + return base91.encode(s) +end +function bin.fromBase91(s) + return base91.decode(s) +end +-- Constructors +function bin.new(data) + data=bin.normalizeData(data) + local c = {} + setmetatable(c, bin) + c.data=data + c.Type="bin" + c.t="bin" + c.pos=1 + c.stream=false + return c +end +function bin.newFromBase64(data) + return bin.new(bin.fromBase64(data)) +end +function bin.newFromBase91(data) + return bin.new(bin.fromBase91(data)) +end +function bin.newFromHex(data) + return bin.new(bin.fromHex(data)) +end +function bin.load(path) + if type(path) ~= "string" then error("Path must be a string!") end + local f = io.open(path, 'rb') + local content = f:read('*a') + f:close() + return bin.new(content) +end +function bin.stream(file,l) + if not(l==false) then l=true end + local c=bin.new() + c.Type="streamable" + c.t="streamable" + if bin.streams[file]~=nil then + c.file=file + c.lock = l + c.workingfile=bin.streams[file][1].workingfile + bin.streams[file][2]=bin.streams[file][2]+1 + c.stream=true + return c + end + if bin.fileExist(file) then + c.file=file + c.lock = l + c.workingfile=io.open(file,'rb+') + else + c.file=file + c.lock = l + c.workingfile=io.open(file,'w') + io.close(c.workingfile) + c.workingfile=io.open(file,'rb+') + end + c.stream=true + bin.streams[file]={c,1} + return c +end +function bin.newTempFile() + local c=bin.new() + c.file=file + c.lock = false + c.workingfile=io.tmpfile() + c.stream=true + return c +end +function bin.freshStream(file) + bin.new():tofile(file) + return bin.stream(file,false) +end +function bin.newStreamFileObject(file) + local c=bin.new() + c.Type="streamable" + c.t="streamable" + c.file="FILE_OBJECT" + c.lock = false + c.workingfile=file + c.stream=true + return c +end +-- Core Methods +function bin:canStreamWrite() + return (self.stream and not(self.lock)) +end +function bin:getSeek() + if self.stream then + return self.workingfile:seek("cur")+1 + else + return self.pos + end +end +function bin:setSeek(n) + if self.stream then + self.workingfile:seek("set",n-1) + else + self.pos=n + end +end +function bin:seek(n) + if self.stream then + if not n then return self.workingfile:seek("cur") end + local cur=self.workingfile:seek("cur") + self.workingfile:seek("set",cur+n) + else + if not n then return self.pos end + if #self.data-(self.pos-1)size then + data = data:sub(1,size) + elseif dsize255 then + nn=nn%256 + elseif nn<0 then + nn=256-math.abs(nn) + end + buf[i]=nn + end + self:setSeek(1) + self:write(buf:getData()) +end +function bin:getData(a,b,fmt) + local data="" + if a or b then + data=self:sub(a,b) + else + if self.stream then + local cur=self.workingfile:seek("cur") + self.workingfile:seek("set",0) + data=self.workingfile:read("*a") + self.workingfile:seek("set",cur) + else + data=self.data + end + end + if fmt=="%x" or fmt=="hex" then + return bin.toHex(data):lower() + elseif fmt=="%X" or fmt=="HEX" then + return bin.toHex(data) + elseif fmt=="%b" or fmt=="b64" then + return bin.toB64(data) + elseif fmt then + return bin.new(data):getBlock(fmt,#data) + end + return data +end +function bin:getSize(fmt) + local len=0 + if self.stream then + local cur=self.workingfile:seek("cur") + len=self.workingfile:seek("end") + self.workingfile:seek("set",cur) + else + len=#self.data + end + if fmt=="%b" then + return bin.toB64() + elseif fmt then + return string.format(fmt, len) + else + return len + end +end +function bin:tackE(data,size,h) + local data=bin.normalizeData(data) + local cur=self:getSize() + self:setSeek(self:getSize()+1) + self:write(data,size) + if h then + self:setSeek(cur+1) + end +end +function bin:tonumber(a,b) + local temp={} + if a then + temp.data=self:sub(a,b) + else + temp=self + end + local l,r=0,0 + local g=#temp.data + for i=1,g do + r=r+(256^(g-i))*string.byte(string.sub(temp.data,i,i)) + l=l+(256^(i-1))*string.byte(string.sub(temp.data,i,i)) + end + return r,l +end +function bin.endianflop(data) + return string.reverse(data) +end +function bin:tofile(name) + if self.stream then return end + if not name then error("Must include a filename to save as!") end + file = io.open(name, "wb") + file:write(self.data) + file:close() +end +function bin:close() + if self.stream then + if bin.streams[self.file][2]==1 then + bin.streams[self.file]=nil + self.workingfile:close() + else + bin.streams[self.file][2]=bin.streams[self.file][2]-1 + self.workingfile=io.tmpfile() + self.workingfile:close() + end + end +end +function bin:getBlock(t,n) + local data="" + if not n then + if bin.registerBlocks[t] then + return bin.registerBlocks[t][1](nil,self) + else + error("Unknown format! Cannot read from file: "..tostring(t)) + end + else + if t=="n" or t=="%e" or t=="%E" then + data=self:read(n) + local numB=bin.defualtBit.new(data) + local numL=bin.defualtBit.new(string.reverse(data)) + local little=numL:tonumber(0) + local big=numB:tonumber(0) + if t=="%E" then + return big + elseif t=="%X" then + return bin.toHex(data):upper() + elseif t=="%x" then + return bin.toHex(data):lower() + elseif t=="%b" then + return bin.toB64(data) + elseif t=="%e" then + return little + end + return big,little + elseif t=="s" then + return self:read(n) + elseif bin.registerBlocks[t] then + return bin.registerBlocks[t][1](n,self) + else + error("Unknown format! Cannot read from file: "..tostring(t)) + end + end +end +function bin:addBlock(d,fit,fmt) + if not fmt then fmt=type(d):sub(1,1) end + if bin.registerBlocks[fmt] then + self:tackE(bin.registerBlocks[fmt][2](d,fit,fmt,self,bin.registerBlocks[fmt][2])) + elseif type(d)=="number" then + local data=bin.defualtBit.numToBytes(d,fit or 4,fmt,function() + error("Overflow! Space allotted for number is smaller than the number takes up. Increase the fit!") + end) + self:tackE(data) + elseif type(d)=="string" then + local data=d:sub(1,fit or -1) + if #data<(fit or #data) then + data=data..string.rep("\0",fit-#data) + end + self:tackE(data) + end +end +bin.registerBlocks={} +function bin.registerBlock(t,funcG,funcA) + bin.registerBlocks[t]={funcG,funcA} +end +function bin.newDataBuffer(size,fill) -- fills with \0 or nul or with what you enter + local c={} + local fill=fill or "\0" + c.data={self=c} + c.Type="buffer" + c.size=size or 0 -- 0 means an infinite buffer, sometimes useful + for i=1,c.size do + c.data[i]=fill + end + local mt={ + __index=function(t,k) + if type(k)=="number" then + local data=t.data[k] + if data then + return string.byte(data) + else + error("Index out of range!") + end + elseif type(k)=="string" then + local num=tonumber(k) + if num then + local data=t.data[num] + if data then + return data + else + error("Index out of range!") + end + else + error("Only number-strings and numbers can be indexed!") + end + else + error("Only number-strings and numbers can be indexed!") + end + end, + __newindex=function(t,k,v) + if type(k)~="number" then error("Can only set a buffers data with a numeric index!") end + local data="" + if type(v)=="string" then + data=v + elseif type(v)=="number" then + data=string.char(v) + else + -- try to normalize the data of type v + data=bin.normalizeData(v) + end + t:fillBuffer(k,data) + end, + __tostring=function(t) + return t:getData() + end, + } + function c:fillBuffer(a,data) + local len=#data + if len==1 then + self.data[a]=data + else + local i=a-1 + for d in data:gmatch(".") do + i=i+1 + if i>c.size then + return #data-i+a + end + self.data[i]=d + end + return #data-i+(a-1) + end + end + function c:getData(a,b,fmt) -- LATER + local dat=bin.new(table.concat(self.data,"",a,b)) + local n=dat:getSize() + return dat:getBlock(fmt or "s",n) + end + function c:getSize() + return #self:getData() + end + setmetatable(c,mt) + return c +end +function bin:newDataBufferFromStream(pos,size,fill) -- fills with \0 or nul or with what you enter IF the nothing exists inside the bin file. + local s=self:getSize() + if not self.stream then error("Can only created a streamed buffer on a streamable file!") end + if s==0 then + self:write(string.rep("\0",pos+size)) + end + self:setSeek(1) + local c=bin.newDataBuffer(size,fill) + rawset(c,"pos",pos) + rawset(c,"size",size) + rawset(c,"fill",fill) + rawset(c,"bin",self) + rawset(c,"sync",function(self) + local cur=self.bin:getSeek() + self.bin:setSeek(self.pos) + self.bin:write(self:getData(),size) + self.bin:setSeek(cur) + end) + c:fillBuffer(1,self:sub(pos,pos+size)) + function c:fillBuffer(a,data) + local len=#data + if len==1 then + self.data[a]=data + self:sync() + else + local i=a-1 + for d in data:gmatch(".") do + i=i+1 + if i>c.size then + self:sync() + return #data-i+a + end + self.data[i]=d + end + self:sync() + return #data-i+(a-1) + end + end + return c +end +function bin:toDataBuffer() + local s=self:getSize() + -- if self:canStreamWrite() then + -- return self:newDataBufferFromStream(0,s) + -- end + local buf=bin.newDataBuffer(s) + local data=self:read(512) + local i=1 + while data~=nil do + buf[i]=data + data=self:read(512) + i=i+512 + end + return buf +end +function bin:getMD5Hash() + self:setSeek(1) + local len=self:getSize() + local md5=bin.md5.new() + local SIZE=2048 + if len>SIZE then + local dat=self:read(SIZE) + while dat~=nil do + md5:update(dat) + dat=self:read(SIZE) + end + return bin.md5.tohex(md5:finish()):upper() + else + return bin.md5.sumhexa(self:getData()):upper() + end +end +function bin:getHash() + if self:getSize()==0 then + return "NaN" + end + n=32 + local rand = randomGen:newND(1,self:getSize(),self:getSize()) + local h,g={},0 + for i=1,n do + g=rand:nextInt() + table.insert(h,bin.toHex(self:sub(g,g))) + end + return table.concat(h,'') +end +function bin:flipbits() + if self:canStreamWrite() then + self:setSeek(1) + for i=1,self:getSize() do + self:write(string.char(255-string.byte(self:sub(i,i)))) + end + else + local temp={} + for i=1,#self.data do + table.insert(temp,string.char(255-string.byte(string.sub(self.data,i,i)))) + end + self.data=table.concat(temp,'') + end +end +function bin:encrypt() + self:flipbits() +end +function bin:decrypt() + self:flipbits() +end +-- Use with small files! +function bin:gsub(...) + local data=self:getData() + local pos=self:getSeek() + self:setSeek(1) + self:write((data:gsub(...)) or data) + self:setSeek(loc) +end +function bin:gmatch(pat) + return self:getData():gmatch(pat) +end +function bin:match(pat) + return self:getData():match(pat) +end +function bin:trim() + local data=self:getData() + local pos=self:getSeek() + self:setSeek(1) + self:write(data:match'^()%s*$' and '' or data:match'^%s*(.*%S)') + self:setSeek(loc) +end +function bin:lines() + local t = {} + local function helper(line) table.insert(t, line) return '' end + helper((self:getData():gsub('(.-)\r?\n', helper))) + return t +end +function bin._lines(str) + local t = {} + local function helper(line) table.insert(t, line) return '' end + helper((str:gsub('(.-)\r?\n', helper))) + return t +end +function bin:wipe() + if self:canStreamWrite() then + self:close() + local c=bin.freshStream(self.file) + self.workingfile=c.workingfile + else + self.data="" + end + self:setSeek(1) +end +function bin:fullTrim(empty) + local t=self:lines() + for i=#t,1,-1 do + t[i]=bin._trim(t[i]) + if empty then + if t[i]=="" then + table.remove(t,i) + end + end + end + self:wipe() + self:write(table.concat(t,"\n")) +end +require("bin.support.extraBlocks") -- registered blocks that you can use +if love then + function bin.load(file,s,r) + content, size = love.filesystem.read(file) + local temp=bin.new(content) + temp.filepath=file + return temp + end + function bin:tofile(filename) + if not(filename) or self.Stream then return nil end + love.filesystem.write(filename,self.data) + end + function bin.stream(file) + return bin.newStreamFileObject(love.filesystem.newFile(file)) + end + function bin:getSize(fmt) + local len=0 + if self.stream then + local len=self.workingfile:getSize() + else + len=#self.data + end + if fmt=="%b" then + return bin.toB64() + elseif fmt then + return string.format(fmt, len) + else + return len + end + end + function bin:getSeek() + if self.stream then + return self.workingfile:tell()+1 + else + return self.pos + end + end + function bin:setSeek(n) + if self.stream then + self.workingfile:seek(n-1) + else + self.pos=n + end + end + function bin:seek(n) + if self.stream then + self.workingfile:seek(n) + else + if not n then return self.pos end + if #self.data-(self.pos-1) 0 then + for i = bnum.len - 2 , 0 , -1 do + for j = 0 , RADIX_LEN - string.len( bnum[i] ) - 1 do + temp = temp .. '0' ; + end + temp = temp .. bnum[i] ; + end + if bnum[bnum.len - 1]==nil then + return "nil" + end + temp = bnum[bnum.len - 1] .. temp ; + if bnum.signal == '-' then + temp = bnum.signal .. temp ; + end + return temp ; + else + return "" ; + end +end + +function BigNum.mt.pow( num1 , num2 ) + local bnum1 = BigNum.new( num1 ) ; + local bnum2 = BigNum.new( num2 ) ; + return BigNum.pow( bnum1 , bnum2 ) ; +end + +function BigNum.mt.eq( num1 , num2 ) + local bnum1 = BigNum.new( num1 ) ; + local bnum2 = BigNum.new( num2 ) ; + return BigNum.eq( bnum1 , bnum2 ) ; +end + +function BigNum.mt.lt( num1 , num2 ) + local bnum1 = BigNum.new( num1 ) ; + local bnum2 = BigNum.new( num2 ) ; + return BigNum.lt( bnum1 , bnum2 ) ; +end + +function BigNum.mt.le( num1 , num2 ) + local bnum1 = BigNum.new( num1 ) ; + local bnum2 = BigNum.new( num2 ) ; + return BigNum.le( bnum1 , bnum2 ) ; +end + +function BigNum.mt.unm( num ) + local ret = BigNum.new( num ) + if ret.signal == '+' then + ret.signal = '-' + else + ret.signal = '+' + end + return ret +end + +BigNum.mt.__metatable = "hidden" +BigNum.mt.__tostring = BigNum.mt.tostring ; +BigNum.mt.__add = BigNum.mt.add ; +BigNum.mt.__sub = BigNum.mt.sub ; +BigNum.mt.__mul = BigNum.mt.mul ; +BigNum.mt.__div = BigNum.mt.div ; +BigNum.mt.__pow = BigNum.mt.pow ; +BigNum.mt.__unm = BigNum.mt.unm ; +BigNum.mt.__mod = BigNum.mt.mod ; +BigNum.mt.__eq = BigNum.mt.eq ; +BigNum.mt.__le = BigNum.mt.le ; +BigNum.mt.__lt = BigNum.mt.lt ; +setmetatable( BigNum.mt, { __index = "inexistent field", __newindex = "not available", __metatable="hidden" } ) ; +function BigNum.add( bnum1 , bnum2 , bnum3 ) + local maxlen = 0 ; + local i = 0 ; + local carry = 0 ; + local signal = '+' ; + local old_len = 0 ; + --Handle the signals + if bnum1 == nil or bnum2 == nil or bnum3 == nil then + error("Function BigNum.add: parameter nil") ; + elseif bnum1.signal == '-' and bnum2.signal == '+' then + bnum1.signal = '+' ; + BigNum.sub( bnum2 , bnum1 , bnum3 ) ; + + if not rawequal(bnum1, bnum3) then + bnum1.signal = '-' ; + end + return 0 ; + elseif bnum1.signal == '+' and bnum2.signal == '-' then + bnum2.signal = '+' ; + BigNum.sub( bnum1 , bnum2 , bnum3 ) ; + if not rawequal(bnum2, bnum3) then + bnum2.signal = '-' ; + end + return 0 ; + elseif bnum1.signal == '-' and bnum2.signal == '-' then + signal = '-' ; + end + -- + old_len = bnum3.len ; + if bnum1.len > bnum2.len then + maxlen = bnum1.len ; + else + maxlen = bnum2.len ; + bnum1 , bnum2 = bnum2 , bnum1 ; + end + --School grade sum + for i = 0 , maxlen - 1 do + if bnum2[i] ~= nil then + bnum3[i] = bnum1[i] + bnum2[i] + carry ; + else + bnum3[i] = bnum1[i] + carry ; + end + if bnum3[i] >= RADIX then + bnum3[i] = bnum3[i] - RADIX ; + carry = 1 ; + else + carry = 0 ; + end + end + --Update the answer's size + if carry == 1 then + bnum3[maxlen] = 1 ; + end + bnum3.len = maxlen + carry ; + bnum3.signal = signal ; + for i = bnum3.len, old_len do + bnum3[i] = nil ; + end + return 0 ; +end + +function BigNum.sub( bnum1 , bnum2 , bnum3 ) + local maxlen = 0 ; + local i = 0 ; + local carry = 0 ; + local old_len = 0 ; + if bnum1 == nil or bnum2 == nil or bnum3 == nil then + error("Function BigNum.sub: parameter nil") ; + elseif bnum1.signal == '-' and bnum2.signal == '+' then + bnum1.signal = '+' ; + BigNum.add( bnum1 , bnum2 , bnum3 ) ; + bnum3.signal = '-' ; + if not rawequal(bnum1, bnum3) then + bnum1.signal = '-' ; + end + return 0 ; + elseif bnum1.signal == '-' and bnum2.signal == '-' then + bnum1.signal = '+' ; + bnum2.signal = '+' ; + BigNum.sub( bnum2, bnum1 , bnum3 ) ; + if not rawequal(bnum1, bnum3) then + bnum1.signal = '-' ; + end + if not rawequal(bnum2, bnum3) then + bnum2.signal = '-' ; + end + return 0 ; + elseif bnum1.signal == '+' and bnum2.signal == '-' then + bnum2.signal = '+' ; + BigNum.add( bnum1 , bnum2 , bnum3 ) ; + if not rawequal(bnum2, bnum3) then + bnum2.signal = '-' ; + end + return 0 ; + end + --Tests if bnum2 > bnum1 + if BigNum.compareAbs( bnum1 , bnum2 ) == 2 then + BigNum.sub( bnum2 , bnum1 , bnum3 ) ; + bnum3.signal = '-' ; + return 0 ; + else + maxlen = bnum1.len ; + end + old_len = bnum3.len ; + bnum3.len = 0 ; + --School grade subtraction + for i = 0 , maxlen - 1 do + if bnum2[i] ~= nil then + bnum3[i] = bnum1[i] - bnum2[i] - carry ; + else + bnum3[i] = bnum1[i] - carry ; + end + if bnum3[i] < 0 then + bnum3[i] = RADIX + bnum3[i] ; + carry = 1 ; + else + carry = 0 ; + end + + if bnum3[i] ~= 0 then + bnum3.len = i + 1 ; + end + end + bnum3.signal = '+' ; + --Check if answer's size if zero + if bnum3.len == 0 then + bnum3.len = 1 ; + bnum3[0] = 0 ; + end + if carry == 1 then + error( "Error in function sub" ) ; + end + for i = bnum3.len , max( old_len , maxlen - 1 ) do + bnum3[i] = nil ; + end + return 0 ; +end + +function BigNum.mul( bnum1 , bnum2 , bnum3 ) + local i = 0 ; j = 0 ; + local temp = BigNum.new( ) ; + local temp2 = 0 ; + local carry = 0 ; + local oldLen = bnum3.len ; + if bnum1 == nil or bnum2 == nil or bnum3 == nil then + error("Function BigNum.mul: parameter nil") ; + --Handle the signals + elseif bnum1.signal ~= bnum2.signal then + BigNum.mul( bnum1 , -bnum2 , bnum3 ) ; + bnum3.signal = '-' ; + return 0 ; + end + bnum3.len = ( bnum1.len ) + ( bnum2.len ) ; + --Fill with zeros + for i = 1 , bnum3.len do + bnum3[i - 1] = 0 ; + end + --Places nil where passes through this + for i = bnum3.len , oldLen do + bnum3[i] = nil ; + end + --School grade multiplication + for i = 0 , bnum1.len - 1 do + for j = 0 , bnum2.len - 1 do + carry = ( bnum1[i] * bnum2[j] + carry ) ; + carry = carry + bnum3[i + j] ; + bnum3[i + j] = ( carry % RADIX ) ; + temp2 = bnum3[i + j] ; + carry = math.floor ( carry / RADIX ) ; + end + if carry ~= 0 then + bnum3[i + bnum2.len] = carry ; + end + carry = 0 ; + end + + --Update the answer's size + for i = bnum3.len - 1 , 1 , -1 do + if bnum3[i] ~= nil and bnum3[i] ~= 0 then + break ; + else + bnum3[i] = nil ; + end + bnum3.len = bnum3.len - 1 ; + end + return 0 ; +end + +function BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) + local temp = BigNum.new() ; + local temp2 = BigNum.new() ; + local one = BigNum.new( "1" ) ; + local zero = BigNum.new( "0" ) ; + --Check division by zero + if BigNum.compareAbs( bnum2 , zero ) == 0 then + error( "Function BigNum.div: Division by zero" ) ; + end + --Handle the signals + if bnum1 == nil or bnum2 == nil or bnum3 == nil or bnum4 == nil then + error( "Function BigNum.div: parameter nil" ) ; + elseif bnum1.signal == "+" and bnum2.signal == "-" then + bnum2.signal = "+" ; + BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) ; + bnum2.signal = "-" ; + bnum3.signal = "-" ; + return 0 ; + elseif bnum1.signal == "-" and bnum2.signal == "+" then + bnum1.signal = "+" ; + BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) ; + bnum1.signal = "-" ; + if bnum4 < zero then --Check if remainder is negative + BigNum.add( bnum3 , one , bnum3 ) ; + BigNum.sub( bnum2 , bnum4 , bnum4 ) ; + end + bnum3.signal = "-" ; + return 0 ; + elseif bnum1.signal == "-" and bnum2.signal == "-" then + bnum1.signal = "+" ; + bnum2.signal = "+" ; + BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) ; + bnum1.signal = "-" ; + if bnum4 < zero then --Check if remainder is negative + BigNum.add( bnum3 , one , bnum3 ) ; + BigNum.sub( bnum2 , bnum4 , bnum4 ) ; + end + bnum2.signal = "-" ; + return 0 ; + end + temp.len = bnum1.len - bnum2.len - 1 ; + + --Reset variables + BigNum.change( bnum3 , "0" ) ; + BigNum.change( bnum4 , "0" ) ; + + BigNum.copy( bnum1 , bnum4 ) ; + + --Check if can continue dividing + while( BigNum.compareAbs( bnum4 , bnum2 ) ~= 2 ) do + if bnum4[bnum4.len - 1] >= bnum2[bnum2.len - 1] then + BigNum.put( temp , math.floor( bnum4[bnum4.len - 1] / bnum2[bnum2.len - 1] ) , bnum4.len - bnum2.len ) ; + temp.len = bnum4.len - bnum2.len + 1 ; + else + BigNum.put( temp , math.floor( ( bnum4[bnum4.len - 1] * RADIX + bnum4[bnum4.len - 2] ) / bnum2[bnum2.len -1] ) , bnum4.len - bnum2.len - 1 ) ; + temp.len = bnum4.len - bnum2.len ; + end + + if bnum4.signal ~= bnum2.signal then + temp.signal = "-"; + else + temp.signal = "+"; + end + BigNum.add( temp , bnum3 , bnum3 ) ; + temp = temp * bnum2 ; + BigNum.sub( bnum4 , temp , bnum4 ) ; + end + + --Update if the remainder is negative + if bnum4.signal == '-' then + decr( bnum3 ) ; + BigNum.add( bnum2 , bnum4 , bnum4 ) ; + end + return 0 ; +end + +function BigNum.pow( bnum1 , bnum2 ) + local n = BigNum.new( bnum2 ) ; + local y = BigNum.new( 1 ) ; + local z = BigNum.new( bnum1 ) ; + local zero = BigNum.new( "0" ) ; + if bnum2 < zero then + error( "Function BigNum.exp: domain error" ) ; + elseif bnum2 == zero then + return y ; + end + while 1 do + if ( n[0] % 2 ) == 0 then + n = n / 2 ; + else + n = n / 2 ; + y = z * y ; + if n == zero then + return y ; + end + end + z = z * z ; + end +end +-- Português : +BigNum.exp = BigNum.pow + +function BigNum.gcd( bnum1 , bnum2 ) + local a = {} ; + local b = {} ; + local c = {} ; + local d = {} ; + local zero = {} ; + zero = BigNum.new( "0" ) ; + if bnum1 == zero or bnum2 == zero then + return BigNum.new( "1" ) ; + end + a = BigNum.new( bnum1 ) ; + b = BigNum.new( bnum2 ) ; + a.signal = '+' ; + b.signal = '+' ; + c = BigNum.new() ; + d = BigNum.new() ; + while b > zero do + BigNum.div( a , b , c , d ) ; + a , b , d = b , d , a ; + end + return a ; +end +-- Português: +BigNum.mmc = BigNum.gcd + +function BigNum.eq( bnum1 , bnum2 ) + if BigNum.compare( bnum1 , bnum2 ) == 0 then + return true ; + else + return false ; + end +end + +function BigNum.lt( bnum1 , bnum2 ) + if BigNum.compare( bnum1 , bnum2 ) == 2 then + return true ; + else + return false ; + end +end + +function BigNum.le( bnum1 , bnum2 ) + local temp = -1 ; + temp = BigNum.compare( bnum1 , bnum2 ) + if temp == 0 or temp == 2 then + return true ; + else + return false ; + end +end + +function BigNum.compareAbs( bnum1 , bnum2 ) + if bnum1 == nil or bnum2 == nil then + error("Function compare: parameter nil") ; + elseif bnum1.len > bnum2.len then + return 1 ; + elseif bnum1.len < bnum2.len then + return 2 ; + else + local i ; + for i = bnum1.len - 1 , 0 , -1 do + if bnum1[i] > bnum2[i] then + return 1 ; + elseif bnum1[i] < bnum2[i] then + return 2 ; + end + end + end + return 0 ; +end + +function BigNum.compare( bnum1 , bnum2 ) + local signal = 0 ; + + if bnum1 == nil or bnum2 == nil then + error("Funtion BigNum.compare: parameter nil") ; + elseif bnum1.signal == '+' and bnum2.signal == '-' then + return 1 ; + elseif bnum1.signal == '-' and bnum2.signal == '+' then + return 2 ; + elseif bnum1.signal == '-' and bnum2.signal == '-' then + signal = 1 ; + end + if bnum1.len > bnum2.len then + return 1 + signal ; + elseif bnum1.len < bnum2.len then + return 2 - signal ; + else + local i ; + for i = bnum1.len - 1 , 0 , -1 do + if bnum1[i] > bnum2[i] then + return 1 + signal ; + elseif bnum1[i] < bnum2[i] then + return 2 - signal ; + end + end + end + return 0 ; +end + +function BigNum.copy( bnum1 , bnum2 ) + if bnum1 ~= nil and bnum2 ~= nil then + local i ; + for i = 0 , bnum1.len - 1 do + bnum2[i] = bnum1[i] ; + end + bnum2.len = bnum1.len ; + else + error("Function BigNum.copy: parameter nil") ; + end +end + +function BigNum.change( bnum1 , num ) + local j = 0 ; + local len = 0 ; + local num = num ; + local l ; + local oldLen = 0 ; + if bnum1 == nil then + error( "BigNum.change: parameter nil" ) ; + elseif type( bnum1 ) ~= "table" then + error( "BigNum.change: parameter error, type unexpected" ) ; + elseif num == nil then + bnum1.len = 1 ; + bnum1[0] = 0 ; + bnum1.signal = "+"; + elseif type( num ) == "table" and num.len ~= nil then --check if num is a big number + --copy given table to the new one + for i = 0 , num.len do + bnum1[i] = num[i] ; + end + if num.signal ~= '-' and num.signal ~= '+' then + bnum1.signal = '+' ; + else + bnum1.signal = num.signal ; + end + oldLen = bnum1.len ; + bnum1.len = num.len ; + elseif type( num ) == "string" or type( num ) == "number" then + if string.sub( num , 1 , 1 ) == '+' or string.sub( num , 1 , 1 ) == '-' then + bnum1.signal = string.sub( num , 1 , 1 ) ; + num = string.sub(num, 2) ; + else + bnum1.signal = '+' ; + end + num = string.gsub( num , " " , "" ) ; + local sf = string.find( num , "e" ) ; + --Handles if the number is in exp notation + if sf ~= nil then + num = string.gsub( num , "%." , "" ) ; + local e = string.sub( num , sf + 1 ) ; + e = tonumber(e) ; + if e ~= nil and e > 0 then + e = tonumber(e) ; + else + error( "Function BigNum.change: string is not a valid number" ) ; + end + num = string.sub( num , 1 , sf - 2 ) ; + for i = string.len( num ) , e do + num = num .. "0" ; + end + else + sf = string.find( num , "%." ) ; + if sf ~= nil then + num = string.sub( num , 1 , sf - 1 ) ; + end + end + + l = string.len( num ) ; + oldLen = bnum1.len ; + if (l > RADIX_LEN) then + local mod = l-( math.floor( l / RADIX_LEN ) * RADIX_LEN ) ; + for i = 1 , l-mod, RADIX_LEN do + bnum1[j] = tonumber( string.sub( num, -( i + RADIX_LEN - 1 ) , -i ) ); + --Check if string dosn't represents a number + if bnum1[j] == nil then + error( "Function BigNum.change: string is not a valid number" ) ; + bnum1.len = 0 ; + return 1 ; + end + j = j + 1 ; + len = len + 1 ; + end + if (mod ~= 0) then + bnum1[j] = tonumber( string.sub( num , 1 , mod ) ) ; + bnum1.len = len + 1 ; + else + bnum1.len = len ; + end + --Eliminate trailing zeros + for i = bnum1.len - 1 , 1 , -1 do + if bnum1[i] == 0 then + bnum1[i] = nil ; + bnum1.len = bnum1.len - 1 ; + else + break ; + end + end + + else + -- string.len(num) <= RADIX_LEN + bnum1[j] = tonumber( num ) ; + bnum1.len = 1 ; + end + else + error( "Function BigNum.change: parameter error, type unexpected" ) ; + end + + --eliminates the deprecated higher order 'algarisms' + if oldLen ~= nil then + for i = bnum1.len , oldLen do + bnum1[i] = nil ; + end + end + + return 0 ; +end + +function BigNum.put( bnum , int , pos ) + if bnum == nil then + error("Function BigNum.put: parameter nil") ; + end + local i = 0 ; + for i = 0 , pos - 1 do + bnum[i] = 0 ; + end + bnum[pos] = int ; + for i = pos + 1 , bnum.len do + bnum[i] = nil ; + end + bnum.len = pos ; + return 0 ; +end + +--printraw{{{2 +function printraw( bnum ) + local i = 0 ; + if bnum == nil then + error( "Function printraw: parameter nil" ) ; + end + while 1 == 1 do + if bnum[i] == nil then + io.write( ' len '..bnum.len ) ; + if i ~= bnum.len then + io.write( ' ERRO!!!!!!!!' ) ; + end + io.write( "\n" ) ; + return 0 ; + end + io.write( 'r'..bnum[i] ) ; + i = i + 1 ; + end +end +--max{{{2 +function max( int1 , int2 ) + if int1 > int2 then + return int1 ; + else + return int2 ; + end +end + +--decr{{{2 +function decr( bnum1 ) + local temp = {} ; + temp = BigNum.new( "1" ) ; + BigNum.sub( bnum1 , temp , bnum1 ) ; + return 0 ; +end diff --git a/game/bin/numbers/BigRat.lua b/game/bin/numbers/BigRat.lua new file mode 100644 index 0000000..40e9777 --- /dev/null +++ b/game/bin/numbers/BigRat.lua @@ -0,0 +1,227 @@ +require( "bin.numbers.BigNum" ) ; + +BigRat = {} ; +BigRat.mt = {} ; +function BigRat.new( num1 , num2 ) --{{{2 + local bigrat = {} ; + local f ; + setmetatable(bigrat, BigRat.mt) ; + if type( num1 ) == "table" then + if num1.num ~= nil and num1.den ~= nil then + bigrat.num = BigNum.new( num1.num ) ; + bigrat.den = BigNum.new( num1.den ) ; + else + bigrat.num = BigNum.new( num1 ) ; + bigrat.den = BigNum.new( "1" ) ; + end + elseif num1 ~= nil then + if num2 == nil then + bigrat.den = BigNum.new( "1" ) ; + else + bigrat.den = BigNum.new( num2 ) ; + end + bigrat.num = BigNum.new( num1 ) ; + else + bigrat.den = BigNum.new( ) ; + bigrat.num = BigNum.new( ) ; + end + + --Update the signals + if bigrat.den.signal == "-" then + if bigrat.num.signal == "-" then + bigrat.num.signal = "+" ; + else + bigrat.num.signal = "-" ; + end + bigrat.den.signal = "+" ; + end + + return bigrat ; +end + +function BigRat.mt.sub( num1 , num2 ) + local temp = BigRat.new() ; + local brat1 = BigRat.new( num1 ) ; + local brat2 = BigRat.new( num2 ) ; + BigRat.sub( brat1 , brat2 , temp ) ; + return temp ; +end + +function BigRat.mt.add( num1 , num2 ) + local temp = BigRat.new() ; + local brat1 = BigRat.new( num1 ) ; + local brat2 = BigRat.new( num2 ) ; + BigRat.add( brat1 , brat2 , temp ) ; + return temp ; +end + +function BigRat.mt.mul( num1 , num2 ) + local temp = BigRat.new() ; + local brat1 = BigRat.new( num1 ) ; + local brat2 = BigRat.new( num2 ) ; + BigRat.mul( brat1 , brat2 , temp ) ; + return temp ; +end + +function BigRat.mt.div( num1 , num2 ) + local brat1 = BigRat.new( num1 ) ; + local brat2 = BigRat.new( num2 ) ; + local brat3 = BigRat.new() ; + local brat4 = BigRat.new() ; + BigRat.div( brat1 , brat2 , brat3 , brat4 ) ; + return brat3 , brat4 ; +end + +function BigRat.mt.tostring( brat ) + BigRat.simplify( brat ) ; + return BigNum.mt.tostring( brat.num ) .. " / " .. BigNum.mt.tostring( brat.den ) ; +end + +function BigRat.mt.pow ( num1 , num2 ) + local brat1 = BigRat.new( num1 ) ; + local brat2 = BigRat.new( num2 ) ; + return BigRat.pow( brat1 , brat2 ) +end + +function BigRat.mt.eq ( num1 , num2 ) + return BigRat.eq( num1 , num2 ) +end + +function BigRat.mt.lt ( num1 , num2 ) + return BigRat.lt( num1 , num2 ) +end + +function BigRat.mt.le ( num1 , num2 ) + return BigRat.le( num1 , num2 ) +end + +function BigRat.mt.unm ( num ) + local ret = BigRat.new( num ) + if ret.num.signal == '-' then + ret.num.signal = '+' + else + ret.num.signal = '-' + end + return ret +end + +BigRat.mt.__metatable = "hidden" +BigRat.mt.__tostring = BigRat.mt.tostring +BigRat.mt.__add = BigRat.mt.add +BigRat.mt.__sub = BigRat.mt.sub +BigRat.mt.__mul = BigRat.mt.mul +BigRat.mt.__div = BigRat.mt.div +BigRat.mt.__pow = BigRat.mt.pow +BigRat.mt.__unm = BigRat.mt.unm +BigRat.mt.__eq = BigRat.mt.eq +BigRat.mt.__le = BigRat.mt.le +BigRat.mt.__lt = BigRat.mt.lt +setmetatable( BigRat.mt, { __index = "inexistent field", __newindex = "not available", __metatable="hidden" } ) ; +function BigRat.add( brat1 , brat2 , brat3 ) + brat3.den = brat1.den * brat2.den ; + brat3.num = ( brat1.num * brat2.den ) + ( brat2.num * brat1.den ) ; + return brat3 ; +end +function BigRat.sub( brat1 , brat2 , brat3 ) + brat3.den = brat1.den * brat2.den ; + brat3.num = ( brat1.num * brat2.den ) - ( brat2.num * brat1.den ) ; + return brat3 ; +end + +function BigRat.mul( brat1 , brat2 , brat3 ) + brat3.num = brat1.num * brat2.num ; + brat3.den = brat1.den * brat2.den ; + return 0 ; +end + +function BigRat.div( brat1 , brat2 , brat3 ) + brat3.num = brat1.num * brat2.den ; + brat3.den = brat1.den * brat2.num ; + return brat3 ; +end + +function BigRat.pow( bnum1 , bnum2 ) + if bnum1 == nil or bnum2 == nil then + error( "Function BigRat.pow: parameter nil" ) ; + end + local x = BigRat.new( "8" ) ; + local n = BigRat.new( bnum2.den ) ; + local n2 ; + local y = BigRat.new( ) ; + local i ; + local temp = BigRat.new( ) ; + + BigRat.simplify( bnum2 ) ; + temp.num = BigNum.exp( bnum1.num , bnum2.num ) ; + temp.den = BigNum.exp( bnum1.den , bnum2.num ) ; + n2 = n - 1 ; + + for i = 0 , 4 do + y.num = x.num ^ n2.num ; + y.den = x.den ^ n2.num ; + x = (( temp / y ) + ( n2 * x )) / n ; + end + return x ; +end + +function BigRat.simplify( brat ) + if brat == nil then + error( "Function BigRat.simplify: parameter nil" ) ; + end + local gcd = BigNum.new( ) ; + local temp = BigRat.new( brat ) ; + local devnull = BigNum.new( ) ; + local zero = BigNum.new( "0" ) ; + --Check if numerator is zero + if BigNum.compareAbs( brat.num , zero ) == 0 then + brat.den = BigNum.new( "1" ) ; + return 0 ; + end + gcd = BigNum.gcd( brat.num , brat.den ) ; + BigNum.div( temp.num , gcd , brat.num , devnull ) ; + BigNum.div( temp.den , gcd , brat.den , devnull ) ; + --Update the signal + if brat.num.signal == '-' and brat.den.signal == '-' then + brat.num.signal = '+' ; + brat.den.signal = '+' ; + end + return 0 ; +end + +function BigRat.eq( brat1 , brat2 ) + if BigRat.compare( brat1 , brat2 ) == 0 then + return true ; + else + return false ; + end +end + +function BigRat.lt( brat1 , brat2 ) + if BigRat.compare( brat1 , brat2 ) == 2 then + return true ; + else + return false ; + end +end + +function BigRat.le( brat1 , brat2 ) + local temp = -1 ; + temp = BigRat.compare( brat1 , brat2 ) + if temp == 0 or temp == 2 then + return true ; + else + return false ; + end +end + +function BigRat.compare( bnum1 , bnum2 ) + local temp ; + temp = bnum1 - bnum2 ; + if temp.num[0] == 0 and temp.num.len == 1 then --Check if is zero + return 0 ; + elseif temp.num.signal == "-" then + return 2 ; + else + return 1 ; + end +end diff --git a/game/bin/numbers/bits.lua b/game/bin/numbers/bits.lua new file mode 100644 index 0000000..579f320 --- /dev/null +++ b/game/bin/numbers/bits.lua @@ -0,0 +1,191 @@ +local bits={} +bits.data='' +bits.t='bits' +bits.Type='bits' +bits.__index = bits +bits.__tostring=function(self) return self.data end +bits.__len=function(self) return (#self.data)/8 end +local floor,insert = math.floor, table.insert +function bits.newBitBuffer(n) + -- +end +function bits.newConverter(bitsIn,bitsOut) + local c={} + -- +end +function basen(n,b) + if not b or b == 10 then return tostring(n) end + local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + local t = {} + local sign = "" + if n < 0 then + sign = "-" + n = -n + end + repeat + local d = n % b + 1 + n = n / b + insert(t, 1, digits:sub(d,d)) + until n == 0 + return sign .. table.concat(t,"") +end +bits.ref={} +function bits.newByte(d) + local c={} + if type(d)=="string" then + if #d>1 or #d<1 then + error("A byte must be one character!") + else + c.data=string.byte(d) + end + elseif type(d)=="number" then + if d>255 or d<0 then + error("A byte must be between 0 and 255!") + else + c.data=d + end + else + error("cannot use type "..type(d).." as an argument! Takes only strings or numbers!") + end + c.__index=function(self,k) + if k>=0 and k<9 then + if self.data==0 then + return 0 + elseif self.data==255 then + return 1 + else + return bits.ref[self.data][k] + end + end + end + c.__tostring=function(self) + return bits.ref[tostring(self.data)] + end + setmetatable(c,c) + return c +end +function bits.newByteArray(s) + local c={} + if type(s)~="string" then + error("Must be a string type or bin/buffer type") + elseif type(s)=="table" then + if s.t=="sink" or s.t=="buffer" or s.t=="bin" then + local data=s:getData() + for i=1,#data do + c[#c+1]=bits.newByte(data:sub(i,i)) + end + else + error("Must be a string type or bin/buffer type") + end + else + for i=1,#s do + c[#c+1]=bits.newByte(s:sub(i,i)) + end + end + return c +end +function bits.new(n,binary) + local temp={} + temp.t="bits" + temp.Type="bits" + if type(n)=="string" then + if binary then + temp.data=n:match("[10]+") + else + local t={} + for i=#n,1,-1 do + table.insert(t,bits:conv(string.byte(n,i))) + end + temp.data=table.concat(t) + end + elseif type(n)=="number" or type(n)=="table" then + temp.data=basen(n,2) + end + if #temp.data%8~=0 then + temp.data=string.rep('0',8-#temp.data%8)..temp.data + end + setmetatable(temp, bits) + return temp +end +for i=0,255 do + local d=bits.new(i).data + bits.ref[i]={d:match("(%d)(%d)(%d)(%d)(%d)(%d)(%d)(%d)")} + bits.ref[tostring(i)]=d + bits.ref[d]=i + bits.ref["\255"..string.char(i)]=d +end +function bits.numToBytes(n,fit,func) + local num=string.reverse(bits.new(n):toSbytes()) + local ref={["num"]=num,["fit"]=fit} + if fit then + if fit<#num then + if func then + print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!") + func(ref) + else + print("Warning: attempting to store a number that takes up more space than allotted!") + end + return ref.num:sub(1,ref.fit) + elseif fit==#num then + return string.reverse(num) + else + return string.reverse(string.rep("\0",fit-#num)..num) + end + else + return string.reverse(num) + end +end +function bits:conv(n) + local tab={} + while n>=1 do + table.insert(tab,n%2) + n=math.floor(n/2) + end + local str=string.reverse(table.concat(tab)) + if #str%8~=0 or #str==0 then + str=string.rep('0',8-#str%8)..str + end + return str +end +function bits:tonumber(s,e) + if s==0 then + return tonumber(self.data,2) + end + s=s or 1 + return tonumber(string.sub(self.data,(8*(s-1))+1,8*s),2) or error('Bounds!') +end +function bits:isover() + return #self.data>8 +end +function bits:flipbits() + tab={} + for i=1,#self.data do + if string.sub(self.data,i,i)=='1' then + table.insert(tab,'0') + else + table.insert(tab,'1') + end + end + self.data=table.concat(tab) +end +function bits:tobytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return bin.new(table.concat(tab)) +end +function bits:toSbytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return table.concat(tab) +end +function bits:getBin() + return self.data +end +function bits:getbytes() + return #self.data/8 +end +return bits diff --git a/game/bin/numbers/infinabits.lua b/game/bin/numbers/infinabits.lua new file mode 100644 index 0000000..69c45ff --- /dev/null +++ b/game/bin/numbers/infinabits.lua @@ -0,0 +1,244 @@ +local binNum=require("bin.numbers.BigNum") +local infinabits={} +infinabits.data='' +infinabits.t='infinabits' +infinabits.Type='infinabits' +infinabits.__index = infinabits +infinabits.__tostring=function(self) return self.data end +infinabits.__len=function(self) return (#self.data)/8 end +local floor,insert = math.floor, table.insert +function basen(n,b) + n=BigNum.new(n) + if not b or b == 10 then return tostring(n) end + local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + local t = {} + local sign = "" + if n < BigNum.new(0) then + sign = "-" + n = -n + end + repeat + local d = tonumber(tostring(n % b)) + 1 + n = n / b + insert(t, 1, digits:sub(d,d)) + until n == BigNum.new(0) + return sign .. table.concat(t,"") +end +function base2to10(num) + local n=BigNum.new(0) + for i = #num-1,0,-1 do + nn=BigNum.new(num:sub(i+1,i+1))*(BigNum.new(2)^((#num-i)-1)) + n=n+nn + end + return n +end +function infinabits.newBitBuffer(n) + -- WIP +end +function infinabits.newConverter(bitsIn,bitsOut) + local c={} + -- WIP +end +infinabits.ref={} +function infinabits.newByte(d)-- WIP + local c={} + if type(d)=="string" then + if #d>1 or #d<1 then + error("A byte must be one character!") + else + c.data=string.byte(d) + end + elseif type(d)=="number" then + if d>255 or d<0 then + error("A byte must be between 0 and 255!") + else + c.data=d + end + else + error("cannot use type "..type(d).." as an argument! Takes only strings or numbers!") + end + c.__index=function(self,k) + if k>=0 and k<9 then + if self.data==0 then + return 0 + elseif self.data==255 then + return 1 + else + return infinabits.ref[self.data][k] + end + end + end + c.__tostring=function(self) + return infinabits.ref[tostring(self.data)] + end + setmetatable(c,c) + return c +end +function infinabits.newByteArray(s)-- WIP + local c={} + if type(s)~="string" then + error("Must be a string type or bin/buffer type") + elseif type(s)=="table" then + if s.t=="sink" or s.t=="buffer" or s.t=="bin" then + local data=s:getData() + for i=1,#data do + c[#c+1]=infinabits.newByte(data:sub(i,i)) + end + else + error("Must be a string type or bin/buffer type") + end + else + for i=1,#s do + c[#c+1]=infinabits.newByte(s:sub(i,i)) + end + end + return c +end +function infinabits.new(n,binary) + local temp={} + temp.t="infinabits" + temp.Type="infinabits" + if type(n)=="string" then + if binary then + temp.data=n:match("[10]+") + else + local t={} + for i=#n,1,-1 do + table.insert(t,infinabits:conv(string.byte(n,i))) + end + temp.data=table.concat(t) + end + elseif type(n)=="number" or type(n)=="table" then + temp.data=basen(tostring(n),2) + end + if #temp.data%8~=0 then + temp.data=string.rep('0',8-#temp.data%8)..temp.data + end + setmetatable(temp, infinabits) + return temp +end +for i=0,255 do + local d=infinabits.new(i).data + infinabits.ref[i]={d:match("(%d)(%d)(%d)(%d)(%d)(%d)(%d)(%d)")} + infinabits.ref[tostring(i)]=d + infinabits.ref[d]=i + infinabits.ref["\255"..string.char(i)]=d +end +function infinabits.numToBytes(n,fit,func) + local num=string.reverse(infinabits.new(BigNum.new(n)):toSbytes()) + local ref={["num"]=num,["fit"]=fit} + if fit then + if fit<#num then + if func then + print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!") + func(ref) + else + print("Warning: attempting to store a number that takes up more space than allotted!") + end + return ref.num:sub(1,ref.fit) + elseif fit==#num then + return string.reverse(num) + else + return string.reverse(string.rep("\0",fit-#num)..num) + end + else + return string.reverse(num) + end +end +function infinabits.numToBytes(n,fit,fmt,func) + if fmt=="%e" then + local num=string.reverse(infinabits.new(BigNum.new(n)):toSbytes()) + local ref={["num"]=num,["fit"]=fit} + if fit then + if fit<#num then + if func then + print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!") + func(ref) + else + print("Warning: attempting to store a number that takes up more space than allotted!") + end + return ref.num:sub(1,ref.fit) + elseif fit==#num then + return num + else + return string.rep("\0",fit-#num)..num + end + else + return num + end + + else + local num=string.reverse(infinabits.new(BigNum.new(n)):toSbytes()) + local ref={["num"]=num,["fit"]=fit} + if fit then + if fit<#num then + if func then + print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!") + func(ref) + else + print("Warning: attempting to store a number that takes up more space than allotted!") + end + return ref.num:sub(1,ref.fit) + elseif fit==#num then + return string.reverse(num) + else + return string.reverse(string.rep("\0",fit-#num)..num) + end + else + return string.reverse(num) + end + end +end +function infinabits:conv(n) + local tab={} + local one=BigNum.new(1) + local n=BigNum.new(n) + while n>=one do + table.insert(tab,tonumber(tostring(n%2))) + n=n/2 + end + local str=string.reverse(table.concat(tab)) + if #str%8~=0 or #str==0 then + str=string.rep('0',8-#str%8)..str + end + return str +end +function infinabits:tonumber(s) + if s==0 then + return tonumber(self.data,2) + end + s=s or 1 + return tonumber(tostring(base2to10(string.sub(self.data,(8*(s-1))+1,8*s)))) or error('Bounds!') +end +function infinabits:isover() + return #self.data>8 +end +function infinabits:flipbits() + tab={} + local s=self.data + s=s:gsub("1","_") + s=s:gsub("0","1") + s=s:gsub("_","0") + self.data=s +end +function infinabits:tobytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return bin.new(table.concat(tab)) +end +function infinabits:toSbytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return table.concat(tab) +end +function infinabits:getBin() + return self.data +end +function infinabits:getbytes() + return #self.data/8 +end +return infinabits diff --git a/game/bin/numbers/no_jit_bit.lua b/game/bin/numbers/no_jit_bit.lua new file mode 100644 index 0000000..2cfdc1d --- /dev/null +++ b/game/bin/numbers/no_jit_bit.lua @@ -0,0 +1,333 @@ +--[[ +LICENSE + + (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT). +--]] + +local M = {_TYPE='module', _NAME='bit.numberlua', _VERSION='0.3.1.20120131'} + +local floor = math.floor + +local MOD = 2^32 +local MODM = MOD-1 + +local function memoize(f) + local mt = {} + local t = setmetatable({}, mt) + function mt:__index(k) + local v = f(k); t[k] = v + return v + end + return t +end + +local function make_bitop_uncached(t, m) + local function bitop(a, b) + local res,p = 0,1 + while a ~= 0 and b ~= 0 do + local am, bm = a%m, b%m + res = res + t[am][bm]*p + a = (a - am) / m + b = (b - bm) / m + p = p*m + end + res = res + (a+b)*p + return res + end + return bitop +end + +local function make_bitop(t) + local op1 = make_bitop_uncached(t,2^1) + local op2 = memoize(function(a) + return memoize(function(b) + return op1(a, b) + end) + end) + return make_bitop_uncached(op2, 2^(t.n or 1)) +end + +-- ok? probably not if running on a 32-bit int Lua number type platform +function M.tobit(x) + return x % 2^32 +end + +M.bxor = make_bitop {[0]={[0]=0,[1]=1},[1]={[0]=1,[1]=0}, n=4} +local bxor = M.bxor + +function M.bnot(a) return MODM - a end +local bnot = M.bnot + +function M.band(a,b) return ((a+b) - bxor(a,b))/2 end +local band = M.band + +function M.bor(a,b) return MODM - band(MODM - a, MODM - b) end +local bor = M.bor + +local lshift, rshift -- forward declare + +function M.rshift(a,disp) -- Lua5.2 insipred + if disp < 0 then return lshift(a,-disp) end + return floor(a % 2^32 / 2^disp) +end +rshift = M.rshift + +function M.lshift(a,disp) -- Lua5.2 inspired + if disp < 0 then return rshift(a,-disp) end + return (a * 2^disp) % 2^32 +end +lshift = M.lshift + +function M.tohex(x, n) -- BitOp style + n = n or 8 + local up + if n <= 0 then + if n == 0 then return '' end + up = true + n = - n + end + x = band(x, 16^n-1) + return ('%0'..n..(up and 'X' or 'x')):format(x) +end +local tohex = M.tohex + +function M.extract(n, field, width) -- Lua5.2 inspired + width = width or 1 + return band(rshift(n, field), 2^width-1) +end +local extract = M.extract + +function M.replace(n, v, field, width) -- Lua5.2 inspired + width = width or 1 + local mask1 = 2^width-1 + v = band(v, mask1) -- required by spec? + local mask = bnot(lshift(mask1, field)) + return band(n, mask) + lshift(v, field) +end +local replace = M.replace + +function M.bswap(x) -- BitOp style + local a = band(x, 0xff); x = rshift(x, 8) + local b = band(x, 0xff); x = rshift(x, 8) + local c = band(x, 0xff); x = rshift(x, 8) + local d = band(x, 0xff) + return lshift(lshift(lshift(a, 8) + b, 8) + c, 8) + d +end +local bswap = M.bswap + +function M.rrotate(x, disp) -- Lua5.2 inspired + disp = disp % 32 + local low = band(x, 2^disp-1) + return rshift(x, disp) + lshift(low, 32-disp) +end +local rrotate = M.rrotate + +function M.lrotate(x, disp) -- Lua5.2 inspired + return rrotate(x, -disp) +end +local lrotate = M.lrotate + +M.rol = M.lrotate -- LuaOp inspired +M.ror = M.rrotate -- LuaOp insipred + + +function M.arshift(x, disp) -- Lua5.2 inspired + local z = rshift(x, disp) + if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end + return z +end +local arshift = M.arshift + +function M.btest(x, y) -- Lua5.2 inspired + return band(x, y) ~= 0 +end + +M.bit32 = {} -- Lua 5.2 'bit32' compatibility + + +local function bit32_bnot(x) + return (-1 - x) % MOD +end +M.bit32.bnot = bit32_bnot + +local function bit32_bxor(a, b, c, ...) + local z + if b then + a = a % MOD + b = b % MOD + z = bxor(a, b) + if c then + z = bit32_bxor(z, c, ...) + end + return z + elseif a then + return a % MOD + else + return 0 + end +end +M.bit32.bxor = bit32_bxor + +local function bit32_band(a, b, c, ...) + local z + if b then + a = a % MOD + b = b % MOD + z = ((a+b) - bxor(a,b)) / 2 + if c then + z = bit32_band(z, c, ...) + end + return z + elseif a then + return a % MOD + else + return MODM + end +end +M.bit32.band = bit32_band + +local function bit32_bor(a, b, c, ...) + local z + if b then + a = a % MOD + b = b % MOD + z = MODM - band(MODM - a, MODM - b) + if c then + z = bit32_bor(z, c, ...) + end + return z + elseif a then + return a % MOD + else + return 0 + end +end +M.bit32.bor = bit32_bor + +function M.bit32.btest(...) + return bit32_band(...) ~= 0 +end + +function M.bit32.lrotate(x, disp) + return lrotate(x % MOD, disp) +end + +function M.bit32.rrotate(x, disp) + return rrotate(x % MOD, disp) +end + +function M.bit32.lshift(x,disp) + if disp > 31 or disp < -31 then return 0 end + return lshift(x % MOD, disp) +end + +function M.bit32.rshift(x,disp) + if disp > 31 or disp < -31 then return 0 end + return rshift(x % MOD, disp) +end + +function M.bit32.arshift(x,disp) + x = x % MOD + if disp >= 0 then + if disp > 31 then + return (x >= 0x80000000) and MODM or 0 + else + local z = rshift(x, disp) + if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end + return z + end + else + return lshift(x, -disp) + end +end + +function M.bit32.extract(x, field, ...) + local width = ... or 1 + if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end + x = x % MOD + return extract(x, field, ...) +end + +function M.bit32.replace(x, v, field, ...) + local width = ... or 1 + if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end + x = x % MOD + v = v % MOD + return replace(x, v, field, ...) +end + +M.bit = {} -- LuaBitOp "bit" compatibility + +function M.bit.tobit(x) + x = x % MOD + if x >= 0x80000000 then x = x - MOD end + return x +end +local bit_tobit = M.bit.tobit + +function M.bit.tohex(x, ...) + return tohex(x % MOD, ...) +end + +function M.bit.bnot(x) + return bit_tobit(bnot(x % MOD)) +end + +local function bit_bor(a, b, c, ...) + if c then + return bit_bor(bit_bor(a, b), c, ...) + elseif b then + return bit_tobit(bor(a % MOD, b % MOD)) + else + return bit_tobit(a) + end +end +M.bit.bor = bit_bor + +local function bit_band(a, b, c, ...) + if c then + return bit_band(bit_band(a, b), c, ...) + elseif b then + return bit_tobit(band(a % MOD, b % MOD)) + else + return bit_tobit(a) + end +end +M.bit.band = bit_band + +local function bit_bxor(a, b, c, ...) + if c then + return bit_bxor(bit_bxor(a, b), c, ...) + elseif b then + return bit_tobit(bxor(a % MOD, b % MOD)) + else + return bit_tobit(a) + end +end +M.bit.bxor = bit_bxor + +function M.bit.lshift(x, n) + return bit_tobit(lshift(x % MOD, n % 32)) +end + +function M.bit.rshift(x, n) + return bit_tobit(rshift(x % MOD, n % 32)) +end + +function M.bit.arshift(x, n) + return bit_tobit(arshift(x % MOD, n % 32)) +end + +function M.bit.rol(x, n) + return bit_tobit(lrotate(x % MOD, n % 32)) +end + +function M.bit.ror(x, n) + return bit_tobit(rrotate(x % MOD, n % 32)) +end + +function M.bit.bswap(x) + return bit_tobit(bswap(x % MOD)) +end + +return M diff --git a/game/bin/numbers/random.lua b/game/bin/numbers/random.lua new file mode 100644 index 0000000..091a7f5 --- /dev/null +++ b/game/bin/numbers/random.lua @@ -0,0 +1,232 @@ +--[[---------------------------------------- +Random +Not all of this is mine +------------------------------------------]] +--[[------------------------------------ +RandomLua v0.3.1 +Pure Lua Pseudo-Random Numbers Generator +Under the MIT license. +copyright(c) 2011 linux-man +--]]------------------------------------ + +local math_floor = math.floor + +local function normalize(n) + return n % 0x80000000 +end + +local function bit_and(a, b) + local r = 0 + local m = 0 + for m = 0, 31 do + if (a % 2 == 1) and (b % 2 == 1) then r = r + 2^m end + if a % 2 ~= 0 then a = a - 1 end + if b % 2 ~= 0 then b = b - 1 end + a = a / 2 b = b / 2 + end + return normalize(r) +end + +local function bit_or(a, b) + local r = 0 + local m = 0 + for m = 0, 31 do + if (a % 2 == 1) or (b % 2 == 1) then r = r + 2^m end + if a % 2 ~= 0 then a = a - 1 end + if b % 2 ~= 0 then b = b - 1 end + a = a / 2 b = b / 2 + end + return normalize(r) +end + +local function bit_xor(a, b) + local r = 0 + local m = 0 + for m = 0, 31 do + if a % 2 ~= b % 2 then r = r + 2^m end + if a % 2 ~= 0 then a = a - 1 end + if b % 2 ~= 0 then b = b - 1 end + a = a / 2 b = b / 2 + end + return normalize(r) +end + +local function seed() + return normalize(os.time()) +end + +--Mersenne twister +local mersenne_twister = {} +mersenne_twister.__index = mersenne_twister + +function mersenne_twister:randomseed(s) + if not s then s = seed() end + self.mt[0] = normalize(s) + for i = 1, 623 do + self.mt[i] = normalize(0x6c078965 * bit_xor(self.mt[i-1], math_floor(self.mt[i-1] / 0x40000000)) + i) + end +end + +function mersenne_twister:random(a, b) + local y + if self.index == 0 then + for i = 0, 623 do + y = self.mt[(i + 1) % 624] % 0x80000000 + self.mt[i] = bit_xor(self.mt[(i + 397) % 624], math_floor(y / 2)) + if y % 2 ~= 0 then self.mt[i] = bit_xor(self.mt[i], 0x9908b0df) end + end + end + y = self.mt[self.index] + y = bit_xor(y, math_floor(y / 0x800)) + y = bit_xor(y, bit_and(normalize(y * 0x80), 0x9d2c5680)) + y = bit_xor(y, bit_and(normalize(y * 0x8000), 0xefc60000)) + y = bit_xor(y, math_floor(y / 0x40000)) + self.index = (self.index + 1) % 624 + if not a then return y / 0x80000000 + elseif not b then + if a == 0 then return y + else return 1 + (y % a) + end + else + return a + (y % (b - a + 1)) + end +end + +local function twister(s) + local temp = {} + setmetatable(temp, mersenne_twister) + temp.mt = {} + temp.index = 0 + temp:randomseed(s) + return temp +end + +--Linear Congruential Generator +local linear_congruential_generator = {} +linear_congruential_generator.__index = linear_congruential_generator + +function linear_congruential_generator:random(a, b) + local y = (self.a * self.x + self.c) % self.m + self.x = y + if not a then return y / 0x10000 + elseif not b then + if a == 0 then return y + else return 1 + (y % a) end + else + return a + (y % (b - a + 1)) + end +end + +function linear_congruential_generator:randomseed(s) + if not s then s = seed() end + self.x = normalize(s) +end + +local function lcg(s, r) + local temp = {} + setmetatable(temp, linear_congruential_generator) + temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C + if r then + if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes. + elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC + end + temp:randomseed(s) + return temp +end + +-- Multiply-with-carry +local multiply_with_carry = {} +multiply_with_carry.__index = multiply_with_carry + +function multiply_with_carry:random(a, b) + local m = self.m + local t = self.a * self.x + self.c + local y = t % m + self.x = y + self.c = math_floor(t / m) + if not a then return y / 0x10000 + elseif not b then + if a == 0 then return y + else return 1 + (y % a) end + else + return a + (y % (b - a + 1)) + end +end + +function multiply_with_carry:randomseed(s) + if not s then s = seed() end + self.c = self.ic + self.x = normalize(s) +end + +local function mwc(s, r) + local temp = {} + setmetatable(temp, multiply_with_carry) + temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C + if r then + if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes. + elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC + end + temp.ic = temp.c + temp:randomseed(s) + return temp +end +-- Little bind for the methods: My code starts +local randomGen={} +randomGen.__index=randomGen +function randomGen:new(s) + local temp={} + setmetatable(temp,randomGen) + temp[1]=twister() + temp[2]=lcg() + temp[3]=mwc() + temp.pos=1 + for i=1,3 do + temp[i]:randomseed(s) + end + return temp +end +function randomGen:randomseed(s) + self.pos=1 + self[1]:randomseed(s) + self[2]:randomseed(s) + self[3]:randomseed(s) +end +function randomGen:randomInt(a,b) + local t=self[self.pos]:random(a,b) + self.pos=self.pos+1 + if self.pos>3 then + self.pos=1 + end + return t +end +function randomGen:newND(a,b,s) + if not(a) or not(b) then error('You must include a range!') end + local temp=randomGen:new(s) + temp.a=a + temp.b=b + temp.range=b-a+1 + temp.dups={no=0} + function temp:nextInt() + local t=self:randomInt(self.a,self.b) + if self.dups[t]==nil then + self.dups[t]=true + self.dups.no=self.dups.no+1 + else + return self:nextInt() + end + if self.dups.no==self.range then + function self:nextInt() + return 1,true + end + return t + else + return t + end + end + function temp:nextIInt() + return function() return self:nextInt() end + end + return temp +end +return randomGen diff --git a/game/bin/support/extraBlocks.lua b/game/bin/support/extraBlocks.lua new file mode 100644 index 0000000..2b8aa3b --- /dev/null +++ b/game/bin/support/extraBlocks.lua @@ -0,0 +1,146 @@ +local __CURRENTVERSION=2 +bin.registerBlock("t",function(SIZE_OR_NIL,ref) + local header=ref:read(3) + if not header:match("(LT.)") then error("Not a valid table struct!") end + if bin.defualtBit.new(header:sub(3,3)):tonumber(1)>__CURRENTVERSION then error("Incompatible Version of LuaTable!") end + local len=ref:getBlock("n",4) -- hehe lets make life easier + local tab={} + local ind + local n=0 + while true do + local _dat=ref:read(2) + if _dat==nil then break end + local it,dt=_dat:match("(.)(.)") + n=n+2 + if it=="N" then -- get the index stuff out of the way first + ind=ref:getBlock("n",4) + n=n+4 + else + indL=ref:getBlock("n",1) + n=n+1+indL + ind=ref:read(indL) + end + if dt=="N" then + tab[ind]=ref:getBlock("d") + n=n+8 + elseif dt=="I" then + tab[ind]=math.huge + ref:getBlock("n",4) + n=n+4 + elseif dt=="i" then + tab[ind]=-math.huge + ref:getBlock("n",4) + n=n+4 + elseif dt=="S" then + local nn=ref:getBlock("n",4) + tab[ind]=ref:read(nn) + n=n+4+nn + elseif dt=="B" then + tab[ind]=({["\255"]=true,["\0"]=false})[ref:read(1)] + n=n+1 + elseif dt=="F" then + local nn=ref:getBlock("n",4) + tab[ind]=loadstring(ref:read(nn)) + n=n+4+nn + elseif dt=="T" then + local cur=ref:getSeek() + local size=ref:getBlock("n",4) + ref:setSeek(cur) + ref:read(4) + if size==7 then + tab[ind]={} + ref:read(7) + n=n+11 + else + local data=bin.new(ref:read(size)) + local dat=data:getBlock("t") + if dat.__RECURSIVE then + tab[ind]=tab + else + tab[ind]=dat + end + n=n+data:getSize()+4 + end + end + if n==len then break end + end + return bin.resolveType(tab) +end,function(d,fit,fmt,self,rec,tabsaw) + -- INGORE FIT WE ARE CREATING A STRUCT!!! + -- fmt will apply to all numbers + local __rem=nil + if not tabsaw then rem=true end + local tabsaw=tabsaw or {} + if rem then + table.insert(tabsaw,d) + end + local bData={} + for i,v in pairs(d) do -- this is for tables, all but userdata is fine. Depending on where you are using lua functions may or may not work + local tp=type(v):sub(1,1):upper() -- uppercase of datatype + if type(i)=="number" then -- Lets handle indexies + if v==math.huge then + tp="I" + v=0 + elseif v==-math.huge then + tp="i" + v=0 + end + table.insert(bData,"N"..tp..bin.defualtBit.numToBytes(i,4)) -- number index? + elseif type(i)=="string" then + if #i>255 then error("A string index cannot be larger than 255 bytes!") end + table.insert(bData,"S"..tp..bin.defualtBit.numToBytes(#i,1)..i) -- string index? + else + error("Only numbers and strings can be a table index!") -- throw error? + end + if type(v)=="number" then + -- How do we handle number data + local temp=bin.new() + temp:addBlock(v,nil,"d") + table.insert(bData,temp.data) + elseif type(v)=="string" then + -- Lets work on strings + table.insert(bData,bin.defualtBit.numToBytes(#v,4)) -- add length of string + table.insert(bData,v) -- add string + elseif type(v)=="boolean" then -- bools are easy :D + table.insert(bData,({[true]="\255",[false]="\0"})[v]) + elseif type(v)=="function" then -- should we allow this? why not... + local dump=string.dump(v) + table.insert(bData,bin.defualtBit.numToBytes(#dump,4)) -- add length of dumped string + table.insert(bData,dump) -- add it + elseif type(v)=="table" then -- tables... + if tabsaw[1]==v then + v={__RECURSIVE=i} + else + tabsaw[i]=v + end + local data=rec(v,nil,"t",self,rec,tabsaw) + table.insert(bData,bin.defualtBit.numToBytes(#data,4)) -- add length of string + table.insert(bData,data) -- add string + end + end + local data=table.concat(bData) + return "LT"..string.char(__CURRENTVERSION)..bin.defualtBit.numToBytes(#data,4)..data +end) +bin.registerBlock("b",function(SIZE_OR_NIL,ref) + return ({["\255"]=true,["\0"]=false})[ref:read(1)] +end,function(d) + return ({[true]="\255",[false]="\0"})[d] +end) +bin.registerBlock("f",function(SIZE_OR_NIL,ref) + local nn=ref:getBlock("n",4) + return loadstring(ref:read(nn)) +end,function(d) + local dump=string.dump(d) + return bin.defualtBit.numToBytes(#dump,4)..dump +end) +bin.registerBlock("d",function(SIZE_OR_NIL,ref) + local w,p=ref:getBlock("n",4),ref:getBlock("n",4) + p=tonumber("0."..tostring(p)) + return w+p +end,function(d,fit,fmt,self,rec,tabsaw) + local w,p = toFraction(d) + local temp=bin.new() + temp:addBlock(w,4) + temp:addBlock(p,4) + return temp.data +end) \ No newline at end of file diff --git a/game/bin/support/utils.lua b/game/bin/support/utils.lua new file mode 100644 index 0000000..957b168 --- /dev/null +++ b/game/bin/support/utils.lua @@ -0,0 +1,123 @@ +function table.print(tbl, indent) + if not indent then indent = 0 end + for k, v in pairs(tbl) do + formatting = string.rep(" ", indent) .. k .. ": " + if type(v) == "table" then + print(formatting) + table.print(v, indent+1) + elseif type(v) == 'boolean' then + print(formatting .. tostring(v)) + else + print(formatting .. tostring(v)) + end + end +end +function table.flip(t) + local tt={} + for i,v in pairs(t) do + tt[v]=i + end + return tt +end +function toFraction(n) + local w,p=math.modf(n) + if p~=0 then + p=tonumber(tostring(p):sub(3)) + end + return w,p +end +function io.cleanName(name) + name=name:gsub("\\","") + name=name:gsub("/","") + name=name:gsub(":","") + name=name:gsub("*","") + name=name:gsub("%?","") + name=name:gsub("\"","''") + name=name:gsub("<","") + name=name:gsub(">","") + name=name:gsub("|","") + return name +end +function math.numfix(n,x) + local str=tostring(n) + if #strx+w or mxy+h or myx+w or mxy+h or my self.x and x < self.x+self.width and y > self.y and y < self.y+self.height and self:TClickable(x,y) and self:eventable()) + end + end + self.id=-1 +end +multi:newTask(function() -- A bit of post-loading haha + gui.touchpressed=multi:newConnection() + gui.touchreleased=multi:newConnection() + gui.touchmoved=multi:newConnection() + love.touchpressed=Library.convert(love.touchpressed or function() end) + love.touchreleased=Library.convert(love.touchreleased or function() end) + love.touchmoved=Library.convert(love.touchmoved or function() end) + love.touchpressed:inject(function(id, x, y, dx, dy, pressure) gui.touchpressed:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + love.touchreleased:inject(function(id, x, y, dx, dy, pressure) gui.touchreleased:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + love.touchmoved:inject(function(id, x, y, dx, dy, pressure) gui.touchmoved:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + _GuiPro.TouchReady=true + _GuiPro.TouchRegister={} + gui.touchpressed:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if #v.tid==0 then + if (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + v:addTID(id) + v.touchcount=1 + for i=1,#v.ToFuncP do + v.ToFuncP[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + elseif not(v:hasTID(id)) then + if (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + v:addTID(id) + v.touchcount=v.touchcount+1 + for i=1,#v.ToFuncP do + v.ToFuncP[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end + end) + gui.touchreleased:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if v:hasTID(id) then + v:removeTID(id) + for i=1,#v.ToFuncR do + v.ToFuncR[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end) + gui.touchmoved:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if v:hasTID(id) and (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + for i=1,#v.ToFuncM do + v.ToFuncM[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + elseif v:hasTID(id) and not((x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable())) then + v:removeTID(id) + for i=1,#v.ToFuncR do + v.ToFuncR[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end) +end) +-- now that that is done lets set up some more post loading checks +_GuiPro.int=multi:newProcess() +_GuiPro.int:Start() +_GuiPro.int:setJobSpeed(.001) +_GuiPro.EXACT=0 +_GuiPro.LAX=.01 +_GuiPro.LAZY=.05 +-- now lets define the reg function +function gui.Compare(a,b,v,tp) + if tp==">" then + if (a+v>b or a-v>b) then + return true + end + elseif tp=="<" then + if (a+v=" then + if (a+v>=b or a-v>=b) then + return true + end + elseif tp=="==" then -- this one is gonna be tricky + if (a>=b-v and a<=b+v) or (b>=a-v and b<=a+v) then + return true + end + end + return false +end +function gui:regesterTouch() + local obj=self + obj.ToFuncP={} + obj.ToFuncM={} + obj.ToFuncR={} + obj.To2Func={} + obj.ToDTFunc={} + obj.touchRendering =_GuiPro.EXACT -- exact(0), lax(), # + function obj:removeTID(id) + for i=1,#self.tid do + if self.tid[i]==id then + table.remove(self.tid,i) + self.touchcount=self.touchcount-1 + return + end + end + end + function obj:hasTID(id) + for i=1,#self.tid do + if self.tid[i]==id then + return true + end + end + return false + end + obj.txl1=0 + obj.tyl1=0 + obj.txl2=0 + obj.tyl2=0 + obj.LS=0 + obj:OnUpdate(function(self) + if self.touchcount==2 then + local x1,y1=love.touch.getPosition( self.tid[1] ) + local x2,y2=love.touch.getPosition( self.tid[2] ) + local CS=math.sqrt((x2-x1)^2+(y2-y1)^2) + if gui.Compare(CS,self.LS,self.touchRendering,">") then + for i=1,#self.To2Func do + self.To2Func[i](self,CS,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + elseif gui.Compare(CS,self.LS,self.touchRendering,"<") then + for i=1,#self.To2Func do + self.To2Func[i](self,-CS,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + elseif gui.Compare(CS,self.LS,self.touchRendering,"==") then + for i=1,#self.To2Func do + self.To2Func[i](self,0,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + end + -- if self.txl1~=x1 or self.txl2~=x2 or self.tyl1~=y1 or self.tyl2~=y2 then + -- for i=1,#self.To2Func do + -- self.To2Func[i](self,0,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + -- end + -- end + self.LS=CS + self.txl1=x1 + self.txl2=x2 + self.tyl1=y1 + self.tyl2=y2 + end + end) + function obj:OnDoubleTap(func) + table.insert(self.ToDTFunc,func) + end + function obj:On2TouchMoved(func) + table.insert(self.To2Func,func) + end + function obj:addTID(id) + table.insert(self.tid,id) + end + function obj:OnTouchPressed(func) + table.insert(self.ToFuncP,func) -- event for touches + end + function obj:OnTouchReleased(func) -- event for touches + table.insert(self.ToFuncR,func) + end + function obj:OnTouchMoved(func) -- event for touches + table.insert(self.ToFuncM,func) + end + if _GuiPro.TouchReady then -- my sneaky test + print("Registred: "..tostring(obj)) + table.insert(_GuiPro.TouchRegister,obj) + else + print("Attempting to register: "..tostring(obj)) + _GuiPro.int:newJob(function() table.insert(_GuiPro.TouchRegister,obj) end) -- a sneaky way to ensure that your object gets registered eventually, even if you call the method before the touch patch was activated. + end +end + +function UpdateThings(items) + for i=#items,1,-1 do + if items[i]:LClicked() then + for g=1,#items[i].funcs do + items[i].funcs[g]("l",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif items[i]:RClicked() then + for g=1,#items[i].funcs do + items[i].funcs[g]("r",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif items[i]:MClicked() then + for g=1,#items[i].funcs do + items[i].funcs[g]("m",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + end + if not(items[i]:LClicked()) and items[i].LRE then + for g=1,#items[i].funcs2 do + items[i].funcs2[g]("l",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif not(items[i]:RClicked()) and items[i].RRE then + for g=1,#items[i].funcs2 do + items[i].funcs2[g]("r",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif not(items[i]:MClicked()) and items[i].MRE then + for g=1,#items[i].funcs2 do + items[i].funcs2[g]("m",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + end + if items[i]:Hovering() and items[i].HE==false then + for g=1,#items[i].funcs3 do + items[i].funcs3[g](items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif not(items[i]:Hovering()) and items[i].HE==true then + for g=1,#items[i].funcs4 do + items[i].funcs4[g](items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif items[i]:Hovering() then + for g=1,#items[i].func9 do + items[i].func9[g](items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + end + for g=1,#items[i].funcs5 do + items[i].funcs5[g](items[i]) + end + end +end +function GetAllChildren(Object) + local Stuff = {} + function Seek(Items) + for i=1,#Items do + if Items[i].Visible==true then + table.insert(Stuff,Items[i]) + local NItems = Items[i]:getChildren() + if NItems ~= nil then + Seek(NItems) + end + end + end + end + local Objs = Object:getChildren() + for i=1,#Objs do + if Objs[i].Visible==true then + table.insert(Stuff,Objs[i]) + local Items = Objs[i]:getChildren() + if Items ~= nil then + Seek(Items) + end + end + end + return Stuff +end +function GetAllChildren2(Object) + local Stuff = {} + function Seek(Items) + for i=1,#Items do + table.insert(Stuff,Items[i]) + local NItems = Items[i]:getChildren() + if NItems ~= nil then + Seek(NItems) + end + end + end + local Objs = Object:getChildren() + for i=1,#Objs do + table.insert(Stuff,Objs[i]) + local Items = Objs[i]:getChildren() + if Items ~= nil then + Seek(Items) + end + end + return Stuff +end +function gui:getTile(i,x,y,w,h)-- returns imagedata + if type(i)=="string" then + i=love.graphics.newImage(i) + elseif type(i)=="userdata" then + -- do nothing + elseif string.find(self.Type,"Image",1,true) then + local i,x,y,w,h=self.Image,i,x,y,w + else + error("getTile invalid args!!! Usage: ImageElement:getTile(x,y,w,h) or gui:getTile(imagedata,x,y,w,h)") + end + local iw,ih=i:getDimensions() + local id,_id=i:getData(),love.image.newImageData(w,h) + for _x=x,w+x-1 do + for _y=y,h+y-1 do + -- + _id:setPixel(_x-x,_y-y,id:getPixel(_x,_y)) + end + end + return love.graphics.newImage(_id) +end +function gui:newAnim(file,delay, x, y, w, h, sx ,sy ,sw ,sh) + local x,y,w,h,sx,sy,sw,sh=filter(file, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation",file, x, y, w, h, sx ,sy ,sw ,sh) + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files={} + c.AnimStart={} + c.AnimEnd={} + local _files=alphanumsort(love.filesystem.getDirectoryItems(file)) + for i=1,#_files do + if string.sub(_files[i],-1,-1)~="b" then + table.insert(c.files,love.graphics.newImage(file.."/".._files[i])) + end + end + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(pos,step) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end +function gui:newAnimFromData(data,delay, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation","FromFile", x, y, w, h, sx ,sy ,sw ,sh) + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files=data + c.AnimStart={} + c.AnimEnd={} + c:SetImage(c.files[1]) + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(pos,step) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end +function gui:newAnimFromTiles(file,xd,yd,delay, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(file, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation",file, x, y, w, h, sx ,sy ,sw ,sh) + local im=love.graphics.newImage(file) + local _x,_y=im:getDimensions() + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files={} + c.AnimStart={} + c.AnimEnd={} + for i=0,_y/yd-1 do + for j=0,_x/xd-1 do + table.insert(c.files,gui:getTile(im,j*xd,i*yd,xd,yd)) + end + end + c:SetImage(c.files[1]) + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(pos,step) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end +function gui:newFullImageLabel(i,name) + return self:newImageLabel(i,name,0,0,0,0,0,0,1,1) +end +function gui:newImageButton(i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageButton",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + else + c.Image=i + end + c.Visibility=0 + c.ImageVisibility=1 + c.rotation=0 + if c.Image~=nil then + c.ImageHeigth=c.Image:getHeight() + c.ImageHeight=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c:OnEnter(function() + --love.mouse.setCursor(_GuiPro.CursorH) + end) + c:OnExit(function() + --love.mouse.setCursor(_GuiPro.CursorN) + end) + return c +end +function gui:newImageLabel(i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageLabel",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + else + c.Image=i + end + c.Visibility=0 + c.ImageVisibility=1 + c.rotation=0 + if c.Image~=nil then + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + return c +end +function gui:newVideo(name,i,x,y,w,h,sx,sy,sw,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("Video",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Video=love.graphics.newVideo(i) + else + c.Video=i + end + c.Visibility=0 + c.VideoVisibility=1 + c.rotation=0 + if c.Video~=nil then + c.VideoHeigth=c.Video:getHeight() + c.VideoWidth=c.Video:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.VideoWidth,c.VideoHeigth) + end + c.funcV={} + function c:Play() + self.handStart=true + self.Video:play() + end + function c:Pause() + self.Video:pause() + end + c.Resume=c.Play + function c:Stop() + self.handStart=false + self:Pause() + self:Rewind() + for i=1,# self.funcV do + self.funcV[i](self) + end + end + function c:OnVideoStopped(func) + table.insert(self.funcV,func) + end + function c:Rewind() + self.Video:rewind() + end + function c:Restart() + self:Rewind() + self:Play() + end + function c:Seek(o) + self.Video:seek(o) + end + function c:Tell() + self.Video:tell() + end + function c:SetFilter(min, mag, anisotropy) + self.Video:setFilter(min, mag, anisotropy) + end + function c:IsPlaying() + return self.Video:isPlaying() + end + c:OnUpdate(function(self) + if self.Video:isPlaying()==false and self.handStart == true then + self:Stop() + end + end) + return c +end +function gui:SetImage(i) + if type(i)=="string" then + self.Image=love.graphics.newImage(i) + else + self.Image=i + end + if self.Image~=nil then + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) + end + return self.ImageWidth,self.ImageHeigth +end +function gui:UpdateImage() + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) +end +function gui:newDropFrame(name,x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("DropFrame",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=false + c.funcD={} + function c:GetDroppedItems() + local t=self:getChildren() + local tab={} + for i=1,#t do + if t[i].Type=="TextImageButtonFrameDrag" then + table.insert(tab,t[i]) + end + end + return tab + end + function c:OnDropped(func) + table.insert(self.funcD,func) + end + c:OnUpdate(function(self) + if _GuiPro.DragItem then + if _GuiPro.DragItem.Type=="TextImageButtonFrameDrag" and love.mouse.isDown(_GuiPro.DragItem.dragbut or "m")==false and self:IsHovering() then + local t=_GuiPro.DragItem + _GuiPro.DragItem={} + for i=1,#t.funcD do + t.funcD[i](self,t) + end + for i=1,#self.funcD do + self.funcD[i](self,t) + end + _GuiPro.hasDrag=false + end + end + end) + return c +end +function gui:newFrame(name,x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("Frame",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=false + return c +end +function gui:newFullFrame(name) + name=name or "" + return self:newFrame(name,0,0,0,0,0,0,1,1) +end + +function gui:newTabFrame(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=gui:newFrame(name, x, y, w, h, sx ,sy ,sw ,sh) + c.tabheight=20 + c.Holder=c:newFrame("Holder",0,c.tabheight,0,0,0,0,1,1) + c.TabHolder=c:newFrame("TabHolder",0,0,0,c.tabheight,0,0,1) + function c:setTabHeight(n) + self.tabheight=n + self.Holder:SetDualDim(0,-self.tabheight,0,0,0,0,1,1) + end + function c:addTab(name,colorT,colorH) + if colorT and not(colorH) then + colorH=colorT + end + local tab=self.TabHolder:newTextButton(name,name,0,0,0,0,0,0,0,1) + tab.Tween=-3 + if colorT then + tab.Color=colorT + end + local holder=self.Holder:newFrame(name,0,0,0,0,0,0,1,1) + if colorH then + holder.Color=colorH + end + tab.frame=holder + tab:OnReleased(function(b,self) + if b=="l" then + local tt=self.Parent:getChildren() + local th=self.Parent.Parent.Holder:getChildren() + for i=1,#th do + th[i].Visible=false + end + for i=1,#tt do + tt[i].frame.Visible=false + tt[i].BorderSize=1 + end + self.BorderSize=0 + self.frame.Visible=true + end + end) + local tt=self.TabHolder:getChildren() + for i=1,#tt do + tt[i].frame.Visible=false + tt[i].BorderSize=1 + end + tab.frame.Visible=true + tab.BorderSize=0 + return tab,holder + end + c:OnUpdate(function(self) + local th=self.TabHolder:getChildren() + local l=self.width/#th + for i=1,#th do + th[i]:SetDualDim(l*(i-1),0,l) + end + if #th==0 then + self:Destroy() + end + end) + return c +end +function gui:newDragItem(t,i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextImageButtonFrameDrag",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=true + c.funcD={} + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + c.ImageVisibility=1 + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + elseif type(i)=="image" then + c.Image=i + c.ImageVisibility=1 + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c:OnDragStart(function(self,x,y) + if _GuiPro.hasDrag==false then + self:setParent(_GuiPro) + self:SetDualDim(x,y) + self:TopStack() + end + end) + c.rotation=0 + c.Tween=0 + c.XTween=0 + c.text = t + c.AutoScaleText=false + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.TextVisibility=1 + c.TextColor = {0, 0, 0} + function c:OnDropped(func) + table.insert(self.funcD,func) + end + c:OnUpdate(function(self) + if love.mouse.isDown("m" or self.dragbut)==false and self==_GuiPro.DragItem and self.hovering==false then + _GuiPro.DragItem={} + for i=1,#self.func7 do + self.func7[i](self,(love.mouse.getX())-self.width/2,(love.mouse.getY())-self.height/2) + end + end + end) + return c +end +function gui:newItem(t,i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextImageButtonFrame",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + else + c.Image=i + end + c.rotation=0 + c.ImageVisibility=1 + c.Draggable=false + if c.Image~=nil then + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c.Tween=0 + c.XTween=0 + c.text = t + c.AutoScaleText=false + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.TextVisibility=1 -- 0=invisible,1=solid (self.TextVisibility*254+1) + c.TextColor = {0, 0, 0} + return c +end +function gui:addDominance() + _GuiPro.TopHovered=self +end +function gui:addHotKey(key) + local temp=self:newFrame(0,0,0,0) + temp.Visible=false + temp:setHotKey(key) + return temp +end +function gui:AdvTextBox(txt,x,y,w,h,sx,sy,sw,sh) + name="AdvTextBox" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("AdvTextBoxFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c.BorderSize=0 + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + --local temp = c:newTextButton("X","Close",-25,5,20,20,1) + --temp.Tween=-5 + --temp.XTween=-2 + --temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + --temp.Color=Color.Red + c.tLink=c:newTextBox("puttext","TextBox",5,h-95,-40,30,0,1,1,1) + c.tLink.Color=Color.light_gray + c.tLink.ClearOnFocus=true + c.tLink:OnFocus(function(self) self.ClearOnFocus=false end) + local temp=c:newTextButton("OK","Ok",-35,h-65,30,30,1,1) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcO do self.Parent.funcO[i](self.Parent,self.Parent.tLink.text) end end) + temp.Color=Color.Green + temp.XTween=-2 + local temp=c:newTextButton("X","Cancel",-35,h-95,30,30,1,1) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent,self.Parent.tLink.text) end end) + temp.Color=Color.Red + temp.XTween=-2 + function c:Close() + self.Visible=false + end + function c:Open() + self.Visible=true + end + function c:OnOk(func) + table.insert(self.funcO,func) + end + function c:OnX(func) + table.insert(self.funcX,func) + end + return c +end +function alphanumsort(o) + local function padnum(d) local dec, n = string.match(d, "(%.?)0*(.+)") + return #dec > 0 and ("%.12f"):format(d) or ("%s%03d%s"):format(dec, #n, n) + end + table.sort(o, function(a,b) return tostring(a):gsub("%.?%d+",padnum)..("%3d"):format(#b)< tostring(b):gsub("%.?%d+",padnum)..("%3d"):format(#a) end) + return o +end +function gui:anchorRight(n) + self:SetDualDim(-(self.width+n),nil,nil,nil,1) +end +function _GuiPro.gradient(colors) + local direction = colors.direction or "horizontal" + colors.direction=nil + trans = colors.trans or 255 + trans=math.floor(trans) + if direction == "horizontal" then + direction = true + elseif direction == "vertical" then + direction = false + else + error("Invalid direction '" .. tostring(direction) "' for gradient. Horizontal or vertical expected.") + end + local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1) + for __i, color in ipairs(colors) do + local x, y + if direction then + x, y = 0, __i - 1 + else + x, y = __i - 1, 0 + end + result:setPixel(x, y, color[1], color[2], color[3], trans) + end + result = love.graphics.newImage(result) + result:setFilter('linear', 'linear') + return result +end +function _GuiPro.drawinrect(img, x, y, w, h, r, ox, oy, kx, ky) + love.graphics.draw(img, x, y, r, w / img:getWidth(), h / img:getHeight(), ox, oy, kx, ky) +end +function gui:ApplyGradient(rules) + self.Image=nil + self.Type=self.Type.."w/GradImage" + self.rotation=0 + self.ImageVisibility=rules.visibility or 1 + self:SetImage(_GuiPro.gradient(rules)) +end +function gui:BottomStack() + childs=self.Parent:getChildren() + for i=1,#childs do + if childs[i]==self then + table.remove(self.Parent.Children,i) + table.insert(self.Parent.Children,1,self) + break + end + end +end +function gui:Center() + local x,y=self:getFullSize() + self:SetDualDim(-math.floor(x/2),-math.floor(y/2),nil,nil,.5,.5) +end +function gui:centerX() + self:SetDualDim(-(self.width/2),nil,nil,nil,.5) +end +function gui:centerY() + self:SetDualDim(nil,-(self.height/2),nil,nil,nil,.5) +end +function gui:Destroy() + check=self.Parent:getChildren() + local cc=0 + for cc=1,#check do + if check[cc]==self then + table.remove(self.Parent.Children,cc) + end + end +end +function gui:disrespectHierarchy() + _GuiPro.Hierarchy=false +end +function gui:GetAllChildren() + local Stuff = {} + function Seek(Items) + for i=1,#Items do + if Items[i].Visible==true then + table.insert(Stuff,Items[i]) + local NItems = Items[i]:getChildren() + if NItems ~= nil then + Seek(NItems) + end + end + end + end + local Objs = self:getChildren() + for i=1,#Objs do + if Objs[i].Visible==true then + table.insert(Stuff,Objs[i]) + local Items = Objs[i]:getChildren() + if Items ~= nil then + Seek(Items) + end + end + end + return Stuff +end +function gui:GetChild(name) + return self.Children[name] or self +end +function gui:getChildren() + return self.Children +end +function gui:getColor(cindex) + return Color[cindex] +end +function gui:getFullSize() + local maxx,maxy=-math.huge,-math.huge + local temp = self:GetAllChildren() + for i=1,#temp do + if temp[i].width>maxx then + maxx=temp[i].width+temp[i].offset.pos.x + elseif temp[i].height>maxy then + maxy=temp[i].height+temp[i].offset.pos.y + end + end + return maxx,maxy +end +function gui:getHighest() + if self.Children[#self.Children]~=nil then + return self.Children[#self.Children] + end +end +function gui:getLowest() + if self.Children[1]~=nil then + return self.Children[1] + end +end +function InGrid(i,x,y,s) + return math.floor((i-1)/x)*s,(i-1)*s-(math.floor((i-1)/y)*(s*x)) +end +function InGridX(i,w,h,xs,ys) + local xc,yc=math.floor(w/xs),math.floor(h/ys) + local xi,yi=(i-1)%xc,math.floor((i-1)/xc) + return xi*xs,yi*ys +end +function InGridY(i,w,h,xs,ys) + local xc,yc=math.floor(w/xs),math.floor(h/ys) + local xi,yi=math.floor((i-1)/yc),(i-1)%yc + return xi*xs,yi*ys +end +function gui:isDescendant(obj) + local things=obj:GetAllChildren() + for i=1,#things do + if things[i]==self then + return true + end + end + return false +end +function gui:isHighest() + return (self==self.Parent:getHighest()) +end +function gui:IsHovering() + return (love.mouse.getX() > self.x and love.mouse.getX() < self.x+self.width and love.mouse.getY() > self.y and love.mouse.getY() < self.y+self.height) +end +function gui:isLowest() + return (self==self.Parent:getLowest()) +end +function gui.massMutate(t,...) + local mut={...} + for i=1,#mut do + mut[i]:Mutate(t) + end +end +function gui:Move(x,y) + self.offset.pos.x=self.offset.pos.x+x + self.offset.pos.y=self.offset.pos.y+y +end +if love.filesystem.exists("CheckBoxes.png") then + _GuiPro.UC=gui:getTile("CheckBoxes.png",0,0,16,16) + _GuiPro.C=gui:getTile("CheckBoxes.png",16,0,16,16) + _GuiPro.UCH=gui:getTile("CheckBoxes.png",0,16,16,16) + _GuiPro.CH=gui:getTile("CheckBoxes.png",16,16,16,16) +end +function gui:newCheckBox(name,x,y) + if not(_GuiPro.UC) then error("CheckBoxes.png not found! Cannot currently use checkbox without the data") end + if type(name)~="String" then + x,y,name=name,x,"CheckBox" + end + local c=self:newImageLabel(_GuiPro.UC,name, x, y, 16,16) + c.Visibility=0 + c.check=false + c:OnEnter(function(self) + if self.check then + self:SetImage(_GuiPro.CH) + else + self:SetImage(_GuiPro.UCH) + end + end) + function c:isChecked() + return self.check + end + c:OnExit(function(self) + if self.check then + self:SetImage(_GuiPro.C) + else + self:SetImage(_GuiPro.UC) + end + end) + c:OnReleased(function(b,self) + self.check=not(self.check) + if self.check then + self:SetImage(_GuiPro.CH) + else + self:SetImage(_GuiPro.UCH) + end + end) + return c +end +function gui:newMessageBox(txt,x,y,w,h,sx,sy,sw,sh) + name="MessageBox" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("MessageBoxFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c.BorderSize=0 + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + local temp = c:newTextButton("X","Close",-25,5,20,20,1) + temp.Tween=-5 + temp.XTween=-2 + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + temp.Color=Color.Red + local temp=c:newTextButton("OK","Ok",0,h-65,0,30,.25,1,.5) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcO do self.Parent.funcO[i](self.Parent) end end) + temp.Color=Color.Green + function c:Close() + self.Visible=false + end + function c:Open() + self.Visible=true + end + function c:OnOk(func) + table.insert(self.funcO,func) + end + function c:OnX(func) + table.insert(self.funcX,func) + end + return c +end +function gui:newPart(x, y,w ,h , sx ,sy ,sw ,sh) + local c = {} + setmetatable(c, gui) + if self==gui then + c.Parent=_GuiPro + else + c.Parent=self + end + c.funcs={} + c.funcs2={} + c.funcs3={} + c.funcs4={} + c.funcs5={} + c.func6={} + c.func7={} + c.func8={} + c.func9={} + c.func10={} + c.form="rectangle" + c.Color = {255, 255, 255} + c.scale={} + c.scale.size={} + c.scale.size.x=sw or 0 + c.scale.size.y=sh or 0 + c.offset={} + c.offset.size={} + c.offset.size.x=w or 0 + c.offset.size.y=h or 0 + c.scale.pos={} + c.scale.pos.x=sx or 0 + c.scale.pos.y=sy or 0 + c.offset.pos={} + c.offset.pos.x=x or 0 + c.offset.pos.y=y or 0 + c.VIS=true + c.Visible=true + c.Visibility=1 + c.BorderColor={0,0,0} + c.BorderSize=0 + c.Type="Part" + c.Name="GuiPart" + _GuiPro.count=_GuiPro.count+1 + c.x=(c.Parent.width*c.scale.pos.x)+c.offset.pos.x+c.Parent.x + c.y=(c.Parent.height*c.scale.pos.y)+c.offset.pos.y+c.Parent.y + c.width=(c.Parent.width*c.scale.size.x)+c.offset.size.x + c.height=(c.Parent.height*c.scale.size.y)+c.offset.size.y + table.insert(c.Parent.Children,c) + return c +end +function gui:newProgressBar(txt,x,y,w,h,sx,sy,sw,sh) + name="newProgressBar" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("newProgressBarFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c.BorderSize=0 + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + local temp = c:newTextButton("X","Close",-25,5,20,20,1) + temp.Tween=-5 + temp.XTween=-2 + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + temp.Color=Color.Red + c.BarBG=c:newTextButton("",5,h-65,-10,30,0,1,1) + c.BarBG:ApplyGradient{Color.Red,Color.light_red} + c.Bar=c.BarBG:newTextLabel("",0,0,0,0,0,0,0,1) + c.Bar:ApplyGradient{Color.Green,Color.light_green} + c.BarDisp=c.BarBG:newTextLabel("0%","0%",0,0,0,0,0,0,1,1) + c.BarDisp.Visibility=0 + c.BarDisp.Link=c.Bar + c.BarDisp:OnUpdate(function(self) + self.text=self.Link.scale.size.x*100 .."%" + end) + c.Func1={} + function c:On100(func) + table.insert(self.Func1,func) + end + c:OnUpdate(function(self) + if self.Bar.scale.size.x*100>=100 then + for P=1,#self.Func1 do + self.Func1[P](self) + end + end + end) + function c:SetPercentage(n) + self.Bar:SetDualDim(0,0,0,0,0,0,n/100,1) + end + return c +end +function gui:newScrollBar(color1,color2) + local scrollbar=self:newFrame(-20,0,20,0,1,0,0,1) + scrollbar.funcS={} + scrollbar.Color=color1 or Color.saddle_brown + scrollbar:OnClicked(function(b,self,x,y) + love.mouse.setX(self.x+10) + if y>=10 and y<=self.height-10 then + self.mover:SetDualDim(0,y-10) + end + if y<10 then + love.mouse.setY(10+self.y) + end + if y>self.height-10 then + love.mouse.setY((self.height-10)+self.y) + end + for i=1,#self.funcS do + self.funcS[i](self,self:getPosition()) + end + end) + scrollbar:OnEnter(function(self) + self:addDominance() + end) + scrollbar:OnExit(function(self) + self:removeDominance() + end) + scrollbar.mover=scrollbar:newTextButton("","",0,0,20,20) + scrollbar.mover.Color=color2 or Color.light_brown + function scrollbar:getPosition() + return ((self.mover.offset.pos.y)/(self.height-20))*100 + end + function scrollbar:setPosition(n) + print((self.height-20),n) + self.mover.offset.pos.y=((self.height-20)/(100/n)) + for i=1,#self.funcS do + self.funcS[i](self,self:getPosition()) + end + end + function scrollbar:OnScroll(func) + table.insert(self.funcS,func) + end + return scrollbar +end +function gui:newScrollMenu(title,tabN,onloop,x, y, w, h, sx ,sy ,sw ,sh) + local Main = self:newFrame(x, y, w, h, sx ,sy ,sw ,sh) + local Title=Main:newTextButton(title,"Title",0,0,0,20,0,0,1) + Title.Tween=-4 + Title.FontSize=12 + Title:OnReleased(function(b,self) + self.Parent.Tick=not(self.Parent.Tick) + end) + local scroll=Main:newTextButton("","Scroll",-20,20,20,-20,1,0,0,1) + scroll:OnClicked(function(b,self,x,y) + self.Parent.Mover:SetDualDim(0,y-10,20,20) + if self.Parent.Mover.offset.pos.y<0 then + self.Parent.Mover:SetDualDim(0,0,20,20) + end + if self.Parent.Mover.offset.pos.y>self.Parent.height-40 then + self.Parent.Mover:SetDualDim(0,self.Parent.height-40,20,20) + end + local temp = #self.Parent.TList + self.Parent.pos=(math.floor((temp*self.Parent.Mover.offset.pos.y)/self.height))+1 + end) + Main:OnUpdate(function(self) + if self.Tick==false then + self.Visibility=0 + end + end) + scroll:OnUpdate(function(self) + self.Visible=self.Parent.Tick + end) + local Mover=scroll:newTextLabel("",0,0,20,20) + Main.Mover=Mover + Main.TList=tabN + Main.pos=1 + Main.Tick=true + function Main:Update(title,tabN,onloop) + ch=self:getChildren() + for i=#ch,1,-1 do + ch[i]:Destroy() + end + Title=Main:newTextButton(title,"Title",0,0,0,20,0,0,1) + Title.Tween=-4 + Title.FontSize=12 + Title:OnReleased(function(b,self) + self.Parent.Tick=not(self.Parent.Tick) + end) + scroll=Main:newTextButton("","Scroll",-20,20,20,-20,1,0,0,1) + scroll:OnClicked(function(b,self,x,y) + self.Parent.Mover:SetDualDim(0,y-10,20,20) + if self.Parent.Mover.offset.pos.y<0 then + self.Parent.Mover:SetDualDim(0,0,20,20) + end + if self.Parent.Mover.offset.pos.y>self.Parent.height-40 then + self.Parent.Mover:SetDualDim(0,self.Parent.height-40,20,20) + end + local temp = #self.Parent.TList + self.Parent.pos=(math.floor((temp*self.Parent.Mover.offset.pos.y)/self.height))+1 + end) + local Mover=scroll:newTextLabel("",0,0,20,20) + Main.Mover=Mover + Main.TList=tabN + Main.pos=1 + Main.Tick=true + scroll:OnUpdate(function(self) + self.Visible=self.Parent.Tick + end) + for i=1,math.floor(Main.height/20)-1 do + local temp=Main:newTextButton("","Item"..i,0,i*20,-20,20,0,0,1) + temp.FontSize=10 + temp.Tween=-4 + temp.pos=i + temp:OnUpdate(function(self) + self.text=self.Parent.TList[(self.Parent.pos+self.pos)-1] + self.Visible=self.Parent.Tick + end) + if onloop then + onloop(temp,i) + end + end + end + io.write(tostring(Main.height).."\n") + for i=1,math.floor(Main.height/20)-1 do + local temp=Main:newTextButton("Item"..i,0,i*20,-20,20,0,0,1) + temp.FontSize=10 + temp.Tween=-4 + temp.pos=i + temp:OnUpdate(function(self) + if self.Parent.TList[(self.Parent.pos+self.pos)-1]~=nil then + self.text=self.Parent.TList[(self.Parent.pos+self.pos)-1] + else + self.text="" + end + self.Visible=self.Parent.Tick + end) + if onloop then + onloop(temp,i) + end + end + return Main +end +function gui:destroyAllChildren() + local c=self.Children + for i=1,#c do + c[i]:Destroy() + end +end +function gui:removeDominance() + _GuiPro.TopHovered=nil +end +function gui:respectHierarchy() + _GuiPro.Hierarchy=true +end +function gui.round(num, idp) + local mult = 10^(idp or 0) + return math.floor(num * mult + 0.5) / mult +end +function gui.setBG(i) + gui.ff:SetImage(i) +end +function gui:setColor(a,b,c) + if type(a)=="string" then + self.Color=Color[a] + elseif type(a)=="number" then + self.Color=Color.new(a,b,c) + end +end +function gui:setTextColor(a,b,c) + if type(a)=="string" then + self.TextColor=Color[a] + elseif type(a)=="number" then + self.TextColor=Color.new(a,b,c) + end +end +function gui:setDefualtFont(font) + _defaultfont = font +end +function gui:SetDualDim(x, y, w, h, sx ,sy ,sw ,sh) + if _GuiPro.DPI_ENABLED then + if x then + x=self.DPI*x + end + if y then + y=self.DPI*y + end + if w then + w=self.DPI*w + end + if h then + h=self.DPI*h + end + end + if sx then + self.scale.pos.x=sx + end + if sy then + self.scale.pos.y=sy + end + if x then + self.offset.pos.x=x + end + if y then + self.offset.pos.y=y + end + if sw then + self.scale.size.x=sw + end + if sh then + self.scale.size.y=sh + end + if w then + self.offset.size.x=w + end + if h then + self.offset.size.y=h + end + if self.Image then + self:SetImage(self.Image) + end +end +function gui:setDualDim(...) + self:SetDualDim(...) +end +function gui:setText(txt) + self.text=txt +end +function gui:getText(txt) + return self.text +end +--_GuiPro.CursorN=love.mouse.getSystemCursor("arrow") +--_GuiPro.CursorH=love.mouse.getSystemCursor("hand") +function gui:SetHand(img,x,y) + --_GuiPro.CursorN=love.mouse.newCursor(img,x,y) +end +function gui:setHotKey(key) + local tab=key:split("+") + self.hotkeys=tab + self.cooldown=false + self.Alarm=multi:newAlarm(1) + self.Alarm.parent=self + self.args={} + self.funcHK=multi:newConnection() + self.Alarm:OnRing(function(alarm) alarm.parent.cooldown=false end) + function self:OnHotKey(func) + self.funcHK:connect(func) + end + self:OnUpdate(function(self) + if self.cooldown then return end + for i=1,#self.hotkeys do + if not(love.keyboard.isDown(self.hotkeys[i])) then + return + end + end + self.cooldown=true + self.funcHK:Fire(self) + self.Alarm:Reset() + end) +end +function gui:SetHover(img,x,y) + --_GuiPro.CursorH=love.mouse.newCursor(img,x,y) +end +function gui:SetName(name) + self.Parent.Children[name]=self + self.Name=name +end +function gui:setNewFont(FontSize) + self.Font=love.graphics.setNewFont(tonumber(FontSize)) +end +function gui:setParent(parent,name)-- Needs fixing!!! + local temp=self.Parent:getChildren() + for i=1,#temp do + if temp[i]==self then + table.remove(self.Parent.Children,i) + break + end + end + table.insert(parent.Children,self) + self.Parent=parent + if name then + self:SetName(name) + end +end +function gui:setVisiblity(val) + self.Visible=val + self.oV=val + doto=self:GetAllChildren() + if val==false then + for i=1,#doto do + doto[i].Visible=val + end + else + for i=1,#doto do + doto[i].Visible=doto[i].oV + end + end +end +function gui:TopStack() + childs=self.Parent:getChildren() + for i=1,#childs do + if childs[i]==self then + table.remove(self.Parent.Children,i) + table.insert(self.Parent.Children,self) + break + end + end +end +function string:insert(p,s) + return ("%s%s%s"):format(self:sub(1,p), s, self:sub(p+1)) +end +function string:remove(p,l) + l=l or 1 + return ("%s%s"):format(self:sub(1,p-1), self:sub(p+l)) +end +function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextBox",name, x, y, w, h, sx ,sy ,sw ,sh) + c.ClearOnFocus=false + c.LoseFocusOnEnter=true + c.Tween=0 + c.XTween=0 + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.text = t + c.ttext= t + c.AutoScaleText=false + c.TextVisibility=1 + c.Color = {220, 220, 220} + c.TextColor = {0, 0, 0} + c.Active=false + c.hidden=false + c.cursor={0,1} + c.mark=nil + c.arrowkeys=false + c.funcF={function() + love.keyboard.setTextInput(true) + end} + c.cooldown=false + c.cooldown2=false + c.funcE={function() + love.keyboard.setTextInput(false) + end} + function c:triggerEnter() + for cc=1,#self.funcE do + self.funcE[cc](self,self.ttext) + end + self.text="" + self.ttext="" + end + c.Enter=true + c.Alarm=multi:newAlarm(.1) + c.Alarm.parent=c + c.Alarm:OnRing(function(alarm) alarm.parent.cooldown=false end) + c.Alarm2=multi:newAlarm(.5) + c.Alarm2.parent=c + c.Alarm2:OnRing(function(alarm) alarm.parent.cooldown2=false end) + c.ArrowAlarm=multi:newAlarm(.1) + c.ArrowAlarm.parent=c + c.ArrowAlarm:OnRing(function(alarm) alarm.parent.arrowkeys=false end) + function c:OnFocus(func) + table.insert(self.funcF,func) + end + function c:OnEnter(func) + table.insert(self.funcE,func) + end + c:OnClicked(function(b,self) + for cc=1,#self.funcF do + self.funcF[cc](self) + end + if self.Active==false then + if self.ClearOnFocus==true then + self.text="" + self.ttext="" + end + for tb=1,#gui.TB do + if gui.TB[tb]~=nil then + gui.TB[tb].Active=false + end + end + self.Active=true + end + end) + c:OnClicked(function(b,self,x,y) + local dwidth, wrappedtext = _defaultfont:getWrap(self.text:sub(1,self.cursor[1]), self.width) + local height = _defaultfont:getHeight() + if #wrappedtext>=1 then + width= _defaultfont:getWidth(wrappedtext[#wrappedtext]) + self.cursor[2]=#wrappedtext + else + self.cursor[2]=1 + width=0 + end + yc=math.ceil(((y/self.DPI)-(self.FontHeight/2)+self.Tween-self.y)/height) + xc=math.floor(x) + end) + c:AddDrawRuleE(function(self) + if self.Active then + local dwidth, wrappedtext = _defaultfont:getWrap(self.text:sub(1,self.cursor[1]), self.width) + local height = _defaultfont:getHeight() + if #wrappedtext>=1 then + width= _defaultfont:getWidth(wrappedtext[#wrappedtext]) + self.cursor[2]=#wrappedtext + else + self.cursor[2]=1 + width=0 + end + x1=width+2+self.x+self.XTween + y1=(self.y+(height*(self.cursor[2]-1))+(self.FontHeight/2)+self.Tween)*self.DPI + x2=width+2+self.x+self.XTween + y2=(self.y+(self.FontHeight/2)+self.Tween*self.DPI)+height*self.cursor[2] + love.graphics.line(x1,y1,x2,y2) + end + end) + c:OnUpdate(function(self) + if love.keyboard.isDown("backspace") and self.Active and self.cooldown==false then + if #self.text>0 then + self.text = self.text:remove(self.cursor[1]) + self.ttext = self.ttext:remove(self.cursor[1]) + self.cursor[1]=self.cursor[1]-1 + end + self.cooldown=true + self.Alarm:Reset() + elseif love.keyboard.isDown("backspace")==false then + self.cooldown=false + end + if love.keyboard.isDown("left") and self.arrowkeys==false and self.Active then + self.arrowkeys=true + self.cursor[1]=self.cursor[1]-1 + if self.cursor[1]<0 then + self.cursor[1]=0 + end + self.ArrowAlarm:Reset() + elseif love.keyboard.isDown("right") and self.arrowkeys==false and self.Active then + self.arrowkeys=true + self.cursor[1]=self.cursor[1]+1 + if self.cursor[1]>#self.text then + self.cursor[1]=#self.text + end + self.ArrowAlarm:Reset() + end + if love.keyboard.isDown("delete") and self.Active then + if #self.text>0 then + self.text = "" + self.ttext = "" + self.cursor[1]=1 + end + elseif (love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift")) and love.keyboard.isDown("return") and self.cooldown2==false then + self.text=self.text.."\n" + self.ttext=self.ttext.."\n" + self.cooldown2=true + c.Alarm2:Reset() + elseif (love.keyboard.isDown("return") or love.keyboard.isDown("enter") or love.keyboard.isDown("kpenter")) and self.Active and self.Enter and not(love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift")) then + if self.LoseFocusOnEnter then + self.Active=false + else + self.Active=true + end + for cc=1,#self.funcE do + self.funcE[cc](self,self.ttext) + end + end + end) + table.insert(gui.TB,c) + return c +end +--TEXT BOX HELPER FUNCTION +function love.textinput(t) + for tb=1,#gui.TB do + if gui.TB[tb]~=nil then + if gui.TB[tb].Active then + if gui.TB[tb].hidden then + --gui.TB[tb].text=gui.TB[tb].text.."*" + gui.TB[tb].text=gui.TB[tb].text:insert(gui.TB[tb].cursor[1],"*") + else + --gui.TB[tb].text=gui.TB[tb].text..t + gui.TB[tb].text=gui.TB[tb].text:insert(gui.TB[tb].cursor[1],t) + end + gui.TB[tb].ttext=gui.TB[tb].ttext:insert(gui.TB[tb].cursor[1],t) + gui.TB[tb].cursor[1]=gui.TB[tb].cursor[1]+1 + end + end + end +end +function gui:newTextButton(t,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextButton",name, x, y, w, h, sx ,sy ,sw ,sh) + c.Tween=0 + c.XTween=0 + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.text = t + c.AutoScaleText=false + c.TextVisibility=1 -- 0=invisible,1=solid (self.TextVisibility*254+1) + c.Color = {220, 220, 220} + c.TextColor = {0, 0, 0} + c:OnEnter(function() + --love.mouse.setCursor(_GuiPro.CursorH) + end) + c:OnExit(function() + --love.mouse.setCursor(_GuiPro.CursorN) + end) + return c +end +function gui:newTextLabel(t,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextLabel",name, x, y, w, h, sx ,sy ,sw ,sh) + c.Tween=0 + c.XTween=0 + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.text = t + c.AutoScaleText=false + c.TextVisibility=1 -- 0=invisible,1=solid (self.TextVisibility*254+1) + c.Color = {220, 220, 220} + c.TextColor = {0, 0, 0} + return c +end +function gui:AddDrawRuleB(rule) + if not(self.DrawRulesB) then self.DrawRulesB={} end + table.insert(self.DrawRulesB,rule) +end +function gui:AddDrawRuleE(rule) + if not(self.DrawRulesE) then self.DrawRulesE={} end + table.insert(self.DrawRulesE,rule) +end +function gui:draw() + if _GuiPro.rotate~=0 then + love.graphics.rotate(math.rad(_GuiPro.rotate)) + end + if self.FormFactor:lower()=="rectangle" then + self:drawR() + elseif self.FormFactor:lower()=="circle" then + self:drawC() + else + error("Unsupported FormFactor: "..self.FormFactor.."!") + end +end +function gui:drawC() + if love.mouse.isDown("l")==false and love.mouse.isDown("m")==false and love.mouse.isDown("r")==false then + _GuiPro.DragItem={} + _GuiPro.hasDrag=false + end + if self.Visible==true and self.VIS==true then + local b=true + for i,v in pairs(_GuiPro.Clips) do + if self:isDescendant(v)==true then + b=false + end + end + if b then + love.graphics.setStencilTest( ) + _GuiPro.HasStencel=false + _GuiPro.StencelHolder=nil + end + local x,y,r,s=(self.offset.pos.x or 0)+self.Parent.x,(self.offset.pos.y or 0)+self.Parent.y,self.offset.size.x or 0,self.offset.size.y or 360 + if self.CC then + x,y=x+r,y+r + end + self.x,self.y=x,y + _GuiPro.circleStencilFunction = function() + love.graphics.circle("fill",x,y,r,s) + end + if math.sqrt((love.mouse.getX()-x)^2+(love.mouse.getY()-y)^2)<=r and self:eventable() and self:Clickable() and self.Active==true then + self.hovering=true + if love.mouse.isDown("l") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.lclicked=true + elseif love.mouse.isDown("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.rclicked=true + elseif love.mouse.isDown("m") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.mclicked=true + else + if string.find(self.Type, "Button") and _GuiPro.hasDrag==false then + love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + self.hovering=false + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + if self.ClipDescendants==true then + _GuiPro.Clips[tostring(self)]=self + _GuiPro.HasStencel=true + _GuiPro.StencelHolder=self + love.graphics.stencil(_GuiPro.circleStencilFunction) + love.graphics.setStencilTest("notequal",0) + end + love.graphics.circle("fill",x,y,r,s) + love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.Visibility*254) + for b=0,self.BorderSize-1 do + love.graphics.circle("line",x,y,r+b,s) + end + if string.find(self.Type, "Text") then + if self.text~=nil then + if self.AutoScaleText then + self.FontSize=math.floor(self.height/1.45833) + end + love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility*254) + love.graphics.setFont(self.Font) + love.graphics.printf(self.text, x-(r/2)+(self.XTween), y-(r/2)+self.Tween, r, self.TextFormat) + end + end + end +end +function gui:drawR() + if love.mouse.isDown("l")==false and love.mouse.isDown("m")==false and love.mouse.isDown("r")==false then + _GuiPro.DragItem={} + _GuiPro.hasDrag=false + end + if self.Visible==true and self.VIS==true then + local b=true + for i,v in pairs(_GuiPro.Clips) do + if self:isDescendant(v)==true then + b=false + end + end + if b==true then + love.graphics.setStencilTest() + love.graphics.setScissor() + end + self.x=(self.Parent.width*self.scale.pos.x)+self.offset.pos.x+self.Parent.x + self.y=(self.Parent.height*self.scale.pos.y)+self.offset.pos.y+self.Parent.y + self.width=(self.Parent.width*self.scale.size.x)+self.offset.size.x + self.height=(self.Parent.height*self.scale.size.y)+self.offset.size.y + if self.DrawRulesB then + for dr=1,#self.DrawRulesB do + self.DrawRulesB[dr](self) + end + end + if (love.mouse.getX() > self.x and love.mouse.getX() < self.x+self.width and love.mouse.getY() > self.y and love.mouse.getY() < self.y+self.height and self:Clickable() and self:eventable()) or self:touchable("r") and self.Active==true then + self.hovering=true + if love.mouse.isDown("l") or self:touchable("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.lclicked=true + elseif love.mouse.isDown("r") or self:touchable("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.rclicked=true + elseif love.mouse.isDown("m") or self:touchable("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.mclicked=true + else + if string.find(self.Type, "Button") or self:touchable("r") and _GuiPro.hasDrag==false then + love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility*254) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + end + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility*254) + self.hovering=false + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + if self.ClipDescendants==true then + _GuiPro.Clips[tostring(self)]=self + love.graphics.setScissor(self.x, self.y, self.width, self.height) + end + if self:hasRoundness() then + love.graphics.stencil(self.stfunc, "replace", 1) + love.graphics.setStencilTest("greater", 0) + end + love.graphics.rectangle("fill", self.x, self.y, self.width, self.height,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI) + if string.find(self.Type, "Image") then + self:ImageRule() + end + if self.Type=="Video" then + self:VideoRule() + end + if self:hasRoundness() then + love.graphics.setStencilTest() + end + love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.Visibility*254) + for b=0,self.BorderSize-1 do + love.graphics.rectangle("line", self.x-(b/2), self.y-(b/2), self.width+b, self.height+b,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI) + end + if string.find(self.Type, "Text") then + if self.text~=nil then + if self.AutoScaleText then + self.FontSize=math.floor(self.height/1.45833) + end + love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility*254) + if self.Font==_defaultfont then + love.graphics.setFont(self.Font) + love.graphics.printf(self.text, self.x+2+(self.XTween*self.DPI)+((self.marginL or 0)*self.DPI or self.XTween*self.DPI), self.y+(self.FontHeight/2)+self.Tween*self.DPI, self.width+(0 or (self.marginR or 0)*self.DPI), self.TextFormat) + else + if type(self.Font)=="string" then + self.Font=love.graphics.newFont(self.Font,self.FontSize) + self.FontHeight=self.Font:getHeight() + else + love.graphics.setFont(self.Font) + end + if type(self.FontSize)=="string" then + self.FontSize=tonumber(self.FontSize) + love.graphics.setNewFont(self.FontSize) + end + love.graphics.printf(self.text, self.x+2+((self.marginL or 0)*self.DPI or self.XTween*self.DPI), self.y+math.floor((self.FontHeight-self.FontSize)/2)+self.Tween*self.DPI, self.width+(0 or (self.marginR or 0)*self.DPI), self.TextFormat) + end + end + end + if self.DrawRulesE then + for dr=1,#self.DrawRulesE do + self.DrawRulesE[dr](self) + end + end + end +end + +gui:respectHierarchy() +_GuiPro.width,_GuiPro.height=love.graphics.getDimensions() +multi:newLoop():OnLoop(function() _GuiPro.width,_GuiPro.height=love.graphics.getDimensions() _GuiPro:update() end) +multi:onDraw(function() _GuiPro:draw() end) +gui.ff=gui:newFrame("",0,0,0,0,0,0,1,1) +gui.ff.Color={255,255,255} +gui.ff:OnUpdate(function(self) + self:BottomStack() +end) + diff --git a/game/core/Library.lua b/game/core/Library.lua new file mode 100644 index 0000000..8260136 --- /dev/null +++ b/game/core/Library.lua @@ -0,0 +1,319 @@ +if table.unpack then + unpack=table.unpack +end +function table.val_to_str ( v ) + if "string" == type( v ) then + v = string.gsub( v, "\n", "\\n" ) + if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then + return "'" .. v .. "'" + end + return '"' .. string.gsub(v,'"', '\\"' ) .. '"' + else + return "table" == type( v ) and table.tostring( v ) or + tostring( v ) + end +end + +function table.key_to_str ( k ) + if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then + return k + else + return "[" .. table.val_to_str( k ) .. "]" + end +end + +function table.tostring( tbl ) + local result, done = {}, {} + for k, v in ipairs( tbl ) do + table.insert( result, table.val_to_str( v ) ) + done[ k ] = true + end + for k, v in pairs( tbl ) do + if not done[ k ] then + table.insert( result, + table.key_to_str( k ) .. "=" .. table.val_to_str( v ) ) + end + end + return "{" .. table.concat( result, "," ) .. "}" +end +function table.merge(t1, t2) + t1,t2= t1 or {},t2 or {} + for k,v in pairs(t2) do + if type(v) == "table" then + if type(t1[k] or false) == "table" then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +Library={} +function Library.optimize(func) + local test=Library.convert(func) + rawset(test,"link",{}) + rawset(test,"last","") + rawset(test,"org",func) + test:inject(function(...) + rawset(test,"last",table.tostring({...})) + if test.link[test.last]~=nil then + return Library.forceReturn(unpack(test.link[test.last])) + end + return {...} + end,1) + test:inject(function(...) + test.link[test.last]={test.org(...)} + return test.org(...) + end) + return test +end +function Library.forceReturn(...) + return {[0]="\1\7\6\3\2\99\125",...} +end +function Library.inject(lib,dat,arg) + if type(lib)=="table" then + if type(dat)=="table" then + table.merge(lib,dat) + elseif type(dat)=="string" then + if lib.Version and dat:match("(%d-)%.(%d-)%.(%d-)") then + lib.Version={dat:match("(%d+)%.(%d+)%.(%d+)")} + elseif dat=="meta" and type(arg)=="table" then + local _mt=getmetatable(lib) or {} + local mt={} + table.merge(mt,arg) + table.merge(_mt,mt) + setmetatable(lib,_mt) + elseif dat=="compat" then + lib["getVersion"]=function(self) return self.Version[1].."."..self.Version[2].."."..self.Version[3] end + if not lib.Version then + lib.Version={1,0,0} + end + elseif dat=="inhert" then + if not(lib["!%"..arg.."%!"]) then print("Wrong Password!!") return end + lib["!%"..arg.."%!"].__index=lib["!!%"..arg.."%!!"] + end + elseif type(dat)=="function" then + for i,v in pairs(lib) do + dat(lib,i,v) + end + end + elseif type(lib)=="function" or type(lib)=="userdata" then + if lib==unpack then + print("function unpack cannot yet be injected!") + return unpack + elseif lib==pairs then + print("function pairs cannot yet be injected!") + return lib + elseif lib==ipairs then + print("function ipairs cannot yet be injected!") + return lib + elseif lib==type then + print("function type cannot yet be injected!") + return lib + end + temp={} + local mt={ + __call=function(t,...) + local consume,MainRet,init={},{},{...} + local tt={} + for i=1,#t.__Link do + tt={} + if t.__Link[i]==t.__Main then + if #consume~=0 then + MainRet={t.__Link[i](unpack(consume))} + else + MainRet={t.__Link[i](unpack(init))} + end + else + if i==1 then + consume=(t.__Link[i](unpack(init))) + else + if type(MainRet)=="table" then + table.merge(tt,MainRet) + end + if type(consume)=="table" then + table.merge(tt,consume) + end + consume={t.__Link[i](unpack(tt))} + end + if i==#t.__Link then + return unpack(consume) + end + if consume then if consume[0]=="\1\7\6\3\2\99\125" then consume[0]=nil return unpack(consume) end end + end + end + if type(MainRet)=="table" then + table.merge(tt,MainRet) + end + if type(consume)=="table" then + table.merge(tt,consume) + end + return unpack(tt) + end, + } + temp.__Link={lib} + temp.__Main=lib + temp.__self=temp + function temp:inject(func,i) + if i then + table.insert(self.__Link,i,func) + else + table.insert(self.__Link,func) + end + end + function temp:consume(func) + for i=1,#self.__Link do + if self.__Link[i]==self.__Main then + self.__Link[i]=func + self.__self.__Main=func + return true + end + end + return false + end + setmetatable(temp,mt) + Library.protect(temp,"lolz") + return temp + else + return "arg1 must be a table or a function" + end +end +function Library.parse(lib) + for i,v in pairs(lib) do + print(i,v) + end +end +function Library.protect(lib,pass) + pass=pass or "*" + local mt={} + local test={ + __index = lib, + __newindex = function(tab, key, value) + local t,b=key:find(tab["!%"..pass.."%!"].__pass,1,true) + if t then + local _k=key:sub(b+1) + rawset(tab,_k,value) + else + error("Cannot alter a protected library!") + end + end, + __metatable = false, + __pass=pass or "*" + } + local _mt=getmetatable(lib) or {} + table.merge(mt,_mt) + table.merge(mt,test) + lib["!%"..pass.."%!"]=test + lib["!!%"..pass.."%!!"]=lib + local temp=setmetatable({},mt) + for i,v in pairs(_G) do + if v==lib then + _G[i]=temp + Library(function(link) + link[i]=v + end) + end + end +end +function Library.unprotect(lib,pass) + if not(lib["!%"..pass.."%!"]) then print("Wrong Password or Library is not Protected!") return end + if lib["!%"..pass.."%!"].__pass==pass then + lib["!%"..pass.."%!"].__newindex=lib["!!%"..pass.."%!!"] + lib["!%"..pass.."%!"].__index=nil + lib["!%"..pass.."%!"].__newindex=nil + lib["!%"..pass.."%!"].__metatable = true + setmetatable(lib["!!%"..pass.."%!!"],lib["!%"..pass.."%!"]) + for i,v in pairs(_G) do + if v==lib then + _G[i]=lib["!!%"..pass.."%!!"] + end + end + lib["!!%"..pass.."%!!"]["!%"..pass.."%!"]=nil + lib["!!%"..pass.."%!!"]["!!%"..pass.."%!!"]=nil + else + print("Wrong Password!!!") + end +end +function Library.addPoll(lib,polldata,ref) + lib.__polldata={} + Library.inject(lib.__polldata,polldata) + if type(ref)=="table" then + Library.inject(ref,"meta",{__newindex=function(t,k,v) + t[k].__polldata=polldata + end}) + end +end +function Library.newPollData(t) + local temp={} + temp.__onPolled=function() end + temp.__pollData=false + temp.__advDisc="" + temp.__pollcalls=-1 -- infinte + for i,v in pairs(t) do + if type(v)=="string" then + temp.__advDisc=v + elseif type(v)=="number" then + temp.__pollcalls=v + elseif type(v)=="table" then + temp[v[1]]=v[2] + elseif type(v)=="function" then + temp.__onPolled=v + elseif type(v)=="boolean" then + temp.__pollData=v + else + temp.__userdata=v + end + end + return temp +end +function Library.convert(...) + local temp,rets={...},{} + for i=1,#temp do + if type(temp[i])=="function" then + table.insert(rets,Library.inject(temp[i])) + else + error("Takes only functions and returns in order from functions given. arg # "..i.." is not a function!!! It is a "..type(temp[i])) + end + end + return unpack(rets) +end +function Library.convertIn(...) + local temp,list={...},{} + for i=1,#temp do + if type(temp[i])=="table" then + for k,v in pairs(temp[i]) do + if type(v)=="function" then + temp[i][k]=Library.inject(temp[i][k]) + end + end + else + error("Takes only tables! Arg "..i.." isn't it is a "..type(temp[i])) + end + end +end +function Library.newInjectedFunction() + return Library.convert(function(...) return unpack{...} end) +end +function Library.capulate(lib) + Library.inject(lib,"meta",{ + __index=function(t,k,v) + for i,_v in pairs(t) do + if k:lower()==i:lower() then + return t[i] + end + end + end, + __newindex=function(t,k,v) + rawset(t,k:lower(),v) + end + }) +end +local link={MainLibrary=Library} +Library.inject(Library,"meta",{ + __Link=link, + __call=function(self,func) func(link) end, +}) +--Library.protect(Library,"N@#P!KLkk1(93320") diff --git a/game/core/Utils.lua b/game/core/Utils.lua new file mode 100644 index 0000000..c80b4bc --- /dev/null +++ b/game/core/Utils.lua @@ -0,0 +1,797 @@ +-- os Additions +function os.getSystemBit() + if (os.getenv('PROCESSOR_ARCHITEW6432')=='AMD64' or os.getenv('PROCESSOR_ARCHITECTURE')=='AMD64') then + return 64 + else + return 32 + end +end +function os.sleep(n) + if not n then n=0 end + local t0 = os.clock() + while os.clock() - t0 <= n do end +end +function os.pause(msg) + if msg ~= nil then + print(msg) + end + io.read() +end +function os.batCmd(cmd) + io.mkFile('temp.bat',cmd) + local temp = os.execute([[temp.bat]]) + io.delFile('temp.bat') + return temp +end +function os._getOS() + if package.config:sub(1,1)=='\\' then + return 'windows' + else + return 'unix' + end +end +function os.getOS(t) + if not t then + return os._getOS() + end + if os._getOS()=='unix' then + fh,err = io.popen('uname -o 2>/dev/null','r') + if fh then + osname = fh:read() + end + if osname then return osname end + end + local winver='Unknown Version' + local a,b,c=os.capture('ver'):match('(%d+).(%d+).(%d+)') + local win=a..'.'..b..'.'..c + if type(t)=='string' then + win=t + end + if win=='4.00.950' then + winver='95' + elseif win=='4.00.1111' then + winver='95 OSR2' + elseif win=='4.00.1381' then + winver='NT 4.0' + elseif win=='4.10.1998' then + winver='98' + elseif win=='4.10.2222' then + winver='98 SE' + elseif win=='4.90.3000' then + winver='ME' + elseif win=='5.00.2195' then + winver='2000' + elseif win=='5.1.2600' then + winver='XP' + elseif win=='5.2.3790' then + winver='Server 2003' + elseif win=='6.0.6000' then + winver='Vista/Windows Server 2008' + elseif win=='6.0.6002' then + winver='Vista SP2' + elseif win=='6.1.7600' then + winver='7/Windows Server 2008 R2' + elseif win=='6.1.7601' then + winver='7 SP1/Windows Server 2008 R2 SP1' + elseif win=='6.2.9200' then + winver='8/Windows Server 2012' + elseif win=='6.3.9600' then + winver='8.1/Windows Server 2012' + elseif win=='6.4.9841' then + winver='10 Technical Preview 1' + elseif win=='6.4.9860' then + winver='10 Technical Preview 2' + elseif win=='6.4.9879' then + winver='10 Technical Preview 3' + elseif win=='10.0.9926' then + winver='10 Technical Preview 4' + end + return 'Windows '..winver +end +function os.getLuaArch() + return (#tostring({})-7)*4 +end +if os.getOS()=='windows' then + function os.sleep(n) + if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end + end +else + function os.sleep(n) + os.execute('sleep ' .. tonumber(n)) + end +end +function os.capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end +function os.getCurrentUser() + return os.getenv('$USER') or os.getenv('USERNAME') +end +-- string Additions +function string.trim(s) + local from = s:match"^%s*()" + return from > #s and "" or s:match(".*%S", from) +end +function string.random(n) + local str = '' + strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'} + for i=1,n do + h = math.random(1,#strings) + str = str..''..strings[h] + end + return str +end +function string.linesToTable(s) + local t = {} + local i = 0 + while true do + i = string.find(s, '\n', i+1) + if i == nil then return t end + table.insert(t, i) + end +end +function string.lines(str) + local t = {} + local function helper(line) table.insert(t, line) return '' end + helper((str:gsub('(.-)\r?\n', helper))) + return t +end +function string.split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = '(.-)' .. pat + local last_end = 1 + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= '' then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + return t +end +function string.shuffle(inputStr) + math.randomseed(os.time()); + local outputStr = ''; + local strLength = string.len(inputStr); + while (strLength ~=0) do + local pos = math.random(strLength); + outputStr = outputStr..string.sub(inputStr,pos,pos); + inputStr = inputStr:sub(1, pos-1) .. inputStr:sub(pos+1); + strLength = string.len(inputStr); + end + return outputStr; +end +function string.genKeys(chars,a,f,s,GG) + if GG then + chars=string.rep(chars,a) + end + if s then + chars=string.shuffle(chars) + end + b=#chars + if a==0 then return end + local taken = {} local slots = {} + for i=1,a do slots[i]=0 end + for i=1,b do taken[i]=false end + local index = 1 + local tab={} + for i=1,#chars do + table.insert(tab,chars:sub(i,i)) + end + while index > 0 do repeat + repeat slots[index] = slots[index] + 1 + until slots[index] > b or not taken[slots[index]] + if slots[index] > b then + slots[index] = 0 + index = index - 1 + if index > 0 then + taken[slots[index]] = false + end + break + else + taken[slots[index]] = true + end + if index == a then + local tt={} + for i=1,a do + table.insert(tt,tab[slots[i]]) + end + f(table.concat(tt)) + taken[slots[index]] = false + break + end + index = index + 1 + until true end +end +-- io Additions +function io.getInput(msg) + if msg ~= nil then + io.write(msg) + end + return io.read() +end +function io.scanDir(directory) + directory=directory or io.getDir() + local i, t, popen = 0, {}, io.popen + if os.getOS()=='unix' then + for filename in popen('ls -a \''..directory..'\''):lines() do + i = i + 1 + t[i] = filename + end + else + for filename in popen('dir \''..directory..'\' /b'):lines() do + i = i + 1 + t[i] = filename + end + end + return t +end +function io.buildFromTree(tbl, indent,folder) + if not indent then indent = 0 end + if not folder then folder = '' end + for k, v in pairs(tbl) do + formatting = string.rep(' ', indent) .. k .. ':' + if type(v) == 'table' then + if not(io.dirExists(folder..string.sub(formatting,1,-2))) then + io.mkDir(folder..string.sub(formatting,1,-2)) + end + io.buildFromTree(v,0,folder..string.sub(formatting,1,-2)..'\\') + else + a=string.find(tostring(v),':',1,true) + if a then + file=string.sub(tostring(v),1,a-1) + data=string.sub(tostring(v),a+1) + io.mkFile(folder..file,data,'wb') + else + io.mkFile(folder..v,'','wb') + end + end + end +end +function io.cpFile(path,topath) + if os.getOS()=='unix' then + os.execute('cp '..file1..' '..file2) + else + os.execute('Copy '..path..' '..topath) + end +end +function io.delDir(directoryname) + if os.getOS()=='unix' then + os.execute('rm -rf '..directoryname) + else + os.execute('rmdir '..directoryname..' /s /q') + end +end +function io.delFile(path) + os.remove(path) +end +function io.mkDir(dirname) + os.execute('mkdir "' .. dirname..'"') +end +function io.mkFile(filename,data,tp) + if not(tp) then tp='wb' end + if not(data) then data='' end + file = io.open(filename, tp) + if file==nil then return end + file:write(data) + file:close() +end +function io.movFile(path,topath) + io.cpFile(path,topath) + io.delFile(path) +end +function io.listFiles(dir) + if not(dir) then dir='' end + local f = io.popen('dir \''..dir..'\'') + if f then + return f:read('*a') + else + print('failed to read') + end +end +function io.getDir(dir) + if not dir then return io.getWorkingDir() end + if os.getOS()=='unix' then + return os.capture('cd '..dir..' ; cd') + else + return os.capture('cd '..dir..' & cd') + end +end +function io.getWorkingDir() + return io.popen'cd':read'*l' +end +function io.fileExists(path) + g=io.open(path or '','r') + if path =='' then + p='empty path' + return nil + end + if g~=nil and true or false then + p=(g~=nil and true or false) + end + if g~=nil then + io.close(g) + else + return false + end + return p +end +function io.fileCheck(file_name) + if not file_name then print('No path inputed') return false end + local file_found=io.open(file_name, 'r') + if file_found==nil then + file_found=false + else + file_found=true + end + return file_found +end +function io.dirExists(strFolderName) + strFolderName = strFolderName or io.getDir() + local fileHandle, strError = io.open(strFolderName..'\\*.*','r') + if fileHandle ~= nil then + io.close(fileHandle) + return true + else + if string.match(strError,'No such file or directory') then + return false + else + return true + end + end +end +function io.getAllItems(dir) + local t=os.capture("cd \""..dir.."\" & dir /a-d | find",true):lines() + return t +end +function io.listItems(dir) + if io.dirExists(dir) then + temp=io.listFiles(dir) -- current directory if blank + if io.getDir(dir)=='C:\\\n' then + a,b=string.find(temp,'C:\\',1,true) + a=a+2 + else + a,b=string.find(temp,'..',1,true) + end + temp=string.sub(temp,a+2) + list=string.linesToTable(temp) + temp=string.sub(temp,1,list[#list-2]) + slist=string.lines(temp) + table.remove(slist,1) + table.remove(slist,#slist) + temp={} + temp2={} + for i=1,#slist do + table.insert(temp,string.sub(slist[i],40,-1)) + end + return temp + else + return nil + end +end +function io.getDirectories(dir,l) + if dir then + dir=dir..'\\' + else + dir='' + end + local temp2=io.scanDir(dir) + for i=#temp2,1,-1 do + if io.fileExists(dir..temp2[i]) then + table.remove(temp2,i) + elseif l then + temp2[i]=dir..temp2[i] + end + end + return temp2 +end +function io.getFiles(dir,l) + if dir then + dir=dir..'\\' + else + dir='' + end + local temp2=io.scanDir(dir) + for i=#temp2,1,-1 do + if io.dirExists(dir..temp2[i]) then + table.remove(temp2,i) + elseif l then + temp2[i]=dir..temp2[i] + end + end + return temp2 +end +function io.getFullName(name) + local temp=name or arg[0] + if string.find(temp,'\\',1,true) or string.find(temp,'/',1,true) then + temp=string.reverse(temp) + a,b=string.find(temp,'\\',1,true) + if not(a) or not(b) then + a,b=string.find(temp,'/',1,true) + end + return string.reverse(string.sub(temp,1,b-1)) + end + return temp +end +function io.getName(file) + local name=io.getFullName(file) + name=string.reverse(name) + a,b=string.find(name,'.',1,true) + name=string.sub(name,a+1,-1) + return string.reverse(name) +end +function io.readFile(file) + local f = io.open(file, 'rb') + local content = f:read('*all') + f:close() + return content +end +function io.getExtension(file) + local file=io.getFullName(file) + file=string.reverse(file) + local a,b=string.find(file,'.',0,true) + local temp=string.sub(file,1,b) + return string.reverse(temp) +end +function io.pathToTable(path) + local p=io.splitPath(path) + local temp={} + temp[p[1]]={} + local last=temp[p[1]] + for i=2,#p do + snd=last + last[p[i]]={} + last=last[p[i]] + end + return temp,last,snd +end +function io.splitPath(str) + return string.split(str,'[\\/]+') +end + +function io.parseDir(dir,t) + io.tempFiles={} + function _p(dir) + local dirs=io.getDirectories(dir,true) + local files=io.getFiles(dir,true) + for i=1,#files do + p,l,s=io.pathToTable(files[i]) + if t then + s[io.getFullName(files[i])]=io.readFile(files[i]) + else + s[io.getFullName(files[i])]=io.open(files[i],'r+') + end + table.merge(io.tempFiles,p) + end + for i=1,#dirs do + table.merge(io.tempFiles,io.pathToTable(dirs[i])) + _p(dirs[i],t) + end + end + _p(dir) + return io.tempFiles +end +function io.parsedir(dir,f) + io.tempFiles={} + function _p(dir,f) + local dirs=io.getDirectories(dir,true) + local files=io.getFiles(dir,true) + for i=1,#files do + if not f then + table.insert(io.tempFiles,files[i]) + else + f(files[i]) + end + end + for i=1,#dirs do + _p(dirs[i],f) + end + end + _p(dir,f) + return io.tempFiles +end +function io.driveReady(drive) + drive=drive:upper() + if not(drive:find(':',1,true)) then + drive=drive..':' + end + drives=io.getDrives() + for i=1,#drives do + if drives[i]==drive then + return true + end + end + return false +end +function io.getDrives() + if os.getOS()=='windows' then + local temp={} + local t1=os.capture('wmic logicaldisk where drivetype=2 get deviceid, volumename',true) + local t2=os.capture('wmic logicaldisk where drivetype=3 get deviceid, volumename',true) + for drive,d2 in t1:gmatch('(.:)%s-(%w+)') do + if #d2>1 then + table.insert(temp,drive) + end + end + for drive in t2:gmatch('(.:)') do + table.insert(temp,drive) + end + return temp + end + error('Command is windows only!') +end +-- table Additions +function table.dump(t,indent) + local names = {} + if not indent then indent = '' end + for n,g in pairs(t) do + table.insert(names,n) + end + table.sort(names) + for i,n in pairs(names) do + local v = t[n] + if type(v) == 'table' then + if(v==t) then + print(indent..tostring(n)..': <-') + else + print(indent..tostring(n)..':') + table.dump(v,indent..' ') + end + else + if type(v) == 'function' then + print(indent..tostring(n)..'()') + else + print(indent..tostring(n)..': '..tostring(v)) + end + end + end +end +function table.alphanumsort(o) + local function padnum(d) local dec, n = string.match(d, '(%.?)0*(.+)') + return #dec > 0 and ('%.12f'):format(d) or ('%s%03d%s'):format(dec, #n, n) + end + table.sort(o, function(a,b) return tostring(a):gsub('%.?%d+',padnum)..('%3d'):format(#b)< tostring(b):gsub('%.?%d+',padnum)..('%3d'):format(#a) end) + return o +end +function table.foreach(t,f) + for i,v in pairs(t) do + f(v) + end +end +function table.merge(t1, t2) + for k,v in pairs(t2) do + if type(v) == 'table' then + if type(t1[k] or false) == 'table' then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +function table.print(tbl, indent) + if not indent then indent = 0 end + for k, v in pairs(tbl) do + formatting = string.rep(' ', indent) .. k .. ': ' + if type(v) == 'table' then + print(formatting) + table.print(v, indent+1) + else + print(formatting .. tostring(v)) + end + end +end +function table.merge(t1, t2) + for k,v in pairs(t2) do + if type(v) == 'table' then + if type(t1[k] or false) == 'table' then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +function table.clear(t) + for k in pairs (t) do + t[k] = nil + end +end +function table.copy(t) + function deepcopy(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[deepcopy(orig_key)] = deepcopy(orig_value) + end + setmetatable(copy, deepcopy(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy + end + return deepcopy(t) +end +function table.swap(tab,i1,i2) + tab[i1],tab[i2]=tab[i2],tab[i1] +end +function table.append(t1, ...) + t1,t2= t1 or {},{...} + for k,v in pairs(t2) do + t1[#t1+1]=t2[k] + end + return t1 +end +function table.compare(t1, t2,d) + if d then + return table.deepCompare(t1,t2) + end + --if #t1 ~= #t2 then return false end + if #t2>#t1 then + for i=1,#t2 do + if t1[i] ~= t2[i] then + return false,t2[i] + end + end + else + for i=1,#t1 do + if t1[i] ~= t2[i] then + return false,t2[i] + end + end + end + return true +end +function table.deepCompare(t1,t2) + if t1==t2 then return true end + if (type(t1)~='table') then return false end + local mt1 = getmetatable(t1) + local mt2 = getmetatable(t2) + if( not table.deepCompare(mt1,mt2) ) then return false end + for k1,v1 in pairs(t1) do + local v2 = t2[k1] + if( not table.deepCompare(v1,v2) ) then return false end + end + for k2,v2 in pairs(t2) do + local v1 = t1[k2] + if( not table.deepCompare(v1,v2) ) then return false end + end + return true +end +function table.has(t,_v) + for i,v in pairs(t) do + if v==_v then + return true + end + end + return false +end +function table.reverse(tab) + local size = #tab + local newTable = {} + for i,v in ipairs (tab) do + newTable[size-i] = v + end + for i=1,#newTable do + tab[i]=newTable[i] + end +end +-- Math Additions +local Y = function(g) local a = function(f) return f(f) end return a(function(f) return g(function(x) local c=f(f) return c(x) end) end) end +local F = function(f) return function(n)if n == 0 then return 1 else return n*f(n-1) end end end +math.factorial = Y(F) +math.fib={} +math.fib.fibL={} +setmetatable(math.fib,{__call=function(self,n) + if n<=2 then + return 1 + else + if self.fibL[n] then + return self.fibL[n] + else + local t=math.fib(n-1)+math.fib(n-2) + self.fibL[n]=t + return t + end + end +end}) +local floor,insert = math.floor, table.insert +function math.basen(n,b) + n = floor(n) + if not b or b == 10 then return tostring(n) end + local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + local t = {} + local sign = '' + if n < 0 then + sign = '-' + n = -n + end + repeat + local d = (n % b) + 1 + n = floor(n / b) + insert(t, 1, digits:sub(d,d)) + until n == 0 + return sign .. table.concat(t,'') +end +function math.convbase(n,b,tb) + return math.basen(tonumber(tostring(n),b),tb) +end +if BigNum then + function BigNum.mod(a,b) + return a-((a/b)*b) + end + local floor,insert = math.floor, table.insert + function math.basen(n,b) + n = BigNum.new(n) + if not b or b == 10 then return tostring(n) end + local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + local t = {} + local sign = '' + if n < BigNum.new(0) then + sign = '-' + n = -n + end + repeat + local d = BigNum.mod(n , b) + 1 + n = n/b + d=tonumber(tostring(d)) + insert(t, 1, digits:sub(d,d)) + until tonumber(tostring(n)) == 0 + return sign .. table.concat(t,'') + end + function math.to10(n,b) + local num=tostring(n) + local sum=BigNum.new() + local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + for i=1,#num do + local v=digits:find(num:sub(i,i),1,true) + sum=sum+BigNum.new(tonumber(v)-1)*BigNum.pow(BigNum.new(b),BigNum.new(#num-i)) + end + return sum + end + function math.convbase(n,b,tb) + return math.basen(math.to10(n,b),tb) + end +end +function math.numfix(n,x) + local str=tostring(n) + if #str olleh +nil = binobj:flipbits() -- flips the binary bits +nil** = binobj:segment(a,b) -- gets a segment of the binobj data works just like string.sub(a,b) without str +nil* = binobj:insert(a,i) -- inserts i (string or number(converts into string)) in position a +nil* = binobj:parseN(n) -- removes ever (nth) byte of data +nil = binobj:getlength() -- gets length or size of binary data +nil* = binobj:shift(n) -- shift the binary data by n positive --> negitive <-- +nil* = binobj:delete(a,b) -- deletes part of a binobj data Usage: binobj:delete(#) deletes at pos # binobj:delete(#1,#2) deletes from #1 to #2 binobj:delete('string') deletes all instances of 'byte' as a string Use string.char(#) or '\#' to get byte as a string +nil* = binobj:encrypt(seed) -- encrypts data using a seed, seed may be left blank +nil* = binobj:decrypt(seed) -- decrypts data encrypted with encrypt(seed) +nil* = binobj:shuffle() -- Shuffles the data randomly Note: there is no way to get it back!!! If original is needed clone beforehand +nil** = binobj:mutate(a,i) -- changes position a's value to i +nil = binobj:merge(o,t) -- o is the binobj you are merging if t is true it merges the new data to the left of the binobj EX: b:merge(o,true) b='yo' o='data' output: b='datayo' b:merge(o) b='yo' o='data' output: b='yodata' +nil* = binobj:parseA(n,a,t) -- n is every byte where you add, a is the data you are adding, t is true or false true before false after +nil = binobj:getHEX(a,b) -- returns the HEX of the bytes between a,b inclusive +nil = binobj:cryptM() -- a mirrorable encryptor/decryptor +nil = binobj:addBlock(d,n) -- adds a block of data to a binobj s is size d is data e is a bool if true then encrypts string values. if data is larger than 'n' then data is lost. n is the size of bytes the data is Note: n is no longer needed but you must use getBlock(type) to get it back +nil = binobj:getBlock(t,n) -- gets block of code by type +nil = binobj:seek(n) -- used with getBlock EX below with all 3 +nil* = binobj:morph(a,b,d) -- changes data between point a and b, inclusive, to d +nil = binobj:fill(n,d) -- fills binobj with data 'd' for n +nil = binobj:fillrandom(n) -- fills binobj with random data for n +nil = binobj:shiftbits(n) -- shifts all bits by n amount +nil = binobj:shiftbit(n,i) -- shifts a bit ai index i by n +nil# = binobj:streamwrite(d,n) -- writes to the streamable binobj d data n position +nil# = binobj:open() -- opens the streamable binobj +nil# = binobj:close() -- closes the streamable binobj +nil = binobj:wipe() -- erases all data in the file +nil* = binobj:tackB(d) -- adds data to the beginning of a file +nil = binobj:tackE(d) -- adds data to the end of a file +nil = binobj:parse(n,f) -- loops through each byte calling function 'f' with the args(i,binobj,data at i) +nil = binobj:flipbit(i) -- flips the binary bit at position i +nil* = binobj:gsub() -- just like string:gsub(), but mutates self +nil = blockWriter:addNamedBlock(name,value) -- writes a named block to the file with name 'name' and the value 'value' + +Note: numbers are written in Big-endian use bin.endianflop(d) to filp to Little-endian + +Note: binobj:tonumber() returns big,little endian so if printing do: b,l=binobj:tonumber() print(l) print(b) + +nil = bitobj:add(i) -- adds i to the bitobj i can be a number (base 10) or a bitobj +nil = bitobj:sub(i) -- subs i to the bitobj i can be a number (base 10) or a bitobj +nil = bitobj:multi(i) -- multiplys i to the bitobj i can be a number (base 10) or a bitobj +nil = bitobj:div(i) -- divides i to the bitobj i can be a number (base 10) or a bitobj +nil = bitobj:flipbits() -- filps the bits 1 --> 0, 0 --> 1 +string = bitobj:getBin() -- returns 1's & 0's of the bitobj + +# stream objects only +* not compatible with stream files +** works but do not use with large files or it works to some degree +*** in stream objects all changes are made directly to the file, so there is no need to do tofile() +*D +]] + +bin.Changelog=[[ +Version.Major.Minor +------------------------- +1.0.0 : initial release load/new/tofile/clone/closeto/compare/sub/reverse/flip/segment/insert/insert/parseN/getlength/shift +1.0.1 : update Delete/tonumber/getbyte/ +1.0.2 : update Changed how delete works. Added encrypt/decrypt/shuffle +1.0.3 : update Added bits class, Added in bin: tobit/mutate/parseA Added in bits: add/sub/multi/div/isover/tobyte/tonumber/flip +1.0.4 : update Changed tobyte() to tobytes()/flipbit() to flipbits() and it now returns a binobj not str Added bin:merge +1.0.5 : update Changed bin.new() now hex data can be inserted EX: bin.new('0xFFC353D') Added in bin: getHEX/cryptM/addBlock/getBlock/seek +1.0.6 : update Added bin.NumtoHEX/bin:getHEX/bin.HEXtoBin/bin.HEXtoStr/bin.tohex/bin.fromhex +1.0.7 : update Added bin:morph/bin.endianflop/bin:scan/bin.ToStr +1.0.8 : update Added bin:fill/bin:fillrandom +1.1.0 : update Added bin.packLLIB/bin.unpackLLIB +1.2.0 : update Updated llib files +1.3.0 : Update Changed bin.unpackLLIB and bin.load() Added: bin.fileExist +1.4.0 : Update Changed bin.unpackLLIB bin.packLLIB Added: bin:shiftbits(n) bin:shiftbit(n,i) + +Woot!!! Version 2 +2.0.0 HUGE UPDATE Added Streamable files!!! lua 5.1, 5.2 and 5.3 compatable!!! +#binobj is the same as binobj:getlength() but only works in 5.2 and 5.3, in 5.1 just use getlength() or getSize() for compatibility +Now you can work with gigabyte sized data without memory crashes(streamable files[WIP]). + +Stream Compatible methods: + sub(a,b) + getlength() + tofile(filename) + flipbits() + tonumber(a,b) + getbyte(n) + segment(a,b) + parse(n,f) + tobits(i) + reverse() + flipbit(i) + cryptM() + getBlock(t,n) + addBlock(d,n) + shiftbits(n) + shiftbit(n,i) + getHEX(a,b) + +Added functions in this version: + binobj:streamwrite(d,n) + binobj:open() + binobj:close() + binobj:tackB(d) + binobj:tackE(d) + binobj:parse(n,f) + binobj:flipbit(i) + bin.stream(file) + binobj:streamData(a,b) + bin.getVersion() + bin.escapeStr(str) + binobj:streamread(a,b) + binobj:canStreamWrite() + binobj:wipe() + +Woot!!! Version 3 +3.0.0 HUGE UPDATE!!! + Added: bin.newVFS() bin.loadVFS() bin.textToBinary(txt) bin.decodeBits(bindata) bitobj:getBin() + Updated: bin.addBlock() <-- Fixed error with added features to the bits.new() function that allow for new functions to work + Notice: The bin library now requires the utils library!!! Put utils.lua in the lua/ directory +3.1.0 + Added: bin.newTempFile(data) binobj:setEndOfFile(n) bin.randomName(n,ext) + Updated: bin:tackE() bin:fill() bin:fillrandom() are now stream compatible! + Notice: bin:setEndOfFile() only works on streamable files! +3.1.1 + Added: bin.trimNul(s) bin:gsub() +3.1.2 + Added: log(data,name,fmt) + In secret something is brewing... + +3.1.3 + Added: bin:getHash(n) +3.2.1 + Added: bin.encryptA(data,seed), bin.decryptA(data,seed), bin.encryptB(data,seed), bin.decryptB(data,seed), bin:flush() + Updated: bin:encrypt(seed) and bin:decrypt(seed) + Fixed: bin:shiftbit() not working right with streamable files +3.2.2 + Fixed: bits.new() -- minor mistake huge error +3.2.3 + General bug fixes + Changed how bin.ToStr(t) -- functions are no longer valid data types +3.3.0 + Added: + bin:getSize() -- same as bin:getlength() just makes more sense. bin:getlength() is still valid and always will be. + bin.newLink() -- creates a link to a file object... Its like opening a file without opening it... Lua can only open a maximum of 200 files so use links if you will be going beyond that or make sure to close your files + bin.getHash2(h,n) -- 'h' hash size 8bit,16bit,32bit,64bit, 128bit, 100000bit whatever. is a number 'n' is the segmentation size defualt is 1024 greater numbers result in faster hashes but eaiser to forge hashes +3.4.1:(7/22/2016) NOTE: I started to add dates so I can see my work flow + Added: + binobj:getData() -- returns bin object as a string + bin:newDataBuffer(s) + Fixed: binobj:tonumber(a,b) +4.0.0:(7/23/2016) + Added: + bin.bufferToBin(b) + bin.binToBuffer(b) + bin.getLuaVersion() + bin.newNamedBlock(indexSize) + bin.newStreamedNamedBlock(indexSize,path) + bin.loadNamedBlock(path) + bin.getIndexSize(tab) + bits.numToBytes(num,occ) +4.1.0:(11/2/2016) NOTE: I took quite a long break due to college lol + Added: + bin.namedBlockManager(name) + Allows for a new way to use NamedBlocks + Example usage: + test=bin.namedBlockManager() + test["name"]="Ryan" -- My name lol + test["age"]=21 -- my age lol + test:tofile("test.dat") + --Now lets load the data we created + test2=bin.namedBlockManager("test.dat") + print(test2["name"]) + print(test2["age"]) + Changed: + bin.newNamedBlock(indexSize) + Now allows for indexSize to be nil and dynamacally adds to the size of the index + Fixed: + bin.loadNamedBlock(name) + Issue with indexing + TODO: + Allow streamed files to have expanding indexes +4.2.0:(12/21/2016) + Added: + bin.gcd(m,n) *takes number types returns a number + gets the greatest common denominator between 2 numbers m and n + bin.numToFraction(num) *takes number type returns a string type + converts a decimal to a fraction + so 5.5 would become 11/2 + bin.doubleToString(double) *takes number type returns string + converts a double to a string + bin.stringToDouble(str) *takes string type returns number type + converts the doublestring into a number + NOTE: this string can be 2 lengths! Either 9 bytes or 25 bytes... depending on the precision needed the program will convert the data + Also: the miniheader -/+ is for 9byte doubles the miniheader _/=(same keys as -/+ on an American keyboard) is for 25byte doubles + Changed: + bits.numToBytes(n,fit,func) + added argument func which is called when the number n takes up more space than size 'fit' + passes a ref table with keys num and fit, modifying these effects the output. + Note: If you change ref.fit make sure to make ref.num fits by adding \0 to the beginning of the numberstring + TODO: + add more useful features :P +4.2.1:(12/23/2016) + Added: + bin.decompress(comp) lzw commpression + bin.compress(uncomp) lzw decommpression + bin:segmentedRead(size,func) +4.3.0:(12/26/2016) + Added: + bin.tob64(data) + converts string data to b64 data + bin.fromb64(data) + converts b64 data to string data + bin:getB64() + returns b64 data from binobj + bits.lsh(value,shift) bit lshift + bits.rsh(value,shift) bit rshift + bits.bit(x,b) bit thing + bits.lor(x,y) or + Changed: + bin.new(data,hex,b64) hex if true treats data as hexdata, b64 if true treats data like b64data + Now allows b64 data to be used in construction of a bin file +4.4.0:(1/1/2017) + Added: + sinkobj=bin:newSink() + nil=sinkobj:tackE(data) + adds data into the sink, same method that binobj and streamobjs have. This does what you would expest the binobj to do but much quicker + nil=sinkobj:tofile(path) + creates a file containing the contents of the sink + str=sinkobj:getData() + returns the data of the sink as a string + nil=sinkobj:reset() + Clears the sink +4.4.1:(1/2/2017) + Changed: + bin.stream(file,lock) + Modified stream files so that multiple streams can link to one file by sharing handles +4.4.2:(1/10/2017) + Added: + bin.freshStream(file) + creates a stream object that wipes all data if the file already exists and readys the object for writing. In short it's doing: bin.new():tofile(file) return bin.stream(file,false) + -- I found myself doing that so much I made a method to simplify the process +4.5.0:(3/31/2017) + Added: + bin:getDataBuffer(a,b) -- a and b are the location to open on the streamed object they are not required though + -- If left out the entire file is open to used as a buffer! Even a empty streamed file works. Be sure to fill the buffer before trying to write to a location without data + -- Index 1 is the start regardless of where you open up the file + Note: Only works on streamed files! Use bin:newDataBuffer(s) to use the non streamed version +]] +bin.data='' +bin.t='bin' +bin.__index = bin +bin.__tostring=function(self) return self:getData() end +bin.__len=function(self) return self:getlength() end +bits={} +bits.data='' +bits.t='bits' +bits.__index = bits +bits.__tostring=function(self) return self.data end +bits.__len=function(self) return (#self.data)/8 end +bin.lastBlockSize=0 +bin.streams={} -- allows for multiple stream objects on one file... tricky stuff lol +--[[---------------------------------------- +Links +------------------------------------------]] +function bin.newLink(path) + if not path then + error("Must include a path when using a link!") + end + local c={} + c.path=path + c.tempfile={} + local mt={ + __tostring=function(self) + if self:getlength()>2048 then + -- + end + end, + __len=function(self) + return self:getlength() + end + } + function c:getlength() + -- + end +end + + +--[[---------------------------------------- +utils +------------------------------------------]] +function cleanName(name) + name=name:gsub("\\","") + name=name:gsub("/","") + name=name:gsub(":","") + name=name:gsub("*","") + name=name:gsub("%?","") + name=name:gsub("\"","''") + name=name:gsub("<","") + name=name:gsub(">","") + name=name:gsub("|","") + return name +end +function math.numfix(n,x) + local str=tostring(n) + if #str/dev/null','r') + if fh then + osname = fh:read() + end + if osname then return osname end + end + local winver='Unknown Version' + local a,b,c=os.capture('ver'):match('(%d+).(%d+).(%d+)') + local win=a..'.'..b..'.'..c + if type(t)=='string' then + win=t + end + if win=='4.00.950' then + winver='95' + elseif win=='4.00.1111' then + winver='95 OSR2' + elseif win=='4.00.1381' then + winver='NT 4.0' + elseif win=='4.10.1998' then + winver='98' + elseif win=='4.10.2222' then + winver='98 SE' + elseif win=='4.90.3000' then + winver='ME' + elseif win=='5.00.2195' then + winver='2000' + elseif win=='5.1.2600' then + winver='XP' + elseif win=='5.2.3790' then + winver='Server 2003' + elseif win=='6.0.6000' then + winver='Vista/Windows Server 2008' + elseif win=='6.0.6002' then + winver='Vista SP2' + elseif win=='6.1.7600' then + winver='7/Windows Server 2008 R2' + elseif win=='6.1.7601' then + winver='7 SP1/Windows Server 2008 R2 SP1' + elseif win=='6.2.9200' then + winver='8/Windows Server 2012' + elseif win=='6.3.9600' then + winver='8.1/Windows Server 2012' + elseif win=='6.4.9841' then + winver='10 Technical Preview 1' + elseif win=='6.4.9860' then + winver='10 Technical Preview 2' + elseif win=='6.4.9879' then + winver='10 Technical Preview 3' + elseif win=='10.0.9926' then + winver='10 Technical Preview 4' + end + return 'Windows '..winver +end +function os.capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end +function io.scanDir(directory) + directory=directory or io.getDir() + local i, t, popen = 0, {}, io.popen + if os.getOS()=='unix' then + for filename in popen('ls -a "'..directory..'"'):lines() do + i = i + 1 + t[i] = filename + end + else + for filename in popen('dir "'..directory..'" /b'):lines() do + i = i + 1 + t[i] = filename + end + end + return t +end +function io.getDir(dir) + if not dir then return io.getWorkingDir() end + if os.getOS()=='unix' then + return os.capture('cd '..dir..' ; cd') + else + return os.capture('cd '..dir..' & cd') + end +end +function string.split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = '(.-)' .. pat + local last_end = 1 + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= '' then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + return t +end +function io.fileExists(path) + g=io.open(path or '','r') + if path =='' then + p='empty path' + return nil + end + if g~=nil and true or false then + p=(g~=nil and true or false) + end + if g~=nil then + io.close(g) + else + return false + end + return p +end +function io.getDirectories(dir,l) + if dir then + dir=dir..'\\' + else + dir='' + end + local temp2=io.scanDir(dir) + for i=#temp2,1,-1 do + if io.fileExists(dir..temp2[i]) then + table.remove(temp2,i) + elseif l then + temp2[i]=dir..temp2[i] + end + end + return temp2 +end +function io.getFiles(dir,l) + if dir then + dir=dir..'\\' + else + dir='' + end + local temp2=io.scanDir(dir) + for i=#temp2,1,-1 do + if io.dirExists(dir..temp2[i]) then + table.remove(temp2,i) + elseif l then + temp2[i]=dir..temp2[i] + end + end + return temp2 +end +function io.readFile(file) + local f = io.open(file, 'rb') + local content = f:read('*all') + f:close() + return content +end +function table.print(tbl, indent) + if not indent then indent = 0 end + for k, v in pairs(tbl) do + formatting = string.rep(' ', indent) .. k .. ': ' + if type(v) == 'table' then + print(formatting) + table.print(v, indent+1) + else + print(formatting .. tostring(v)) + end + end +end +function io.dirExists(strFolderName) + strFolderName = strFolderName or io.getDir() + local fileHandle, strError = io.open(strFolderName..'\\*.*','r') + if fileHandle ~= nil then + io.close(fileHandle) + return true + else + if string.match(strError,'No such file or directory') then + return false + else + return true + end + end +end +function io.getFullName(name) + local temp=name or arg[0] + if string.find(temp,'\\',1,true) or string.find(temp,'/',1,true) then + temp=string.reverse(temp) + a,b=string.find(temp,'\\',1,true) + if not(a) or not(b) then + a,b=string.find(temp,'/',1,true) + end + return string.reverse(string.sub(temp,1,b-1)) + end + return temp +end +function io.getName(file) + local name=io.getFullName(file) + name=string.reverse(name) + a,b=string.find(name,'.',1,true) + name=string.sub(name,a+1,-1) + return string.reverse(name) +end +function io.getPathName(path) + return path:sub(1,#path-#io.getFullName(path)) +end +function table.merge(t1, t2) + for k,v in pairs(t2) do + if type(v) == 'table' then + if type(t1[k] or false) == 'table' then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +function io.splitPath(str) + return string.split(str,'[\\/]+') +end +function io.pathToTable(path) + local p=io.splitPath(path) + local temp={} + temp[p[1]]={} + local last=temp[p[1]] + for i=2,#p do + snd=last + last[p[i]]={} + last=last[p[i]] + end + return temp,last,snd +end +function io.parseDir(dir,t) + io.tempFiles={} + function _p(dir) + local dirs=io.getDirectories(dir,true) + local files=io.getFiles(dir,true) + for i=1,#files do + p,l,s=io.pathToTable(files[i]) + if t then + s[io.getFullName(files[i])]=io.readFile(files[i]) + else + s[io.getFullName(files[i])]=io.open(files[i],'r+') + end + table.merge(io.tempFiles,p) + end + for i=1,#dirs do + table.merge(io.tempFiles,io.pathToTable(dirs[i])) + _p(dirs[i],t) + end + end + _p(dir) + return io.tempFiles +end +function io.parsedir(dir,f) + io.tempFiles={} + function _p(dir,f) + local dirs=io.getDirectories(dir,true) + local files=io.getFiles(dir,true) + for i=1,#files do + if not f then + table.insert(io.tempFiles,files[i]) + else + f(files[i]) + end + end + for i=1,#dirs do + _p(dirs[i],f) + end + end + _p(dir,f) + return io.tempFiles +end +--[[---------------------------------------- +Random +Not all of this is mine +------------------------------------------]] +--[[------------------------------------ +RandomLua v0.3.1 +Pure Lua Pseudo-Random Numbers Generator +Under the MIT license. +copyright(c) 2011 linux-man +--]]------------------------------------ + +local math_floor = math.floor + +local function normalize(n) --keep numbers at (positive) 32 bits + return n % 0x80000000 +end + +local function bit_and(a, b) + local r = 0 + local m = 0 + for m = 0, 31 do + if (a % 2 == 1) and (b % 2 == 1) then r = r + 2^m end + if a % 2 ~= 0 then a = a - 1 end + if b % 2 ~= 0 then b = b - 1 end + a = a / 2 b = b / 2 + end + return normalize(r) +end + +local function bit_or(a, b) + local r = 0 + local m = 0 + for m = 0, 31 do + if (a % 2 == 1) or (b % 2 == 1) then r = r + 2^m end + if a % 2 ~= 0 then a = a - 1 end + if b % 2 ~= 0 then b = b - 1 end + a = a / 2 b = b / 2 + end + return normalize(r) +end + +local function bit_xor(a, b) + local r = 0 + local m = 0 + for m = 0, 31 do + if a % 2 ~= b % 2 then r = r + 2^m end + if a % 2 ~= 0 then a = a - 1 end + if b % 2 ~= 0 then b = b - 1 end + a = a / 2 b = b / 2 + end + return normalize(r) +end + +local function seed() + --return normalize(tonumber(tostring(os.time()):reverse())) + return normalize(os.time()) +end + +--Mersenne twister +mersenne_twister = {} +mersenne_twister.__index = mersenne_twister + +function mersenne_twister:randomseed(s) + if not s then s = seed() end + self.mt[0] = normalize(s) + for i = 1, 623 do + self.mt[i] = normalize(0x6c078965 * bit_xor(self.mt[i-1], math_floor(self.mt[i-1] / 0x40000000)) + i) + end +end + +function mersenne_twister:random(a, b) + local y + if self.index == 0 then + for i = 0, 623 do + --y = bit_or(math_floor(self.mt[i] / 0x80000000) * 0x80000000, self.mt[(i + 1) % 624] % 0x80000000) + y = self.mt[(i + 1) % 624] % 0x80000000 + self.mt[i] = bit_xor(self.mt[(i + 397) % 624], math_floor(y / 2)) + if y % 2 ~= 0 then self.mt[i] = bit_xor(self.mt[i], 0x9908b0df) end + end + end + y = self.mt[self.index] + y = bit_xor(y, math_floor(y / 0x800)) + y = bit_xor(y, bit_and(normalize(y * 0x80), 0x9d2c5680)) + y = bit_xor(y, bit_and(normalize(y * 0x8000), 0xefc60000)) + y = bit_xor(y, math_floor(y / 0x40000)) + self.index = (self.index + 1) % 624 + if not a then return y / 0x80000000 + elseif not b then + if a == 0 then return y + else return 1 + (y % a) + end + else + return a + (y % (b - a + 1)) + end +end + +function twister(s) + local temp = {} + setmetatable(temp, mersenne_twister) + temp.mt = {} + temp.index = 0 + temp:randomseed(s) + return temp +end + +--Linear Congruential Generator +linear_congruential_generator = {} +linear_congruential_generator.__index = linear_congruential_generator + +function linear_congruential_generator:random(a, b) + local y = (self.a * self.x + self.c) % self.m + self.x = y + if not a then return y / 0x10000 + elseif not b then + if a == 0 then return y + else return 1 + (y % a) end + else + return a + (y % (b - a + 1)) + end +end + +function linear_congruential_generator:randomseed(s) + if not s then s = seed() end + self.x = normalize(s) +end + +function lcg(s, r) + local temp = {} + setmetatable(temp, linear_congruential_generator) + temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C + if r then + if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes. + elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC + end + temp:randomseed(s) + return temp +end + +-- Multiply-with-carry +multiply_with_carry = {} +multiply_with_carry.__index = multiply_with_carry + +function multiply_with_carry:random(a, b) + local m = self.m + local t = self.a * self.x + self.c + local y = t % m + self.x = y + self.c = math_floor(t / m) + if not a then return y / 0x10000 + elseif not b then + if a == 0 then return y + else return 1 + (y % a) end + else + return a + (y % (b - a + 1)) + end +end + +function multiply_with_carry:randomseed(s) + if not s then s = seed() end + self.c = self.ic + self.x = normalize(s) +end + +function mwc(s, r) + local temp = {} + setmetatable(temp, multiply_with_carry) + temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C + if r then + if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes. + elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC + end + temp.ic = temp.c + temp:randomseed(s) + return temp +end +-- Little bind for the methods: My code starts +randomGen={} +randomGen.__index=randomGen +function randomGen:new(s) + local temp={} + setmetatable(temp,randomGen) + temp[1]=twister() + temp[2]=lcg() + temp[3]=mwc() + temp.pos=1 + for i=1,3 do + temp[i]:randomseed(s) + end + return temp +end +function randomGen:randomseed(s) + self.pos=1 + self[1]:randomseed(s) + self[2]:randomseed(s) + self[3]:randomseed(s) +end +function randomGen:randomInt(a,b) + local t=self[self.pos]:random(a,b) + self.pos=self.pos+1 + if self.pos>3 then + self.pos=1 + end + return t +end +function randomGen:newND(a,b,s) + if not(a) or not(b) then error('You must include a range!') end + local temp=randomGen:new(s) + temp.a=a + temp.b=b + temp.range=b-a+1 + temp.dups={no=0} + function temp:nextInt() + local t=self:randomInt(self.a,self.b) + if self.dups[t]==nil then + self.dups[t]=true + self.dups.no=self.dups.no+1 + else + return self:nextInt() + end + if self.dups.no==self.range then + function self:nextInt() + return 1,true + end + return t + else + return t + end + end + function temp:nextIInt() + return function() return self:nextInt() end + end + return temp +end +lzw = {} +function lzw.encode(uncompressed) -- string + local dictionary, result, dictSize, w, c = {}, {}, 255, "" + for i = 0, 255 do + dictionary[string.char(i)] = i + end + for i = 1, #uncompressed do + c = string.sub(uncompressed, i, i) + if dictionary[w .. c] then + w = w .. c + else + table.insert(result, dictionary[w]) + dictSize = dictSize + 1 + dictionary[w .. c] = dictSize + w = c + end + end + if w ~= "" then + table.insert(result, dictionary[w]) + end + return result +end + +function lzw.decode(compressed) -- table + local dictionary, dictSize, entry, result, w, k = {}, 255, "", "", "" + for i = 0, 255 do + dictionary[i] = string.char(i) + end + for i = 1, #compressed do + k = compressed[i] + if dictionary[k] then + entry = dictionary[k] + elseif k == dictSize then + entry = w .. string.sub(w, 1, 1) + else + return nil, i + end + result = result .. entry + dictionary[dictSize] = w .. string.sub(entry, 1, 1) + dictSize = dictSize + 1 + w = entry + end + return result +end +--[[---------------------------------------- +BIN +------------------------------------------]] + +function bin:newSink() + local c={} + c.data={} + c.name="sinkobj" + c.num=1 + c.type="sink" + function c:tackE(data) + self.data[self.num]=data + self.num=self.num+1 + end + function c:tofile(path) + bin.new(table.concat(self.data)):tofile(path) + end + function c:getData() + return table.concat(self.data) + end + function c:reset() + self.data={} + end + function c:close() + -- does nothing lol + end + return c +end +function bin:segmentedRead(size,func) + local mSize=self:getSize() + local pSize=size + local iter=math.ceil(mSize/pSize) + for i=0,iter-1 do + func(self:sub((i*pSize)+1,(i+1)*pSize)) + end +end +function bin.compress(uncomp,n) + n=n or 9 + local cipher = lzw.encode(uncomp) + local dat={} + for i=1,#cipher do + local fix=bits.new(cipher[i]).data:match("0*(%d+)") + if cipher[i]==0 then + fix=string.rep("0",n) + end + fix=string.rep("0",n-#fix)..fix + table.insert(dat,fix) + end + str=table.concat(dat,"") + str=string.rep("0",8-#str%8)..str + comp={} + for i=0,(#str/8) do + table.insert(comp,bits.new(str:sub(i*8+1,i*8+8)):toSbytes()) + end + return table.concat(comp,"") +end +function bin.decompress(comp,n) + n=n or 9 + local tab={} + for i=1,#comp do + table.insert(tab,bits.new(comp:sub(i,i)).data) + end + tab=table.concat(tab,"") + tab=tab:match("0*(%d+)") + tab=string.rep("0",n-#tab%n)..tab + uncomp={} + for i=0,(#tab/n) do + table.insert(uncomp,tonumber(tab:sub(i*n+1,i*n+n),2)) + end + return lzw.decode(uncomp) +end +function bin:getSize() + return self:getlength() +end +function bin.getVersion() + return bin.Version[1]..'.'..bin.Version[2]..'.'..bin.Version[3] +end +function bin:gsub(...) + self.data=self.data:gsub(...) +end +-- +function bin:trim() + self.data=self.data:match'^()%s*$' and '' or self.data:match'^%s*(.*%S)' +end +function bin._trim(str) + return str:match'^()%s*$' and '' or str:match'^%s*(.*%S)' +end +function bin:fullTrim(empty) + local t=self:lines() + for i=#t,1,-1 do + t[i]=bin._trim(t[i]) + if empty then + if t[i]=="" then + table.remove(t,i) + end + end + end + self.data = table.concat(t,"\n") +end +function bin:lines() + local t = {} + local function helper(line) table.insert(t, line) return '' end + helper((self.data:gsub('(.-)\r?\n', helper))) + return t +end +function bin._lines(str) + local t = {} + local function helper(line) table.insert(t, line) return '' end + helper((str:gsub('(.-)\r?\n', helper))) + return t +end +-- +function bin:find(...) + return self.data:find(...) +end +function bin.fromhex(str) + return (str:gsub('..', function (cc) + return string.char(tonumber(cc, 16)) + end)) +end + +-- working lua base64 codec (c) 2006-2008 by Alex Kloss +-- compatible with lua 5.1 +-- http://www.it-rfc.de +-- licensed under the terms of the LGPL2 +bin.base64chars = {[0]='A',[1]='B',[2]='C',[3]='D',[4]='E',[5]='F',[6]='G',[7]='H',[8]='I',[9]='J',[10]='K',[11]='L',[12]='M',[13]='N',[14]='O',[15]='P',[16]='Q',[17]='R',[18]='S',[19]='T',[20]='U',[21]='V',[22]='W',[23]='X',[24]='Y',[25]='Z',[26]='a',[27]='b',[28]='c',[29]='d',[30]='e',[31]='f',[32]='g',[33]='h',[34]='i',[35]='j',[36]='k',[37]='l',[38]='m',[39]='n',[40]='o',[41]='p',[42]='q',[43]='r',[44]='s',[45]='t',[46]='u',[47]='v',[48]='w',[49]='x',[50]='y',[51]='z',[52]='0',[53]='1',[54]='2',[55]='3',[56]='4',[57]='5',[58]='6',[59]='7',[60]='8',[61]='9',[62]='-',[63]='_'} +function bin.tob64(data) + local bytes = {} + local result = "" + for spos=0,string.len(data)-1,3 do + for byte=1,3 do bytes[byte] = string.byte(string.sub(data,(spos+byte))) or 0 end + result = string.format('%s%s%s%s%s',result,bin.base64chars[bits.rsh(bytes[1],2)],bin.base64chars[bits.lor(bits.lsh((bytes[1] % 4),4), bits.rsh(bytes[2],4))] or "=",((#data-spos) > 1) and bin.base64chars[bits.lor(bits.lsh(bytes[2] % 16,2), bits.rsh(bytes[3],6))] or "=",((#data-spos) > 2) and bin.base64chars[(bytes[3] % 64)] or "=") + end + return result +end +bin.base64bytes = {['A']=0,['B']=1,['C']=2,['D']=3,['E']=4,['F']=5,['G']=6,['H']=7,['I']=8,['J']=9,['K']=10,['L']=11,['M']=12,['N']=13,['O']=14,['P']=15,['Q']=16,['R']=17,['S']=18,['T']=19,['U']=20,['V']=21,['W']=22,['X']=23,['Y']=24,['Z']=25,['a']=26,['b']=27,['c']=28,['d']=29,['e']=30,['f']=31,['g']=32,['h']=33,['i']=34,['j']=35,['k']=36,['l']=37,['m']=38,['n']=39,['o']=40,['p']=41,['q']=42,['r']=43,['s']=44,['t']=45,['u']=46,['v']=47,['w']=48,['x']=49,['y']=50,['z']=51,['0']=52,['1']=53,['2']=54,['3']=55,['4']=56,['5']=57,['6']=58,['7']=59,['8']=60,['9']=61,['-']=62,['_']=63,['=']=nil} +function bin.fromb64(data) + local chars = {} + local result="" + for dpos=0,string.len(data)-1,4 do + for char=1,4 do chars[char] = bin.base64bytes[(string.sub(data,(dpos+char),(dpos+char)) or "=")] end + result = string.format('%s%s%s%s',result,string.char(bits.lor(bits.lsh(chars[1],2), bits.rsh(chars[2],4))),(chars[3] ~= nil) and string.char(bits.lor(bits.lsh(chars[2],4), bits.rsh(chars[3],2))) or "",(chars[4] ~= nil) and string.char(bits.lor(bits.lsh(chars[3],6) % 192, (chars[4]))) or "") + end + return result +end +-- ^^ + +function bin:getB64() + return bin.tob64(self.data) +end +if table.unpack==nil then + table.unpack=unpack +end +function bin.tohex(str) + return (str:gsub('.', function (c) + return string.format('%02X', string.byte(c)) + end)) +end +function bin:streamData(a,b) + if type(a)=='table' then + a,b,t=table.unpack(a) + end + if type(a)=='number' and type(b)=='string' then + return bin.load(self.file,a,b),bin.load(self.file,a,b).data + else + error('Invalid args!!! Is do you have a valid stream handle or is this a streamable object?') + end +end +function bin.new(data,hex,b64) + data=data or "" + data=tostring(data) + local c = {} + setmetatable(c, bin) + if string.sub(data,1,2)=='0x' and hex then + data=string.sub(data,3) + data=bin.fromhex(data) + elseif hex then + data=bin.fromhex(data) + end + if b64 then + data=bin.fromb64(data) + end + c.data=data + c.t='bin' + c.Stream=false + return c +end +function bin.freshStream(file) + bin.new():tofile(file) + return bin.stream(file,false) +end +function bin.stream(file,l) + local c=bin.new() + if bin.streams[file]~=nil then + c.file=file + c.lock = l + c.workingfile=bin.streams[file].workingfile + c.Stream=true + return c + end + if bin.fileExist(file) then + c.file=file + c.lock = l + c.workingfile=io.open(file,'rb+') + else + c.file=file + c.lock = l + c.workingfile=io.open(file,'w') + io.close(c.workingfile) + c.workingfile=io.open(file,'rb+') + end + c.Stream=true + bin.streams[file]=c + return c +end +function bin:streamwrite(d,n) + if self:canStreamWrite() then + if n then + self.workingfile:seek('set',n) + else + self.workingfile:seek('set',self.workingfile:seek('end')) + end + self.workingfile:write(d) + end +end +function bin:streamread(a,b) + a=a-1 + local loc=self.workingfile:seek('cur') + self.workingfile:seek('set',a) + local dat=self.workingfile:read(b-a) + self.workingfile:seek('set',loc) + return dat +end +function bin:streamreadNext(a) + return self.workingfile:read(a) +end +function bin:close() + if self:canStreamWrite() then + self.workingfile:close() + end +end +function bin:flush() + if self:canStreamWrite() then + self.workingfile:flush() + else + self:tofile(self.filepath) + end +end +function bin:open() + if self:canStreamWrite() then + self.workingfile=io.open(self.file,'r+') + end +end +function bin:canStreamWrite() + return (self.Stream==true and self.lock==false) +end +function bin:getDataBuffer(a,b,filler) + if self:canStreamWrite() then + if not(a) and not(b) then + a=1 + b=math.huge + elseif a and not(b) then + b=a + a=1 + if self:getSize()=k then + me:streamwrite(string.char(v),k+(ss-1)) + elseif type(v)=="string" and s>=k then + if #v~=1 then + t:fillBuffer(v,k+(ss)) + elseif s>=k then + me:streamwrite(v,k+(ss-1)) + else + print("Buffer Overflow!") + end + else + print("Warning Attempting to index outside defined range!") + end + end, + __tostring=function(t) -- GOOD + return t:getBuffer() + end + } + c.t="buffer" + c.dataS={} + function c:getBuffer(a,b) -- GOOD + if not(a) and not(b) then + local str={} + for i=ss,max do + table.insert(str,me:streamread(i+(ss-1),i+(ss-1))) + end + return table.concat(str) + else + return me:streamread(a+(ss-1),b+(ss-1)) + end + end + function c:getData() -- GOOD + return self:getBuffer() + end + function c:getBufferTable() -- GOOD + local str={} + for i=ss,max do + table.insert(str,me:streamread(i+(ss-1),i+(ss-1))) + end + return str + end + function c:getBufferSize() -- GOOD + return #self:getBuffer() + end + function c:getlength() -- GOOD + return #self:getBuffer() + end + function c:tonumber(a,b) -- GOOD + return bin.new(self:getBuffer(a,b)):tonumber() + end + c.getSize=c.getlength + function c:fillBuffer(sg,a) -- GOOD + for i=#sg+(a-1),a,-1 do + if i<=max then + local ii=(a+#sg)-i + self[ii+(a-1)]=sg:sub(ii,ii) + else + return print("Buffer Overflow!") + end + end + return a,a+#sg-1 + end + setmetatable(c,mt) + return c + else + error("Stream not opened for writing!") + end +end +function bin.load(file,s,r) + if not(s) or not(r) then + if type(file)~="string" then return bin.new() end + local f = io.open(file, 'rb') + local content = f:read('*a') + f:close() + return bin.new(content) + end + s=s or 0 + r=r or -1 + if type(r)=='number' then + r=r+s-1 + elseif type(r)=='string' then + r=tonumber(r) or -1 + end + local f = io.open(file, 'rb') + f:seek('set',s) + local content = f:read((r+1)-s) + f:close() + local temp=bin.new(content) + temp.filepath=file + return temp +end +function bin:tofile(filename) + if not(filename) or self.Stream then return nil end + io.mkFile(filename,self.data) +end +function bin.trimNul(s) + for i=1,#s do + if s:sub(i,i)=='\0' then + return s:sub(1,i-1) + end + end + return s +end +function bin:match(pat) + return self.data:match(pat) +end +function bin:gmatch(pat) + return self.data:gmatch(pat) +end +function bin:getHash(n) + if self:getlength()==0 then + return "NaN" + end + n=(n or 32)/2 + local rand = randomGen:newND(1,self:getlength(),self:getlength()) + local h,g={},0 + for i=1,n do + g=rand:nextInt() + table.insert(h,bin.tohex(self:sub(g,g))) + end + return table.concat(h,'') +end +function bin:getRandomHash(n) + if self:getlength()==0 then + return "NaN" + end + n=(n or 32)/2 + local rand = randomGen:new(math.random(1,self:getlength()^2)) + local h,g={},0 + for i=1,n do + g=rand:randomInt(1,self:getlength()) + table.insert(h,bin.tohex(self:sub(g,g))) + end + return table.concat(h,'') +end +function bin:newDataBuffer(s,def) + local c={} + local mt={ + __index=function(t,k,v) + if k<=t.maxBuffer then + if t.dataS[k] then + return string.byte(t.dataS[k]) + else + return "NOINDEX" + end + else + return + end + end, + __newindex=function(t,k,v) + if type(v)=="number" and t.maxBuffer>=k then + t.dataS[k]=string.char(v) + elseif type(v)=="string" and t.maxBuffer>=k then + if #v~=1 then + t:fillBuffer(v,k) + elseif t.maxBuffer>=k then + t.dataS[k]=v + else + print("Buffer Overflow!") + end + end + end, + __tostring=function(t) + return t:getBuffer() + end + } + c.t="buffer" + c.dataS={} + if s then + if type(s)=="number" then + c.maxBuffer=s + s=string.rep(def or"\0",s) + else + c.maxBuffer=math.huge + end + for i=1,#s do + c.dataS[i]=s:sub(i,i) + end + else + c.maxBuffer=math.huge + end + function c:getBuffer(a,b) + if a and b then + return table.concat(self.dataS,""):sub(a,b) + else + return table.concat(self.dataS,"") + end + end + function c:getData() + return table.concat(self.dataS,"") + end + function c:getBufferTable() + return self.dataS + end + function c:getBufferSize() + if self.maxBuffer~=math.huge then + return self.maxBuffer + end + return #self:getBuffer() + end + function c:getlength() + return #self:getBuffer(a,b) + end + function c:tonumber(a,b) + return bin.new(self:getBuffer(a,b)):tonumber() + end + c.getSize=c.getlength + function c:fillBuffer(s,a) + for i=0,#s-1 do + if i+a<=self.maxBuffer then + c.dataS[i+a]=s:sub(i+1,i+1) + else + return "Buffer Overflow!" + end + end + return a,a+#s-1 + end + setmetatable(c,mt) + return c +end +function bin:getHash2(h,n) + n=n or 1024 + h=(h or 32) + local temp=bin.new() + local len=self:getSize() + local seg=math.ceil(len/n) + temp:fill("\0",h) + for i=1,seg do + local s=bin.new(self:sub(n*(i-1)+1,n*i)):getHash(h) + for i=1,h do + temp:shiftbit(string.byte(s:sub(i,i)),i) + end + end + return temp:getHEX() +end +function bin.encryptA(data,seed) + seed=seed or 1 + local d=bin.new(data) + local r=randomGen:newND(1,#d.data,seed) + for i=1,#d.data do + d:shiftbit(r:nextInt(),i) + end + return bin.tohex(d.data) +end +function bin.decryptA(data,seed) + seed=seed or 1 + local d=bin.new('0x'..data) + local r=randomGen:newND(1,#d.data,seed) + for i=1,#d.data do + d:shiftbit(-r:nextInt(),i) + end + return d.data +end +function bin.encryptB(data,seed) + seed=seed or 'abcdefghijklmnopqrstuvwxyz' + seed=tostring(seed) + local d=bin.new(data) + local r,mr=1,#seed + for i=1,#d.data do + d:shiftbit(string.byte(seed:sub(r,r)),i) + r=r+1 + if r>mr then + r=1 + end + end + return bin.tohex(d.data) +end +function bin.decryptB(data,seed) + seed=seed or 'abcdefghijklmnopqrstuvwxyz' + seed=tostring(seed) + local d=bin.new('0x'..data) + local r,mr=1,#seed + for i=1,#d.data do + d:shiftbit(-string.byte(seed:sub(r,r)),i) + r=r+1 + if r>mr then + r=1 + end + end + return d.data +end +function bin:encrypt(seed) + seed=seed or 'abcdefghijklmnopqrstuvwxyz' + seed=tostring(seed) + local r,mr=1,#seed + for i=1,self:getlength() do + self:shiftbit(string.byte(seed:sub(r,r)),i) + r=r+1 + if r>mr then + r=1 + end + end +end +function bin:decrypt(seed) + seed=seed or 'abcdefghijklmnopqrstuvwxyz' + seed=tostring(seed) + local r,mr=1,#seed + for i=1,self:getlength() do + self:shiftbit(-string.byte(seed:sub(r,r)),i) + r=r+1 + if r>mr then + r=1 + end + end +end +function bin.randomName(n,ext) + n=n or math.random(7,15) + if ext then + a,b=ext:find('.',1,true) + if a and b then + ext=ext:sub(2) + end + end + local str,h = '',0 + strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'} + for i=1,n do + h = math.random(1,#strings) + str = str..''..strings[h] + end + return str..'.'..(ext or 'tmp') +end +function bin.newTempFile(data) + data=data or '' + local name=bin.randomName() + bin.new():tofile(name) + local tempfile=bin.stream(name,false) + tempfile:streamwrite(data,0) + tempfile:setEndOfFile(#data) + return tempfile +end +function bin:wipe() + if self:canStreamWrite() then + self:close() + os.remove(self.file) + self:open() + else + self.data='' + end +end +function bin:setEndOfFile(n) + if self:canStreamWrite() then + local name=bin.randomName() + local tempfile=bin.stream(name,false) + tempfile:streamwrite(self:sub(0,n-1)) + self:close() + os.remove(self.file) + tempfile:close() + os.rename(name,self.file) + self:open() + tempfile=nil + else + self.data=self.data:sub(1,n) + end +end +function bin:reverse() + if self:canStreamWrite() then + local x,f,b=self:getlength(),0,0 + for i=0,math.floor((x-1)/2) do + self:streamwrite(self:sub(i+1,i+1),x-i-1) + self:streamwrite(self:sub(x-i,x-i),i) + end + elseif self.Stream==false then + self.data=string.reverse(self.data) + end +end +function bin:flipbits() + if self:canStreamWrite() then + for i=0,self:getlength()-1 do + self:streamwrite(string.char(255-string.byte(self:streamread(i,i))),i) + end + elseif self.Stream==false then + local temp={} + for i=1,#self.data do + table.insert(temp,string.char(255-string.byte(string.sub(self.data,i,i)))) + end + self.data=table.concat(temp,'') + end +end +function bin:flipbit(i) + if self:canStreamWrite() then + self:streamwrite(string.char(255-string.byte(self:streamread(i-1,i-1))),i-1) + elseif self.Stream==false then + self:mutate(string.char(255-string.byte(string.sub(self.data,i,i))),i) + end +end +function bin:segment(a,b) -- needs to be updated!!! + if self:canStreamWrite() then + --[[local pos=1 + for i=a,b do + self:streamwrite(self:sub(i,i),b-a-i) + end]] + local temp=self:sub(a,b) + self:close() + local f=io.open(self.file,'w') + f:write(temp) + io.close(f) + self:open() + elseif self.Stream==false then + self.data=string.sub(self.data,a,b) + end +end +function bin:insert(i,a) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + if type(i)=='number' then i=string.char(i) end + self.data=string.sub(self.data,1,a)..i..string.sub(self.data,a+1) + end +end +function bin:parseN(n) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + local temp={} + for i=1,#self.data do + if i%n==0 then + table.insert(temp,string.sub(self.data,i,i)) + end + end + self.data=table.concat(temp,'') + end +end +function bin:parse(n,f) + local f = f + local n=n or 1 + if not(f) then return end + for i=1,self:getlength() do + if i%n==0 then + f(i,self,self:sub(i,i)) + end + end +end +function bin.copy(file,tofile,s) + if not(s) then + bin.load(file):tofile(tofile) + else + rf=bin.stream(file) + wf=bin.stream(tofile,false) + for i=1,rf:getlength(),s do + wf:streamwrite(rf:sub(i,i-1+s)) + end + end +end +function bin:getlength() + if self.Stream then + if self.workingfile==nil then print("Error getting size of file!") return 0 end + local current = self.workingfile:seek() -- get current position + local size = self.workingfile:seek('end') -- get file size + self.workingfile:seek('set', current) -- restore position + return size + elseif self.Stream==false then + return #self.data + end +end +function bin:sub(a,b) + if self.Stream then + return bin.load(self.file,a-1,tostring(b-1)).data + elseif self.Stream==false then + return string.sub(self.data,a,b) + end +end +function bin:tackB(d) + if self:canStreamWrite() then + -- do something don't know if possible + elseif self.Stream==false then + self.data=d..self.data + end +end +function bin:tackE(d) + if type(d)=='table' then + if d:canStreamWrite() then + d=d:sub(1,d:getlength()) + else + d=d.data + end + return + end + if self:canStreamWrite() then + self:streamwrite(d) + elseif self.Stream==false then + self.data=self.data..d + end +end +function bin:clone(filename) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + return bin.new(self.data) + end +end +function bin.closeto(a,b,v) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + if type(a)~=type(b) then + error('Attempt to compare unlike types') + elseif type(a)=='number' and type(b)=='number' then + return math.abs(a-b)<=v + elseif type(a)=='table' and type(b)=='table' then + if a.data and b.data then + return (math.abs(string.byte(a.data)-string.byte(b.data)))<=v + else + error('Attempt to compare non-bin data') + end + elseif type(a)=='string' and type(b)=='string' then + return math.abs(string.byte(a)-string.byte(b))<=v + else + error('Attempt to compare non-bin data') + end + end +end +function bin:compare(_bin,t) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + t=t or 1 + local tab={} + local a,b=self:getlength(),_bin:getlength() + if not(a==b) then + print('Unequal Lengths!!! Equalizing...') + if a>b then + _bin.data=_bin.data..string.rep(string.char(0),a-b) + else + self.data=self.data..string.rep(string.char(0),b-a) + end + end + if t==1 then + for i=1,self:getlength() do + table.insert(tab,self:sub(i,i)==_bin:sub(i,i)) + end + else + for i=1,self:getlength() do + table.insert(tab,bin.closeto(self:sub(i,i),_bin:sub(i,i),t)) + end + end + local temp=0 + for i=1,#tab do + if tab[i]==true then + temp=temp+1 + end + end + return (temp/#tab)*100 + end +end +function bin:shift(n) + if self:canStreamWrite() then + local a,b,x,p='','',self:getlength(),0 + for i=1,x do + if i+n>x then + p=(i+n)-(x) + else + p=i+n + end + end + elseif self.Stream==false then + n=n or 0 + local s=#self.data + if n>0 then + self.data = string.sub(self.data,s-n+1)..string.sub(self.data,1,s-n) + elseif n<0 then + n=math.abs(n) + self.data = string.sub(self.data,n+1)..string.sub(self.data,1,n*1) + end + end +end +function bin:delete(a,b) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + if type(a)=='string' then + local tab={} + for i=1,self:getlength() do + if self:getbyte(i)~=string.byte(a) then + table.insert(tab,self:sub(i,i)) + end + end + self.data=table.concat(tab) + elseif a and not(b) then + self.data=self:sub(1,a-1)..self:sub(a+1) + elseif a and b then + self.data=self:sub(1,a-1)..self:sub(b+1) + else + self.data='' + end + end +end +function bin:tonumber(a,b) + local temp={} + if a then + temp.data=self:sub(a,b) + else + temp=self + end + local l,r=0,0 + local g=#temp.data + for i=1,g do + r=r+(256^(g-i))*string.byte(string.sub(temp.data,i,i)) + l=l+(256^(i-1))*string.byte(string.sub(temp.data,i,i)) + end + return r,l +end +function bin:getbyte(n) + return string.byte(self:sub(n,n)) +end +function bin:shuffle(s) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + s=tonumber(s) or 4546 + math.randomseed(s) + local t={} + for i=1,self:getlength() do + table.insert(t,self:sub(i,i)) + end + local n = #t + while n >= 2 do + local k = math.random(n) + t[n], t[k] = t[k], t[n] + n = n - 1 + end + self.data=table.concat(t) + end +end +function bin:tobits(i) + return bits.new(self:getbyte(i)) +end +function bin:mutate(a,i) + if self:canStreamWrite() then + self:streamwrite(a,i-1) + elseif self.Stream==false then + self:delete(i) + self:insert(a,i-1) + end +end +function bin:parseA(n,a,t) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + local temp={} + for i=1,#self.data do + if i%n==0 then + if t then + table.insert(temp,a) + table.insert(temp,string.sub(self.data,i,i)) + else + table.insert(temp,string.sub(self.data,i,i)) + table.insert(temp,a) + end + else + table.insert(temp,string.sub(self.data,i,i)) + end + end + self.data=table.concat(temp,'') + end +end +function bin:merge(o,t) + if self:canStreamWrite() then + self:close() + self.workingfile=io.open(self.file,'a+') + self.workingfile:write(o.data) + self:close() + self:open() + elseif self.Stream==false then + if not(t) then + self.data=self.data..o.data + else + seld.data=o.data..self.data + end + end +end +function bin:cryptM() + self:flipbits() + self:reverse() +end +function bin.escapeStr(str) + local temp='' + for i=1,#str do + temp=temp..'\\'..string.byte(string.sub(str,i,i)) + end + return temp +end + +function bin.ToStr(val, name, skipnewlines, depth) + skipnewlines = skipnewlines or false + depth = depth or 0 + local tmp = string.rep(" ", depth) + if name then + if type(name) == "string" then + tmp = tmp .. "[\""..name.."\"] = " + else + tmp = tmp .. "["..(name or "").."] = " + end + end + if type(val) == "table" then + tmp = tmp .. "{" .. (not skipnewlines and " " or "") + for k, v in pairs(val) do + tmp = tmp .. bin.ToStr(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and " " or "") + end + tmp = tmp .. string.rep(" ", depth) .. "}" + elseif type(val) == "number" then + tmp = tmp .. tostring(val) + elseif type(val) == "string" then + tmp = tmp .. string.format("%q", val) + elseif type(val) == "boolean" then + tmp = tmp .. (val and "true" or "false") + else + tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\"" + end + return tmp +end +function bin:addBlock(d,n,e) + local temp={} + if type(d)=='table' then + if d.t=='bin' then + temp=d + elseif d.t=='bit' then + temp=bin.new(d:tobytes()) + else + self:addBlock('return '..bin.ToStr(d)) + return + end + elseif type(d)=='string' then + temp=bin.new(d) + if e or not(n) then + temp.data=temp.data..'_EOF' + temp:flipbits() + end + elseif type(d)=='function' then + temp=bin.new(string.dump(d)) + if e or not(n) then + temp.data=temp.data..'_EOF' + temp:flipbits() + end + elseif type(d)=='number' then + local nn=tostring(d) + if nn:find('.',1,true) then + temp=bin.new(nn) + temp.data=temp.data..'_EOF' + temp:flipbits() + else + temp=bin.new(bits.numToBytes(d,n)) + if not n then + temp.data=temp.data..'_EOF' + temp:flipbits() + end + end + elseif type(d)=='boolean' then + n=1 + if d then + temp=bits.new(math.random(0,127)):tobytes() + else + temp=bits.new(math.random(128,255)):tobytes() + end + end + if n then + if temp:getlength()n then + temp:segment(1,n) + end + end + self:merge(temp) +end +function bin:getBlock(t,n,se) + if not(self.Block) then + self.Block=1 + end + local x=self.Block + local temp=bin.new() + if n then + temp=bin.new(self:sub(x,x+n-1)) + self.Block=self.Block+n + end + if se then + self.Block=self.Block+se + end + if t=='stringe' or t=='stre' or t=='se' and n then + temp:flipbits() + bin.lastBlockSize=#temp + return temp.data + elseif t=='string' or t=='str' or t=='s' and n then + bin.lastBlockSize=#temp + return temp.data + elseif t=='number' or t=='num' or t=='n' and n then + bin.lastBlockSize=n + return self:tonumber(x,x+n-1) + elseif t=='boolean' or t=='bool' or t=='b' then + self.Block=self.Block+1 + bin.lastBlockSize=1 + return self:tonumber(x,x)<127 + elseif t=='stringe' or t=='stre' or t=='se' or t=='string' or t=='str' or t=='s' then + local a,b=self:scan('_EOF',self.Block,true) + if not(b) then return nil end + local t=bin.new(self:sub(self.Block,b-4)) + bin.lastBlockSize=t:getlength() + t:flipbits() + self.Block=self.Block+t:getlength()+4 + return tostring(t) + elseif t=='table' or t=='tab' or t=='t' then + temp=self:getBlock('s') + bin.lastBlockSize=#temp + return assert(loadstring(temp))() + elseif t=='function' or t=='func' or t=='f' then + local temp=self:getBlock('s') + bin.lastBlockSize=#temp + return assert(loadstring(temp)) + elseif t=='number' or t=='num' or t=='n' then + local num=bin.new(self:getBlock('s')) + bin.lastBlockSize=#num + if tonumber(num.data) then + return tonumber(num.data) + end + local a,b=num:tonumber() + return a + elseif n then + -- C data + else + print('Invalid Args!!!') + end +end +function bin:seek(n) + self.Block=self.Block+n +end +function bin.NumtoHEX(num) + local hexstr = '0123456789ABCDEF' + local s = '' + while num > 0 do + local mod = math.fmod(num, 16) + s = string.sub(hexstr, mod+1, mod+1) .. s + num = math.floor(num / 16) + end + if s == '' then + s = '0' + end + return s +end +function bin:getHEX(a,b,e) + a=a or 1 + local temp = self:sub(a,b) + if e then temp=string.reverse(temp) end + return bin.tohex(temp) +end +function bin.HEXtoBin(hex,e) + if e then + return bin.new(string.reverse(bin.fromhex(hex))) + else + return bin.new(bin.fromhex(hex)) + end +end +function bin.HEXtoStr(hex,e) + if e then + return string.reverse(bin.fromhex(hex)) + else + return bin.fromhex(hex) + end +end +function bin:morph(a,b,d) + if self:canStreamWrite() then + local len=self:getlength() + local temp=bin.newTempFile(self:sub(b+1,self:getlength())) + self:streamwrite(d,a-1) + print(temp:sub(1,temp:getlength())) + self:setEndOfFile(len+(b-a)+#d) + self:streamwrite(temp:sub(1,temp:getlength()),a-1) + temp:remove() + elseif self.Stream==false then + if a and b then + self.data=self:sub(1,a-1)..d..self:sub(b+1) + else + print('error both arguments must be numbers and the third a string') + end + end +end +function bin.endianflop(data) + return string.reverse(data) +end +function bin:scan(s,n,f) + n=n or 1 + if self.Stream then + for i=n,self:getlength() do + if f then + local temp=bin.new(self:sub(i,i+#s-1)) + temp:flipbits() + if temp.data==s then + return i,i+#s-1 + end + else + if self:sub(i,i+#s-1)==s then + return i,i+#s-1 + end + end + end + elseif self.Stream==false then + if f then + s=bin.new(s) + s:flipbits() + s=s.data + end + n=n or 1 + local a,b=string.find(self.data,s,n,true) + return a,b + end +end +function bin:fill(s,n) + if self:canStreamWrite() then + self:streamwrite(string.rep(s,n),0) + self:setEndOfFile(n*#s) + elseif self.Stream==false then + self.data=string.rep(s,n) + end +end +function bin:fillrandom(n) + if self:canStreamWrite() then + local t={} + for i=1,n do + table.insert(t,string.char(math.random(0,255))) + end + self:streamwrite(table.concat(t),0) + self:setEndOfFile(n) + elseif self.Stream==false then + local t={} + for i=1,n do + table.insert(t,string.char(math.random(0,255))) + end + self.data=table.concat(t) + end +end +function bin.packLLIB(name,tab,ext) + local temp=bin.new() + temp:addBlock('³Šž³–') + temp:addBlock(bin.getVersion()) + temp:addBlock(tab) + for i=1,#tab do + temp:addBlock(tab[i]) + temp:addBlock(bin.load(tab[i]).data) + end + temp:addBlock('Done') + temp:tofile(name.. ('.'..ext or '.llib')) +end +function bin.unpackLLIB(name,exe,todir,over,ext) + local temp=bin.load(name..('.'..ext or '.llib')) + local name='' + Head=temp:getBlock('s') + ver=temp:getBlock('s') + infiles=temp:getBlock('t') + if ver~=bin.getVersion() then + print('Incompatable llib file') + return nil + end + local tab={} + while name~='Done' do + name,data=temp:getBlock('s'),bin.new(temp:getBlock('s')) + if string.find(name,'.lua',1,true) then + table.insert(tab,data.data) + else + if not(bin.fileExist((todir or '')..name) and not(over)) then + data:tofile((todir or '')..name) + end + end + end + os.remove((todir or '')..'Done') + if exe then + for i=1,#tab do + assert(loadstring(tab[i]))() + end + end + return infiles +end +function bin.fileExist(path) + g=io.open(path or '','r') + if path =='' then + p='empty path' + return nil + end + if g~=nil and true or false then + p=(g~=nil and true or false) + end + if g~=nil then + io.close(g) + else + return false + end + return p +end +function bin:shiftbits(n) + if self:canStreamWrite() then + n=n or 0 + if n>=0 then + for i=0,self:getlength() do + print(string.byte(self:sub(i,i))+n%256) + self:streamwrite(string.char(string.byte(self:sub(i,i))+n%256),i-1) + end + else + n=math.abs(n) + for i=0,self:getlength() do + self:streamwrite(string.char((string.byte(self:sub(i,i))+(256-n%256))%256),i-1) + end + end + elseif self.Stream==false then + n=n or 0 + if n>=0 then + for i=1,self:getlength() do + self:morph(i,i,string.char(string.byte(self:sub(i,i))+n%256)) + end + else + n=math.abs(n) + for i=1,self:getlength() do + self:morph(i,i,string.char((string.byte(self:sub(i,i))+(256-n%256))%256)) + end + end + end +end +function bin:shiftbit(n,i) + if self:canStreamWrite() then + i=i-1 + n=n or 0 + if n>=0 then + print((string.byte(self:sub(i,i))+n)%256,n) + self:streamwrite(string.char((string.byte(self:sub(i,i))+n)%256),i-1) + else + n=math.abs(n) + print((string.byte(self:sub(i,i))+(256-n))%256,n) + self:streamwrite(string.char((string.byte(self:sub(i,i))+(256-n%256))%256),i-1) + end + elseif self.Stream==false then + n=n or 0 + if n>=0 then + self:morph(i,i,string.char((string.byte(self:sub(i,i))+n)%256)) + else + n=math.abs(n) + self:morph(i,i,string.char((string.byte(self:sub(i,i))+(256-n%256))%256)) + end + end +end +function bin.decodeBits(par) + if type(par)=='table' then + if par.t=='bit' then + return bin.new(par:toSbytes()) + end + else + if par:find(' ') then + par=par:gsub(' ','') + end + local temp=bits.new() + temp.data=par + return bin.new((temp:toSbytes()):reverse()) + end +end +function bin.textToBinary(txt) + return bin.new(bits.new(txt:reverse()):getBin()) +end +function bin:getData() + if self.Stream then + return self:sub(1,self:getSize()) + else + return self.data + end +end +function bin.getLuaVersion() + if type(jit)=="table" then + if jit.version then + return "JIT",jit.version + end + end + return "PUC",_VERSION:match("(%d-)%.(%d+)") +end +function bin.binToBuffer(b) + return bin:newDataBuffer(b.data) +end +function bin.bufferToBin(b) + return bin.new(b:getBuffer()) +end +function bin.newNamedBlock(indexSize) + local c={} + c.data=bin.new() + c.lastLoc=0 + if indexSize then + indexSize=indexSize+4 + end + c.index=bin:newDataBuffer(indexSize) + c.conv={ + ["n"]="\1", + ["b"]="\2", + ["s"]="\3", + ["t"]="\4", + ["f"]="\5" + } + if indexSize then + c.index:fillBuffer(bits.numToBytes(indexSize,4),1) + c.lastLoc=4 + else + --c.index:fillBuffer(bits.numToBytes(2048,4),1) + end + function c:tofile(path) + bin.new(self:tostring()):tofile(path) + end + function c:tostring() + c.index:fillBuffer(bits.numToBytes(c.index:getSize()-4,4),1) + return self.index:getBuffer()..self.data.data + end + function c:setPointer(name,data,t) + t=c.conv[t] + data=t..data + local dSize=#data + local index=bin:newDataBuffer() + local nLen=#name + local test="" + index:fillBuffer(bits.numToBytes(self.data:getSize()+1,4),1) + index:fillBuffer(name,5) + self.data:tackE(data) + test=self.index:fillBuffer(index:getBuffer().."\31",self.lastLoc+1) + self.lastLoc=self.lastLoc+1+index:getBufferSize() + if test=="Buffer Overflow!" then + error("Increase Index size!") + end + end + function c:addNamedBlock(name,value) + local bSize=#name + local ftype={} + if type(value)=="number" then + local dat=bits.numToBytes(value,8) -- makes 64 bit version of lua compatable + self:setPointer(name,dat,"n") + elseif type(value)=="boolean" then + if value then + self:setPointer(name,"1","b") + else + self:setPointer(name,"0","b") + end + elseif type(value)=="string" then + self:setPointer(name,value,"s") + elseif type(value)=="table" then + local str=bin.ToStr(value) + self:setPointer(name,str,"t") + elseif type(value)=="function" then + local ver,verM,verm=bin.getLuaVersion() + local data=string.dump(value) + if ver=="JIT" then + ftype=bin:newDataBuffer(bits.numToBytes(0,4)) -- luajit version + else + ftype=bin:newDataBuffer(bits.numToBytes(tonumber(verM..verm),4)) -- lua version with MajorMinor data + end + local fdata=bin.new() + fdata:tackE(ftype:getBuffer()..data) + self:setPointer(name,fdata.data,"f") + elseif type(value)=="userdata" then + error("Userdata cannot be put into a block!") + end + end + if not indexSize then + c:addNamedBlock("__UNBOUNDEDINDEX__",true) + end + return c +end +function bin.newStreamedNamedBlock(indexSize,path,update) + local c={} + c.data=bin.stream(path,false) + c.lastLoc=4 + c.conv={ + ["n"]="\1", + ["b"]="\2", + ["s"]="\3", + ["t"]="\4", + ["f"]="\5" + } + if not update then + c.data:tackE(bin:newDataBuffer(indexSize+4 or 2052):getBuffer()) + if indexSize then + c.data:mutate(bits.numToBytes(indexSize,4),1) + else + c.data:mutate(bits.numToBytes(2048,4),1) + end + c.indexSize=indexSize+4 or 2052 + else + c.indexSize=c.data:tonumber(1,4) + local i=bin.new(c.data:sub(5,c.indexSize+4)).data + local last=0 + for b=#i,1,-1 do + if i:sub(b,b)=="\31" then + last=b+4 + break + end + end + c.lastLoc=last + end + function c:tofile(path) + --No need when using a streamed block + end + function c:tostring() + return self.index:getBuffer()..self.data.data + end + function c:setPointer(name,data,t) + t=c.conv[t] + data=t..data + local dSize=#data + local index=bin:newDataBuffer() + local nLen=#name + local test="" + index:fillBuffer(bits.numToBytes((self.data:getSize()+1)-self.indexSize,4),1) + index:fillBuffer(name,5) + local test=self.data:mutate(index:getBuffer().."\31",self.lastLoc+1) + self.lastLoc=self.lastLoc+1+index:getBufferSize() + self.data:tackE(data) + if test=="Buffer Overflow!" then + error("Increase Index size!") + end + end + function c:addNamedBlock(name,value) + local bSize=#name + local ftype={} + if type(value)=="number" then + local dat=bits.numToBytes(value,8) -- makes 64 bit version of lua compatable + self:setPointer(name,dat,"n") + elseif type(value)=="boolean" then + if value then + self:setPointer(name,"1","b") + else + self:setPointer(name,"0","b") + end + elseif type(value)=="string" then + self:setPointer(name,value,"s") + elseif type(value)=="table" then + local str=bin.ToStr(value) + self:setPointer(name,str,"t") + elseif type(value)=="function" then + local ver,verM,verm=bin.getLuaVersion() + local data=string.dump(value) + if ver=="JIT" then + ftype=bin:newDataBuffer(bits.numToBytes(0,4)) -- luajit version + else + ftype=bin:newDataBuffer(bits.numToBytes(tonumber(verM..verm),4)) -- lua version with MajorMinor data + end + local fdata=bin.new() + fdata:tackE(ftype:getBuffer()..data) + self:setPointer(name,fdata.data,"f") + elseif type(value)=="userdata" then + error("Userdata cannot be put into a block!") + end + end + function c:close() + self:addNamedBlock("",false) + self.data:close() + end + return c +end +function bin.loadNamedBlock(path) + local c={} + c.data=bin.stream(path) + c.iSize=c.data:tonumber(1,4) + c.index=bin.new(c.data:sub(5,c.iSize+4)) + c.sData=bin.new(c.data:sub(c.iSize+5,-1)) + function c:CheckRestOfIndex(name) + local a,b=self.index:scan(name) + local d=self.index:tonumber(b+2,b+5) + if d==0 or b+5>self.iSize then + return -1 + end + return d + end + function c:getIndexes() + local tab={} + ind=5 + while ind do + local a=self.index:find("\31",ind) + if not a then break end + local b=self.index:sub(ind,a-1) + table.insert(tab,b) + ind=a+5 + end + return tab + end + function c:getBlock(name) + local a,b=self.index:scan(name) + if not a then return "index not found" end + local dloc=self.index:tonumber(a-4,a-1) + local dindex=bin:newDataBuffer(self.sData:sub(dloc,dloc)) + if dindex[1]==0x01 then -- type number + return self.sData:tonumber(dloc+1,dloc+8) + elseif dindex[1]==0x02 then -- type bool + return ({[1]=true,[0]=false})[tonumber(self.sData:sub(dloc+1,dloc+1))] + elseif dindex[1]==0x03 then -- type string + local dend=self:CheckRestOfIndex(name)--self.index:tonumber(b+2,b+5) + return self.sData:sub(dloc+1,dend-1) + elseif dindex[1]==0x04 then -- type table + local dend=self.index:tonumber(b+2,b+5) + return loadstring("return "..self.sData:sub(dloc+1,dend-1))() + elseif dindex[1]==0x05 then -- type function + local dend=self:CheckRestOfIndex(name)--self.index:tonumber(b+2,b+5) + local _ver=self.sData:tonumber(dloc+1,dloc+4) + local ver,verM,verm=bin.getLuaVersion() + if tonumber(verM..verm)==_ver then + return loadstring(self.sData:sub(dloc+5,dend-1)) + else + return function() error("This lua function is not compatible with the current version of lua!") end + end + end + end + return c +end +function bin.namedBlockManager(name) + if type(name)=="string" then + local i={} + local data=bin.loadNamedBlock(name) + local mt={ + __index=function(t,k) + return data:getBlock(k) + end, + } + setmetatable(i,mt) + return i + else + local i={} + local data=bin.newNamedBlock(name) + local mt={ + __newindex=function(t,k,v) + data:addNamedBlock(k,v) + end, + __index=data + } + setmetatable(i,mt) + return i + end +end +function bin.getIndexSize(tab) + size=0 + for i=1,#tab do + size=size+#tab[i]+5 + end + return size+5 +end +function bin.gcd( m, n ) + while n ~= 0 do + local q = m + m = n + n = q % n + end + return m +end +function bin.numToFraction(num) + num=num or error("Must enter a number!") + local n=#tostring(num) + num=num*(10^n) + local d=(10^n) + local g=bin.gcd(num,d) + return tostring(num/g).."/"..tostring(d/g),num/g,d/g +end +function bin.doubleToString(double) + local s=({[false]="-",[true]="+"})[double>=0] + double=math.abs(double) + local _,n,d=bin.numToFraction(double) + gfit=4 + local a=bits.numToBytes(n,gfit,function(ref) + ref.fit=12 -- should be able to pack any number into that space + ref.num=string.rep("\0",12-#ref.num)..ref.num + if s=="-" then + s="_" + else + s="=" + end + gfit=12 + end) + local b=bits.numToBytes(d,gfit) + return s..a..b +end +function bin.stringToDouble(str) + local s=str:sub(1,1) + if #str~=9 and #str~=25 then + if s~="-" and s~="+" and s~="_" and s~="=" then + print(s) + error("Not a double encoded string") + end + error("Not a double encoded string") + end + local n,d + if s=="_" or s=="=" then + n,d=str:sub(2,13),str:sub(14) + else + n,d=str:sub(2,5),str:sub(6) + end + local n=bin.new(n):tonumber() + local d=bin.new(d):tonumber() + local num=n/d + if s=="-" or s=="_" then + num=-num + end + return num +end +--[[---------------------------------------- +VFS +------------------------------------------]] +local _require = require +function require(path,vfs) + if bin.fileExist(path..'.lvfs') then + local data = bin.loadVFS(path..'.lvfs') + if data:fileExist(vsf) then + loadstring(data:readFile(vfs))() + end + else + return _require(path) + end +end +function bin.loadVFS(path) + local vfs=bin.newVFS() + local temp=bin.stream(path,false) + local files=temp:getBlock("t") + local size=0 + for i=1,#files do + local p,len=files[i]:match("(.-)|(.+)") + len=tonumber(len) + size=size+bin.lastBlockSize + local dat=temp:sub(size+5,size+len+4) + bin.lastBlockSize=len + vfs:mkfile(p:gsub("%./",""),dat) + end + return vfs +end +function bin.copyDir(dir,todir) + local vfs=bin.newVFS(dir,true) + vfs:toFS(todir) + vfs=nil +end +function bin.newVFS(t,l) + l=l or true + if type(t)=='string' then + t=io.parseDir(t,l) + end + local c={} + c.FS= t or {} + function c:merge(vfs) + bin.newVFS(table.merge(self.FS,vfs.FS)) + end + function c:mirror(file) + self:mkfile(file,file) + end + function c:mkdir(path) + table.merge(self.FS,io.pathToTable(path)) + end + function c:scanDir(path) + path=path or '' + local tab={} + if path=='' then + for i,v in pairs(self.FS) do + tab[#tab+1]=i + end + return tab + end + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath-1 do + last=last[spath[i]] + end + return last[spath[#spath]] + end + function c:getFiles(path) + if not self:dirExist(path) then return end + path=path or '' + local tab={} + if path=='' then + for i,v in pairs(self.FS) do + if self:fileExist(i) then + tab[#tab+1]=i + end + end + return tab + end + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath-1 do + last=last[spath[i]] + end + local t=last[spath[#spath]] + for i,v in pairs(t) do + if self:fileExist(path..'/'..i) then + tab[#tab+1]=path..'/'..i + end + end + return tab + end + function c:getDirectories(path) + if not self:dirExist(path) then return end + path=path or '' + local tab={} + if path=='' then + for i,v in pairs(self.FS) do + if self:dirExist(i) then + tab[#tab+1]=i + end + end + return tab + end + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath-1 do + last=last[spath[i]] + end + local t=last[spath[#spath]] + for i,v in pairs(t) do + if self:dirExist(path..'/'..i) then + tab[#tab+1]=path..'/'..i + end + end + return tab + end + function c:mkfile(path,data) + local name=io.getFullName(path) + local temp=path:reverse() + local a,b=temp:find('/') + if not a then + a,b=temp:find('\\') + end + if a then + temp=temp:sub(a+1):reverse() + path=temp + local t,l=io.pathToTable(path) + l[name]=data + table.merge(self.FS,t) + else + self.FS[name]=data + end + end + function c:remove(path) + if path=='' or path==nil then return end + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath-1 do + last=last[spath[i]] + end + last[spath[#spath]]=nil + end + function c:readFile(path) + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath do + last=last[spath[i]] + end + if type(last)=='userdata' then + last=last:read('*all') + end + return last + end + function c:copyFile(p1,p2) + self:mkfile(p2,self:readFile(p1)) + end + function c:moveFile(p1,p2) + self:copyFile(p1,p2) + self:remove(p1) + end + function c:fileExist(path) + return type(self:readFile(path))=='string' + end + function c:dirExist(path) + if path=='' or path==nil then return end + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath-1 do + last=last[spath[i]] + end + if last[spath[#spath]]~=nil then + if type(last[spath[#spath]])=='table' then + return true + end + end + return false + end + function c:_getHierarchy() + local ord={} + local datlink=bin.new() + local function toStr(val, name, skipnewlines, depth, path) + skipnewlines = skipnewlines or false + path=path or "." + depth = depth or 0 + local tmp = string.rep(" ", depth) + if name then + if type(name) == "string" then + tmp = tmp .. "[\""..name.."\"] = " + else + tmp = tmp .. "["..(name or "").."] = " + end + end + if type(val) == "table" then + tmp = tmp .. "{" .. (not skipnewlines and "\n" or "") + for k, v in pairs(val) do + tmp = tmp .. toStr(v, k, skipnewlines, depth + 1,path.."/"..k) .. "," .. (not skipnewlines and "\n" or "") + end + tmp = tmp .. string.rep(" ", depth) .. "}" + elseif type(val) == "string" then + tmp = tmp .. #val + datlink:tackE(val) + ord[#ord+1]=path.."|"..#val + end + return tmp + end + return toStr(self.FS),ord,datlink + end + function c:getHierarchy() + local ord={} + local function toStr(val, name, skipnewlines, depth, path) + skipnewlines = skipnewlines or false + path=path or "." + depth = depth or 0 + local tmp = string.rep(" ", depth) + if name then + if type(name) == "string" then + tmp = tmp .. "[\""..name.."\"] = " + else + tmp = tmp .. "["..(name or "").."] = " + end + end + if type(val) == "table" then + tmp = tmp .. "{" .. (not skipnewlines and "\n" or "") + for k, v in pairs(val) do + tmp = tmp .. toStr(v, k, skipnewlines, depth + 1,path.."/"..k) .. "," .. (not skipnewlines and "\n" or "") + end + tmp = tmp .. string.rep(" ", depth) .. "}" + elseif type(val) == "string" then + tmp = tmp .. ";" + ord[#ord+1]=path.."|"..#val + end + return tmp + end + return toStr(self.FS),ord + end + function c:tofile(path) + local temp=bin.new() + local h,o,link=self:_getHierarchy() + temp:addBlock(o) + temp:merge(link) + temp:tofile(path) + end + function c:toFS(path) + if path then + if path:sub(-1,-1)~='\\' then + path=path..'\\' + elseif path:find('/') then + path=path:gsub('/','\\') + end + io.mkDir(path) + else + path='' + end + function build(tbl, indent, folder) + if not indent then indent = 0 end + if not folder then folder = '' end + for k, v in pairs(tbl) do + formatting = string.rep(' ', indent) .. k .. ':' + if type(v) == 'table' then + if v.t~=nil then + io.mkFile(folder..k,tostring(v),'wb') + else + if not(io.dirExists(path..folder..string.sub(formatting,1,-2))) then + io.mkDir(folder..string.sub(formatting,1,-2)) + end + build(v,0,folder..string.sub(formatting,1,-2)..'\\') + end + elseif type(v)=='string' then + io.mkFile(folder..k,v,'wb') + elseif type(v)=='userdata' then + io.mkFile(folder..k,v:read('*all'),'wb') + end + end + end + build(self.FS,0,path) + end + function c:print() + table.print(self.FS) + end + return c +end +--[[---------------------------------------- +BITS +------------------------------------------]] +function bits.lsh(value,shift) + return (value*(2^shift)) % 256 +end +function bits.rsh(value,shift) + return math.floor(value/2^shift) % 256 +end +function bits.bit(x,b) + return (x % 2^b - x % 2^(b-1) > 0) +end +function bits.lor(x,y) + result = 0 + for p=1,8 do result = result + (((bits.bit(x,p) or bits.bit(y,p)) == true) and 2^(p-1) or 0) end + return result +end +function bits.newBitBuffer(n) + -- +end +function bits.newConverter(bitsIn,bitsOut) + local c={} + -- +end +bits.ref={} +function bits.newByte(d) + local c={} + if type(d)=="string" then + if #d>1 or #d<1 then + error("A byte must be one character!") + else + c.data=string.byte(d) + end + elseif type(d)=="number" then + if d>255 or d<0 then + error("A byte must be between 0 and 255!") + else + c.data=d + end + else + error("cannot use type "..type(d).." as an argument! Takes only strings or numbers!") + end + c.__index=function(self,k) + if k>=0 and k<9 then + if self.data==0 then + return 0 + elseif self.data==255 then + return 1 + else + return bits.ref[self.data][k] + end + end + end + c.__tostring=function(self) + return bits.ref[tostring(self.data)] + end + setmetatable(c,c) + return c +end +function bits.newByteArray(s) + local c={} + if type(s)~="string" then + error("Must be a string type or bin/buffer type") + elseif type(s)=="table" then + if s.t=="sink" or s.t=="buffer" or s.t=="bin" then + local data=s:getData() + for i=1,#data do + c[#c+1]=bits.newByte(data:sub(i,i)) + end + else + error("Must be a string type or bin/buffer type") + end + else + for i=1,#s do + c[#c+1]=bits.newByte(s:sub(i,i)) + end + end + return c +end +function bits.new(n,s) + if type(n)=='string' then + local t=tonumber(n,2) + if t and #n<8 and not(s) then + t=nil + end + if not(t) then + t={} + for i=#n,1,-1 do + table.insert(t,bits:conv(string.byte(n,i))) + end + n=table.concat(t) + else + n=t + end + end + local temp={} + temp.t='bit' + setmetatable(temp, bits) + if type(n)~='string' then + local tab={} + while n>=1 do + table.insert(tab,n%2) + n=math.floor(n/2) + end + local str=string.reverse(table.concat(tab)) + if #str%8~=0 then + str=string.rep('0',8-#str%8)..str + end + temp.data=str + else + temp.data=n + end + setmetatable({__tostring=function(self) return self.data end},temp) + return temp +end +for i=0,255 do + local d=bits.new(i).data + bits.ref[i]={d:match("(%d)(%d)(%d)(%d)(%d)(%d)(%d)(%d)")} + bits.ref[tostring(i)]=d + bits.ref[d]=i + bits.ref["\255"..string.char(i)]=d +end +function bits.numToBytes(n,fit,func) + local num=bits.new(n):toSbytes() + num=bin.endianflop(num) + local ref={["num"]=num,["fit"]=fit} + if fit then + if fit<#num then + if func then + print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!") + func(ref) + else + print("Warning: attempting to store a number that takes up more space than allotted!") + end + return ref.num:sub(1,ref.fit) + elseif fit==#num then + return num + else + return string.rep("\0",fit-#num)..num + end + else + return num + end +end +function bits:conv(n) + local tab={} + while n>=1 do + table.insert(tab,n%2) + n=math.floor(n/2) + end + local str=string.reverse(table.concat(tab)) + if #str%8~=0 then + str=string.rep('0',8-#str%8)..str + end + return str +end +function bits:add(i) + if type(i)=='number' then + i=bits.new(i) + end + self.data=self:conv(tonumber(self.data,2)+tonumber(i.data,2)) +end +function bits:sub(i) + if type(i)=='number' then + i=bits.new(i) + end + self.data=self:conv(tonumber(self.data,2)-tonumber(i.data,2)) +end +function bits:multi(i) + if type(i)=='number' then + i=bits.new(i) + end + self.data=self:conv(tonumber(self.data,2)*tonumber(i.data,2)) +end +function bits:div(i) + if type(i)=='number' then + i=bits.new(i) + end + self.data=self:conv(tonumber(self.data,2)/tonumber(i.data,2)) +end +function bits:tonumber(s) + if type(s)=='string' then + return tonumber(self.data,2) + end + s=s or 1 + return tonumber(string.sub(self.data,(8*(s-1))+1,8*s),2) or error('Bounds!') +end +function bits:isover() + return #self.data>8 +end +function bits:flipbits() + tab={} + for i=1,#self.data do + if string.sub(self.data,i,i)=='1' then + table.insert(tab,'0') + else + table.insert(tab,'1') + end + end + self.data=table.concat(tab) +end +function bits:tobytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return bin.new(table.concat(tab)) +end +function bits:toSbytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return table.concat(tab) +end +function bits:getBin() + return self.data +end +function bits:getbytes() + return #self.data/8 +end diff --git a/game/core/test.lua b/game/core/test.lua new file mode 100644 index 0000000..f551bde --- /dev/null +++ b/game/core/test.lua @@ -0,0 +1,18 @@ +require("Library") +local clock = os.clock +function sleep(n) -- seconds + local t0 = clock() + while clock() - t0 <= n do end +end +function tester(test) + sleep(1) + return test*10 +end +--~ require("bin") +--~ test=bin.namedBlockManager() +--~ test["name"]="Ryan" +--~ test["age"]=21 +--~ test:tofile("test.dat") +--~ test2=bin.namedBlockManager("test.dat") +--~ print(test2["name"]) +--~ print(test2["age"]) diff --git a/game/main.lua b/game/main.lua new file mode 100644 index 0000000..237119a --- /dev/null +++ b/game/main.lua @@ -0,0 +1,9 @@ +love.filesystem.setIdentity("love2dstreamtest") +require("core.Utils") +require("core.Library") +require("bin") +GLOBAL,sThread=require("multi.integration.loveManager").init() +require("core.AudioManager") +require("core.GuiManager") +require("parseManager") +gui.ff.Color=Color.Black diff --git a/game/multi/all.lua b/game/multi/all.lua new file mode 100644 index 0000000..d14aac6 --- /dev/null +++ b/game/multi/all.lua @@ -0,0 +1 @@ +require("multi") diff --git a/game/multi/compat/backwards[1,5,0].lua b/game/multi/compat/backwards[1,5,0].lua new file mode 100644 index 0000000..a0f52a8 --- /dev/null +++ b/game/multi/compat/backwards[1,5,0].lua @@ -0,0 +1,305 @@ +--[[ +MIT License + +Copyright (c) 2017 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +multi.OnObjectCreated(function(obj) + if obj.Type=="loop" then + function obj:Act() + for i=1,#self.func do + self.func[i](self.Parent.clock()-self.Start,self) + end + end + elseif obj.Type=="step" then + function obj:Act() + if self~=nil then + if self.spos==0 then + if self.pos==self.start then + for fe=1,#self.funcS do + self.funcS[fe](self) + end + end + for i=1,#self.func do + self.func[i](self.pos,self) + end + self.pos=self.pos+self.count + if self.pos-self.count==self.endAt then + self:Pause() + for fe=1,#self.funcE do + self.funcE[fe](self) + end + self.pos=self.start + end + end + end + self.spos=self.spos+1 + if self.spos>=self.skip then + self.spos=0 + end + end + elseif obj.Type=="tstep" then + function c:Act() + if self.clock()-self.timer>=self.set then + self:Reset() + if self.pos==self.start then + for fe=1,#self.funcS do + self.funcS[fe](self) + end + end + for i=1,#self.func do + self.func[i](self.pos,self) + end + self.pos=self.pos+self.count + if self.pos-self.count==self.endAt then + self:Pause() + for fe=1,#self.funcE do + self.funcE[fe](self) + end + self.pos=self.start + end + end + end + end +end) +if thread then + function multi:newThreadedLoop(name,func) + local c=self:newTBase() + c.Type='loopThread' + c.Start=os.clock() + if func then + c.func={func} + end + function c:tofile(path) + local m=bin.new() + m:addBlock(self.Type) + m:addBlock(self.func) + m:addBlock(self.Active) + m:tofile(path) + end + function c:Resume() + self.rest=false + end + function c:Pause() + self.rest=true + end + function c:OnLoop(func) + table.insert(self.func,func) + end + c.rest=false + c.updaterate=0 + c.restRate=.75 + multi:newThread(name,function(ref) + while true do + if c.rest then + thread.sleep(c.restRate) + else + for i=1,#c.func do + c.func[i](os.clock()-self.Start,c) + end + thread.sleep(c.updaterate) + end + end + end) + self:create(c) + return c + end + function multi:newThreadedStep(name,start,reset,count,skip) + local c=self:newTBase() + local think=1 + c.Type='stepThread' + c.pos=start or 1 + c.endAt=reset or math.huge + c.skip=skip or 0 + c.spos=0 + c.count=count or 1*think + c.funcE={} + c.funcS={} + c.start=start or 1 + if start~=nil and reset~=nil then + if start>reset then + think=-1 + end + end + function c:tofile(path) + local m=bin.new() + m:addBlock(self.Type) + m:addBlock(self.func) + m:addBlock(self.funcE) + m:addBlock(self.funcS) + m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start}) + m:addBlock(self.Active) + m:tofile(path) + end + function c:Resume() + self.rest=false + end + function c:Pause() + self.rest=true + end + c.Reset=c.Resume + function c:OnStart(func) + table.insert(self.funcS,func) + end + function c:OnStep(func) + table.insert(self.func,1,func) + end + function c:OnEnd(func) + table.insert(self.funcE,func) + end + function c:Break() + self.rest=true + end + function c:Update(start,reset,count,skip) + self.start=start or self.start + self.endAt=reset or self.endAt + self.skip=skip or self.skip + self.count=count or self.count + self:Resume() + end + c.updaterate=0 + c.restRate=.1 + multi:newThread(name,function(ref) + while true do + if c.rest then + ref:sleep(c.restRate) + else + if c~=nil then + if c.spos==0 then + if c.pos==c.start then + for fe=1,#c.funcS do + c.funcS[fe](c) + end + end + for i=1,#c.func do + c.func[i](c.pos,c) + end + c.pos=c.pos+c.count + if c.pos-c.count==c.endAt then + c:Pause() + for fe=1,#c.funcE do + c.funcE[fe](c) + end + c.pos=c.start + end + end + end + c.spos=c.spos+1 + if c.spos>=c.skip then + c.spos=0 + end + ref:sleep(c.updaterate) + end + end + end) + self:create(c) + return c + end + function multi:newThreadedTStep(name,start,reset,count,set) + local c=self:newTBase() + local think=1 + c.Type='tstepThread' + c.Priority=self.Priority_Low + c.start=start or 1 + local reset = reset or math.huge + c.endAt=reset + c.pos=start or 1 + c.skip=skip or 0 + c.count=count or 1*think + c.funcE={} + c.timer=os.clock() + c.set=set or 1 + c.funcS={} + function c:Update(start,reset,count,set) + self.start=start or self.start + self.pos=self.start + self.endAt=reset or self.endAt + self.set=set or self.set + self.count=count or self.count or 1 + self.timer=os.clock() + self:Resume() + end + function c:tofile(path) + local m=bin.new() + m:addBlock(self.Type) + m:addBlock(self.func) + m:addBlock(self.funcE) + m:addBlock(self.funcS) + m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set}) + m:addBlock(self.Active) + m:tofile(path) + end + function c:Resume() + self.rest=false + end + function c:Pause() + self.rest=true + end + function c:OnStart(func) + table.insert(self.funcS,func) + end + function c:OnStep(func) + table.insert(self.func,func) + end + function c:OnEnd(func) + table.insert(self.funcE,func) + end + function c:Break() + self.Active=nil + end + function c:Reset(n) + if n then self.set=n end + self.timer=os.clock() + self:Resume() + end + c.updaterate=0 + c.restRate=0 + multi:newThread(name,function(ref) + while true do + if c.rest then + thread.sleep(c.restRate) + else + if os.clock()-c.timer>=c.set then + c:Reset() + if c.pos==c.start then + for fe=1,#c.funcS do + c.funcS[fe](c) + end + end + for i=1,#c.func do + c.func[i](c.pos,c) + end + c.pos=c.pos+c.count + if c.pos-c.count==c.endAt then + c:Pause() + for fe=1,#c.funcE do + c.funcE[fe](c) + end + c.pos=c.start + end + end + thread.skip(c.updaterate) + end + end + end) + self:create(c) + return c + end +end diff --git a/game/multi/compat/love2d.lua b/game/multi/compat/love2d.lua new file mode 100644 index 0000000..cc4015d --- /dev/null +++ b/game/multi/compat/love2d.lua @@ -0,0 +1,114 @@ +--[[ +MIT License + +Copyright (c) 2017 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +require("multi") +os.sleep=love.timer.sleep +function love.run() + if love.math then + love.math.setRandomSeed(os.time()) + end + if love.event then + love.event.pump() + end + if love.load then love.load(arg) end + if love.timer then love.timer.step() end + local dt = 0 + while true do + -- Process events. + if love.event then + love.event.pump() + for e,a,b,c,d in love.event.poll() do + if e == "quit" then + if not love.quit or not love.quit() then + if love.audio then + love.audio.stop() + end + return + end + end + love.handlers[e](a,b,c,d) + end + end + if love.timer then + love.timer.step() + dt = love.timer.getDelta() + end + if love.update then love.update(dt) end + if multi.boost then + for i=1,multi.boost-1 do + multi:uManager(dt) + end + end + multi:uManager(dt) + if love.window and love.graphics and love.window.isCreated() then + love.graphics.clear() + love.graphics.origin() + if love.draw then love.draw() end + multi.dManager() + love.graphics.setColor(255,255,255,255) + if multi.draw then multi.draw() end + love.graphics.present() + end + end +end +multi.drawF={} +function multi:dManager() + for ii=1,#multi.drawF do + multi.drawF[ii]() + end +end +function multi:onDraw(func,i) + i=i or 1 + table.insert(self.drawF,i,func) +end +function multi:lManager() + if love.event then + love.event.pump() + for e,a,b,c,d in love.event.poll() do + if e == "quit" then + if not love.quit or not love.quit() then + if love.audio then + love.audio.stop() + end + return nil + end + end + love.handlers[e](a,b,c,d) + end + end + if love.timer then + love.timer.step() + dt = love.timer.getDelta() + end + if love.update then love.update(dt) end + multi:uManager(dt) + if love.window and love.graphics and love.window.isCreated() then + love.graphics.clear() + love.graphics.origin() + if love.draw then love.draw() end + multi.dManager() + love.graphics.setColor(255,255,255,255) + if multi.draw then multi.draw() end + love.graphics.present() + end +end diff --git a/game/multi/init.lua b/game/multi/init.lua new file mode 100644 index 0000000..c824b9e --- /dev/null +++ b/game/multi/init.lua @@ -0,0 +1,2278 @@ +--[[ +MIT License + +Copyright (c) 2017 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +require("bin") +if table.unpack then + unpack=table.unpack +end +function table.merge(t1, t2) + for k,v in pairs(t2) do + if type(v) == 'table' then + if type(t1[k] or false) == 'table' then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +_print=print +function print(...) + if not __SUPPRESSPRINTS then + _print(...) + end +end +_write=io.write +function io.write(...) + if not __SUPPRESSWRITES then + _write(...) + end +end +multi = {} +multi.Version="1.9.2" +multi._VERSION="1.9.2" +multi.stage='mostly-stable' +multi.__index = multi +multi.Mainloop={} +multi.Tasks={} +multi.Tasks2={} +multi.Garbage={} +multi.ender={} +multi.Children={} +multi.Paused={} +multi.Active=true +multi.fps=60 +multi.Id=-1 +multi.Type='mainprocess' +multi.Rest=0 +multi._type=type +multi.Jobs={} +multi.queue={} +multi.jobUS=2 +multi.clock=os.clock +multi.time=os.time +multi.LinkedPath=multi +multi.isRunning=false +multi.queuefinal=function(self) + self:Destroy() + if self.Parent.Mainloop[#self.Parent.Mainloop] then + if self.Parent.Mainloop[#self.Parent.Mainloop].Type=="alarm" then + self.Parent.Mainloop[#self.Parent.Mainloop]:Reset() + self.Parent.Mainloop[#self.Parent.Mainloop].Active=true + else + self.Parent.Mainloop[#self.Parent.Mainloop]:Resume() + end + else + for i=1,#self.Parent.funcE do + self.Parent.funcE[i](self) + end + self.Parent:Remove() + end +end +--Do not change these ever...Any other number will not work (Unless you are using enablePriority2()) +multi.Priority_Core=1 +multi.Priority_High=4 +multi.Priority_Above_Normal=16 +multi.Priority_Normal=64 +multi.Priority_Below_Normal=256 +multi.Priority_Low=1024 +multi.Priority_Idle=4096 +multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle} +multi.PStep=1 +--^^^^ +multi.PriorityTick=1 -- Between 1,2 and 4 +multi.Priority=multi.Priority_Core +multi.threshold=256 +multi.threstimed=.001 +function multi:setThreshold(n) + self.threshold=n or 120 +end +function multi:setThrestimed(n) + self.threstimed=n or .001 +end +function multi:getLoad() + return multi:newFunction(function(self) + multi.scheduler:Pause() + local sample=#multi.Mainloop + local FFloadtest=0 + multi:benchMark(multi.threstimed):OnBench(function(_,l3) FFloadtest=l3*(1/multi.threstimed) end) + self:hold(function() return FFloadtest~=0 end) + local val=FFloadtest/sample + multi.scheduler:Resume() + if val>multi.threshold then + return 0 + else + return 100-((val/multi.threshold)*100) + end + end)() +end +function multi:setDomainName(name) + self[name]={} +end +function multi:linkDomain(name) + return self[name] +end +function multi:_Pause() + self.Active=false +end +function multi:setPriority(s) + if type(s)==number then + self.Priority=s + elseif type(s)=='string' then + if s:lower()=='core' or s:lower()=='c' then + self.Priority=self.Priority_Core + elseif s:lower()=='high' or s:lower()=='h' then + self.Priority=self.Priority_High + elseif s:lower()=='above' or s:lower()=='an' then + self.Priority=self.Priority_Above_Normal + elseif s:lower()=='normal' or s:lower()=='n' then + self.Priority=self.Priority_Normal + elseif s:lower()=='below' or s:lower()=='bn' then + self.Priority=self.Priority_Below_Normal + elseif s:lower()=='low' or s:lower()=='l' then + self.Priority=self.Priority_Low + elseif s:lower()=='idle' or s:lower()=='i' then + self.Priority=self.Priority_Idle + end + end +end +-- System +function os.getOS() + if package.config:sub(1,1)=='\\' then + return 'windows' + else + return 'unix' + end +end +if os.getOS()=='windows' then + function os.sleep(n) + if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end + end +else + function os.sleep(n) + os.execute('sleep ' .. tonumber(n)) + end +end +function multi:getParentProcess() + return self.Mainloop[self.CID] +end +multi.GetParentProcess=multi.getParentProcess +function multi:Stop() + self.Active=false +end +function multi:condition(cond) + if not self.CD then + self:Pause() + self.held=true + self.CD=cond.condition + elseif not(cond.condition()) then + self.held=false + self:Resume() + self.CD=nil + return false + end + self.Parent:Do_Order() + return true +end +multi.Condition=multi.condition +function multi:isHeld() + return self.held +end +multi.important={} +multi.IsHeld=multi.isHeld +function multi.executeFunction(name,...) + if type(_G[name])=='function' then + _G[name](...) + else + print('Error: Not a function') + end +end +function multi:waitFor(obj) + local value=false + self.__waiting=function() + value=true + end + obj:connectFinal(self.__waiting) + self:hold(function() return value end) +end +multi.WaitFor=multi.waitFor +function multi:reboot(r) + local before=collectgarbage('count') + multi.Mainloop={} + multi.Tasks={} + multi.Tasks2={} + multi.Garbage={} + multi.ender={} + multi.Children={} + multi.Paused={} + multi.Active=true + multi.fps=60 + multi.Id=-1 + multi.Type='mainprocess' + multi.Rest=0 + multi._type=type + multi.Jobs={} + multi.queue={} + multi.jobUS=2 + multi.clock=os.clock + multi.time=os.time + multi.LinkedPath=multi + multi.isRunning=false + multi.Priority_Core=1 + multi.Priority_High=4 + multi.Priority_Above_Normal=16 + multi.Priority_Normal=64 + multi.Priority_Below_Normal=256 + multi.Priority_Low=1024 + multi.Priority_Idle=4096 + multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle} + multi.PStep=1 + multi.PriorityTick=1 + multi.Priority=multi.Priority_Core + multi.threshold=256 + multi.threstimed=.001 + if r then + for i,v in pairs(_G) do + if type(i)=='table' then + if i.Parent and i.Id and i.Act then + _G[i]={} + end + end + end + end + collectgarbage() + local after=collectgarbage('count') + print([[Before rebooting total Ram used was ]]..before..[[Kb +After rebooting total Ram used is ]]..after..[[ Kb +A total of ]]..(before-after)..[[Kb was cleaned up]]) +end +function multi:getChildren() + return self.Mainloop +end +function multi:getVersion() + return multi.Version +end +function multi:getPlatform() + if love then + if love.thread then + return "love2d" + end + else + return "lanes" + end +end +function multi:canSystemThread() + return false +end +--Processor +function multi:getError() + if self.error then + return self.error + end +end +function multi:Do_Order() + local Loop=self.Mainloop + _G.ID=0 + for _D=#Loop,1,-1 do + if Loop[_D] then + if Loop[_D].Active then + Loop[_D].Id=_D + self.CID=_D + Loop[_D]:Act() + end + end + end +end +function multi:enablePriority() + function self:Do_Order() + local Loop=self.Mainloop + _G.ID=0 + local PS=self + for _D=#Loop,1,-1 do + for P=1,7 do + if Loop[_D] then + if (PS.PList[P])%Loop[_D].Priority==0 then + if Loop[_D].Active then + Loop[_D].Id=_D + self.CID=_D + Loop[_D]:Act() + end + end + end + end + end + end +end +function multi:enablePriority2() + function self:Do_Order() + local Loop=self.Mainloop + _G.ID=0 + local PS=self + for _D=#Loop,1,-1 do + if Loop[_D] then + if (PS.PStep)%Loop[_D].Priority==0 then + if Loop[_D].Active then + Loop[_D].Id=_D + self.CID=_D + Loop[_D]:Act() + end + end + end + end + PS.PStep=PS.PStep+1 + if PS.PStep>self.Priority_Idle then + PS.PStep=1 + end + end +end +multi.disablePriority=multi.unProtect +function multi:benchMark(sec,p,pt) + local temp=self:newLoop(function(self,t) + if self.clock()-self.init>self.sec then + if pt then + print(pt.." "..self.c.." Steps in "..sec.." second(s)!") + end + self.tt(self.sec,self.c) + self:Destroy() + else + self.c=self.c+1 + end + end) + temp.Priority=p or 1 + function temp:OnBench(func) + self.tt=func + end + self.tt=function() end + temp.sec=sec + temp.init=self.clock() + temp.c=0 + return temp +end +function multi.startFPSMonitior() + if not multi.runFPS then + multi.doFPS(s) + multi.runFPS=true + end +end +function multi.doFPS(s) + multi:benchMark(1):OnBench(doFPS) + if s then + multi.fps=s + end +end +--Helpers +function multi.timer(func,...) + local timer=multi:newTimer() + timer:Start() + args={func(...)} + return timer:Get(),unpack(args) +end +function multi:IsAnActor() + return ({watcher=true,tstep=true,step=true,updater=true,loop=true,alarm=true,event=true})[self.Type] +end +function multi:OnMainConnect(func) + table.insert(self.func,func) +end +function multi:protect() + function self:Do_Order() + local Loop=self.Mainloop + for _D=#Loop,1,-1 do + if Loop[_D]~=nil then + Loop[_D].Id=_D + self.CID=_D + local status, err=pcall(Loop[_D].Act,Loop[_D]) + if err and not(Loop[_D].error) then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + end + end + end + end +end +function multi:unProtect() + local Loop=self.Mainloop + _G.ID=0 + for _D=#Loop,1,-1 do + if Loop[_D] then + if Loop[_D].Active then + Loop[_D].Id=_D + self.CID=_D + Loop[_D]:Act() + end + end + end +end +function multi:reallocate(o,n) + n=n or #o.Mainloop+1 + local int=self.Parent + self:Destroy() + self.Parent=o + table.insert(o.Mainloop,n,self) + self.Active=true +end +multi.Reallocate=multi.Reallocate +function multi:setJobSpeed(n) + self.jobUS=n +end +function multi:hasJobs() + return #self.Jobs>0,#self.Jobs +end +function multi:getJobs() + return #self.Jobs +end +function multi:removeJob(name) + for i=#self.Jobs,1,-1 do + if self.Jobs[i][2]==name then + table.remove(self.Jobs,i) + end + end +end +function multi:FreeMainEvent() + self.func={} +end +function multi:connectFinal(func) + if self.Type=='event' then + self:OnEvent(func) + elseif self.Type=='alarm' then + self:OnRing(func) + elseif self.Type=='step' or self.Type=='tstep' then + self:OnEnd(func) + else + print("Warning!!! "..self.Type.." doesn't contain a Final Connection State! Use "..self.Type..":Break(function) to trigger it's final event!") + self:OnBreak(func) + end +end +multi.ConnectFinal=multi.connectFinal +function multi:Break() + self:Pause() + self.Active=nil + for i=1,#self.ender do + if self.ender[i] then + self.ender[i](self) + end + end +end +function multi:OnBreak(func) + table.insert(self.ender,func) +end +function multi:isPaused() + return not(self.Active) +end +multi.IsPaused=multi.isPaused +function multi:isActive() + return self.Active +end +multi.IsActive=multi.isActive +function multi:getType() + return self.Type +end +multi.GetType=multi.getType +function multi:Sleep(n) + self:hold(n) +end +multi.sleep=multi.Sleep +-- Advance Timer stuff +function multi:SetTime(n) + if not n then n=3 end + local c=multi:newBase() + c.Type='timemaster' + c.timer=multi:newTimer() + c.timer:Start() + c.set=n + c.link=self + self._timer=c.timer + function c:Act() + if self.timer:Get()>=self.set then + self.link:Pause() + for i=1,#self.link.funcTM do + self.link.funcTM[i](self.link) + end + self:Destroy() + end + end + return c +end +multi.ResetTime=multi.SetTime +function multi:ResolveTimer(...) + self._timer:Pause() + for i=1,#self.funcTMR do + self.funcTMR[i](self,...) + end + self:Pause() +end +function multi:OnTimedOut(func) + self.funcTM[#self.funcTM+1]=func +end +function multi:OnTimerResolved(func) + self.funcTMR[#self.funcTMR+1]=func +end +-- Timer stuff done +function multi:Pause() + if self.Type=='mainprocess' then + print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()") + else + self.Active=false + if self.Parent.Mainloop[self.Id]~=nil then + table.remove(self.Parent.Mainloop,self.Id) + table.insert(self.Parent.Paused,self) + self.PId=#self.Parent.Paused + end + end +end +function multi:Resume() + if self.Type=='process' or self.Type=='mainprocess' then + self.Active=true + local c=self:getChildren() + for i=1,#c do + c[i]:Resume() + end + else + if self:isPaused() then + table.remove(self.Parent.Paused,self.PId) + table.insert(self.Parent.Mainloop,self) + self.Id=#self.Parent.Mainloop + self.Active=true + end + end +end +function multi:resurrect() + table.insert(self.Parent.Mainloop,self) + self.Active=true +end +multi.Resurrect=multi.resurrect +function multi:Destroy() + if self.Type=='process' or self.Type=='mainprocess' then + local c=self:getChildren() + for i=1,#c do + self.OnObjectDestroyed:Fire(c[i]) + c[i]:Destroy() + end + else + for i=1,#self.Parent.Mainloop do + if self.Parent.Mainloop[i]==self then + self.Parent.OnObjectDestroyed:Fire(self) + table.remove(self.Parent.Mainloop,i) + break + end + end + self.Active=false + end +end + +function multi:hold(task) + self:Pause() + self.held=true + if type(task)=='number' then + local timer=multi:newTimer() + timer:Start() + while timer:Get()0 then +--~ for i=1,#self.Parent.FC do +--~ self.Parent.FC[i]:Fire(...) +--~ end +--~ end + if self.Parent.protect then + local t=pcall(self.func,...) + if t then + return t + end + else + return self.func(...) + end + end, + Remove=function(self) + for i=1,#self.Link do + if self.Link[i][2]~=nil then + if self.Link[i][2]==self.ID then + table.remove(self.Link,i) + self.remove=function() end + self.Link=nil + self.ID=nil + return true + end + end + end + end, + } + temp.Destroy=temp.Remove + if name then + self.connections[name]=temp + end + return temp + end + c.Connect=c.connect + function c:tofile(path) + local m=bin.new() + m:addBlock(self.Type) + m:addBlock(self.func) + m:tofile(path) + end + return c +end +multi.OnObjectCreated=multi:newConnection() +multi.OnObjectDestroyed=multi:newConnection() +function multi:newJob(func,name) + if not(self.Type=='mainprocess' or self.Type=='process') then error('Can only create an object on multi or an interface obj') return false end + local c = {} + if self.Type=='process' then + setmetatable(c, self.Parent) + else + setmetatable(c, self) + end + c.Active=true + c.func={} + c.Id=0 + c.PId=0 + c.Parent=self + c.Type='job' + c.trigfunc=func or function() end + function c:Act() + self:trigfunc(self) + end + table.insert(self.Jobs,{c,name}) + if self.JobRunner==nil then + self.JobRunner=self:newAlarm(self.jobUS) + self.JobRunner:OnRing(function(self) + if #self.Parent.Jobs>0 then + if self.Parent.Jobs[1] then + self.Parent.Jobs[1][1]:Act() + table.remove(self.Parent.Jobs,1) + end + end + self:Reset(self.Parent.jobUS) + end) + end +end +function multi:newRange() + local selflink=self + local temp={ + getN = function(self) selflink:Do_Order() self.n=self.n+self.c if self.n>self.b then self.Link.held=false self.Link:Resume() return nil end return self.n end, + } + setmetatable(temp,{ + __call=function(self,a,b,c) + self.c=c or 1 + self.n=a-self.c + self.a=a + self.b=b + self.Link=selflink--.Parent.Mainloop[selflink.CID] or + self.Link:Pause() + self.Link.held=true + return function() return self:getN() end + end + }) + self:create(temp) + return temp +end +multi.NewRange=multi.newRange +function multi:newCondition(func) + local c={['condition']=func,Type="condition"} + self:create(c) + return c +end +multi.NewCondition=multi.newCondition +function multi:mainloop() + if not multi.isRunning then + multi.isRunning=true + for i=1,#self.Tasks do + self.Tasks[i](self) + end + rawset(self,'Start',self.clock()) + while self.Active do + self:Do_Order() + end + else + return "Already Running!" + end +end +function multi:protectedMainloop() + multi:protect() + if not multi.isRunning then + multi.isRunning=true + for i=1,#self.Tasks do + self.Tasks[i](self) + end + rawset(self,'Start',self.clock()) + while self.Active do + self:Do_Order() + end + else + return "Already Running!" + end +end +function multi:unprotectedMainloop() + multi:unProtect() + if not multi.isRunning then + multi.isRunning=true + for i=1,#self.Tasks do + self.Tasks[i](self) + end + rawset(self,'Start',self.clock()) + while self.Active do + local Loop=self.Mainloop + _G.ID=0 + for _D=#Loop,1,-1 do + if Loop[_D] then + if Loop[_D].Active then + Loop[_D].Id=_D + self.CID=_D + Loop[_D]:Act() + end + end + end + end + else + return "Already Running!" + end +end +function multi:prioritizedMainloop1() + multi:enablePriority() + if not multi.isRunning then + multi.isRunning=true + for i=1,#self.Tasks do + self.Tasks[i](self) + end + rawset(self,'Start',self.clock()) + while self.Active do + local Loop=self.Mainloop + _G.ID=0 + local PS=self + for _D=#Loop,1,-1 do + if Loop[_D] then + if (PS.PList[PS.PStep])%Loop[_D].Priority==0 then + if Loop[_D].Active then + Loop[_D].Id=_D + self.CID=_D + Loop[_D]:Act() + end + end + end + end + PS.PStep=PS.PStep+1 + if PS.PStep>7 then + PS.PStep=1 + end + end + else + return "Already Running!" + end +end +function multi:prioritizedMainloop2() + multi:enablePriority2() + if not multi.isRunning then + multi.isRunning=true + for i=1,#self.Tasks do + self.Tasks[i](self) + end + rawset(self,'Start',self.clock()) + while self.Active do + local Loop=self.Mainloop + _G.ID=0 + local PS=self + for _D=#Loop,1,-1 do + if Loop[_D] then + if (PS.PStep)%Loop[_D].Priority==0 then + if Loop[_D].Active then + Loop[_D].Id=_D + self.CID=_D + Loop[_D]:Act() + end + end + end + end + PS.PStep=PS.PStep+1 + if PS.PStep>self.Priority_Idle then + PS.PStep=1 + end + end + else + return "Already Running!" + end +end +function multi._tFunc(self,dt) + for i=1,#self.Tasks do + self.Tasks[i](self) + end + if dt then + self.pump=true + end + self.pumpvar=dt + rawset(self,'Start',self.clock()) +end +function multi:uManager(dt) + if self.Active then + self:oneTime(self._tFunc,self,dt) + function self:uManager(dt) + self:Do_Order() + end + self:Do_Order() + end +end +--Core Actors +function multi:newCustomObject(objRef,t) + local c={} + if t=='process' then + c=self:newBase() + if type(objRef)=='table' then + table.merge(c,objRef) + end + if not c.Act then + function c:Act() + -- Empty function + end + end + else + c=objRef or {} + end + if not c.Type then + c.Type='coustomObject' + end + self:create(c) + return c +end +function multi:newEvent(task) + local c=self:newBase() + c.Type='event' + c.Task=task or function() end + function c:Act() + if self.Task(self) then + self:Pause() + for _E=1,#self.func do + self.func[_E](self) + end + end + end + function c:SetTask(func) + self.Task=func + end + function c:OnEvent(func) + table.insert(self.func,func) + end + self:create(c) + return c +end +function multi:newUpdater(skip) + local c=self:newBase() + c.Type='updater' + c.pos=1 + c.skip=skip or 1 + function c:Act() + if self.pos>=self.skip then + self.pos=0 + for i=1,#self.func do + self.func[i](self) + end + end + self.pos=self.pos+1 + end + function c:setSkip(n) + self.skip=n + end + c.OnUpdate=self.OnMainConnect + self:create(c) + return c +end +function multi:newAlarm(set) + local c=self:newBase() + c.Type='alarm' + c.Priority=self.Priority_Low + c.timer=self:newTimer() + c.set=set or 0 + function c:Act() + if self.timer:Get()>=self.set then + self:Pause() + self.Active=false + for i=1,#self.func do + self.func[i](self) + end + end + end + function c:Resume() + self.Parent.Resume(self) + self.timer:Resume() + end + function c:Reset(n) + if n then self.set=n end + self:Resume() + self.timer:Reset() + end + function c:OnRing(func) + table.insert(self.func,func) + end + function c:Pause() + self.timer:Pause() + self.Parent.Pause(self) + end + self:create(c) + return c +end +function multi:newLoop(func) + local c=self:newBase() + c.Type='loop' + c.Start=self.clock() + if func then + c.func={func} + end + function c:Act() + for i=1,#self.func do + self.func[i](self,self.Parent.clock()-self.Start) + end + end + function c:OnLoop(func) + table.insert(self.func,func) + end + self:create(c) + return c +end +function multi:newFunction(func) + local c={} + c.func=func + mt={ + __index=multi, + __call=function(self,...) if self.Active then return self:func(...) end local t={...} return "PAUSED" end + } + c.Parent=self + function c:Pause() + self.Active=false + end + function c:Resume() + self.Active=true + end + setmetatable(c,mt) + self:create(c) + return c +end +function multi:newStep(start,reset,count,skip) + local c=self:newBase() + think=1 + c.Type='step' + c.pos=start or 1 + c.endAt=reset or math.huge + c.skip=skip or 0 + c.spos=0 + c.count=count or 1*think + c.funcE={} + c.funcS={} + c.start=start or 1 + if start~=nil and reset~=nil then + if start>reset then + think=-1 + end + end + function c:Act() + if self~=nil then + if self.spos==0 then + if self.pos==self.start then + for fe=1,#self.funcS do + self.funcS[fe](self) + end + end + for i=1,#self.func do + self.func[i](self,self.pos) + end + self.pos=self.pos+self.count + if self.pos-self.count==self.endAt then + self:Pause() + for fe=1,#self.funcE do + self.funcE[fe](self) + end + self.pos=self.start + end + end + end + self.spos=self.spos+1 + if self.spos>=self.skip then + self.spos=0 + end + end + c.Reset=c.Resume + function c:OnStart(func) + table.insert(self.funcS,func) + end + function c:OnStep(func) + table.insert(self.func,1,func) + end + function c:OnEnd(func) + table.insert(self.funcE,func) + end + function c:Break() + self.Active=nil + end + function c:Update(start,reset,count,skip) + self.start=start or self.start + self.endAt=reset or self.endAt + self.skip=skip or self.skip + self.count=count or self.count + self:Resume() + end + self:create(c) + return c +end +function multi:newTask(func) + table.insert(self.Tasks,func) +end +function multi:newTLoop(func,set) + local c=self:newBase() + c.Type='tloop' + c.set=set or 0 + c.timer=self:newTimer() + c.life=0 + if func then + c.func={func} + end + function c:Act() + if self.timer:Get()>=self.set then + self.life=self.life+1 + for i=1,#self.func do + self.func[i](self,self.life) + end + self.timer:Reset() + end + end + function c:Resume() + self.Parent.Resume(self) + self.timer:Resume() + end + function c:Pause() + self.timer:Pause() + self.Parent.Pause(self) + end + function c:OnLoop(func) + table.insert(self.func,func) + end + self:create(c) + return c +end +function multi:newTrigger(func) + local c={} + c.Type='trigger' + c.trigfunc=func or function() end + function c:Fire(...) + self:trigfunc(...) + end + self:create(c) + return c +end +function multi:newTStep(start,reset,count,set) + local c=self:newBase() + think=1 + c.Type='tstep' + c.Priority=self.Priority_Low + c.start=start or 1 + local reset = reset or math.huge + c.endAt=reset + c.pos=start or 1 + c.skip=skip or 0 + c.count=count or 1*think + c.funcE={} + c.timer=self.clock() + c.set=set or 1 + c.funcS={} + function c:Update(start,reset,count,set) + self.start=start or self.start + self.pos=self.start + self.endAt=reset or self.endAt + self.set=set or self.set + self.count=count or self.count or 1 + self.timer=self.clock() + self:Resume() + end + function c:Act() + if self.clock()-self.timer>=self.set then + self:Reset() + if self.pos==self.start then + for fe=1,#self.funcS do + self.funcS[fe](self) + end + end + for i=1,#self.func do + self.func[i](self,self.pos) + end + self.pos=self.pos+self.count + if self.pos-self.count==self.endAt then + self:Pause() + for fe=1,#self.funcE do + self.funcE[fe](self) + end + self.pos=self.start + end + end + end + function c:OnStart(func) + table.insert(self.funcS,func) + end + function c:OnStep(func) + table.insert(self.func,func) + end + function c:OnEnd(func) + table.insert(self.funcE,func) + end + function c:Break() + self.Active=nil + end + function c:Reset(n) + if n then self.set=n end + self.timer=self.clock() + self:Resume() + end + self:create(c) + return c +end +function multi:newWatcher(namespace,name) + local function WatcherObj(ns,n) + if self.Type=='queue' then + print("Cannot create a watcher on a queue! Creating on 'multi' instead!") + self=multi + end + local c=self:newBase() + c.Type='watcher' + c.ns=ns + c.n=n + c.cv=ns[n] + function c:OnValueChanged(func) + table.insert(self.func,func) + end + function c:Act() + if self.cv~=self.ns[self.n] then + for i=1,#self.func do + self.func[i](self,self.cv,self.ns[self.n]) + end + self.cv=self.ns[self.n] + end + end + self:create(c) + return c + end + if type(namespace)~='table' and type(namespace)=='string' then + return WatcherObj(_G,namespace) + elseif type(namespace)=='table' and (type(name)=='string' or 'number') then + return WatcherObj(namespace,name) + else + print('Warning, invalid arguments! Nothing returned!') + end +end +-- Threading stuff +thread={} +multi.GlobalVariables={} +if os.getOS()=="windows" then + thread.__CORES=tonumber(os.getenv("NUMBER_OF_PROCESSORS")) +else + thread.__CORES=tonumber(io.popen("nproc --all"):read("*n")) +end +function thread.sleep(n) + coroutine.yield({"_sleep_",n or 0}) +end +function thread.hold(n) + coroutine.yield({"_hold_",n or function() return true end}) +end +function thread.skip(n) + coroutine.yield({"_skip_",n or 0}) +end +function thread.kill() + coroutine.yield({"_kill_",":)"}) +end +function thread.yeild() + coroutine.yield({"_sleep_",0}) +end +function thread.getCores() + return thread.__CORES +end +function thread.set(name,val) + multi.GlobalVariables[name]=val + return true +end +function thread.get(name) + return multi.GlobalVariables[name] +end +function thread.waitFor(name) + thread.hold(function() return thread.get(name)~=nil end) + return thread.get(name) +end +function thread.testFor(name,val,sym) + thread.hold(function() return thread.get(name)~=nil end) + return thread.get(name) +end +function multi:newTBase(name) + local c = {} + c.name=name + c.Active=true + c.func={} + c.ender={} + c.Id=0 + c.PId=0 + c.Parent=self + c.important={} + c.held=false + c.ToString=multi.ToString + c.ToFile=multi.ToFile + return c +end +function multi:newThread(name,func) + local c={} + c.ref={} + c.Name=name + c.thread=coroutine.create(func) + c.sleep=1 + c.Type="thread" + c.firstRunDone=false + c.timer=multi.scheduler:newTimer() + c.ref.Globals=self:linkDomain("Globals") + function c.ref:send(name,val) + ret=coroutine.yield({Name=name,Value=val}) + self:syncGlobals(ret) + end + function c.ref:get(name) + return self.Globals[name] + end + function c.ref:kill() + err=coroutine.yield({"_kill_"}) + if err then + error("Failed to kill a thread! Exiting...") + end + end + function c.ref:sleep(n) + if type(n)=="function" then + ret=coroutine.yield({"_hold_",n}) + self:syncGlobals(ret) + elseif type(n)=="number" then + n = tonumber(n) or 0 + ret=coroutine.yield({"_sleep_",n}) + self:syncGlobals(ret) + else + error("Invalid Type for sleep!") + end + end + function c.ref:syncGlobals(v) + self.Globals=v + end + table.insert(self:linkDomain("Threads"),c) + if not multi.scheduler:isActive() then + multi.scheduler:Resume() + end +end +multi:setDomainName("Threads") +multi:setDomainName("Globals") +multi.scheduler=multi:newLoop() +multi.scheduler.Type="scheduler" +function multi.scheduler:setStep(n) + self.skip=tonumber(n) or 24 +end +multi.scheduler.skip=0 +multi.scheduler.counter=0 +multi.scheduler.Threads=multi:linkDomain("Threads") +multi.scheduler.Globals=multi:linkDomain("Globals") +multi.scheduler:OnLoop(function(self) + self.counter=self.counter+1 + for i=#self.Threads,1,-1 do + ret={} + if coroutine.status(self.Threads[i].thread)=="dead" then + table.remove(self.Threads,i) + else + if self.Threads[i].timer:Get()>=self.Threads[i].sleep then + if self.Threads[i].firstRunDone==false then + self.Threads[i].firstRunDone=true + self.Threads[i].timer:Start() + _,ret=coroutine.resume(self.Threads[i].thread,self.Threads[i].ref) + else + _,ret=coroutine.resume(self.Threads[i].thread,self.Globals) + end + if _==false then + self.Parent.OnError:Fire(self.Threads[i],ret) + print("Error in thread: <"..self.Threads[i].Name.."> "..ret) + end + if ret==true or ret==false then + print("Thread Ended!!!") + ret={} + end + end + if ret then + if ret[1]=="_kill_" then + table.remove(self.Threads,i) + elseif ret[1]=="_sleep_" then + self.Threads[i].timer:Reset() + self.Threads[i].sleep=ret[2] + elseif ret[1]=="_skip_" then + self.Threads[i].timer:Reset() + self.Threads[i].sleep=math.huge + local event=multi:newEvent(function(evnt) return multi.scheduler.counter>=evnt.counter end) + event.link=self.Threads[i] + event.counter=self.counter+ret[2] + event:OnEvent(function(evnt) + evnt.link.sleep=0 + end) + elseif ret[1]=="_hold_" then + self.Threads[i].timer:Reset() + self.Threads[i].sleep=math.huge + local event=multi:newEvent(ret[2]) + event.link=self.Threads[i] + event:OnEvent(function(evnt) + evnt.link.sleep=0 + end) + elseif ret.Name then + self.Globals[ret.Name]=ret.Value + end + end + end + end +end) +multi.scheduler:Pause() +multi.OnError=multi:newConnection() +function multi:newThreadedAlarm(name,set) + local c=self:newTBase(name) + c.Type='alarmThread' + c.timer=self:newTimer() + c.set=set or 0 + function c:Resume() + self.rest=false + self.timer:Resume() + end + function c:Reset(n) + if n then self.set=n end + self.rest=false + self.timer:Reset(n) + end + function c:OnRing(func) + table.insert(self.func,func) + end + function c:Pause() + self.timer:Pause() + self.rest=true + end + c.rest=false + c.updaterate=multi.Priority_Low -- skips + c.restRate=0 -- secs + multi:newThread(name,function(ref) + while true do + if c.rest then + thread.sleep(c.restRate) -- rest a bit more when a thread is paused + else + if c.timer:Get()>=c.set then + c:Pause() + for i=1,#c.func do + c.func[i](c) + end + end + thread.skip(c.updaterate) -- lets rest a bit + end + end + end) + self:create(c) + return c +end +function multi:newThreadedUpdater(name,skip) + local c=self:newTBase(name) + c.Type='updaterThread' + c.pos=1 + c.skip=skip or 1 + function c:Resume() + self.rest=false + end + function c:Pause() + self.rest=true + end + c.OnUpdate=self.OnMainConnect + c.rest=false + c.updaterate=0 + c.restRate=.75 + multi:newThread(name,function(ref) + while true do + if c.rest then + thread.sleep(c.restRate) -- rest a bit more when a thread is paused + else + for i=1,#c.func do + c.func[i](c) + end + c.pos=c.pos+1 + thread.skip(c.skip) + end + end + end) + self:create(c) + return c +end +function multi:newThreadedTStep(name,start,reset,count,set) + local c=self:newTBase(name) + local think=1 + c.Type='tstepThread' + c.start=start or 1 + local reset = reset or math.huge + c.endAt=reset + c.pos=start or 1 + c.skip=skip or 0 + c.count=count or 1*think + c.funcE={} + c.timer=os.clock() + c.set=set or 1 + c.funcS={} + function c:Update(start,reset,count,set) + self.start=start or self.start + self.pos=self.start + self.endAt=reset or self.endAt + self.set=set or self.set + self.count=count or self.count or 1 + self.timer=os.clock() + self:Resume() + end + function c:Resume() + self.rest=false + end + function c:Pause() + self.rest=true + end + function c:OnStart(func) + table.insert(self.funcS,func) + end + function c:OnStep(func) + table.insert(self.func,func) + end + function c:OnEnd(func) + table.insert(self.funcE,func) + end + function c:Break() + self.Active=nil + end + function c:Reset(n) + if n then self.set=n end + self.timer=os.clock() + self:Resume() + end + c.updaterate=0--multi.Priority_Low -- skips + c.restRate=0 + multi:newThread(name,function(ref) + while true do + if c.rest then + thread.sleep(c.restRate) -- rest a bit more when a thread is paused + else + if os.clock()-c.timer>=c.set then + c:Reset() + if c.pos==c.start then + for fe=1,#c.funcS do + c.funcS[fe](c) + end + end + for i=1,#c.func do + c.func[i](c,c.pos) + end + c.pos=c.pos+c.count + if c.pos-c.count==c.endAt then + c:Pause() + for fe=1,#c.funcE do + c.funcE[fe](c) + end + c.pos=c.start + end + end + thread.skip(c.updaterate) -- lets rest a bit + end + end + end) + self:create(c) + return c +end +function multi:newThreadedTLoop(name,func,n) + local c=self:newTBase(name) + c.Type='tloopThread' + c.restN=n or 1 + if func then + c.func={func} + end + function c:Resume() + self.rest=false + end + function c:Pause() + self.rest=true + end + function c:OnLoop(func) + table.insert(self.func,func) + end + c.rest=false + c.updaterate=0 + c.restRate=.75 + multi:newThread(name,function(ref) + while true do + if c.rest then + thread.sleep(c.restRate) -- rest a bit more when a thread is paused + else + for i=1,#c.func do + c.func[i](c) + end + thread.sleep(c.restN) -- lets rest a bit + end + end + end) + self:create(c) + return c +end +function multi:newThreadedStep(name,start,reset,count,skip) + local c=self:newTBase(name) + local think=1 + c.Type='stepThread' + c.pos=start or 1 + c.endAt=reset or math.huge + c.skip=skip or 0 + c.spos=0 + c.count=count or 1*think + c.funcE={} + c.funcS={} + c.start=start or 1 + if start~=nil and reset~=nil then + if start>reset then + think=-1 + end + end + function c:Resume() + self.rest=false + end + function c:Pause() + self.rest=true + end + c.Reset=c.Resume + function c:OnStart(func) + table.insert(self.funcS,func) + end + function c:OnStep(func) + table.insert(self.func,1,func) + end + function c:OnEnd(func) + table.insert(self.funcE,func) + end + function c:Break() + self.rest=true + end + function c:Update(start,reset,count,skip) + self.start=start or self.start + self.endAt=reset or self.endAt + self.skip=skip or self.skip + self.count=count or self.count + self:Resume() + end + c.updaterate=0 + c.restRate=.1 + multi:newThread(name,function(ref) + while true do + if c.rest then + ref:sleep(c.restRate) -- rest a bit more when a thread is paused + else + if c~=nil then + if c.spos==0 then + if c.pos==c.start then + for fe=1,#c.funcS do + c.funcS[fe](c) + end + end + for i=1,#c.func do + c.func[i](c,c.pos) + end + c.pos=c.pos+c.count + if c.pos-c.count==c.endAt then + c:Pause() + for fe=1,#c.funcE do + c.funcE[fe](c) + end + c.pos=c.start + end + end + end + c.spos=c.spos+1 + if c.spos>=c.skip then + c.spos=0 + end + ref:sleep(c.updaterate) -- lets rest a bit + end + end + end) + self:create(c) + return c +end +function multi:newThreadedProcess(name) + local c = {} + setmetatable(c, multi) + function c:newBase(ins) + local ct = {} + setmetatable(ct, self.Parent) + ct.Active=true + ct.func={} + ct.ender={} + ct.Id=0 + ct.PId=0 + ct.Act=function() end + ct.Parent=self + ct.held=false + ct.ref=self.ref + table.insert(self.Mainloop,ct) + return ct + end + c.Parent=self + c.Active=true + c.func={} + c.Id=0 + c.Type='process' + c.Mainloop={} + c.Tasks={} + c.Tasks2={} + c.Garbage={} + c.Children={} + c.Paused={} + c.Active=true + c.Id=-1 + c.Rest=0 + c.updaterate=.01 + c.restRate=.1 + c.Jobs={} + c.queue={} + c.jobUS=2 + c.rest=false + function c:getController() + return nil + end + function c:Start() + self.rest=false + end + function c:Resume() + self.rest=false + end + function c:Pause() + self.rest=true + end + function c:Remove() + self.ref:kill() + end + function c:kill() + err=coroutine.yield({"_kill_"}) + if err then + error("Failed to kill a thread! Exiting...") + end + end + function c:sleep(n) + if type(n)=="function" then + ret=coroutine.yield({"_hold_",n}) + elseif type(n)=="number" then + n = tonumber(n) or 0 + ret=coroutine.yield({"_sleep_",n}) + else + error("Invalid Type for sleep!") + end + end + c.hold=c.sleep + multi:newThread(name,function(ref) + while true do + if c.rest then + ref:Sleep(c.restRate) -- rest a bit more when a thread is paused + else + c:uManager() + ref:sleep(c.updaterate) -- lets rest a bit + end + end + end) + return c +end +function multi:newThreadedLoop(name,func) + local c=self:newTBase(name) + c.Type='loopThread' + c.Start=os.clock() + if func then + c.func={func} + end + function c:Resume() + self.rest=false + end + function c:Pause() + self.rest=true + end + function c:OnLoop(func) + table.insert(self.func,func) + end + c.rest=false + c.updaterate=0 + c.restRate=.75 + multi:newThread(name,function(ref) + while true do + if c.rest then + thread.sleep(c.restRate) -- rest a bit more when a thread is paused + else + for i=1,#c.func do + c.func[i](os.clock()-self.Start,c) + end + thread.sleep(c.updaterate) -- lets rest a bit + end + end + end) + self:create(c) + return c +end +function multi:newThreadedEvent(name,task) + local c=self:newTBase(name) + c.Type='eventThread' + c.Task=task or function() end + function c:OnEvent(func) + table.insert(self.func,func) + end + function c:Resume() + self.rest=false + end + function c:Pause() + self.rest=true + end + c.rest=false + c.updaterate=0 + c.restRate=1 + multi:newThread(name,function(ref) + while true do + if c.rest then + ref:sleep(c.restRate) -- rest a bit more when a thread is paused + else + if c.Task(self) then + for _E=1,#c.func do + c.func[_E](c) + end + c:Pause() + end + ref:sleep(c.updaterate) -- lets rest a bit + end + end + end) + self:create(c) + return c +end +-- State Saving Stuff +function multi:IngoreObject() + self.Ingore=true +end +multi.scheduler:IngoreObject() +function multi:ToString() + if self.Ingore then return end + local t=self.Type + local data; + print(t) + if t:sub(-6)=="Thread" then + data={ + Type=t, + rest=self.rest, + updaterate=self.updaterest, + restrate=self.restrate, + name=self.name, + func=self.func, + important=self.important, + Active=self.Active, + ender=self.ender, + -- IDK if these need to be present... + -- Id=self.Id, + -- PId=self.PId, + held=self.held, + } + else + data={ + Type=t, + func=self.func, + funcTM=self.funcTM, + funcTMR=self.funcTMR, + important=self.important, + ender=self.ender, + -- IDK if these need to be present... + -- Id=self.Id, + -- PId=self.PId, + held=self.held, + } + end + if t=="eventThread" or t=="event" then + table.merge(data,{ + Task=self.Task, + }) + elseif t=="loopThread" or t=="loop" then + table.merge(data,{ + Start=self.Start, + }) + elseif t=="stepThread" or t=="step" then + table.merge(data,{ + funcE=self.funcE, + funcS=self.funcS, + pos=self.pos, + endAt=self.endAt, + start=self.start, + spos=self.spos, + skip=self.skip, + count=self.count, + }) + elseif t=="tloopThread" then + table.merge(data,{ + restN=self.restN, + }) + elseif t=="tloop" then + table.merge(data,{ + set=self.set, + life=self.life, + }) + elseif t=="tstepThread" or t=="tstep" then + table.merge(data,{ + funcE=self.funcE, + funcS=self.funcS, + pos=self.pos, + endAt=self.endAt, + start=self.start, + spos=self.spos, + skip=self.skip, + count=self.count, + timer=self.timer, + set=self.set, + reset=self.reset, + }) + elseif t=="updaterThread" or t=="updater" then + table.merge(data,{ + pos=self.pos, + skip=self.skip, + }) + elseif t=="alarmThread" or t=="alarm" then + table.merge(data,{ + set=self.set, + }) + elseif t=="watcher" then + print("Currently cannot sterilize a watcher object!") + -- needs testing + -- table.merge(data,{ + -- ns=self.ns, + -- n=self.n, + -- cv=self.cv, + -- }) + elseif t=="timemaster" then + -- Weird stuff is going on here! + -- Need to do some testing + table.merge(data,{ + timer=self.timer, + _timer=self._timer, + set=self.set, + link=self.link, + }) + elseif t=="process" or t=="mainprocess" then + local loop=self.Mainloop + local dat={} + for i=1,#loop do + local ins=loop[i]:ToString() + if ins~=nil then + table.insert(dat,ins) + end + end + local str=bin.new() + str:addBlock({Type=t}) + str:addBlock(#dat,4,"n") + for i=1,#dat do + str:addBlock(#dat[i],4,"n") + str:addBlock(dat[i]) + end + return str.data + end + for i,v in pairs(self.important) do + data[v]=self[v] + end + local str=bin.new() + str:addBlock(data) + return str.data +end +function multi:newFromString(str) + if type(str)=="table" then + if str.Type=="bin" then + str=str.data + end + end + local handle=bin.new(str) + local data=handle:getBlock("t") + local t=data.Type + if t=="mainprocess" then + local objs=handle:getBlock("n",4) + for i=1,objs do + self:newFromString(handle:getBlock("s",(handle:getBlock("n",4)))) + end + return self + elseif t=="process" then + local temp=multi:newProcess() + local objs=handle:getBlock("n",4) + for i=1,objs do + temp:newFromString(handle:getBlock("s",(handle:getBlock("n",4)))) + end + return temp + elseif t=="step" then -- GOOD + local item=self:newStep() + table.merge(item,data) + return item + elseif t=="tstep" then -- GOOD + local item=self:newTStep() + table.merge(item,data) + return item + elseif t=="tloop" then -- GOOD + local item=self:newTLoop() + table.merge(item,data) + return item + elseif t=="event" then -- GOOD + local item=self:newEvent(data.task) + table.merge(item,data) + return item + elseif t=="alarm" then -- GOOD + local item=self:newAlarm() + table.merge(item,data) + return item + elseif t=="watcher" then -- NEEDS TESTING + local item=self:newWatcher() + table.merge(item,data) + return item + elseif t=="updater" then -- GOOD + local item=self:newUpdater() + table.merge(item,data) + return item + elseif t=="loop" then -- GOOD + local item=self:newLoop() + table.merge(item,data) + return item + elseif t=="eventThread" then -- GOOD + local item=self:newThreadedEvent(data.name) + table.merge(item,data) + return item + elseif t=="loopThread" then -- GOOD + local item=self:newThreadedLoop(data.name) + table.merge(item,data) + return item + elseif t=="stepThread" then -- GOOD + local item=self:newThreadedStep(data.name) + table.merge(item,data) + return item + elseif t=="tloopThread" then -- GOOD + local item=self:newThreadedTLoop(data.name,nil,data.restN) + table.merge(item,data) + return item + elseif t=="tstepThread" then -- GOOD + local item=self:newThreadedTStep(data.name) + table.merge(item,data) + return item + elseif t=="updaterThread" then -- GOOD + local item=self:newThreadedUpdater(data.name) + table.merge(item,data) + return item + elseif t=="alarmThread" then -- GOOD + local item=self:newThreadedAlarm(data.name) + table.merge(item,data) + return item + end +end +function multi:Important(varname) + table.insert(important,varname) +end +function multi:ToFile(path) + bin.new(self:ToString()):tofile(path) +end +function multi:fromFile(path) + self:newFromString(bin.load(path)) +end +function multi:SetStateFlag(opt) + -- +end +function multi:quickStateSave(b) + -- +end +function multi:saveState(path,opt) + -- +end +function multi:loadState(path) + -- +end +function multi:setDefualtStateFlag(opt) + -- +end diff --git a/game/multi/integration/lanesManager.lua b/game/multi/integration/lanesManager.lua new file mode 100644 index 0000000..7b66bad --- /dev/null +++ b/game/multi/integration/lanesManager.lua @@ -0,0 +1,144 @@ +--[[ +MIT License + +Copyright (c) 2017 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +package.path="?/init.lua;?.lua;"..package.path +function os.getOS() + if package.config:sub(1,1)=='\\' then + return 'windows' + else + return 'unix' + end +end +-- Step 1 get lanes +lanes=require("lanes").configure() +--~ package.path="lua/?/init.lua;lua/?.lua;"..package.path +require("multi") -- get it all and have it on all lanes +function multi:canSystemThread() + return true +end +function multi:getPlatform() + return "lanes" +end +local multi=multi +-- Step 2 set up the linda objects +local __GlobalLinda = lanes.linda() -- handles global stuff +local __SleepingLinda = lanes.linda() -- handles sleeping stuff +-- For convience a GLOBAL table will be constructed to handle requests +local GLOBAL={} +setmetatable(GLOBAL,{ + __index=function(t,k) + return __GlobalLinda:get(k) + end, + __newindex=function(t,k,v) + __GlobalLinda:set(k,v) + end, +}) +-- Step 3 rewrite the thread methods to use lindas +local THREAD={} +function THREAD.set(name,val) + __GlobalLinda:set(name,val) +end +function THREAD.get(name) + __GlobalLinda:get(name) +end +local function randomString(n) + local str = '' + local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'} + for i=1,n do + str = str..''..strings[math.random(1,#strings)] + end + return str +end +function THREAD.waitFor(name) + local function wait() + math.randomseed(os.time()) + __SleepingLinda:receive(.001,randomString(12)) + end + repeat wait() until __GlobalLinda:get(name) + return __GlobalLinda:get(name) +end +function THREAD.testFor(name,val,sym) + -- +end +function THREAD.getCores() + return THREAD.__CORES +end +if os.getOS()=="windows" then + THREAD.__CORES=tonumber(os.getenv("NUMBER_OF_PROCESSORS")) +else + THREAD.__CORES=tonumber(io.popen("nproc --all"):read("*n")) +end +function THREAD.kill() -- trigger the lane destruction + -- coroutine.yield({"_kill_",":)"}) +end +function THREAD.getName() + return THREAD_NAME +end +--[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait +Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method +however, a linda recieve will in fact be a idle wait! So we use that and wrap it in a nice package]] +function THREAD.sleep(n) + math.randomseed(os.time()) + __SleepingLinda:receive(n,randomString(12)) +end +function THREAD.hold(n) + local function wait() + math.randomseed(os.time()) + __SleepingLinda:receive(.001,randomString(12)) + end + repeat wait() until n() +end +-- Step 5 Basic Threads! +function multi:newSystemThread(name,func,...) + local c={} + local __self=c + c.name=name + c.Type="sthread" + local THREAD_NAME=name + local function func2(...) + + end + c.thread=lanes.gen("*", func)(...) + function c:kill() + --self.status:Destroy() + self.thread:cancel() + print("Thread: '"..self.name.."' has been stopped!") + end + c.status=multi:newUpdater(multi.Priority_IDLE) + c.status.link=c + c.status:OnUpdate(function(self) + local v,err,t=self.link.thread:join(.001) + if err then + multi.OnError:Fire(self.link,err) + print("Error in systemThread: '"..self.link.name.."' <"..err..">") + self:Destroy() + end + end) + return c +end +print("Integrated Lanes!") +multi.integration={} -- for module creators +multi.integration.GLOBAL=GLOBAL +multi.integration.THREAD=THREAD +require("multi.integration.shared") +return {init=function() return GLOBAL,THREAD end} diff --git a/game/multi/integration/loveManager.lua b/game/multi/integration/loveManager.lua new file mode 100644 index 0000000..0e57633 --- /dev/null +++ b/game/multi/integration/loveManager.lua @@ -0,0 +1,365 @@ +require("multi.compat.love2d") +function multi:canSystemThread() + return true +end +function multi:getPlatform() + return "love2d" +end +multi.integration={} +multi.integration.love2d={} +multi.integration.love2d.ThreadBase=[[ +tab={...} +__THREADID__=table.remove(1,tab) +__THREADNAME__=table.remove(1,tab) +require("love.filesystem") +require("love.system") +require("love.timer") +require("multi") +GLOBAL={} +setmetatable(GLOBAL,{ + __index=function(t,k) + __sync__() + return __proxy__[k] + end, + __newindex=function(t,k,v) + __sync__() + __proxy__[k]=v + if type(v)=="userdata" then + __MainChan__:push(v) + else + __MainChan__:push("SYNC "..type(v).." "..k.." "..resolveData(v)) + end + end, +}) +function __sync__() + local data=__mythread__:pop() + while data do + love.timer.sleep(.001) + if type(data)=="string" then + local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)") + if name=="__DIEPLZ"..__THREADID__.."__" then + error("Thread: "..__THREADID__.." has been stopped!") + end + if cmd=="SYNC" then + __proxy__[name]=resolveType(tp,d) + end + else + __proxy__[name]=data + end + data=__mythread__:pop() + end +end +function ToStr(val, name, skipnewlines, depth) + skipnewlines = skipnewlines or false + depth = depth or 0 + local tmp = string.rep(" ", depth) + if name then + if type(name) == "string" then + tmp = tmp .. "[\""..name.."\"] = " + else + tmp = tmp .. "["..(name or "").."] = " + end + end + if type(val) == "table" then + tmp = tmp .. "{" .. (not skipnewlines and " " or "") + for k, v in pairs(val) do + tmp = tmp .. ToStr(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and " " or "") + end + tmp = tmp .. string.rep(" ", depth) .. "}" + elseif type(val) == "number" then + tmp = tmp .. tostring(val) + elseif type(val) == "string" then + tmp = tmp .. string.format("%q", val) + elseif type(val) == "boolean" then + tmp = tmp .. (val and "true" or "false") + elseif type(val) == "function" then + tmp = tmp .. "loadDump([===["..dump(val).."]===])" + else + tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\"" + end + return tmp +end +function resolveType(tp,d) + if tp=="number" then + return tonumber(d) + elseif tp=="bool" then + return (d=="true") + elseif tp=="function" then + return loadDump("[==["..d.."]==]") + elseif tp=="table" then + return loadstring("return "..d)() + elseif tp=="nil" then + return nil + else + return d + end +end +function resolveData(v) + local data="" + if type(v)=="table" then + return ToStr(v) + elseif type(v)=="function" then + return dump(v) + elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" or type(v)=="nil" then + return tostring(v) + end + return data +end +sThread={} +local function randomString(n) + local c=os.clock() + local a=0 + while os.clock()" + c.thread=love.thread.newThread(multi.integration.love2d.ThreadBase:gsub("INSERT_USER_CODE",dump(func))) + c.thread:start(c.ID,c.name,...) + function c:kill() + multi.integration.GLOBAL["__DIEPLZ"..self.ID.."__"]="__DIEPLZ"..self.ID.."__" + end + return c +end +function love.threaderror( thread, errorstr ) + multi.OnError:Fire(thread,errorstr) + print("Error in systemThread: "..tostring(thread)..": "..errorstr) +end +local THREAD={} +function THREAD.set(name,val) + GLOBAL[name]=val +end +function THREAD.get(name) + return GLOBAL[name] +end +function THREAD.waitFor(name) + multi.OBJ_REF:Pause() + repeat multi:lManager() until GLOBAL[name] + multi.OBJ_REF:Resume() + return GLOBAL[name] +end +function THREAD.getCores() + return love.system.getProcessorCount() +end +function THREAD.sleep(n) + love.timer.sleep(n) +end +function THREAD.hold(n) + multi.OBJ_REF:Pause() + repeat multi:lManager() until n() + multi.OBJ_REF:Resume() +end +__channels__={} +multi.integration.GLOBAL=GLOBAL +multi.integration.THREAD=THREAD +updater=multi:newUpdater() +updater:OnUpdate(function(self) + local data=multi.integration.love2d.mainChannel:pop() + while data do + --print("MAIN:",data) + if type(data)=="string" then + local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)") + if cmd=="SYNC" then + __proxy__[name]=resolveType(tp,d) + for i=1,#__channels__ do + -- send data to other threads + if type(v)=="userdata" then + __channels__[i]:push(v) + else + __channels__[i]:push("SYNC "..tp.." "..name.." "..d) + end + end + elseif cmd=="NEWTHREAD" then + __channels__[#__channels__+1]=love.thread.getChannel(tp) + for k,v in pairs(__proxy__) do -- sync the global with each new thread + if type(v)=="userdata" then + __channels__[#__channels__]:push(v) + else + __channels__[#__channels__]:push("SYNC "..type(v).." "..k.." "..resolveData(v)) + end + end + end + else + __proxy__[name]=data + end + data=multi.integration.love2d.mainChannel:pop() + end +end) +require("multi.integration.shared") +print("Integrated Love2d!") +return { + init=function(t) + if t then + if t.threadNamespace then + multi.integration.THREADNAME=t.threadNamespace + multi.integration.love2d.ThreadBase:gsub("sThread",t.threadNamespace) + end + if t.globalNamespace then + multi.integration.GLOBALNAME=t.globalNamespace + multi.integration.love2d.ThreadBase:gsub("GLOBAL",t.globalNamespace) + end + end + return GLOBAL,THREAD + end +} diff --git a/game/multi/integration/luvitManager.lua b/game/multi/integration/luvitManager.lua new file mode 100644 index 0000000..04af6c9 --- /dev/null +++ b/game/multi/integration/luvitManager.lua @@ -0,0 +1,126 @@ +--[[ +MIT License + +Copyright (c) 2017 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] + +-- I DEMAND USAGE FOR LUVIT +-- Cannot use discordia without my multitasking library (Which I love more that the luvit platform... then again i'm partial :P) +package.path="?/init.lua;?.lua;"..package.path +local function _INIT(luvitThread,timer) + -- lots of this stuff should be able to stay the same + function os.getOS() + if package.config:sub(1,1)=='\\' then + return 'windows' + else + return 'unix' + end + end + -- Step 1 get setup threads on luvit... Sigh how do i even... + require("multi") + function multi:canSystemThread() + return true + end + function multi:getPlatform() + return "luvit" + end + local multi=multi + -- Step 2 set up the Global table... is this possible? + local GLOBAL={} + setmetatable(GLOBAL,{ + __index=function(t,k) + --print("No Global table when using luvit integration!") + return nil + end, + __newindex=function(t,k,v) + --print("No Global table when using luvit integration!") + end, + }) + local THREAD={} + function THREAD.set(name,val) + --print("No Global table when using luvit integration!") + end + function THREAD.get(name) + --print("No Global table when using luvit integration!") + end + local function randomString(n) + local str = '' + local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'} + for i=1,n do + str = str..''..strings[math.random(1,#strings)] + end + return str + end + function THREAD.waitFor(name) + --print("No Global table when using luvit integration!") + end + function THREAD.testFor(name,val,sym) + --print("No Global table when using luvit integration!") + end + function THREAD.getCores() + return THREAD.__CORES + end + if os.getOS()=="windows" then + THREAD.__CORES=tonumber(os.getenv("NUMBER_OF_PROCESSORS")) + else + THREAD.__CORES=tonumber(io.popen("nproc --all"):read("*n")) + end + function THREAD.kill() -- trigger the thread destruction + error("Thread was Killed!") + end + -- hmmm if im cleaver I can get this to work... but since data passing isn't going to be a thing its probably not important + function THREAD.sleep(n) + --print("No Global table when using luvit integration!") + end + function THREAD.hold(n) + --print("No Global table when using luvit integration!") + end + -- Step 5 Basic Threads! + local function entry(path,name,func,...) + local timer = require'timer' + local luvitThread = require'thread' + package.path=path + loadstring(func)(...) + end + function multi:newSystemThread(name,func,...) + local c={} + local __self=c + c.name=name + c.Type="sthread" + c.thread={} + c.func=string.dump(func) + function c:kill() + -- print("No Global table when using luvit integration!") + end + luvitThread.start(entry,package.path,name,c.func,...) + return c + end + print("Integrated Luvit!") + multi.integration={} -- for module creators + multi.integration.GLOBAL=GLOBAL + multi.integration.THREAD=THREAD + require("multi.integration.shared") + -- Start the main mainloop... This allows you to process your multi objects, but the engine on the main thread will be limited to .001 or 1 millisecond sigh... + local interval = timer.setInterval(1, function () + multi:uManager() + end) +end +return {init=function(threadHandle,timerHandle) _INIT(threadHandle,timerHandle) return GLOBAL,THREAD end} diff --git a/game/multi/integration/shared.lua b/game/multi/integration/shared.lua new file mode 100644 index 0000000..acd365a --- /dev/null +++ b/game/multi/integration/shared.lua @@ -0,0 +1,382 @@ +--[[ +MIT License + +Copyright (c) 2017 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +function multi.randomString(n) + local str = '' + local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'} + for i=1,n do + str = str..''..strings[math.random(1,#strings)] + end + return str +end +function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a channel on both ends + local c={} -- where we will store our object + c.name=name -- set the name this is important for the love2d side + if love then -- check love + if love.thread then -- make sure we can use the threading module + function c:init() -- create an init function so we can mimic on bith love2d and lanes + self.chan=love.thread.getChannel(self.name) -- create channel by the name self.name + function self:push(v) -- push to the channel + self.chan:push({type(v),resolveData(v)}) + end + function self:pop() -- pop from the channel + local tab=self.chan:pop() + --print(tab) + if not tab then return end + return resolveType(tab[1],tab[2]) + end + function self:peek() + local tab=self.chan:peek() + --print(tab) + if not tab then return end + return resolveType(tab[1],tab[2]) + end + GLOBAL[self.name]=self -- send the object to the thread through the global interface + return self -- return the object + end + return c + else + error("Make sure you required the love.thread module!") -- tell the user if he/she didn't require said module + end + else + c.linda=lanes.linda() -- lanes is a bit eaiser, create the linda on the main thread + function c:push(v) -- push to the queue + self.linda:send("Q",v) + end + function c:pop() -- pop the queue + return ({self.linda:receive(0,"Q")})[2] + end + function c:peek() + return self.linda:get("Q") + end + function c:init() -- mimic the feature that love2d requires, so code can be consistent + return self + end + multi.integration.GLOBAL[name]=c -- send the object to the thread through the global interface + end + return c +end +function multi:systemThreadedBenchmark(n,p) + n=n or 1 + local cores=multi.integration.THREAD.getCores() + local queue=multi:newSystemThreadedQueue("QUEUE") + multi.integration.GLOBAL["__SYSTEMBENCHMARK__"]=n + local sThread=multi.integration.THREAD + local GLOBAL=multi.integration.GLOBAL + for i=1,cores do + multi:newSystemThread("STHREAD_BENCH",function() + require("multi") + if multi:getPlatform()=="love2d" then + GLOBAL=_G.GLOBAL + sThread=_G.sThread + end -- we cannot have upvalues... in love2d globals not locals must be used + queue=sThread.waitFor("QUEUE"):init() -- always wait for when looking for a variable at the start of the thread! + multi:benchMark(sThread.waitFor("__SYSTEMBENCHMARK__")):OnBench(function(self,count) + queue:push(count) + multi:Stop() + end) + multi:mainloop() + end) + end + local c={} + c.tt=function() end + c.p=p + function c:OnBench(func) + self.tt=func + end + multi:newThread("THREAD_BENCH",function() + thread.sleep(n+.1) + GLOBAL["QUEUE"]=nil -- time to clean up + local num=0 + data=queue:pop() + while data do + num=num+data + data=queue:pop() + end + if p then + print(tostring(p)..num) + end + c.tt(c,num) + end) + return c +end +function multi:newSystemThreadedTable(name,n) -- NEDS FIXING SING SO MUCH WORK!!! + local c={} -- where we will store our object + c.name=name -- set the name this is important for the love2d side + c.cores=n + c.hasT={} + if love then -- check love + if love.thread then -- make sure we can use the threading module + function c:init() -- create an init function so we can mimic on bith love2d and lanes + self.tab={} + self.chan=love.thread.getChannel(self.name) -- create channel by the name self.name + function self:waitFor(name) -- pop from the channel + repeat self:sync() until self[name] + return self[name] + end + function self:sync() + local data=self.chan:peek() + if data then + local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)") + if not self.hasT[name] then + if type(data)=="string" then + if cmd=="SYNC" then + self.tab[name]=resolveType(tp,d) -- this is defined in the loveManager.lua file + self.hasT[name]=true + end + else + self.tab[name]=data + end + self.chan:pop() + end + end + end + function self:reset(name) + self.hasT[core]=nil + end + setmetatable(self,{ + __index=function(t,k) + self:sync() + return self.tab[k] + end, + __newindex=function(t,k,v) + self:sync() + self.tab[k]=v + if type(v)=="userdata" then + self.chan:push(v) + else + for i=1,self.cores do + self.chan:push("SYNC "..type(v).." "..k.." "..resolveData(v)) -- this is defined in the loveManager.lua file + end + end + end, + }) + GLOBAL[self.name]=self -- send the object to the thread through the global interface + return self -- return the object + end + return c + else + error("Make sure you required the love.thread module!") -- tell the user if he/she didn't require said module + end + else + c.linda=lanes.linda() -- lanes is a bit eaiser, create the linda on the main thread + function c:waitFor(name) + while self[name]==nil do + -- Waiting + end + return self[name] + end + function c:sync() + return -- just so we match the love2d side + end + function c:init() -- set the metatable + setmetatable(self,{ + __index=function(t,k) + return self.linda:get(k) + end, + __newindex=function(t,k,v) + self.linda:set(k,v) + end, + }) + return self + end + multi.integration.GLOBAL[name]=c -- send the object to the thread through the global interface + end + return c +end +function multi:newSystemThreadedJobQueue(numOfCores) + local c={} + c.jobnum=1 + c.cores=numOfCores or multi.integration.THREAD.getCores() + c.queueIN=multi:newSystemThreadedQueue("THREADED_JQ"):init() + c.queueOUT=multi:newSystemThreadedQueue("THREADED_JQO"):init() + c.queueALL=multi:newSystemThreadedQueue("THREADED_QALL"):init() + c.REG=multi:newSystemThreadedQueue("THREADED_JQ_F_REG"):init() + c.OnReady=multi:newConnection() + function c:registerJob(name,func) + for i=1,self.cores do + self.REG:push({name,func}) + end + end + function c:pushJob(name,...) + self.queueOUT:push({self.jobnum,name,...}) + self.jobnum=self.jobnum+1 + end + local GLOBAL=multi.integration.GLOBAL -- set up locals incase we are using lanes + local sThread=multi.integration.THREAD -- set up locals incase we are using lanes + function c:doToAll(func) + local TaskName=multi.randomString(16) + for i=1,self.cores do + self.queueALL:push({TaskName,func}) + end + end + function c:start() + multi:newEvent(function() + return self.ThreadsLoaded==true + end):OnEvent(function(evnt) + GLOBAL["THREADED_JQ"]=nil -- remove it + GLOBAL["THREADED_JQO"]=nil -- remove it + GLOBAL["THREADED_JQ_F_REG"]=nil -- remove it + self:doToAll(function() + _G["__started__"]=true + SFunc() + end) + evnt:Destroy() + end) + end + GLOBAL["__JQ_COUNT__"]=c.cores + for i=1,c.cores do + multi:newSystemThread("System Threaded Job Queue Worker Thread #"..i,function(name,ind) + require("multi") + ThreadName=name + __sleep__=.001 + if love then -- lets make sure we don't reference upvalues if using love2d + GLOBAL=_G.GLOBAL + sThread=_G.sThread + __sleep__=.1 + end + JQI=sThread.waitFor("THREADED_JQO"):init() -- Grab it + JQO=sThread.waitFor("THREADED_JQ"):init() -- Grab it + REG=sThread.waitFor("THREADED_JQ_F_REG"):init() -- Grab it + QALL=sThread.waitFor("THREADED_QALL"):init() -- Grab it + QALLT={} + FUNCS={} + SFunc=multi:newFunction(function(self) + MainLoop:Pause() + self:hold(.1) + MainLoop:Resume() + self:Pause() + end) + multi:newLoop(function() + local rd=REG:peek() + if rd then + if not FUNCS[rd[1]] then + FUNCS[rd[1]]=rd[2] + rd=nil -- lets clean up + REG:pop() + end + end + local d=QALL:peek() + if d then + if not QALLT[d[1]] then + QALLT[d[1]]=true + d[2]() + d=nil -- lets clean up + QALL:pop() + end + end + end) + setmetatable(_G,{ + __index=function(t,k) + return FUNCS[k] + end + }) + lastjob=os.clock() + MainLoop=multi:newLoop(function(self) + if __started__ then + local job=JQI:pop() + if job then + lastjob=os.clock() + local d=QALL:peek() + if d then + if not QALLT[d[1]] then + QALLT[d[1]]=true + d[2]() + d=nil -- lets clean up + QALL:pop() + end + end + local ID=table.remove(job,1) -- return and remove + local name=table.remove(job,1) -- return and remove + if FUNCS[name] then + JQO:push({ID,FUNCS[name](unpack(job))}) + else + self:hold(function() return FUNCS[name] end) + JQO:push({ID,FUNCS[name](unpack(job))}) + end + end + end + end) + multi:newThread("Idler",function() + while true do + if os.clock()-lastjob>1 then + sThread.sleep(.1) + end + thread.sleep(.001) + end + end) + JQO:push({"_THREADINIT_",ind}) + if not love then + multi:mainloop() + end + end,"Thread<"..i..">",i) + end + c.OnJobCompleted=multi:newConnection() + c.updater=multi:newLoop(function(self) + local data=self.link.queueIN:pop() + while data do + if data then + local a,b=unpack(data) + if a=="_THREADINIT_" then + if b==self.link.cores then + self.link.ThreadsLoaded=true + self.link.OnReady:Fire() + end + else + self.link.OnJobCompleted:Fire(unpack(data)) + end + end + data=self.link.queueIN:pop() + end + end) + c.updater.link=c + return c +end +function multi:newSystemThreadedExecute(cmd) + local c={} + local GLOBAL=multi.integration.GLOBAL -- set up locals incase we are using lanes + local sThread=multi.integration.THREAD -- set up locals incase we are using lanes + local name="Execute_Thread"..multi.randomString(16) + c.name=name + GLOBAL[name.."CMD"]=cmd + multi:newSystemThread(name,function() + if love then -- lets make sure we don't reference upvalues if using love2d + GLOBAL=_G.GLOBAL + sThread=_G.sThread + name=__THREADNAME__ -- global data same as the name we used in this functions creation + end -- Lanes should take the local upvalues ^^^ + cmd=sThread.waitFor(name.."CMD") + local ret=os.execute(cmd) + GLOBAL[name.."R"]=ret + end) + c.OnCMDFinished=multi:newConnection() + c.looper=multi:newLoop(function(self) + local ret=GLOBAL[self.link.name.."R"] + if ret then + self.link.OnCMDFinished:Fire(ret) + self:Destroy() + end + end) + c.looper.link=c + return c +end diff --git a/game/parseManager/AICM.lua b/game/parseManager/AICM.lua new file mode 100644 index 0000000..23496fa --- /dev/null +++ b/game/parseManager/AICM.lua @@ -0,0 +1,37 @@ +AICM={} +AICM.functions={ + getAICMVersion=function(self) + return "1.0.0" + end, +} +function AICM:InitSyntax(obj,name) + obj:debug("Now using the Artificial Intelligence Communication module!") + obj.OnExtendedBlock(self.blockModule) + obj.OnCustomSyntax(self.syntaxModule) + obj:define(self.functions) +end +AICM.syntaxModule=function(self,line) + pVars,mStr=line:match("p%((.-)%)(.+)") + if pVars then + local vRef,vars=pVars:match("(.-):(.+)") + if vars:find(",") then + vars={unpack(vars:split(","))} + else + vars={vars} + end + tab={self:varExists(vRef):match(mStr)} -- self:varExists allows for all internal structures to just work + for i=1,#tab do + if vars[i] then + self._variables[vars[i]]=tab[i] + end + end + self:p() -- requried to progress the script + return { + text=line, + Type="AICMModule" + } + end +end +AICM.blockModule=function(obj,name,t,chunk,filename) + -- +end diff --git a/game/parseManager/EBIM.lua b/game/parseManager/EBIM.lua new file mode 100644 index 0000000..08ac193 --- /dev/null +++ b/game/parseManager/EBIM.lua @@ -0,0 +1,71 @@ +EBIM={} +EBIM.functions={ + getEBIMVersion=function(self) + return "1.0.0" + end, +} +EBIM.registry={} +function EBIM:registerEBlock(name,func) + self.registry[name]=func +end +function EBIM:InitSyntax(obj,name) + obj:debug("Now using the Extended Block Interface module!") + obj.OnExtendedBlock(self.blockModule) + obj.OnCustomSyntax(self.syntaxModule) + obj:define(self.functions) +end +EBIM.syntaxModule=function(self,line) + local cmd,args=line:match("(.-) (.+):") + if cmd then + local goal=nil + local _tab={} + for i=self.pos+1,#self._cblock do + if self._cblock[i]=="end"..cmd then + goal=i + break + else + table.insert(_tab,self._cblock[i]) + end + end + if goal==nil then + self:pushError("'end"..cmd.."' Expected to close '"..cmd.."'") + end + if EBIM.registry[cmd] then + EBIM.registry[cmd](self,args,_tab) + self.pos=goal+1 + else + self:pushError("Unknown command: "..cmd) + end + return { + Type="EBIM-Data", + text=cmd.." Block" + } + else + return + end +end +EBIM.blockModule=function(obj,name,t,chunk,filename) + --print(">: ",obj,name,t,chunk,filename) +end +EBIM:registerEBlock("string",function(self,args,tab) + local str={} + for i=1,#tab do + table.insert(str,tab[i]) + end + self:setVariable(args,table.concat(str,"\n")) +end) +EBIM:registerEBlock("list",function(self,args,tab) + local str={} + for i=1,#tab do + table.insert(str,self:varExists(tab[i])) + end + self:setVariable(args,str) +end) +EBIM:registerEBlock("dict",function(self,args,tab) + local str={} + for i=1,#tab do + local a,b=tab[i]:match("(.-):%s*(.+)") + str[a]=self:varExists(b) + end + self:setVariable(args,str) +end) diff --git a/game/parseManager/bytecode.lua b/game/parseManager/bytecode.lua new file mode 100644 index 0000000..26fb46f --- /dev/null +++ b/game/parseManager/bytecode.lua @@ -0,0 +1,44 @@ +-- In an attempt to speed up my library I will use a virtual machine that runs bytecode +compiler={} +compiler.cmds={ -- list of all of the commands + EVAL="\01", -- evaluate + SPLT="\02", -- split + TRIM="\03", -- trim + VEXT="\04", -- variable exists + ILST="\05", -- is a list + LSTR="\06", -- load string + FCAL="\07", -- Function call + SVAR="\08", -- set variable + LOAD="\09", -- load file + LAOD="\10", -- _load file + DEFN="\11", -- define external functions + HCBK="\12", -- Has c Block + CMBT="\13", -- combine truths + SETB="\14", -- set block + STRT="\15", -- start + PERR="\16", -- push error + PROG="\17", -- progress + PHED="\18", -- parse header + SSLT="\19", -- split string + NEXT="\20", -- next + -- Needs refining... One step at a time right! +} +function compiler:compile(filename) -- compiles the code into bytecode + -- First we load the code but don't run it + local engine=parseManager:load(filename) + -- This captures all of the methods and important info. This also ensures that the compiler and interperter stay in sync! + local bytecodeheader=bin.new() -- header will contain the order of blocks and important flags + local bytecode=bin.newDataBuffer() -- lets leave it at unlimited size because we don't know how long it will need to be + local functions={} -- will be populated with the important methods that must be preloaded + local prebytecode={} -- this contains bytecode that has yet to be sterilized + for blockname,blockdata in pairs(engine._chunks) do + -- lets get some variables ready + local code,_type,nextblock,filename=blockdata[1],blockdata[2],blockdata.next,blockdata.file + -- note nextblock may be nil on 2 condidions. The first is when the leaking flag is disabled and the other is when the block in question was the last block defined + local lines=bin._lines(code) + print("\n["..blockname.."]\n") + for i=1,#lines do + print(lines[i]) + end + end +end diff --git a/game/parseManager/init.lua b/game/parseManager/init.lua new file mode 100644 index 0000000..af90212 --- /dev/null +++ b/game/parseManager/init.lua @@ -0,0 +1,1277 @@ +function trim(s) + return s:match'^()%s*$' and '' or s:match'^%s*(.*%S)' +end +parseManager={} +parseManager._VERSION={1,0,0} +dialogueManager=parseManager -- for backwards purposes +parseManager.OnExtendedBlock=multi:newConnection(true) -- true protects the module from crashes +parseManager.OnCustomSyntax=multi:newConnection(true) -- true protects the module from crashes +function string:split( inSplitPattern, outResults ) + if not outResults then + outResults = {} + end + local theStart = 1 + local theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart ) + while theSplitStart do + table.insert( outResults, string.sub( self, theStart, theSplitStart-1 ) ) + theStart = theSplitEnd + 1 + theSplitStart, theSplitEnd = string.find( self, inSplitPattern, theStart ) + end + table.insert( outResults, string.sub( self, theStart ) ) + return outResults +end +function parseManager:debug(txt) + if self.stats.debugging then + self._methods:debug(txt) + end +end +function parseManager.split(s,pat) + local pat=pat or "," + local res = {} + local start = 1 + local state = 0 + local c = '.' + local elem = '' + for i = 1, #s do + c = s:sub(i, i) + if state == 0 or state == 3 then -- start state or space after comma + if state == 3 and c == ' ' then + state = 0 -- skipped the space after the comma + else + state = 0 + if c == '"' or c=="'" then + state = 1 + elem = elem .. '"' + elseif c=="[" then + state = 1 + elem = elem .. '[' + elseif c == pat then + res[#res + 1] = elem + elem = '' + state = 3 -- skip over the next space if present + else + elem = elem .. c + end + end + elseif state == 1 then -- inside quotes + if c == '"' or c=="'" then --quote detection could be done here + state = 0 + elem = elem .. '"' + elseif c=="]" then + state = 0 + elem = elem .. ']' + elseif c == '\\' then + state = 2 + else + elem = elem .. c + end + elseif state == 2 then -- after \ in string + elem = elem .. c + state = 1 + end + end + res[#res + 1] = elem + return res +end +parseManager._chunks={} +parseManager._cblock={} +parseManager._cblockname="" +parseManager._pos=1 +parseManager._labels={ + -- {chunkname,pos} +} +parseManager.stats={ + leaking=false, + debugging=false, + topdown=true, + forseelabels=true, +} +parseManager._types={} +parseManager.__index=parseManager +parseManager._variables={__TYPE="ENV"} +parseManager.defualtENV=parseManager._variables +function parseManager:varExists(var) + if var==nil or var=="nil" then return end + if type(var)=="userdata" then return var end + if tonumber(var) then + return tonumber(var) + end + local aa,bb=var:match("(.-)%[\"(.-)\"%]") + if aa and bb then + return self.defualtENV[aa][bb] + end + if var:find('"') then + return self:parseHeader(var:sub(2,-2),self.defualtENV) + end + if var:find("%[%]") then + return {} + end + if var:sub(1,1)=="[" and var:sub(-1,-1)=="]" then + local list=var:match("[(.+)]") + if not list then + self:pushError("Invalid List assignment!") + end + local t=list:split(",") + local nlist={} + local a=":)" + for i=1,#t do + a=self:varExists(t[i]) + if a then + table.insert(nlist,a) + end + end + return nlist + end + if var=="true" then + return true + elseif var=="false" then + return false + end + local a,b=var:match("(.-)%[(.-)%]") + if a and b then + if type(self.defualtENV[a])=="table" then + if b=="-1" then + return self.defualtENV[a][#self.defualtENV[a]] + elseif b=="#" then + return self.defualtENV[a][math.random(1,#self.defualtENV[a])] + else + return self.defualtENV[a][tonumber(b) or self:varExists(b)] + end + end + if type(self.defualtENV[var])=="table" then + return self.defualtENV[var] + end + end + return self.defualtENV[var] or var -- if all tests fail, just pass on the data for the function to manage +end +function parseManager:isList(var) + local a,b=var:match("(.-)%[(.-)%]") + if not a or b then return end + if type(self.defualtENV[a])=="table" then + if b=="-1" then + return self.defualtENV[a][#self.defualtENV[a]] + else + return self.defualtENV[a][tonumber(b)] + end + end + return +end +function parseManager:loadString(data) + self:_load(bin.new(data),self) +end +parseManager.loadeddata={} +parseManager.envs={} +parseManager._methods={ + getLength=function(self,list) + return #(self:varExists(list) or {}) + end, + emptyList=function(self) + return {} + end, + DEBUG=function(self,text) + print(text) + end, + DIS=function(self,var) + print(var) + end, + SEED=function(self,n) + math.randomseed(tonumber(self:varExists(n) or n) or os.time()) + end, + delElem=function(self,l,i) + table.remove(l,i) + end, + addElem=function(self,l,d,i) + table.insert(l,(i or -1),d) + return l + end, + RANDOM=function(self,v1,v2) + if v1 then + return math.random(1,v1) + elseif v1 or v2 then + return math.random(tonumber(v1),tonumber(v2)) + else + return math.random() + end + end, + CALC=function(self,eq) + return self:evaluate(eq) + end, + GOTOV=function(self,label) + print(self:varExists(label)) + self._methods.GOTO(self,self:varExists(label)) + end, + GOTO=function(self,label) + label=label:gsub("-","") + if label=="__LASTGOTO" then + self:setBlock(self._labels.__LASTGOTO[1]) + self.pos=self._labels[label][2] + return true + end + --search current block for a label + if self.pos==nil then + error("Attempt to load a non existing block from the host script!") + end + for i=self.pos,#self._cblock do + local line=self._cblock[i] + local labeltest=line:match("::(.-)::") + if labeltest==label then + self._labels["__LASTGOTO"]={self._cblockname,self.pos} + self.pos=i + return true + end + end + --search for saved labels + if self._labels[label] then + self._labels["__LASTGOTO"]={self._cblockname,self.pos} + self:setBlock(self._labels[label][1]) + self.pos=self._labels[label][2] + return true + end + --search other blocks if enabled for labels + if self.stats.forseelabels then + for i,v in pairs(self._chunks) do + local chunks=bin._lines(v[1]) + for p=1,#chunks do + local line=chunks[p] + local labeltest=line:match("::(.-)::") + if labeltest==label then + self._labels["__LASTGOTO"]={self._cblockname,self.pos} + self:setBlock(i) + self.pos=p-1 + return true + end + end + end + end + if self.stats.forseelabels then + if self._methods.GOTOV(self,label) then return end + end + self:pushError("Attempt to goto a non existing label! You can only access labels in the current scope! Or labels that the code has seen thus far! "..label.." does not exist as a label!") + end, + QUIT=function() + os.exit() + end, + EXIT=function(self) + self.pos=math.huge + end, + TYPE=function(self,val) + return type(val) + end, + SAVE=function(self,filename) + if trim(filename)=="" then filename="saveData.sav" end + local t=bin.new() + t:addBlock(self.defualtENV) + t:addBlock(self._cblockname) + t:addBlock(self.pos) + t:addBlock(self._labels) + t:tofile(filename) + end, + UNSAVE=function(self,filename) + if trim(filename)=="" then filename="saveData.sav" end + self.defualtENV={} + os.remove(filename) + end, + RESTORE=function(self) + if not(self.loadeddata.load) then self:pushError("A call to RESTORE without calling LOAD") end + self.defualtENV=self.loadeddata:getBlock("t") + self:setBlock(self.loadeddata:getBlock("s")) + self.pos=self.loadeddata:getBlock("n") + self._labels=self.loadeddata:getBlock("t") + end, + LOAD=function(self,filename) + print(filename) + if not filename then filename="saveData.sav" end + if io.fileExists(filename) then + self.loadeddata=bin.load(filename) + return 1 + end + return 0 + end, + JUMP=function(self,to) + self:setBlock(to) + end, + SKIP=function(self,n) + self.pos=self.pos+tonumber(n) + end, + PRINT=function(self,text) print(text) end, + TRIGGER=function(self,to) + self:setBlock(to) + end, + COMPARE=function(self,t,v1,v2,trueto,falseto) -- if a blockname is __STAY then it will continue on + if t=="=" or t=="==" then + if v1==v2 then + self:setBlock(trueto) + else + self:setBlock(falseto) + end + elseif t==">=" then + if v1>=v2 then + self:setBlock(trueto) + else + self:setBlock(falseto) + end + elseif t=="<=" then + if v1<=v2 then + self:setBlock(trueto) + else + self:setBlock(falseto) + end + elseif t==">" then + if v1>v2 then + self:setBlock(trueto) + else + self:setBlock(falseto) + end + elseif t=="<" then + if v1"..a + end) + local choicetest=line:find("<$") or line:find("^<") + local lasttest=line:match("^\"(.+)\"$") + local labeltest=line:match("::(.-)::") + local var,list=line:match("([%w_]-)=%[(.+)%]") + local assignA,assignB=line:match("(.-)=(.+)") + local cond,f1,f2=line:match("^if%s*(.-)%s*then%s*([%w-%(%)]-)%s*|%s*([%w-%(%)]*)") + if choicetest then + local c=self._chunks[self._cblockname][1] + local test=bin.new(c:match("\"<(.-)>")) + test:fullTrim(true) + local header=line:match("\"(.-)\"<") + local stuff=test:lines() + local cho,met={},{} + for i=1,#stuff do + local a1,a2=stuff[i]:match("\"(.-)\" (.+)") + a1=tostring(self:parseHeader(a1,env)) + table.insert(cho,a1) + table.insert(met,a2) + end + return { + Type="choice", + text=tostring(self:parseHeader(header,env)), + choices=cho, + methods=met, + blocktype=self._chunks[self._cblockname][2] + } + elseif cond and f1 and f2 then + conds={["andors"]={}} + mtc="" + for a,b in cond:gmatch("(.-)([and ]+[or ]+)") do + b=b:gsub(" ","") + mtc=mtc..".-"..b + v1,c,v2=a:match("(.-)%s*([<>!~=]+)%s*(.+)") + table.insert(conds,{v1,c,v2}) + table.insert(conds.andors,b) + end + a=cond:match(mtc.."%s*(.+)") + v1,c,v2=a:match("(.-)%s*([<>!~=]+)%s*(.+)") + table.insert(conds,{v1,c,v2}) + truths={} + for i=1,#conds do + conds[i][1]=conds[i][1]:gsub("\"","") + conds[i][3]=conds[i][3]:gsub("\"","") + if conds[i][2]=="==" then + table.insert(truths,tostring((self:varExists(conds[i][1]) or conds[i][1]))==tostring((self:varExists(conds[i][3]) or conds[i][3]))) + elseif conds[i][2]=="!=" or conds[i][2]=="~=" then + table.insert(truths,tostring((self:varExists(conds[i][1]) or conds[i][1]))~=tostring((self:varExists(conds[i][3]) or conds[i][3]))) + elseif conds[i][2]==">=" then + table.insert(truths,tonumber((self:varExists(conds[i][1]) or conds[i][1]))>=tonumber((self:varExists(conds[i][3]) or conds[i][3]))) + elseif conds[i][2]=="<=" then + table.insert(truths,tonumber((self:varExists(conds[i][1]) or conds[i][1]))<=tonumber((self:varExists(conds[i][3]) or conds[i][3]))) + elseif conds[i][2]==">" then + table.insert(truths,tonumber((self:varExists(conds[i][1]) or conds[i][1]))>tonumber((self:varExists(conds[i][3]) or conds[i][3]))) + elseif conds[i][2]=="<" then + table.insert(truths,tonumber((self:varExists(conds[i][1]) or conds[i][1]))])(.+)") + if d then + if d=="<-" then + self:setVariable(assignA,self.defualtENV[_env][vv]) + self:p() + return { + Type="assignment", + var=assignA, + value=assignB, + env=true, + text=assignA.."="..assignB + } + elseif d=="->" then + self.defualtENV[_env][assignA]=self:varExists(vv) + self:p() + return { + Type="assignment", + var=assignA, + value=assignB, + env=true, + text=assignA.."="..assignB + } + end + end + local a1,a2=parseManager.split(assignA),parseManager.split(assignB) + for i=1,#a1 do + local a=self._methods.CALC(self,a2[i]) + if a then + a2[i]=a + end + local t=tonumber(a2[i]) + if not t then + t=a2[i] + end + env[a1[i]]=t + end + self:p() + return { + Type="assignment", + var=assignA, + value=assignB, + text=assignA.."="..assignB + } + else + local rets=self.OnCustomSyntax:Fire(self,line) + for i=1,#rets do + if type(rets[i][1])=="table" then + return rets[i][1] + else + return { + Type="unknown", + text=line + } + end + end + self:p() + return { + Type="unknown", + text=line + } + end +end +function parseManager:RunCode(code,entry,sel,env) -- returns an env or selectVarName + local file = bin.new("ENTRY "..(entry or "START").."\n"..code) + local run=parseManager:load(file) + run._methods = self._methods + run.defualtENV=self.defualtENV + run.defualtENV=self.defualtENV + for i,v in pairs(env or {}) do + run.defualtENV[i]=v + end + local t=run:start() + while true do + if t.Type=="text" then + print(t.text) + t=run:next() + elseif t.Type=="condition" then + t=run:next() + elseif t.Type=="assignment" then + t=run:next() + elseif t.Type=="label" then + t=run:next() + elseif t.Type=="method" then + t=run:next() + elseif t.Type=="choice" then + t=run:next(nil,math.random(1,#t.choices),nil,t) + elseif t.Type=="end" then + if t.text=="leaking" then -- go directly to the block right under the current block if it exists + t=run:next() + else + return (run.defualtENV[sel] or run.defualtENV) + end + elseif t.Type=="error" then + error(t.text) + else + t=run:next() + end + end +end +parseManager.symbols={} -- {sym,code} +function parseManager:registerSymbol(sym,code) + self.symbols[#self.symbols+1]={sym,code} +end +function parseManager:populateSymbolList(o) + local str="" + for i=1,#self.symbols do + str=self.symbols[i][1]..str + end + return str +end +function parseManager:isRegisteredSymbol(o,r,v) + for i=1,#self.symbols do + if self.symbols[i][1]==o then + return parseManager:RunCode(self.symbols[i][2],"CODE","ret-urn",{["l"]=r,["r"]=v,["mainenv"]=self.defualtENV}) + end + end + return false --self:pushError("Invalid Symbol "..o.."!") +end +function parseManager:evaluate(cmd,v) + v=v or 0 + local loop + local count=0 + local function helper(o,v,r) + if type(v)=="string" then + if v:find("%D") then + v=self:varExists(v) + end + end + if type(r)=="string" then + if r:find("%D") then + r=self:varExists(r) + end + end + local r=tonumber(r) or 0 + local gg=self:isRegisteredSymbol(o,r,v) + if gg then + return gg + elseif o=="+" then + return r+v + elseif o=="-" then + return r-v + elseif o=="/" then + return r/v + elseif o=="*" then + return r*v + elseif o=="^" then + return r^v + end + end + for i,v in pairs(math) do + cmd=cmd:gsub(i.."(%b())",function(a) + a=a:sub(2,-2) + if a:sub(1,1)=="-" then + a="0"..a + end + return v(self:evaluate(a)) + end) + end + cmd=cmd:gsub("%b()",function(a) + return self:evaluate(a:sub(2,-2)) + end) + for l,o,r in cmd:gmatch("(.*)([%+%^%-%*/"..self:populateSymbolList().."])(.*)") do + loop=true + count=count+1 + if l:find("[%+%^%-%*/]") then + v=self:evaluate(l,v) + v=helper(o,r,v) + else + if count==1 then + v=helper(o,r,l) + end + end + end + if not loop then return self:varExists(cmd) end + return v +end +parseManager.constructType=function(self,name,t,data,filename) + if t~="construct" then return end + --print(name,t,"[CODE]{"..data.."}") + self:registerSymbol(name,"[CODE]{"..data.."}") +end +-- Let's add function +Stack = {} +function Stack:Create() + local t = {} + t._et = {} + function t:push(...) + if ... then + local targs = {...} + for _,v in ipairs(targs) do + table.insert(self._et, v) + end + end + end + function t:pop(num) + local num = num or 1 + local entries = {} + for i = 1, num do + if #self._et ~= 0 then + table.insert(entries, self._et[#self._et]) + table.remove(self._et) + else + break + end + end + return unpack(entries) + end + function t:getn() + return #self._et + end + function t:list() + for i,v in pairs(self._et) do + print(i, v) + end + end + return t +end +parseManager.funcstack=Stack:Create() +parseManager:define{ + __TRACEBACK=function(self) -- internal function to handle function calls + local t=self.funcstack:pop() + self:setBlock(t[1]) + self.pos=t[2] + -- We finished the function great. Lets restore the old env + self._methods.setENV(self,t[3]) + end +} +parseManager.funcType=function(link,name,t,data,filename) + local test,args=t:match("(function)%(*([%w,]*)%)*") + if not test then return false end + local vars={} + if args~="" then + for k, v in ipairs(parseManager.split(args)) do + table.insert(vars,v) + end + -- Time to collect local vars to populate we will use these below + end + link._chunks[name][1]=link._chunks[name][1].."\n__TRACEBACK()" + local func=function(self,...) + -- Here we will use the vars. First lets capture the args from the other side + local args={...} + -- Here we will play a matching game assigning vars to values. This cannot be done yet... + -- Now we have to change the enviroment so function vars are local to the function. + -- Also we need functions to be able to access the globals too + -- Now we invoke the createnv method + local env=self._methods.createENV(self) + -- A little messy compared to how its done within the interpreted language + -- Now we need a copy of the previous Env + -- We then invoke getEnv method + local lastEnv=self._methods.getENV(self) + -- Great now we have a new enviroment to play with and the current one + -- Next we need to store the current one somewhere + self.funcstack:push({self._cblockname,self.pos,lastEnv}) + -- We use a stack to keep track of function calls. Before I tried something else and it was a horrible mess + -- Stacks make it real nice and easy to use. We store a bit of data into the stack to use later + if self.funcstack:getn()>1024 then self:pushError("Stack Overflow!") end + -- Throw an error if the stack reaches 1024 elements. We don't want it to go forever and odds are neither does the user + -- Lets set that new env and prepare for the jump. To do this we invoke setEnv + self._methods.setENV(self,env) + -- Now lets play match making + for i=1,#vars do + self:setVariable(vars[i],args[i]) -- this method defualts to the current env + end + -- We are ready to make the jump with our stored data + self._methods.JUMP(self,name) + -- we need to be able to catch returns... This is where things get tricky. + -- We need a way to run the other code while also waiting here so we can return data + -- What we can do is return a reference to the enviroment and from there you can take what you want from the function + -- This is a really strange way to do things, but whats wrong with different + return env + end + link._methods[name]=func +end +parseManager.OnExtendedBlock(parseManager.funcType) +parseManager.constructType=function(link,name,t,data,filename) + local test,args=t:match("(construct)%(*([%w,]*)%)*") + if not test then return false end + local vars={} + if args~="" then + for k, v in ipairs(parseManager.split(args)) do + table.insert(vars,v) + end + end + link._chunks[name][1]=link._chunks[name][1].."\n__TRACEBACK()" + local func=function(self,...) + local args={...} + local env=self._methods.createENV(self) + local lastEnv=self._methods.getENV(self) + self.funcstack:push({self._cblockname,self.pos,lastEnv}) + if self.funcstack:getn()>1024 then self:pushError("Stack Overflow!") end + self._methods.setENV(self,env) + for i=1,#vars do + self:setVariable(vars[i],args[i]) + end + self._methods.JUMP(self,name) + return env + end + link._methods[name]=func +end +parseManager.OnExtendedBlock(parseManager.constructType) diff --git a/game/parseManager/interpreter.lua b/game/parseManager/interpreter.lua new file mode 100644 index 0000000..e4a5b84 --- /dev/null +++ b/game/parseManager/interpreter.lua @@ -0,0 +1,10 @@ +engine={} +function engine:init(bytecodeFile) + self.code=bin.load(bytecodeFile).data +end +--[[OP-CODES + +]] +function engine:run(assessors) + -- +end