diff --git a/OpenAL32.dll b/OpenAL32.dll new file mode 100644 index 0000000..301355d Binary files /dev/null and b/OpenAL32.dll differ diff --git a/SDL2.dll b/SDL2.dll new file mode 100644 index 0000000..3acfb32 Binary files /dev/null and b/SDL2.dll differ diff --git a/changes.txt b/changes.txt new file mode 100644 index 0000000..5b50368 --- /dev/null +++ b/changes.txt @@ -0,0 +1,1084 @@ +LOVE 0.10.2 [Super Toast] +------------------------- + +Released: 2016-10-31 + + * Added lovec.exe in Windows. It is the same as love.exe but built with the Console subsystem, so it always uses or provides a console. + * Added the ability to restart the game via love.event.quit("restart"). + * Added support for passing a table to love.mouse.isDown, love.keyboard.isDown, love.keyboard.isScancodeDown, Joystick:isDown, and Joystick:isGamepadDown. + * Added love.window.isMaximized. + * Added 'shaderswitches' field to the table returned by love.graphics.getStats. + * Added Quad:getTextureDimensions. + * Added 'ellipse' area distribution to ParticleSystems. + * Added support for BC4-7 compressed texture formats in KTX files. + * Added PrismaticJoint:getAxis and WheelJoint:getAxis. + * Added 2-point version of love.physics.newRevoluteJoint. + * Added table variants of Fixture:setCategory and Fixture:setMask. + * Added getNextVertex and getPreviousVertex to ChainShape and EdgeShape. + * Added optional reference angle arguments to RevoluteJoint, PrismaticJoint, and WeldJoint constructors. + * Added RevoluteJoint:getReferenceAngle, PrismaticJoint:getReferenceAngle, and WeldJoint:getReferenceAngle. + + * Deprecated undocumented Shader:sendTexture, Shader:sendMatrix, Shader:sendInt, and Shader:sendFloat functions. + + * Fixed love on iOS 6. + * Fixed os.execute always returning -1 on Linux. + * Fixed the love.lowmemory callback to call collectgarbage() after the callback has fired, instead of before. + * Fixed love.math.noise(nil) to error instead of returning nil. + * Fixed an occasional crash when a Thread ends. + * Fixed a hang at the end of video playback with some video files. + * Fixed the video decoding thread to not do any work when there are no videos to decode. + * Fixed love.graphics.newVideo(file) to no longer error if love.audio is disabled. + * Fixed a rare bug in Source:play for streaming Sources if the associated OpenAL source object was previously used for a static Source. + * Fixed corrupted Font glyphs in rare cases. + * Fixed stencils inside Canvases on some OpenGL ES 2 devices. + * Fixed an OpenGL error in OpenGL ES 3 when multiple render targets are used. + * Fixed love.window.setMode crashing when called with a Canvas active. + * Fixed love.window.maximize to update the reported window dimensions immediately. + * Fixed gamma correction of ImageFonts and BMFonts with colored images. + * Fixed the default shader improperly applying gamma correction to per-vertex colors when gamma correction is requested but not supported on OpenGL ES. + * Fixed text coloring breaking because of an empty string. + * Fixed large burst of particles when dramatically increasing the emission rate of a ParticleSystem. + * Fixed SpriteBatch:setBufferSize to keep old sprite data if it can fit. + * Fixed MouseJoint:getBodies unconditionally erroring. + * Fixed memory leak in Text:set. + * Fixed incorrect kerning caused by using kerning information for the wrong character in some fonts. + * Fixed ImageData:setPixel/getPixel/mapPixel and SoundData:setSample/getSample to properly handle non-integer coordinates. + + * Improved performance of Channel methods by roughly 2x in many cases. + * Improved performance of Shader:send when small numbers of arguments are given. + + * Updated love.filesystem.mount to accept a DroppedFile as the first parameter. + * Updated Shader:send to do type and argument checking based on the specified uniform variable's information instead of the arguments to the function. + * Updated Shader:send to accept a flat table for matrix uniforms. + + +LOVE 0.10.1 [Super Toast] +------------------------- + +Released: 2016-02-14 + + * Added a new love.conf flag t.externalstorage, which determines whether files are saved in internal or external storage on Android devices. + * Added a new variant of love.graphics.arc which can draw different types of arcs ("pie", "open", or "closed"). + * Added "lighten" and "darken" BlendModes. They can only be used with the "premultiplied" BlendAlphaMode. + * Added the "lighten" GraphicsFeature constant. + * Added the ability to avoid clearing specific Canvases when calling love.graphics.clear, if multiple Canvases are active at once via love.graphics.setCanvas. + * Added Text:getDimensions. + * Added optional "collideconnected" argument to love.physics.newMotorJoint. + + * Fixed a Lua error in the no-game screen if the window's height is too small. + * Fixed the default error handler to reset the mouse Cursor. + * Fixed love.filesystem functions crashing when called if liblove is used directly without calling love.filesystem.init. + * Fixed audio on Android to pause when the app is inactive, and resume when the app becomes active again. + * Fixed the Video decoding thread hanging after Video:seek or when a Video finishes. + * Fixed Video:isPlaying to always return false after it finishes playing. + * Fixed RandomGenerator:random crashing if a nil 'self' is used. + * Fixed loading BMFont files which have characters with 0 width or height (a space character, for example). + * Fixed love.graphics.newFont causing crashes if FileData is passed in. + * Fixed love.graphics.clear(colortable) causing crashes on OpenGL ES 2 systems when a Canvas is active. + * Fixed a driver bug on some Android devices which caused all objects to show up as black. + * Fixed a driver bug on Windows with AMD graphics cards where love.graphics.clear would not always work. + * Fixed Shader:sendColor incorrectly converting alpha values from sRGB to linear RGB when gamma-correct rendering is enabled. + * Fixed love.graphics.newMesh(vertices) double-converting colors from sRGB to linear RGB when gamma-correct rendering is enabled. + * Fixed love.graphics.new* crashing when there is no graphics context/window. + + * Updated the Windows executable to prefer the high-powered AMD graphics card on systems which have switchable Intel+AMD GPUs. + * Updated love.touch.getTouches to return the list of IDs in the relative order that the touches initially happened, instead of being in a random order. + * Updated the error messages caused by invalid or bad arguments to ImageData and SoundData methods to be more descriptive. + + +LOVE 0.10.0 [Super Toast] +------------------------- + +Released: 2015-12-22 + + * Added an iOS port. + * Added an Android port. + * Added the flag t.accelerometerjoystick to love.conf. Disables accelerometer-as-joystick functionality on mobile devices when false. + * Added the flag t.gammacorrect to love.conf (replaces t.window.srgb.) Enabling it globally enables gamma-correct rendering, when supported. + * Added video playback support for Ogg Theora videos, via love.graphics.newVideo and Video objects. + * Added love.video module. It is not used for displaying videos on-screen, only decoding them. + * Added love.touch module. Note that it has important differences from the touch implementation in the LÖVE 0.9 Android and iOS ports. + * Added love.touchpressed, love.touchreleased, and love.touchmoved. + * Added love.system.vibrate. + * Added love.filesystem.setRequirePath and love.filesystem.getRequirePath. + * Added an optional program exit argument to love.event.quit. + * Added love.filedropped and love.directorydropped event callback functions. + * Added love.lowmemory event callback function, called when the app is running out of memory on mobile operating systems. + * Added love.textedited event callback function, called when the user is compositing text (e.g. via an IME.) + * Added love.wheelmoved event callback function (replaces "wu" and "wd" constants for love.mousepressed.) + * Added love.mouse.hasCursor. + * Added a boolean argument to love.mousepressed and love.mousereleased indicating whether the button event originated from a touch press. + * Added optional x/y/width/height arguments to love.keyboard.setTextInput. They tell the system where text will show up so on-screen keyboards can avoid that area. + * Added Source:getType (replaces Source:isStatic.) + * Added Source:getDuration and Decoder:getDuration. + * Added an optional string argument containing raw pixel byte data to the width/height variant of love.image.newImageData. + * Added love.graphics.ellipse. + * Added rounded-rectangle support to love.graphics.rectangle. + * Added love.graphics.points (replaces love.graphics.point.) + * Added love.graphics.intersectScissor. + * Added an optional argument to love.graphics.setBlendMode which indicates whether to treat the colors of drawn objects as having pre-multiplied alpha. + * Added love.graphics.getSupported (replaces love.graphics.isSupported.) + * Added love.graphics.getSystemLimits (replaces love.graphics.getSystemLimit.) + * Added love.graphics.stencil and love.graphics.set/getStencilTest (replaces love.graphics.setStencil.) + * Added love.graphics.isActive. + * Added color arguments to love.graphics.clear. It no longer always uses the background color value. + * Added love.graphics.discard. + * Added love.graphics.isGammaCorrect. + * Added the "clampzero" WrapMode. + * Added the ability to specify custom mipmaps when creating an image, via love.graphics.newImage(filename, {mipmaps={mip1, mip2, ...}}) + * Added optional x/y/width/height arguments to Image:refresh and Canvas:newImageData. + * Added Image:getFlags. + * Added one- and two-channel Canvas formats: r8, rg8, r16f, rg16f, r32f, and rg32f. + * Added support for different formats in each Canvas when using multi-canvas rendering. Added the "multicanvasformats" Graphics Feature constant. + * Added support for OpenGL ES 2 and 3. + * Added support for loading ETC, EAC, PVRTC, and ASTC compressed textures on systems that support them. + * Added custom vertex attribute support for Meshes via new variants of love.graphics.newMesh. + * Added Mesh:setVertexAttribute and Mesh:getVertexAttribute. + * Added Mesh:getVertexFormat. + * Added Mesh:flush. + * Added an optional 'startvertex' argument to Mesh:setVertices. + * Added the ability for love.graphics.newMesh and Mesh:setVertices to accept a Data object. + * Added Mesh:setAttributeEnabled and Mesh:isAttributeEnabled. + * Added Mesh:attachAttribute. + * Added SpriteBatch:attachAttribute. + * Added Shader:sendColor. + * Added new shader functions: gammaCorrectColor, gammaToLinear, and linearToGamma. The functions also have 'precise' and 'fast' variants. + * Added Text objects and love.graphics.newText. + * Added per-character color support to love.graphics.print/printf and to Text objects. + * Added BMFont bitmap font file support to love.graphics.newFont and love.font. + * Added kerning support for TrueType/OpenType and BMFont Fonts. + * Added an optional font hinting argument to love.graphics.newFont when loading TrueType fonts. + * Added an optional spacing argument to love.graphics.newImageFont, which applies additional spacing to all rendered glyphs. + * Added Font:setFallbacks. + * Added love.window.maximize. + * Added love.window.close. + * Added love.window.requestAttention. + * Added love.window.setDisplaySleepEnabled and love.window.isDisplaySleepEnabled. + * Added BezierCurve:renderSegment and BezierCurve:removeControlPoint. + * Added BezierCurve:getSegment. + * Added love.math.compress and love.math.decompress. + * Added Channel:performAtomic. + + * Changed love.mousepressed, love.mousereleased, and love.mouse.isDown to use button numbers instead of named button constants. + * Changed love.keypressed to be love.keypressed(key, scancode, isrepeat). + * Changed love.keyreleased to be love.keyreleased(key, scancode). + * Changed Font:getWrap's second return value to be a table containing the text split into lines. + * Changed love.graphics.newImage's optional second argument to be a table of flags (flags are "mipmaps" and "linear".) + * Changed the arguments for the standard variants of love.graphics.newMesh to newMesh(vertices [, drawmode, usage]) and newMesh(vertexcount [, drawmode, usage]). + * Changed ImageData:encode to return a FileData object. ImageData:encode's first parameter is now the format to encode to, and the second parameter is an optional filename to write to. + + * Renamed the "normal" Fullscreen Type to "exclusive". + * Renamed the DistanceModel constants "inverse clamped", "linear clamped", and "exponent clamped" to "inverseclamped", "linearclamped", and "exponentclamped". + * Renamed the "additive", "subtractive", and "multiplicative" BlendModes to "add", "subtract", and "multiply". + * Renamed the KeyConstant and Scancode representing the spacebar from " " to "space". + * Renamed File:eof to File:isEOF. + * Renamed Canvas:getImageData to Canvas:newImageData. + * Renamed love.image's CompressedData type to CompressedImageData. + + * Removed callback variant of love.filesystem.getDirectoryItems. + * Removed the "wu" and "wd" constants for love.mousepressed (replaced by love.wheelmoved.) + * Removed the named mouse button constants (replaced by button numbers.) + * Removed Source:isStatic (replaced by Source:getType.) + * Removed image loading support for all (non-compressed texture) file formats except for PNG, JPEG, TGA, and BMP. + * Removed JPEG encoding support from ImageData:encode. + * Removed love.graphics.point (replaced by love.graphics.points.) + * Removed love.graphics.setPointStyle and love.graphics.getPointStyle. + * Removed love.graphics.isSupported (replaced by love.graphics.getSupported.) + * Removed love.graphics.getSystemLimit (replaced by love.graphics.getSystemLimits.) + * Removed love.graphics.setStencil (replaced by love.graphics.stencil and love.graphics.setStencilTest.) + * Removed the "canvas", "shader", "npot", "subtractive", and "mipmap" Graphics Feature constants (the features always have guaranteed support now.) + * Removed the "multicanvas" Graphics Feature constant (use love.graphics.getSystemLimits instead.) + * Removed the "srgb" Graphics Feature constant (use love.graphics.isGammaCorrect() or love.graphics.getCanvasFormats().srgb instead.) + * Removed the "srgb" flag in love.window.setMode and in the t.window table in love.conf (Replaced by t.gammacorrect.) + * Removed the "premultiplied" blend mode (love.graphics.setBlendMode("alpha", "premultiplied") now does the same thing.) + * Removed Canvas:getPixel (use Canvas:newImageData instead.) + * Removed Canvas:clear (use love.graphics.clear instead.) + * Removed Mesh:getVertices. + * Removed Mesh:setVertexColors and Mesh:hasVertexColors (use Mesh:setAttributeEnabled("VertexColor", enable) instead.) + * Removed functions deprecated in LOVE 0.9.1 and 0.9.2: + * Removed love.graphics.getMaxImageSize and love.graphics.getMaxPointSize (replaced by love.graphics.getSystemLimits.) + * Removed Mesh:set/getImage, SpriteBatch:set/getImage, and ParticleSystem:set/getImage (replaced by set/getTexture.) + * Removed SpriteBatch:bind/unbind. + * Removed Canvas:getFSAA and the "fsaa" flag in love.conf and love.window.setMode (replaced by Canvas:getMSAA and "msaa".) + * Removed the "dxt" and "bc5" Graphics Feature constant (replaced by love.graphics.getCompressedImageFormats.) + * Removed the "hdrcanvas" Graphics Feature constant (replaced by love.graphics.getCanvasFormats.) + * Removed love.window.getWidth/getHeight/getDimensions (use love.graphics.getWidth/getHeight/getDimensions or love.window.getMode instead.) + + * Fixed utf8.char. + * Fixed detection of fused love games. + * Fixed World:getCallbacks and World:getContactFilter when used in coroutines. + * Fixed crashes when objects which store Lua callback functions are garbage collected after being used in coroutines. + * Fixed memory leaks in love.physics if World:destroy is never called. When a World is GCed it now destroys all objects it owns. + * Fixed love.keyboard.getKeyFromScancode crashing when an invalid scancode is given. + * Fixed decoding of 8-bit WAV files. + * Fixed a crash issue when rewinding streaming ogg Sources, when certain versions of libvorbis are used. + * Fixed love.audio.stop() not rewinding streaming Sources. + * Fixed the stencil buffer in Canvases when an unsupported MSAA value is used to create the Canvas. + * Fixed Canvas:renderTo to restore the previous Canvas if an error occurs in the passed function. + * Fixed love.graphics.draw(canvas) to cause an error if that Canvas is the active one. + * Fixed Mesh:getVertexMap to return nil rather than an empty table, if no vertex map has been set. + * Fixed love.graphics.getColorMask. + * Fixed the default offset for particles when ParticleSystem:setQuads or ParticleSystem:setTexture is used. + * Fixed love.graphics.shear resetting all love.graphics transformations. + * Fixed the "add" and "subtract" blend modes to no longer modify the alpha of the Canvas / screen. + + * Improved the performance of World:rayCast and World:queryBoundingBox. + * Improved the performance of love.graphics.line and other line drawing functions, when the "smooth" LineStyle is used. + * Improved the performance of Shader:send when matrices are used. + * Improved the performance of ImageData and SoundData methods when LuaJIT's JIT compiler is enabled, by using efficient FFI code. + * Improved the performance of love.math.noise, love.math.gammaToLinear, love.math.linearToGamma, love.math.random, and RandomGenerator:random when LuaJIT's JIT compiler is enabled. + + * Updated the compatibility warning notice to use a message box and to show the version specified in love.conf. + * Updated the compatibility warning notice to display before main.lua is loaded. + * Updated the __tostring metamethod of love objects to output the pointer value, similar to tostring(table). + * Updated World:setCallbacks, World:setContactFilter, World:queryBoundingBox, and World:rayCast to have improved argument type checking. + * Updated threads to load love.filesystem automatically. + * Updated love.filesystem to enable symlinks by default. + * Updated love.math.setRandomSeed and RandomGenerator:setSeed to produce better results for the first few random() calls. + * Updated love.math.random and RandomGenerator:random to produce slightly better results in general. + * Updated Source methods that deal with spatial audio to error rather than failing silently if the Source isn't mono. + * Updated the 3D and 4D variants of love.math.noise to use Perlin noise rather than Simplex noise, to avoid patent issues. + * Updated ImageFonts to no longer treat separator pixels as spacing. + * Updated the default font to use less memory. + * Updated the behavior of text wrapping with love.graphics.printf and Font:getWrap to work better. + * Updated love.graphics.print and love.graphics.printf to no longer automatically round the x and y position arguments. + * Updated some error messages for love.graphics.newImage to be more descriptive. + * Updated love.graphics color functions to automatically apply love.math.gammaToLinear to color values when gamma-correct rendering is enabled. + * Updated the 'normal' Canvas format to internally use 'srgb' rather than 'rgba8' when gamma-correct rendering is enabled. + * Updated love.graphics.setColor to affect all drawn objects, including ParticleSystems, SpriteBatches, and Meshes. + * Updated the default fullscreen type to be "desktop" rather than "exclusive". + * Updated the minimum runtime system requirements of LOVE to require OpenGL 2.1 or OpenGL ES 2 support. + * Updated the pixel shader effect function so screen_coords.y is 0 at the top of the screen instead of the bottom. + * Updated Images to require setting the mipmaps flag to true on creation in order to use mipmaps. + * Updated Images to allow mipmaps for non-power-of-two sizes. + +LOVE 0.9.2 [Baby Inspector] +--------------------------- + + Released: 2015-02-14 + + * Added Lua 5.3's UTF-8 module (via utf8 = require("utf8")). + * Added Shader:getExternVariable. + * Added several new canvas texture formats. + * Added love.graphics.getCanvasFormats. + * Added love.graphics.getCompressedImageFormats. + * Added ParticleSystem:setQuads. + * Added ParticleSystem:setLinearDamping. + * Added SpriteBatch:flush. + * Added love.graphics.getStats. + * Added "mirroredrepeat" wrap mode. + * Added love.audio.setDopplerScale and love.audio.getDopplerScale. + * Added optional duration argument to Joystick:setVibration. + * Added love.joystick.loadGamepadMappings and love.joystick.saveGamepadMappings. + * Added Joint:setUserData and Joint:getUserData. + * Added Joint:getBodies. + * Added GearJoint:getJoints. + * Added Contact:getFixtures and Body:getContactList. + * Added Body:getWorld. + * Added Body:getJointList. + * Added Body/Contact/Fixture/Joint/World:isDestroyed. + * Added love.mousemoved event callback. + * Added love.mouse.setRelativeMode and love.mouse.getRelativeMode. + * Added Scancode enums, love.keyboard.getKeyFromScancode, and love.keyboard.getScancodeFromKey. + * Added love.window.getDisplayName. + * Added love.window.minimize. + * Added love.window.showMessageBox. + * Added 'refreshrate' field to the table returned by love.window.getMode. + * Added love.window.toPixels and love.window.fromPixels. + * Added love.window.setPosition and love.window.getPosition, and 'x' and 'y' fields to love.window.setMode and t.window in love.conf. + * Added love.filesystem.isSymlink, love.filesystem.setSymlinksEnabled, and love.filesystem.areSymlinksEnabled. + * Added love.filesystem.getRealDirectory. + + * Deprecated SpriteBatch:bind and SpriteBatch:unbind. + * Deprecated all uses of the name 'FSAA' in favor of 'MSAA'. + * Deprecated the 'hdrcanvas' graphics feature enum in favor of getCanvasFormats. + * Deprecated the 'dxt' and 'bc5' graphics feature enums in favor of getCompressedImageFormats. + + * Fixed crashes when love objects are used in multiple threads. + * Fixed love.filesystem.setIdentity breaking in some situations when called multiple times. + * Fixed the default love.filesystem identity when in Fused mode in Windows. + * Fixed love.system.openURL sometimes blocking indefinitely on Linux. + * Fixed love.joystick.setGamepadMapping. + * Fixed the order of vertices in ChainShapes. + * Fixed love.mouse.getPosition returning outdated values if love.mouse.setPosition is used in the same frame. + * Fixed love.graphics.newFont to error when given an invalid size argument. + * Fixed the filename and backtrace given when love.graphics.print errors. + * Fixed a small memory leak if love.graphics.newCanvas errors. + * Fixed shader:getWarnings returning unnecessary information. + * Fixed some cases of noncompliant shader code not properly erroring on some nvidia drivers. + * Fixed a potential crash when Shader objects are garbage collected. + * Fixed a potential small memory leak triggered when love.graphics.newShader errors. + * Fixed love.graphics.newMesh(vertexcount, ...) causing the Mesh to do instanced rendering. + * Fixed Mesh:getVertexMap. + * Fixed Image:refresh generating mipmaps multiple times if mipmap filtering is enabled. + * Fixed Image:setMipmapFilter to not keep bad state around if it errors. + * Fixed Mesh:setDrawRange when the Mesh has a vertex map set. + * Fixed internal detection of the 'position' and 'effect' shader functions. + * Fixed Texture memory leak when Meshes are garbage collected. + * Fixed the default line join mode to be 'miter' instead of an undefined value. + * Fixed the default error handler text size when highdpi mode is enabled on a Retina monitor. + * Fixed the default error handler background color when sRGB mode is enabled for the window. + * Fixed love.window.setMode to fall back to the largest available mode if a width or height greater than the largest supported is specified and fullscreen is used. + * Fixed the state of wireframe mode when love.window.setMode is called. + * Fixed Canvas:getPixel to error if the coordinates are not within the Canvas' size. + * Fixed detection of compressed textures to work regardless of the file's extension. + + * Renamed all cases of FSAA to MSAA. The FSAA names still exist for backward-compatibility. + + * Updated the Windows executable to automatically prefer the higher performance GPU on nvidia Optimus systems. + * Updated the --console command-line argument in Windows to open the console before conf.lua is loaded. + * Updated t.console and the --console command-line argument in Windows to use the existing Console window, if love was launched from one. + * Updated the love executable to verify that the love library's version matches. + * Updated the Lua wrapper code for modules to avoid crashes when the module's instance is created, deleted, and recreated. + * Updated internal code for handling garbage collection of love objects to be more efficient. + * Updated love's initialization code to trigger a Lua error if love.conf has an error in it. + * Updated the paths returned by love.filesystem.getSaveDirectory and friends to strip double-slashes from the string. + * Updated the error message when love.filesystem.write or File:open fails because the directory doesn't exist. + * Updated the error message when love.math.setRandomseed(0) is attempted. + * Updated the error message when invalid UTF-8 strings are used in love functions that expect UTF-8. + * Updated love.physics.newPolygonShape and love.physics.newChainShape to accept a table of vertices. + * Updated love.physics.newChainShape to error if the number of arguments is invalid. + * Updated love.thread.newThread to accept a literal string of code directly. + * Updated love-created threads to use names visible in external debuggers. + * Updated SpriteBatch:unbind to use less VRAM if the SpriteBatch has the static usage hint. + * Updated love.graphics.newImage, love.image.newImageData, etc. to leave less Lua-owned memory around. + * Updated love.graphics.push to accept different stack types to push. Current types are "transform" and "all". + * Updated love shaders to accept GLSL ES precision qualifiers on variables, although they do nothing. + * Updated the error message for love.graphics.newShader to be less cryptic if an invalid filename is given. + * Updated compressed texture loading code to allow BC6 and BC7 compressed textures (if the graphics driver supports them.) + +LOVE 0.9.1 [Baby Inspector] +--------------------------- + + Released: 2014-04-01 + + * Added Source:clone. + * Added blend mode "screen". + * Added ParticleSystem:clone. + * Added ParticleSystem:moveTo, has smoother emitter movement compared to setPosition. + * Added ParticleSystem:setRelativeRotation. + * Added love.graphics.setWireframe for debugging. + * Added Mesh:setDrawRange and Mesh:getDrawRange. + * Added CircleShape:getPoint and CircleShape:setPoint. + * Added Mesh/SpriteBatch/ParticleSystem:setTexture, accepts Canvases and Images. + * Added high-dpi window support for Retina displays in OS X, via the 'highdpi' window flag. + * Added love.window.getPixelScale. + * Added love.graphics.getSystemLimit. + * Added antialiasing support to Canvases. + * Added Canvas:getFSAA. + * Added 'love_ScreenSize' built-in variable in shaders. + * Added love.getVersion. + * Added support for gamma-correct rendering. + * Added love.graphics.isSupported("srgb"). + * Added love.math.gammaToLinear and love.math.linearToGamma. + * Added RandomGenerator:getState and RandomGenerator:setState. + * Added Body:setUserData and Body:getUserData. + * Added some missing obscure key constants. + * Added optional callback function argument to love.filesystem.getDirectoryItems. + * Added love.system.openURL. + + * Deprecated Mesh/SpriteBatch/ParticleSystem:setImage. + * Deprecated love.graphics.getMaxImageSize and love.graphics.getMaxPointSize. + + * Fixed love.graphics.scale with negative values causing incorrect line widths. + * Fixed Joystick:isDown using 0-based button index arguments. + * Fixed Source:setPitch to error when infinity or NaN is given. + * Fixed love.graphics.setCanvas() to restore the proper viewport and scissor rectangles. + * Fixed TrueType font glyphs which request a monochrome bitmap pixel mode. + * Fixed love.graphics.reset causing crashes when called in between love.graphics.push/pop. + * Fixed tab characters ("\t") to display properly with love.graphics.print. + * Fixed love.graphics.isCreated to return false when love.window.setMode fails completely. + * Fixed love.window.setMode to not destroy OpenGL resources before checking whether a fullsceren size is supported. + * Fixed World:getBodyList and World:getJointList causing hard crashes. + * Fixed loading BC4 compressed textures. + * Fixed SoundData objects being initialized with garbage values. + * Fixed 8-bit SoundData samples when used in love.audio Sources. + + * Updated the error text for love.filesystem’s module searchers when require fails. + * Updated the love.filesystem module searchers to be tried after package.preload instead of before. + * Updated love.graphics.newParticleSystem, newSpriteBatch, and newMesh to accept Canvases. + * Updated Canvas drawing code, texture coordinates are no longer flipped vertically. + * Updated Canvas:renderTo to work properly if a Canvas is currently active. + * Updated ParticleSystem:setEmissionRate to accept non-integer numbers. + * Updated Source:play to return a boolean indicating success. + * Updated t.console in conf.lua to create the console before modules are loaded in Windows. + * Updated Mesh vertex maps (index buffers) to use less space in VRAM. + * Updated love.graphics.newMesh and Mesh:setVertices to default the UV parameters to 0,0. + * Updated Fixture:set/getUserData to work in Coroutines. + * Updated fullscreen-desktop and resizable window modes in OS X to use Mac OS 10.7's fullscreen Spaces. + * Updated love.filesystem's C library loader to look in paths added via love.filesystem.mount, in Fused mode. + * Updated the default love.run code to make initial love.math.random calls more random. + +LOVE 0.9.0 [Baby Inspector] +--------------------------- + + Released: 2013-12-13 + + * Added better multiplayer networking support via ENet. + * Added --fused command line argument, to simulate fusing. + * Added liblove. + * Added the ability to have exit values. + * Added exit value of 1 in case of error by default. + * Added basic support for the file:// uri scheme. + * Added love.filesystem.isFused. + * Added love.filesystem.getIdentity. + * Added love.filesystem.append. + * Added love.filesystem.getSize. + * Added love.filesystem.mount and love.filesystem.unmount. + * Added optional file search order parameter to love.filesystem.setIdentity. + * Added File:isOpen and File:getMode. + * Added Fie:setBuffer, File:getBuffer, and File:flush. + * Added textinput event for unicode text input. + * Added love.keyboard.setTextInput and love.keyboard.hasTextInput. + * Added previously internal Rasterizer and GlyphData object methods. + * Added support for UTF-8 ImageFonts. + * Added Font:getAscent/getDescent/getBaseline. + * Added Font:setFilter/getFilter. + * Added Font:hasGlyphs. + * Added angle, scale, and shear parameters to love.graphics.printf. + * Added HDR canvas support. + * Added mipmapping support (has isSupported test). + * Added vertex shader support. + * Added boolean support to Shader:send. + * Added Canvas:getPixel. + * Added blend mode "replace". + * Added line join modes. + * Added Mesh objects, allowing for arbitrary textured polygons. + * Added multiple render target support to love.graphics.setCanvas. + * Added love.graphics.setColorMask. + * Added love.graphics.origin. + * Added love.graphics.getRendererInfo. + * Added love.graphics.getMaxImageSize. + * Added SpriteBatch:getCount and SpriteBatch:getBufferSize. + * Added SpriteBatch:getColor. + * Added ParticleSystem:emit. + * Added ParticleSystem:setInsertMode and ParticleSystem:getInsertMode. + * Added many ParticleSystem getter methods. + * Added DXT compressed texture support via love.image.newCompressedData. + * Added love.image.isCompressed and Image:isCompressed. + * Added Image/Canvas/ImageData:getDimensions. + * Added anisotropic filtering support for Images, Canvases, and Fonts. + * Added Image:refresh. + * Added Image:getData. + * Added SoundData:getDuration and SoundData:getSampleCount. + * Added Source:isPlaying. + * Added Source:setRelative and Source:isRelative. + * Added Source:setCone and Source:getCone. + * Added Source:getChannels. + * Added new Channels API for love.thread. + * Added limited table support to Channel:push. + * Added Thread:getError. + * Added Thread:isRunning. + * Added threaderror event. + * Added love.math module. + * Added a platform-independent (good) random implementation to love.math. + * Added RandomGenerator objects. + * Added BezierCurve objects. + * Added love.math.triangulate and love.math.isConvex. + * Added love.math.noise. + * Added love.timer.getAverageDelta. + * Added Data:getString. + * Added Contact:getChildren. + * Added love.system module. + * Added love.system.getClipboardText and love.system.setClipboardText. + * Added love.system.getOS and love.system.getProcessorCount. + * Added love.window module. + * Added love.window.isVisible. + * Added flags to love.window.setMode. + * Added monitor choosing support to love.window.setMode. + * Added support for resizable, borderless, and non-centered windows. + * Added support for "fullscreen-desktop" mode. + * Added window resize and visible events. + * Added love.window.getDimensions. + * Added love.window.getIcon. + * Added t.window.icon to love.conf. + * Added love.mousefocus and love.window.hasMouseFocus. + * Added custom hardware cursors via love.mouse.newCursor. + * Added love.mouse.setX/setY. + * Added Joystick objects. + * Added love.joystick.getJoystick. + * Added joystick connect and disconnect events. + * Added joystickaxis and joystickhat events. + * Added unified Gamepad API for joysticks which have a similar layout to the Xbox controller. + * Added joystick vibration support, works with most common gamepads. + * OPTIONAL: Added support for Game Music Emu. + + * Fixed fused mode in OS X. + * Fixed printing to the console in Windows before love.load is called. + * Fixed the default love.run to not include the time taken by love.load in the first frame's dt. + * Fixed the error screen not always appearing until the next input event. + * Fixed love.event.clear. + * Fixed love.mouse.setPosition when called in love.load. + * Fixed scaling in several love.physics functions. + * Fixed Box2D exception in World:update. + * Fixed many uncaught Box2D / love.physics exceptions for Bodies and Joints. + * Fixed ChainShape:getPoints running out of Lua stack space and crashing. + * Fixed File:read reading past end of file. + * Fixed love.filesystem.setIdentity not removing read access from old directories. + * Fixed possible memory leak in utf-8 decoder. + * Fixed spacing for the last character in an ImageFont. + * Fixed line wrapping in love.graphics.printf. + * Fixed love.graphics.printf to error if the wrap limit is negative. + * Fixed love.graphics.print truncating strings with embedded zeros. + * Fixed crashes with font drawing on some ATI cards. + * Fixed artifacts when drawing lines at huge scale. + * Fixed Fonts and Canvases ignoring default image filter. + * Fixed scissor boxes when a canvas is set after love.graphics.setScissor is called. + * Fixed love.graphics.getLineWidth returning incorrect values. + * Fixed love.graphics.getColor on some Windows systems. + * Fixed alpha blend mode. + * Fixed multiplicative blend mode. + * Fixed love.graphics.getPointStyle. + * Fixed line numbers in shader errors. + * Fixed Shader:send with Images and Canvases failing sometimes. + * Fixed Shader:send to keep a reference to sent Images and Canvases. + * Fixed crash when binding SpriteBatches multiple times. + * Fixed SpriteBatches with more than 16,384 sprites. + * Fixed particle draw order for ParticleSystems. + * Fixed ParticleSystem:setSizes resetting the size variation. + * Fixed the graphics viewport not matching the window size when using an unsupported fullscreen mode. + * Fixed getMode and friends returning wrong values when using desktop size. + * Fixed keyrepeat settings being lost after (indirect) setMode. + * Fixed the icon being reset after setMode. + * Fixed memory leak in the mp3 decoder. + * Fixed sound issues with some versions of OpenAL soft, by enabling direct channels. + * Fixed 'random' hangs in audio. + * Fixed love.sound.newDecoder not accepting FileData. + * Fixed case (in)sensitivity of sound file extension parsing. + * Fixed looping support in tracker music formats. + * Fixed skipping/looping issues when playing streaming audio Sources. + * Fixed race condition in Source:play. + * Fixed WAVE sound playback. + + * Moved love's startup to modules/love. + * Moved window-related functions from love.graphics to love.window. + + * Renamed love's boot script to 'love.boot', which can be required. + * Renamed love.filesystem.mkdir to love.filesystem.createDirectory. + * Renamed love.filesystem.enumerate to love.filesystem.getDirectoryItems. + * Renamed World:setAllowSleeping to World:setSleepingAllowed. + * Renamed ChainShape:setPrevVertex to ChainShape:setPreviousVertex. + * Renamed Joint:enableMotor to Joint:setMotorEnabled. + * Renamed Joint:enableLimit and Joint:isLimitEnabled to Joint:setLimitsEnabled and Joint:hasLimitsEnabled. + * Renamed t.screen to t.window in love.conf. + * Renamed love.graphics.setCaption to love.window.setTitle. + * Renamed PixelEffect to Shader (but now with vertex shaders). + * Renamed love.graphics.setDefaultImageFilter to love.graphics.setDefaultFilter. + * Renamed ParticleSystem:setSprite to ParticleSystem:setImage. + * Renamed ParticleSystem:setGravity to ParticleSystem:setLinearAcceleration. + * Renamed ParticleSystem:setLifetime/setParticleLife to setEmitter/ParticleLifetime. + * Renamed ParticleSystem:count and all getNum* functions to get*Count. + * Renamed Source:setDistance to Source:setAttenuationDistances. + * Renamed SoundData:getBits and Decoder:getBits to SoundData:getBitDepth and Decoder:getBitDepth. + * Renamed love.mouse.setGrab to love.mouse.setGrabbed. + + * Removed release mode. + * Removed love.keyboard.getKeyRepeat (see love.keyboard.hasKeyRepeat). + * Removed the unicode argument from love.keypressed (see love.textinput). + * Removed love.graphics.drawTest. + * Removed love.graphics.quad/triangle. + * Removed love.graphics.setColorMode. + * Removed love.graphics.newStencil. + * Removed love.graphics.setLine/setPoint. + * Removed love.graphics.drawq (functionality is merged into love.graphics.draw). + * Removed SpriteBatch:addq/setq (functionality is merged into SpriteBatch:add/set). + * Removed Quad:flip. + * Removed ParticleSystem:isFull/isEmpty. + * Removed ParticleSystem:getX/getY. + * Removed love.graphics.checkMode. + * Removed love.joystick.open and friends. + * Removed love.joystick module functions which operated on individual joysticks (see Joystick objects). + * Removed joystick ball support. + * Removed thread names. + * Removed old thread messaging API (see Channels). + * Removed love.timer.getMicroTime. + + * Updated functions which return love objects to re-use the Lua-side object instead of always recreating it. + * Updated the windows console, it now tries to re-use an active one first. + * Updated error handling, error handlers now get resolved when the error occurs. + * Updated order of sleep/present in love.run (now draws, *then* sleeps). + * Updated love.filesystem to try to create the appdata directory if it doesn't exist yet. + * Updated the default filesystem identity to omit file extension. + * Updated love.filesystem.newFile to optionally open the file. + * Updated most love.filesystem functions to return nil, error on internal failure. + * Updated love.keyboard.setKeyRepeat to take a boolean argument instead of numbers. + * Updated love.keypressed's second argument to be a boolean indicating key repeat. + * Updated keyboard key constants for some more modern keyboard keys. + * Updated window code to use adaptive vsync when available, if vsync is enabled. + * updated love.graphics.print's x and y arguments to default to 0. + * Updated the setFilter and setWrap methods, the second argument is now optional. + * Updated Font and ParticleSystem rendering code, now more performant. + * Updated SpriteBatch code, now more performant when adding/setting and (un)binding. + * Updated Canvas code to support more systems. + * Updated Canvas:getImageData and love.graphics.newScreenshot to be more efficient. + * Updated love.graphics.newScreenshot to create a fully opaque image by default. + * Updated error messages when sending bad values to Shaders. + * Updated love.graphics.newParticleSystem to have a default buffer size of 1000. + * Updated ImageData:setPixel to accept a table and default to 255 alpha. + * Updated ImageData:mapPixel, is now more efficient and accepts optional x,y,w,h arguments. + * Updated love.image memory handling, improves errors and thread-safety. + * Updated all love object constructors to optionally accept FileData if they accept a filename. + * Updated allocation for SoundData, it's more efficient and less wasteful. + * Updated SoundData:set/getSample to error for invalid samples. + * Updated Source:set* functions to default z to 0. + * Updated Source:seek to error for negative offsets. + * Updated Thread:start to accept arguments which get passed to the thread. + * Updated love.timer.getFPS to be microsecond-accurate. + * Updated love.timer.getTime to be microsecond-accurate and monotonic. + * Updated Box2D to version 2.3.0. + +LOVE 0.8.0 [Rubber Piggy] +------------------------- + + Released: 2012-04-02 + + * Added release error screen. + * Added alpha to love.graphics.setBackgroundColor. + * Added Canvas:clear(r, g, b, a). + * Added Canvas support to love.graphics.drawq. + * Added Canvas:getWidth and Canvas:getHeight. + * Added love.graphics.arc. + * Added seek and tell to Source objects. + * Added color interpolation to ParticleSystem. + * Added automatic PO2 padding for systems not supporting the OpenGL extension. + * Added UTF-8 support for fonts. + * Added Box2D error handling for some commonly failing functions. + * Added ability for fused release games to have their write dir in appdata. + * Added shear transformation to drawing functions. + * Added origin to font printing. + * Added love.graphics.getMode. + * Added per-sprite colors on SpriteBatches. + * Added PixelEffects. + * Added love.graphics.isSupported. + * Added love.graphics.getCanvas. + * Added love.event.quit. + * Added stencil masks. + * Added alternative SpriteBatch provider, it should work everywhere now. + * Added a loader for binary modules. + * Added Thread:getKeys. + * Added option of fractions for Quads. + * Added PNG, JPEG and GIF support to ImageData:encode. + * Added 64-bit support for Mac OS X. + * Added premultiplied blending mode. + * Added functions to set/get default image filter modes. + * Added SpriteBatch:set. + * Added new events system, with support for custom events and long event names. + * Added sound attenuation by distance. + * Added SpriteBatch:getImage. + * Added combine color mode. + * Added automatic random seeding to love.run. + * Added support for the subtract BlendMode on older graphics cards. + * Added love._os field, which contains the OS the game is running on. + + * Fixed wrapping for single words. + * Fixed tracebacks not showing filenames. + * Fixed love.graphics.push/pop capable of causing overflows/underflows. + * Fixed setScissor on Canvases. + * Fixed several issues with audio, e.g. clicks and pops in mp3s. + * Fixed crashes when bodies were destroyed during collisions. + * Fixed bound SpriteBatches corrupting when drawing. + * Fixed thread-safety issues with ImageData. + * Fixed memory leaks in audio sources. + * Fixed thread's set (previously send) accidentally changing the type. + * Fixed SoundData allocating the wrong number of samples. + * Fixed SpriteBatch support on Intel cards. + * Fixed love.filesystem.lines() leaking. + * Fixed most leaking on unclosed File objects. + * Fixed crashes when operating on non-existent files. + * Fixed a bug where empty files on windows would never reach eof. + * Fixed crash when SoundData runs out of memory. + * Fixed ordering of loaders, love should have priority over lua. + * Fixed several miscellaneous memory leaks. + * Fixed a few cases where strings with \0 in them would not be stored correctly. + * Fixed love's startup time being in the first dt. + * Fixed internal string conversions, they are faster now. + * Fixed (bad) performance of ImageData:paste. + * Fixed love.graphics.toggleFullscreen not maintaining graphics state. + + * Renamed SpriteBatch's lock/unlock to bind/unbind. + * Renamed Framebuffer to Canvas. + * Renamed love.thread.send/receive to set/get. + * Renamed love.graphics.setRenderTarget to setCanvas. + + * Removed canvas auto-clearing. + * Removed EncodedImageData. + * Removed old syntax for require (with extension). + * Removed love.graphics.setFont([file], [size]). + * Removed Thread:kill. + + * Updated love.joystick to be 1-indexed. + * Updated Sources to update more cleanly and control more intuitively. + * Updated font engine. + * Updated line drawing to a custom system. + * Updated love.timer.sleep to use seconds, like the rest of love. + * Updated love.timer to be more accurate. + * Updated love.graphics.circle to have max(10, r) as default for segments. + * Updated ImageData:encode to write to files directly. + * Updated version compatibility system to actually do something. + * Updated love.run's order, events are checked just before update. + * Updated Box2D to version 2.2.1. + +LOVE 0.7.2 [Game Slave] +----------------------- + + Released: 2011-05-04 + + * Added Framebuffer:get/setWrap. + * Added love.event.clear. + * Added support for any number of arguments to love.keyboard.isDown, love.mouse.isDown and love.joystick.isDown. + * Added SpriteBatch:setImage(). + + * Fixed fused games not working. + * Fixed ParticleSystem:setSize ignoring the variation argument. + * Fixed some file-opening exceptions not being caught. + * Fixed files loaded by libmodplug being too loud. + * Fixed paths with periods in them not working. + * Fixed love.graphics.getBlendMode not detecting subtractive and multiplicative blend modes. + * Fixed crash when there was no memory available for newImageData(w, h). + + * Updated PhysicsFS version to 2.0.2 on Windows + * Updated OpenAL Soft version to 1.13 on Windows + * Updated libmodplug version to 0.8.8.1 on Windows + * Updated FreeType version to 2.4.4 on Windows + * Updated libmpg123 version to 1.13.2 on Windows + * Windows binary no longer depends on VC2005 runtime. + * Windows binary no longer depends on SSE2 support. + +LOVE 0.7.1 [Game Slave] +----------------------- + + Released: 2011-02-14 + + * Added source:isPaused() + * Added error when initial window can't be created. + * Added framebuffer filter modes. + * Added love.filesystem.getLastModified. + * Added filter modes for ImageFonts. + * Added dead key support by using "unknown" key with correct unicode value. + * Added 0 width and height in love.conf. (for current desktop resolution) + * Added alpha support when encoding TGA images. + + * Fixed a lot of bugs regarding zero characters in threads. + * Fixed handling of a directory named "love" in current directory. + * Fixed a few unhandled errors in setScissor. + * Fixed a bug where old physics callbacks were never dereferenced. + * Fixed loss of mouse visibility settings on setMode. + * Fixed creation of a framebuffer unbinding current framebuffer. + * Fixed several race conditions in love.thread. + * Fixed 'love .', so it won't use lovedir/. as save dir. + * Fixed setLineHeight. + * Fixed extended ascii and ImageFonts. + * Fixed printf's line wrapping. + * Fixed crash when playing sounds. + * Fixed playback of mp3s with arbitrary sample rates. + * Fixed handling of negative indices in love.joystick. + * Fixed toggleFullscreen. + * Fixed unexpected behaviour with hash tables to love.graphics.line. + * Fixed mouse coordinates being capped after setMode. + * Fixed setFont's error handling on a non-existant file. + * Fixed issue where Windows builds would hard crash on Lua errors + + * Removed custom sample rates for Decoders. + +LOVE 0.7.0 [Game Slave] +----------------------- + + Released: 2010-12-05 + + * Added love.thread. + * Added love.font. + * Added love.graphics.Framebuffer. + * Added Source:play, Source:pause, etc. + * Added Source:isStatic(). + * Added get/setPosition, get/setVelocity, and get/setDirection to Source. + * Added get/setGroupIndex to CircleShape and PolygonShape. + * Added Font:getWrap. + * Added identity field to love.conf. + * Added love.quit callback. + * Added love.focus callback. + * Added extra meter parameter to love.physics.newWorld. + * Added love.graphics.setIcon. + * Added way to make the window desktop resolution. + * Added subtractive and multiplicative blend modes. + * Added body:getAllowSleeping. + * Added shape:getBody. + * Added love.filesystem.FileData for public usage. + * Added base64 support for love.filesystem.FileData. + * Added table support for love.graphics.setColor and love.graphics.setBackgroundColor. + * Added love.graphics.hasFocus(). + * Added ?/init.lua to the loader. + + * Fixed the debug module not being an upvalue of the error handlers. (you can now override debug) + * Fixed some cases when love.audio.pause and friends, were acting on everything, not just the passed Source. + * Fixed setFixedRotation enabling other flags. + * Fixed a bug in the loader (for require). + * Fixed ParticleSystem::setSprite not retaining the new image. + * Fixed setMode removing images settings (wrapping, filters). + * Fixed shape:getBody, it's now exposed for LÖVE usage. + * Fixed DistanceJoint:getType() returning "circle" - it now returns "distance". + * Fixed SpriteBatches being unaffected by setColor + * Fixed the audio bug. + * Fixed invalid FSAA values crashing LÖVE. + * Fixed a bunch of compiler warnings. + * Fixed OS X not properly using UTIs for .love files. + * Fixed the modplug decoder not properly handeling files that fail to load. + * Fixed a memory leak in setFont. + * Fixed bug where errors in threads wouldn't get picked up by demand. + * Fixed part of the bug with newlines when scaling text (rotating still messes up the lines). + * Fixed the bug where newImageFont would try to created ImageData out of ImageData. + * Fixed error handler not resetting the blend mode. + + * Changed fonts, they're now po2 safe. + * Changed the traceback in the error screen. + * Changed font origin to top-left. + * Changed linux save dir location to obey to Freedesktop.org's XDG specs. (~/.local/share/love by default.) + + * Removed font functions from love.graphics. + * Removed love.physics.newWorld(w, h). Use love.physics.newWorld(x1, y1, x2, y2) instead. + +LOVE 0.6.2 [Jiggly Juice] +------------------------- + + Released: 2010-03-06 + + * Fixed a bug causing ImageFonts to cut off some pixels. + * Fixed a bug where filled rectangles were too small. + * Fixed a bug in Image:setFilter where it would switch the parameters. + * Fixed a bug in ImageRasterizer where it wasn't using the data. + * Image filter and wrap modes now use string constants as well. + * Fixed double-transform bug in SpriteBatch. + * Errors are reported on stdout again. + * Another fix for the icons on ubuntu. + +LOVE 0.6.1 [Jiggly Juice] +------------------------- + + Released: 2010-02-07 + + * Added Shape:setGroupIndex and getGroupIndex. + * Added Body:setFixedRotation and Body:getFixedRotation. + * Added Body:setInertia. + * Added CircleShape:getLocalCenter and CircleShape:getWorldCenter. + * Added icons and file associations for the debs. + * Added the demos folder to the Mac OS X DMG. + * It's now possible to run a .love from Resources in Mac OS X, thanks to Steve Johnson. + * Fixed a bug with multiple Sources on the same Music. + * Fixed a bug so the mouse doesn't get crippled when the keyboard is disabled. + * Fixed a bug where love.graphics.rectangle drew a too large rectangle. + * Fixed a bug where memory wouldn't be released correctly. + * Fixed epic physics typo (getRestituion->getRestitution). + * Fixed crash on opening non-existent image. + * The error screen redraws when an event occurs. + * The default love.run() now gracefully handles disabled modules. + * The debian packages should now successfully include icons, file associations, etc, and should give the correct architecture. + * Added support for drawing polylines to love.graphics.line - the syntax is the same as love.graphics.polygon. + * Removed Music and Sound. There are now only sources. + * Improved the stability of love.audio/love.sound. + +LOVE 0.6.0 [Jiggly Juice] +------------------------- + + Released: 2009-12-24 + + * Lost track of 0.6.0 changes a long while ago. Don't trust the list below. + + * Added love.graphics.print()/printf(). + * Added unicode-translated parameter to love.keypressed(). + * Added love.event. + * Added love.filesystem.setIdentity(). + * Added OpenAL dependency. + + * Fixed love.fileystem problems with internal \0 in strings. + * Fixed love.filesystem.mkdir/remove not working when write directory not set. + * Fixed position of Window. + + * Changed parameter order of draws(). + * Changed origin for images to top-left. + * Changed love.filesystem.open to accept mode (removed from love.filesystem.newFile). + * Changed love.filesystem.read() which now returns two parameters (data, length). + * Changed love.filesystem.write() which now takes up to four parameters (file, data, length, mode). + * Changed default color mode to "modulate". + * Changed name of love.color_normal to "replace". + * Changed name of love.blend_normal to "alpha". + * Changed the conf file format. + + * Removed Color object. + * Removed Animation. + * Removed several constants. + * Removed love.graphics.draw() for strings. + * Removed love.system. + * Removed SWIG. + * Removed boost. + * Removed SDL_mixer. + + +LOVE 0.5.0 [Salted Nuts] +------------------------ + + Released: 2009-01-02 + + * Added love.joystick. + * Added network support via LuaSocket. + * Added support for loading of appended .love-file. + + * Added love.filesystem.lines(). + * Added a loader function to enable use of normal require(). + * Added love.filesystem.load(). + * Added love.filesystem.getSaveDirectory() + * Added love.filesystem.getWorkingDirectory() + + * Added optional explicit destruction of Box2D objects. + * Added shape:testSegment(). + * Added love.graphics.screenshot() (.bmp only). + * Added default size (12) to font-related functions. + * Added love.graphics.setFont( filename, size ) + * Added love.graphics.setLineStippe and related functions. + * Added love.graphics.setPointSize and related functions. + + * Changed love.filesystem.read() to accept file name. + * Changed love.filesystem.write() to accept file name. + * Changed love.graphics.triangle() to accept CCW and CW ordering. + + * Fixed love.graphics.read adding bogus characters at the end of string. + * Fixed epic swigfusion bug. + * Fixed love.graphics.getFont so it returns nil if no font is present. + * Fixed bug where love.graphics.getBlendMode() always returns blend_normal. + * Fixed bug which caused error screen to be scissored (when enabled). + * Fixed Body:setAngle to accept degrees like everything else. + + * Cleaned up love::File and love_physfs. + * Cleaned up love::Reference so it stores its reference in _G. + +LOVE 0.4.0 [Taco Beam] +---------------------- + + Released: 2008-08-29 + + * Added love.physics. (YES!) + * Added love.audio.setMode(). + * Added love.audio.setChannels(). + * Added love.graphics.polygon(). + * Added love.graphics.setScissor() and love.graphics.getScissor() to handle scissoring the graphical area. + * Fixed missing constants related to image optimization. + * Fixed memory leak related to love::File (thanks amnesiasoft!). + + +LOVE 0.3.2 [Lemony Fresh] +------------------------- + + Released: 2008-07-04 + + * Added love.graphics.rectangle() + * Added love.graphics.setLineWidth() + * Added love.graphics.setLineStyle() + * Added love.graphics.getLineWidth() + * Added love.graphics.getLineStyle() + * Added love.mouse.getPosition() + * Added love.audio_loop + * Added love.timer.getTime() + * Changed love.graphics.quad() to accept CCW and CW ordering. + * Fixed default color mode bug. + * Fixed line width being applied unnecessarily. + * Fixed line width bug related to fullscreen toggle. + * Fixed music not looping. + +LOVE 0.3.1 [Space Meat] +----------------------- + + Released: 2008-06-21 + + * Fixed segfault related to graphics. + * Fixed wait-forever bug related to audio. + * Fixed error reporting not working across modules. + * Fixed bug where games with a trailing "/" would not start. + * Fixed bug which caused love.timer.sleep to delay for (way) too long. + +LOVE 0.3.0 [Mutant Vermin] +-------------------------- + + Released: 2008-06-17 + + * Added ParticleSystem. + * Added visual error reporting. + * Added love.system for game control needs. + * Added input grabbing. + * Added functions in love.graphics for display management. + * Added love.graphics.point(). + * Added functions in love.graphics for getting current color, font, etc. + * Added love.filesystem.enumerate() for getting folder contents. + * Added functions for setting the window caption. + * Added version checking. An error occurs if the game is incompatible. + * Fixed print() :) + * Removed all keyboard shortcuts. + * Save folders are now created only if required. + * On Windows, the new save location is %APPDATA%\LOVE\game + +LOVE 0.2.1 [Impending Doom] +--------------------------- + + Released: 2008-03-29 + + * Added many functions in love.filesystem. + * Added a dedicated save-folder for each game. + * Added timer.sleep. + * Added line heights to font objects. + * Added love.graphics.getWidth/getHeight. + * Added scaling and rotation for text. + * Added variable spacing to ImageFont. + * Added support for variable line quality when drawing primitives. + * Added several functions for drawing sections of images. (love.graphics.draws) + * Added image optimization function and padding function. + * Added love.graphics.getWidth/Height. + + * Split devices up into actual SWIG-modules. This means that: + - Functions are used like this: love.graphics.draw, not love.graphics:draw + - love.objects is no more. Objects are created by an appropriate device. + * How you draw primitives has been altered. + * draw(string, x, y, wrap, align) has become drawf(string, x, y, wrap, align) + + * Changed getFps to getFPS. + * Escape is no more ... enter: Alt+F4. + * love.filesystem.include has been renamed to love.filesystem.require. + * ImageFonts now consider the spacing as well as the glyph size. + * Fixed a massive ImageFont bug which resulted in float-positioning failure. + * Fixed a bug when loading fonts where the specified size doesn't represent the true size of the font. + + * Updated DevIL to version 1.6.8-rc2 (Windows) + * Updated FreeType to freetype-2.3.5-1 (Windows) + * Updated Lua to 5.1.3 (Windows) + * Updated SDL to 1.2.13 (Windows) + * Removed boost::filesystem. + +LOVE 0.2.0 [Mini-Moose] +----------------------- + + Released: 2008-02-06 + + * Added ImageFont + * Added Animation + * Added text formatting functions + * Added setCenter for Image and Animation. + * Added methods for rendering of scaled/rotated sprites. + * Added the drawing of basic shapes. + * Added default font and embedded resources. + * Added Ctrl+R for reload. + * Added blending and color modes. + * Fixed memory usage of Graphics. + * Fixed a bug where the set text color would change the color of any images rendered. + * Fixed CWD bug. + * Fixed titlebar. Game title is now displayed. + + +LOVE 0.1.1 [Santa-Power] +------------------------ + + Initial release! + Released: 2008-01-13 + + * Image loading and rendering. + * Sound loading and playing. + * Font loading and rendering. + * Lua-scriptable games. + * Config files. + * Stuff is loadable from archive files. + * Keyboard, mouse, display, timer, etc. (Basic devices). diff --git a/game.ico b/game.ico new file mode 100644 index 0000000..ecc5c0d Binary files /dev/null and b/game.ico differ diff --git a/game/GuiManagerDebug/Core/Clickable.int b/game/GuiManager/Core/Clickable.int similarity index 100% rename from game/GuiManagerDebug/Core/Clickable.int rename to game/GuiManager/Core/Clickable.int diff --git a/game/GuiManagerDebug/Core/Colors.int b/game/GuiManager/Core/Colors.int similarity index 100% rename from game/GuiManagerDebug/Core/Colors.int rename to game/GuiManager/Core/Colors.int diff --git a/game/GuiManagerDebug/Core/DrawThings.int b/game/GuiManager/Core/DrawThings.int similarity index 100% rename from game/GuiManagerDebug/Core/DrawThings.int rename to game/GuiManager/Core/DrawThings.int diff --git a/game/GuiManagerDebug/Core/EventDefinitions.int b/game/GuiManager/Core/EventDefinitions.int similarity index 100% rename from game/GuiManagerDebug/Core/EventDefinitions.int rename to game/GuiManager/Core/EventDefinitions.int diff --git a/game/GuiManagerDebug/Core/UpdateThings.int b/game/GuiManager/Core/UpdateThings.int similarity index 100% rename from game/GuiManagerDebug/Core/UpdateThings.int rename to game/GuiManager/Core/UpdateThings.int diff --git a/game/GuiManagerDebug/Core/_GetAllChildren.int b/game/GuiManager/Core/_GetAllChildren.int similarity index 100% rename from game/GuiManagerDebug/Core/_GetAllChildren.int rename to game/GuiManager/Core/_GetAllChildren.int diff --git a/game/GuiManagerDebug/Core/_GetAllChildren2.int b/game/GuiManager/Core/_GetAllChildren2.int similarity index 100% rename from game/GuiManagerDebug/Core/_GetAllChildren2.int rename to game/GuiManager/Core/_GetAllChildren2.int diff --git a/game/GuiManagerDebug/Core/eventable.int b/game/GuiManager/Core/eventable.int similarity index 100% rename from game/GuiManagerDebug/Core/eventable.int rename to game/GuiManager/Core/eventable.int diff --git a/game/GuiManagerDebug/Core/full.int b/game/GuiManager/Core/full.int similarity index 100% rename from game/GuiManagerDebug/Core/full.int rename to game/GuiManager/Core/full.int diff --git a/game/GuiManagerDebug/Core/newBase.int b/game/GuiManager/Core/newBase.int similarity index 99% rename from game/GuiManagerDebug/Core/newBase.int rename to game/GuiManager/Core/newBase.int index bb75483..ad4b096 100644 --- a/game/GuiManagerDebug/Core/newBase.int +++ b/game/GuiManager/Core/newBase.int @@ -42,7 +42,6 @@ function gui:newBase(tp,name, x, y, w, h, sx ,sy ,sw ,sh) c:SetName(name) c.BorderSize=1 c.BorderColor={0,0,0} - c.BorderVisibility=1 c.VIS=true c.Visible=true c.oV=true diff --git a/game/GuiManagerDebug/Core/patches.int b/game/GuiManager/Core/patches.int similarity index 100% rename from game/GuiManagerDebug/Core/patches.int rename to game/GuiManager/Core/patches.int diff --git a/game/GuiManagerDebug/Core/touchManager.int b/game/GuiManager/Core/touchManager.int similarity index 100% rename from game/GuiManagerDebug/Core/touchManager.int rename to game/GuiManager/Core/touchManager.int diff --git a/game/GuiManagerDebug/Drawing/AddDrawRuleB.int b/game/GuiManager/Drawing/AddDrawRuleB.int similarity index 100% rename from game/GuiManagerDebug/Drawing/AddDrawRuleB.int rename to game/GuiManager/Drawing/AddDrawRuleB.int diff --git a/game/GuiManagerDebug/Drawing/AddDrawRuleE.int b/game/GuiManager/Drawing/AddDrawRuleE.int similarity index 100% rename from game/GuiManagerDebug/Drawing/AddDrawRuleE.int rename to game/GuiManager/Drawing/AddDrawRuleE.int diff --git a/game/GuiManagerDebug/Drawing/draw.int b/game/GuiManager/Drawing/draw.int similarity index 100% rename from game/GuiManagerDebug/Drawing/draw.int rename to game/GuiManager/Drawing/draw.int diff --git a/game/GuiManagerDebug/Drawing/drawC.int b/game/GuiManager/Drawing/drawC.int similarity index 98% rename from game/GuiManagerDebug/Drawing/drawC.int rename to game/GuiManager/Drawing/drawC.int index 22782ed..84592b5 100644 --- a/game/GuiManagerDebug/Drawing/drawC.int +++ b/game/GuiManager/Drawing/drawC.int @@ -71,7 +71,7 @@ function gui:drawC() 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) + 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 diff --git a/game/GuiManagerDebug/Drawing/drawR.int b/game/GuiManager/Drawing/drawR.int similarity index 94% rename from game/GuiManagerDebug/Drawing/drawR.int rename to game/GuiManager/Drawing/drawR.int index ad4297b..33a1d0c 100644 --- a/game/GuiManagerDebug/Drawing/drawR.int +++ b/game/GuiManager/Drawing/drawR.int @@ -67,10 +67,10 @@ function gui:drawR() _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 + 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() @@ -78,10 +78,10 @@ function gui:drawR() 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) + 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 diff --git a/game/GuiManagerDebug/Frame/newDropFrame.int b/game/GuiManager/Frame/newDropFrame.int similarity index 100% rename from game/GuiManagerDebug/Frame/newDropFrame.int rename to game/GuiManager/Frame/newDropFrame.int diff --git a/game/GuiManagerDebug/Frame/newFrame.int b/game/GuiManager/Frame/newFrame.int similarity index 100% rename from game/GuiManagerDebug/Frame/newFrame.int rename to game/GuiManager/Frame/newFrame.int diff --git a/game/GuiManagerDebug/Frame/newFullFrame.int b/game/GuiManager/Frame/newFullFrame.int similarity index 100% rename from game/GuiManagerDebug/Frame/newFullFrame.int rename to game/GuiManager/Frame/newFullFrame.int diff --git a/game/GuiManagerDebug/Frame/newTabFrame.int b/game/GuiManager/Frame/newTabFrame.int similarity index 100% rename from game/GuiManagerDebug/Frame/newTabFrame.int rename to game/GuiManager/Frame/newTabFrame.int diff --git a/game/GuiManagerDebug/Frame/newratioFrame.int b/game/GuiManager/Frame/newratioFrame.int similarity index 100% rename from game/GuiManagerDebug/Frame/newratioFrame.int rename to game/GuiManager/Frame/newratioFrame.int diff --git a/game/GuiManagerDebug/Image-Animation/SetImage.int b/game/GuiManager/Image-Animation/SetImage.int similarity index 100% rename from game/GuiManagerDebug/Image-Animation/SetImage.int rename to game/GuiManager/Image-Animation/SetImage.int diff --git a/game/GuiManagerDebug/Image-Animation/UpdateImage.int b/game/GuiManager/Image-Animation/UpdateImage.int similarity index 100% rename from game/GuiManagerDebug/Image-Animation/UpdateImage.int rename to game/GuiManager/Image-Animation/UpdateImage.int diff --git a/game/GuiManagerDebug/Image-Animation/getTile.int b/game/GuiManager/Image-Animation/getTile.int similarity index 100% rename from game/GuiManagerDebug/Image-Animation/getTile.int rename to game/GuiManager/Image-Animation/getTile.int diff --git a/game/GuiManagerDebug/Image-Animation/newAnim.int b/game/GuiManager/Image-Animation/newAnim.int similarity index 100% rename from game/GuiManagerDebug/Image-Animation/newAnim.int rename to game/GuiManager/Image-Animation/newAnim.int diff --git a/game/GuiManagerDebug/Image-Animation/newAnimFromData.int b/game/GuiManager/Image-Animation/newAnimFromData.int similarity index 100% rename from game/GuiManagerDebug/Image-Animation/newAnimFromData.int rename to game/GuiManager/Image-Animation/newAnimFromData.int diff --git a/game/GuiManagerDebug/Image-Animation/newAnimFromTiles.int b/game/GuiManager/Image-Animation/newAnimFromTiles.int similarity index 100% rename from game/GuiManagerDebug/Image-Animation/newAnimFromTiles.int rename to game/GuiManager/Image-Animation/newAnimFromTiles.int diff --git a/game/GuiManagerDebug/Image-Animation/newFullImageLabel.int b/game/GuiManager/Image-Animation/newFullImageLabel.int similarity index 100% rename from game/GuiManagerDebug/Image-Animation/newFullImageLabel.int rename to game/GuiManager/Image-Animation/newFullImageLabel.int diff --git a/game/GuiManagerDebug/Image-Animation/newImageButton.int b/game/GuiManager/Image-Animation/newImageButton.int similarity index 100% rename from game/GuiManagerDebug/Image-Animation/newImageButton.int rename to game/GuiManager/Image-Animation/newImageButton.int diff --git a/game/GuiManagerDebug/Image-Animation/newImageLabel.int b/game/GuiManager/Image-Animation/newImageLabel.int similarity index 100% rename from game/GuiManagerDebug/Image-Animation/newImageLabel.int rename to game/GuiManager/Image-Animation/newImageLabel.int diff --git a/game/GuiManagerDebug/Image-Animation/newVideo.int b/game/GuiManager/Image-Animation/newVideo.int similarity index 100% rename from game/GuiManagerDebug/Image-Animation/newVideo.int rename to game/GuiManager/Image-Animation/newVideo.int diff --git a/game/GuiManagerDebug/Item/newDragItem.int b/game/GuiManager/Item/newDragItem.int similarity index 100% rename from game/GuiManagerDebug/Item/newDragItem.int rename to game/GuiManager/Item/newDragItem.int diff --git a/game/GuiManagerDebug/Item/newItem.int b/game/GuiManager/Item/newItem.int similarity index 100% rename from game/GuiManagerDebug/Item/newItem.int rename to game/GuiManager/Item/newItem.int diff --git a/game/GuiManagerDebug/Misc/AdvTextBox.int b/game/GuiManager/Misc/AdvTextBox.int similarity index 100% rename from game/GuiManagerDebug/Misc/AdvTextBox.int rename to game/GuiManager/Misc/AdvTextBox.int diff --git a/game/GuiManagerDebug/Misc/ApplyGradient.int b/game/GuiManager/Misc/ApplyGradient.int similarity index 100% rename from game/GuiManagerDebug/Misc/ApplyGradient.int rename to game/GuiManager/Misc/ApplyGradient.int diff --git a/game/GuiManagerDebug/Misc/BottomStack.int b/game/GuiManager/Misc/BottomStack.int similarity index 100% rename from game/GuiManagerDebug/Misc/BottomStack.int rename to game/GuiManager/Misc/BottomStack.int diff --git a/game/GuiManagerDebug/Misc/Center.int b/game/GuiManager/Misc/Center.int similarity index 100% rename from game/GuiManagerDebug/Misc/Center.int rename to game/GuiManager/Misc/Center.int diff --git a/game/GuiManagerDebug/Misc/Destroy.int b/game/GuiManager/Misc/Destroy.int similarity index 100% rename from game/GuiManagerDebug/Misc/Destroy.int rename to game/GuiManager/Misc/Destroy.int diff --git a/game/GuiManagerDebug/Misc/GetAllChildren.int b/game/GuiManager/Misc/GetAllChildren.int similarity index 100% rename from game/GuiManagerDebug/Misc/GetAllChildren.int rename to game/GuiManager/Misc/GetAllChildren.int diff --git a/game/GuiManagerDebug/Misc/GetChild.int b/game/GuiManager/Misc/GetChild.int similarity index 100% rename from game/GuiManagerDebug/Misc/GetChild.int rename to game/GuiManager/Misc/GetChild.int diff --git a/game/GuiManagerDebug/Misc/InGrid.int b/game/GuiManager/Misc/InGrid.int similarity index 100% rename from game/GuiManagerDebug/Misc/InGrid.int rename to game/GuiManager/Misc/InGrid.int diff --git a/game/GuiManagerDebug/Misc/InGridX.int b/game/GuiManager/Misc/InGridX.int similarity index 100% rename from game/GuiManagerDebug/Misc/InGridX.int rename to game/GuiManager/Misc/InGridX.int diff --git a/game/GuiManagerDebug/Misc/InGridY.int b/game/GuiManager/Misc/InGridY.int similarity index 100% rename from game/GuiManagerDebug/Misc/InGridY.int rename to game/GuiManager/Misc/InGridY.int diff --git a/game/GuiManagerDebug/Misc/IsHovering.int b/game/GuiManager/Misc/IsHovering.int similarity index 100% rename from game/GuiManagerDebug/Misc/IsHovering.int rename to game/GuiManager/Misc/IsHovering.int diff --git a/game/GuiManagerDebug/Misc/Move.int b/game/GuiManager/Misc/Move.int similarity index 100% rename from game/GuiManagerDebug/Misc/Move.int rename to game/GuiManager/Misc/Move.int diff --git a/game/GuiManagerDebug/Misc/SetDualDim.int b/game/GuiManager/Misc/SetDualDim.int similarity index 100% rename from game/GuiManagerDebug/Misc/SetDualDim.int rename to game/GuiManager/Misc/SetDualDim.int diff --git a/game/GuiManagerDebug/Misc/SetHand.int b/game/GuiManager/Misc/SetHand.int similarity index 100% rename from game/GuiManagerDebug/Misc/SetHand.int rename to game/GuiManager/Misc/SetHand.int diff --git a/game/GuiManagerDebug/Misc/SetHover.int b/game/GuiManager/Misc/SetHover.int similarity index 100% rename from game/GuiManagerDebug/Misc/SetHover.int rename to game/GuiManager/Misc/SetHover.int diff --git a/game/GuiManagerDebug/Misc/SetName.int b/game/GuiManager/Misc/SetName.int similarity index 100% rename from game/GuiManagerDebug/Misc/SetName.int rename to game/GuiManager/Misc/SetName.int diff --git a/game/GuiManagerDebug/Misc/TopStack.int b/game/GuiManager/Misc/TopStack.int similarity index 100% rename from game/GuiManagerDebug/Misc/TopStack.int rename to game/GuiManager/Misc/TopStack.int diff --git a/game/GuiManagerDebug/Misc/addDominance.int b/game/GuiManager/Misc/addDominance.int similarity index 100% rename from game/GuiManagerDebug/Misc/addDominance.int rename to game/GuiManager/Misc/addDominance.int diff --git a/game/GuiManagerDebug/Misc/addHotKey.int b/game/GuiManager/Misc/addHotKey.int similarity index 100% rename from game/GuiManagerDebug/Misc/addHotKey.int rename to game/GuiManager/Misc/addHotKey.int diff --git a/game/GuiManagerDebug/Misc/alphanumsort.int b/game/GuiManager/Misc/alphanumsort.int similarity index 100% rename from game/GuiManagerDebug/Misc/alphanumsort.int rename to game/GuiManager/Misc/alphanumsort.int diff --git a/game/GuiManagerDebug/Misc/anchorRight.int b/game/GuiManager/Misc/anchorRight.int similarity index 100% rename from game/GuiManagerDebug/Misc/anchorRight.int rename to game/GuiManager/Misc/anchorRight.int diff --git a/game/GuiManagerDebug/Misc/centerX.int b/game/GuiManager/Misc/centerX.int similarity index 100% rename from game/GuiManagerDebug/Misc/centerX.int rename to game/GuiManager/Misc/centerX.int diff --git a/game/GuiManagerDebug/Misc/centerY.int b/game/GuiManager/Misc/centerY.int similarity index 100% rename from game/GuiManagerDebug/Misc/centerY.int rename to game/GuiManager/Misc/centerY.int diff --git a/game/GuiManagerDebug/Misc/disrespectHierarchy.int b/game/GuiManager/Misc/disrespectHierarchy.int similarity index 100% rename from game/GuiManagerDebug/Misc/disrespectHierarchy.int rename to game/GuiManager/Misc/disrespectHierarchy.int diff --git a/game/GuiManagerDebug/Misc/getChildren.int b/game/GuiManager/Misc/getChildren.int similarity index 100% rename from game/GuiManagerDebug/Misc/getChildren.int rename to game/GuiManager/Misc/getChildren.int diff --git a/game/GuiManagerDebug/Misc/getColor.int b/game/GuiManager/Misc/getColor.int similarity index 100% rename from game/GuiManagerDebug/Misc/getColor.int rename to game/GuiManager/Misc/getColor.int diff --git a/game/GuiManagerDebug/Misc/getFullSize.int b/game/GuiManager/Misc/getFullSize.int similarity index 100% rename from game/GuiManagerDebug/Misc/getFullSize.int rename to game/GuiManager/Misc/getFullSize.int diff --git a/game/GuiManagerDebug/Misc/getHighest.int b/game/GuiManager/Misc/getHighest.int similarity index 100% rename from game/GuiManagerDebug/Misc/getHighest.int rename to game/GuiManager/Misc/getHighest.int diff --git a/game/GuiManagerDebug/Misc/getLowest.int b/game/GuiManager/Misc/getLowest.int similarity index 100% rename from game/GuiManagerDebug/Misc/getLowest.int rename to game/GuiManager/Misc/getLowest.int diff --git a/game/GuiManagerDebug/Misc/isDescendant.int b/game/GuiManager/Misc/isDescendant.int similarity index 100% rename from game/GuiManagerDebug/Misc/isDescendant.int rename to game/GuiManager/Misc/isDescendant.int diff --git a/game/GuiManagerDebug/Misc/isHighest.int b/game/GuiManager/Misc/isHighest.int similarity index 100% rename from game/GuiManagerDebug/Misc/isHighest.int rename to game/GuiManager/Misc/isHighest.int diff --git a/game/GuiManagerDebug/Misc/isLowest.int b/game/GuiManager/Misc/isLowest.int similarity index 100% rename from game/GuiManagerDebug/Misc/isLowest.int rename to game/GuiManager/Misc/isLowest.int diff --git a/game/GuiManagerDebug/Misc/massMutate.int b/game/GuiManager/Misc/massMutate.int similarity index 100% rename from game/GuiManagerDebug/Misc/massMutate.int rename to game/GuiManager/Misc/massMutate.int diff --git a/game/GuiManagerDebug/Misc/newCheckBox.int b/game/GuiManager/Misc/newCheckBox.int similarity index 100% rename from game/GuiManagerDebug/Misc/newCheckBox.int rename to game/GuiManager/Misc/newCheckBox.int diff --git a/game/GuiManagerDebug/Misc/newMessageBox.int b/game/GuiManager/Misc/newMessageBox.int similarity index 100% rename from game/GuiManagerDebug/Misc/newMessageBox.int rename to game/GuiManager/Misc/newMessageBox.int diff --git a/game/GuiManagerDebug/Misc/newPart.int b/game/GuiManager/Misc/newPart.int similarity index 100% rename from game/GuiManagerDebug/Misc/newPart.int rename to game/GuiManager/Misc/newPart.int diff --git a/game/GuiManagerDebug/Misc/newProgressBar.int b/game/GuiManager/Misc/newProgressBar.int similarity index 100% rename from game/GuiManagerDebug/Misc/newProgressBar.int rename to game/GuiManager/Misc/newProgressBar.int diff --git a/game/GuiManagerDebug/Misc/newScrollBar.int b/game/GuiManager/Misc/newScrollBar.int similarity index 100% rename from game/GuiManagerDebug/Misc/newScrollBar.int rename to game/GuiManager/Misc/newScrollBar.int diff --git a/game/GuiManagerDebug/Misc/newScrollMenu.int b/game/GuiManager/Misc/newScrollMenu.int similarity index 100% rename from game/GuiManagerDebug/Misc/newScrollMenu.int rename to game/GuiManager/Misc/newScrollMenu.int diff --git a/game/GuiManagerDebug/Misc/removeAllChildren.int b/game/GuiManager/Misc/removeAllChildren.int similarity index 100% rename from game/GuiManagerDebug/Misc/removeAllChildren.int rename to game/GuiManager/Misc/removeAllChildren.int diff --git a/game/GuiManagerDebug/Misc/removeDominance.int b/game/GuiManager/Misc/removeDominance.int similarity index 100% rename from game/GuiManagerDebug/Misc/removeDominance.int rename to game/GuiManager/Misc/removeDominance.int diff --git a/game/GuiManagerDebug/Misc/respectHierarchy.int b/game/GuiManager/Misc/respectHierarchy.int similarity index 100% rename from game/GuiManagerDebug/Misc/respectHierarchy.int rename to game/GuiManager/Misc/respectHierarchy.int diff --git a/game/GuiManagerDebug/Misc/round.int b/game/GuiManager/Misc/round.int similarity index 100% rename from game/GuiManagerDebug/Misc/round.int rename to game/GuiManager/Misc/round.int diff --git a/game/GuiManagerDebug/Misc/setBG.int b/game/GuiManager/Misc/setBG.int similarity index 100% rename from game/GuiManagerDebug/Misc/setBG.int rename to game/GuiManager/Misc/setBG.int diff --git a/game/GuiManagerDebug/Misc/setColor.int b/game/GuiManager/Misc/setColor.int similarity index 100% rename from game/GuiManagerDebug/Misc/setColor.int rename to game/GuiManager/Misc/setColor.int diff --git a/game/GuiManagerDebug/Misc/setDefualtFont.int b/game/GuiManager/Misc/setDefualtFont.int similarity index 100% rename from game/GuiManagerDebug/Misc/setDefualtFont.int rename to game/GuiManager/Misc/setDefualtFont.int diff --git a/game/GuiManagerDebug/Misc/setHotKey.int b/game/GuiManager/Misc/setHotKey.int similarity index 100% rename from game/GuiManagerDebug/Misc/setHotKey.int rename to game/GuiManager/Misc/setHotKey.int diff --git a/game/GuiManagerDebug/Misc/setNewFont.int b/game/GuiManager/Misc/setNewFont.int similarity index 100% rename from game/GuiManagerDebug/Misc/setNewFont.int rename to game/GuiManager/Misc/setNewFont.int diff --git a/game/GuiManagerDebug/Misc/setParent.int b/game/GuiManager/Misc/setParent.int similarity index 100% rename from game/GuiManagerDebug/Misc/setParent.int rename to game/GuiManager/Misc/setParent.int diff --git a/game/GuiManagerDebug/Misc/setVisibility.int b/game/GuiManager/Misc/setVisibility.int similarity index 100% rename from game/GuiManagerDebug/Misc/setVisibility.int rename to game/GuiManager/Misc/setVisibility.int diff --git a/game/GuiManagerDebug/Misc/setgetText.int b/game/GuiManager/Misc/setgetText.int similarity index 100% rename from game/GuiManagerDebug/Misc/setgetText.int rename to game/GuiManager/Misc/setgetText.int diff --git a/game/GuiManagerDebug/Text/newTextBox.int b/game/GuiManager/Text/newTextBox.int similarity index 98% rename from game/GuiManagerDebug/Text/newTextBox.int rename to game/GuiManager/Text/newTextBox.int index b243ca7..c98b847 100644 --- a/game/GuiManagerDebug/Text/newTextBox.int +++ b/game/GuiManager/Text/newTextBox.int @@ -28,7 +28,7 @@ function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh) c.mark=nil c.arrowkeys=false c.funcF={function() - love.keyboard.setTextInput(true) + love.keyboard.setTextInput(true,0,200,400,200) end} c.cooldown=false c.cooldown2=false diff --git a/game/GuiManagerDebug/Text/newTextButton.int b/game/GuiManager/Text/newTextButton.int similarity index 100% rename from game/GuiManagerDebug/Text/newTextButton.int rename to game/GuiManager/Text/newTextButton.int diff --git a/game/GuiManagerDebug/Text/newTextLabel.int b/game/GuiManager/Text/newTextLabel.int similarity index 100% rename from game/GuiManagerDebug/Text/newTextLabel.int rename to game/GuiManager/Text/newTextLabel.int diff --git a/game/GuiManagerDebug/init.lua b/game/GuiManager/init.lua similarity index 92% rename from game/GuiManagerDebug/init.lua rename to game/GuiManager/init.lua index 2060ee7..7980f37 100644 --- a/game/GuiManagerDebug/init.lua +++ b/game/GuiManager/init.lua @@ -14,7 +14,7 @@ function gui:LoadInterface(file) if love.filesystem.exists(file..add) then a,b=pcall(love.filesystem.load(file..add)) if a then - print("Loaded: "..file) + --print("Loaded: "..file) else print("Error loading file: "..file) print(a,b) @@ -34,7 +34,6 @@ function gui.LoadAll(dir) end -- Start Of Load ---gui.LoadAll("GuiManager/LibCore") gui.LoadAll("GuiManager/Core") gui.LoadAll("GuiManager/Image-Animation") gui.LoadAll("GuiManager/Frame") @@ -42,8 +41,7 @@ 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 diff --git a/game/Interface/colorpicker.int b/game/Interface/colorpicker.int new file mode 100644 index 0000000..2c58170 --- /dev/null +++ b/game/Interface/colorpicker.int @@ -0,0 +1,5 @@ +function gui:newColorPicker(x,y,w) + local c=self:newFrame("ColorPicker",x,y,w,w) + c.wheel=c:newImageLabel("Resources/wheel.png","Wheel",0,0,w,w) + return c +end \ No newline at end of file diff --git a/game/Interface/console.int b/game/Interface/console.int new file mode 100644 index 0000000..b05bba4 --- /dev/null +++ b/game/Interface/console.int @@ -0,0 +1,40 @@ +function gui:newConsole(x,y,w,h) + local c=self:newTextLabel("Console","Console",x,y,w,20,sx,sy,sw) + c.dragbut="l" + c.Draggable=true + c.Tween=-3 + c.BG=c:newTextLabel("","",0,20,0,h,0,0,1,1) + c.BG.ClipDescendants=true + c.output=c.BG:newTextLabel("","",0,0,0,0,0,0,1,1) + c.output.Visibility=0 + c.scroll=c.BG:newScrollBar() + c.scroll.output=c.output + c.output.Tween=-3 + c.output.TextColor=Color.sexy_purple + c.input=c:newTextBox("> ","> ",0,h+20,-20,20,0,0,1) + c.input.Tween=-3 + c.input.TextFormat="left" + c.output.TextFormat="left" + c.output.count=0 + c:ApplyGradient({Color.Red,Color.Darken(Color.Red,.25)}) + c.BG:ApplyGradient({Color.Black,Color.Lighten(Color.Black,.15)}) + c.input:ApplyGradient({Color.Gray,Color.Darken(Color.Gray,.25)}) + c.scroll:OnScroll(function(self,pos) + self.output:SetDualDim(0,0,0,0,0,-((pos/(h*8))*self.output.count)) + end) + c.input:OnEnter(function(self,text) + self.Parent.output.text=self.Parent.output.text..text.."\n" + self.text="> " + self.Parent.output.count=self.Parent.output.count+1 + end) + c.input:OnFocus(function(self) + self.text="> " + end) + function c:showConsole() + self.Parent.Visible=true + end + function c:hideConsole() + self.Parent.Visible=false + end + return c +end diff --git a/game/Interface/header.int b/game/Interface/header.int new file mode 100644 index 0000000..3d6f2be --- /dev/null +++ b/game/Interface/header.int @@ -0,0 +1,81 @@ +function gui:newHeader() + local header=self:newFrame(0,0,0,20,0,0,1) + header:ApplyGradient({Color.white,Color.light_blue,Color.blue,trans=200}) + header.last={x=0,width=0} + function header:newTab(name) + local font=love.graphics.getFont() + local tab=self:newTextButton(name,self.last.x+self.last.width,0,font:getWidth(name)+6,20) + self.last=tab + tab.Visibility=0 + tab.Tween=-3 + tab.XTween=-2 + tab.Color=Color.white + tab.largest={x=0,width=0} + tab.Options=tab:newFrame("Options",0,20) + tab.Options.Visible=false + tab.Options.Color=Color.light_gray + tab:OnEnter(function(self) + self.Visibility=.5 + end) + tab:OnExit(function(self) + self.Visibility=0 + end) + tab:OnReleased(function(b,self) + if b=="l" then + self.Options.Visible=true + self:addDominance() + end + end) + tab.Options:OnExit(function(self) + self.Visible=false + self:removeDominance() + end) + function tab:newOption(name,func,HK) + local opt=self.Options:newTextButton(name,0,#self.Options:getChildren()*20,0,20,0,0,1) + if HK then + if type(HK)=="table" then + for i=1,#HK do + opt:addHotKey(HK[i]):OnHotKey(func) + name=name.."\t\t\t\t\t\t" + local temp=opt:newTextLabel(HK[i],-(font:getWidth(HK[i])+2),0,font:getWidth(HK[i])+2,20,1) + temp.Visibility=0 + temp.Tween=-3 + temp.XTween=-2 + opt.text=name + end + else + opt:setHotKey(HK) + opt:OnHotKey(func) + name=name.."\t\t\t\t\t\t" + local temp=opt:newTextLabel(HK,-(font:getWidth(HK)+2),0,font:getWidth(HK)+2,20,1) + temp.Visibility=0 + temp.Tween=-3 + temp.XTween=-2 + opt.text=name + end + end + opt.TextFormat="left" + opt.Visibility=0 + opt.Color=Color.white + opt.Tween=-3 + opt:OnEnter(function(self) + self.Visibility=.5 + end) + opt:OnExit(function(self) + self.Visibility=0 + end) + local font=love.graphics.getFont() + local c=self:getChildren() + if font:getWidth(name)+6>self.largest.width then + self.largest={width=font:getWidth(name)+6} + end + self.Options:SetDualDim(0,20,self.largest.width,#self.Options:getChildren()*20) + if func then + opt:OnReleased(func) + end + return opt + end + return tab + end + return header +end \ No newline at end of file diff --git a/game/Interface/player.int b/game/Interface/player.int new file mode 100644 index 0000000..91fa354 --- /dev/null +++ b/game/Interface/player.int @@ -0,0 +1,20 @@ +function gui:newPlayer(source,x,y,w,h,sx,sy,sw,sh) + local c=self:newFrame("MediaPlayer",x,y,w,h,sx,sy,sw,sh) + c.visuals=c:newFrame(0,0,0,-20,0,0,1,1) + c.bar=c:newFrame(40,-20,-40,20,0,1,1) + c.bar:ApplyGradient{Color.blue,Color.Darken(Color.blue,.25)} + c.action=c:newTextButton("Play",0,-20,40,20,0,1) + c.action:ApplyGradient{Color.blue,Color.Darken(Color.blue,.25)} + c.action:OnReleased(function(b,self) + if self.text=="Play" then + self.Parent.Source:play() + self.text="Pause" + else + self.Parent.Source:pause() + self.text="Play" + end + end) + c.action.Tween=-3 + c.VPush=multi:newStep(0,1,1,10) + c.Source=audio:new(source) +end \ No newline at end of file diff --git a/game/Interface/system.int b/game/Interface/system.int new file mode 100644 index 0000000..e0fc435 --- /dev/null +++ b/game/Interface/system.int @@ -0,0 +1,77 @@ +function gui:addTip(tip,n,padding) + local font=love.graphics.getFont() + self.t=gui:newTextLabel(tip,"Tooltip",0,0,font:getWidth(tip)+(padding or 4),14) + self.t:setNewFont(10) + self.t.Visible=false + self.t.Tween=1 + self.t.Color=Color.tan + self.alarm=multi:newAlarm(0) + self.alarm:Pause() + self.alarm.parent=self + self.time=n or 2 + self.padding=padding or 4 + self.alarm:OnRing(function(alarm) + alarm.parent.t:SetDualDim(love.mouse.getX()-2,love.mouse.getY()-2) + alarm.parent.t.Visible=true + alarm.parent.t:addDominance() + end) + self:OnEnter(function(self) + self.Visibility=.5 + self.alarm:Reset(self.time) + end) + self:OnExit(function(self) + self.alarm:Pause() + self.Visibility=0 + end) + self.t:OnExit(function(self) + self.Visible=false + self:removeDominance() + end) +end +function gui:newWindow(name) + local win=self:newFrame(0,0,400,20) + win.Draggable=true + win.dragbut="r" + win:OnDragStart(function(self) + self:TopStack() + end) + if name then + local font=love.graphics.getFont() + win.title=win:newTextLabel(name,0,0,font:getWidth(name),20) + win.title.TextFormat="left" + win.title.Visibility=0 + win.title.XTween=3 + win.title.Tween=-3 + end + win:ApplyGradient({Color.white,Color.light_blue,Color.blue,trans=200}) + win.close=win:newImageButton("icons/cancel.png",-20,2,16,16,1) + win.close:OnEnter(function(self) + self.Parent:removeDominance() + self:addDominance() + end) + win.close:OnReleased(function(b,self) + self.Parent:Destroy() + self:removeDominance() + love.mouse.setCursor() + end) + win.close:OnExit(function(self) + self:removeDominance() + end) + win.holder=win:newFrame(0,0,0,280,0,1,1) + win:OnUpdate(function(self) + if self.y<40 then self:SetDualDim(nil,0) love.mouse.setY(50) end + end) + win:OnEnter(function(self) + self:addDominance() + end) + win:OnExit(function(self) + self:removeDominance() + end) + win.holder:OnEnter(function(self) + self:addDominance() + end) + win.holder:OnExit(function(self) + self:removeDominance() + end) + return win.holder,win +end \ No newline at end of file diff --git a/game/core/AudioManager.lua b/game/Libs/AudioManager.lua similarity index 100% rename from game/core/AudioManager.lua rename to game/Libs/AudioManager.lua diff --git a/game/core/Library.lua b/game/Libs/Library.lua similarity index 100% rename from game/core/Library.lua rename to game/Libs/Library.lua diff --git a/game/Libs/MultiManager.lua b/game/Libs/MultiManager.lua new file mode 100644 index 0000000..d3a2dd2 --- /dev/null +++ b/game/Libs/MultiManager.lua @@ -0,0 +1,1391 @@ +if not bin then + print('Warning the \'bin\' library wasn\'t required! multi:tofile(path) and the multi:fromfile(path,int) features will not work!') +end +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 +multi = {} +multi.Version={'A',0,1}-- History: EventManager,EventManager+,MultiManager <-- Current After 6.3.0 Versioning scheme was altered. A.0.0 +multi.help=[[ +For a list of features do print(multi.Features) +For a list of changes do print(multi.changelog) +For current version do print(multi.Version) +For current stage do print(multi.stage) +For help do print(multi.help) :D +]] +multi.stage='stable' +multi.Features='Current Version: '..multi.Version[1]..'.'..multi.Version[2]..'.'..multi.Version[3]..' '..multi.stage..[[ +MultiManager has 19 Objects: # indicates most commonly used 1-19 1 being the most used by me ++Events #7 ++Alarms #2 ++Loops #3 ++Steps #4 ++TSteps #6 ++Triggers #16 ++Tasks #12 ++Connections #1 -- This is a rather new feature of this library, but has become the most useful for async handling. Knowing this is already 50% of this library ++Timers #14 -- this was tricky because these make up both Alarms and TSteps, but in purly using this standalone is almost non existent ++Jobs #11 ++Process #10 ++Conditions #15 ++Ranges #8 ++Threads #13 ++Functions #5 ++Queuers #17 ++Updaters #9 ++Watchers #18 ++CustomObjects #19 + +Constructors [Runners] +---------------------- Note: multi is the main Processor Obj It cannot be paused or destroyed (kinda) +intObj=multi:newProcess([string: FILE defualt: nil]) +intObj=multi:newQueuer([string: FILE defualt: nil]) + +Constructors [ACTORS] +--------------------- Note: everything is a multiObj! +eventObj=multi:newEvent([function: TASK defualt: function() end]) +alarmObj=multi:newAlarm([number: SET defualt: 0]) +loopObj=multi:newLoop([function: FUNC]) +stepObj=multi:newStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SKIP defualt: 0]) +tstepObj=multi:newTStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SET defualt: 1]) +updaterObj=multi:newUpdater([number: SKIP defualt: 0]) +watcherObj=multi:newWatcher(table: NAMESPACE,string: NAME) +multiObj=multi:newCustomObject([table: OBJREF],[string: T='process']) +void=multi:newThread(string: name,function: func) + +Constructors [Semi-ACTORS] +-------------------------- +multi:newJob(function: func,[string: name]) +multi:newRange(number: a,number: b,[number: c]) +multi:newCondition(func) + +Constructors [NON-ACTORS] +------------------------- +multi:newTrigger(function: func) +multi:newTask(function: func) +multi:newConnection() +multi:newTimer() +multi:newFunction(function: func) +]] +multi.changelog=[[Changelog starts at Version A.0.0 +New in A.0.0 + Nothing really however a changelog will now be recorded! Feel free to remove this extra strings if space is a requriment + version.major.minor +New in A.1.0 + Changed: multi:newConnection(protect) method + Changed the way you are able to interact with it by adding the __call metamethod + Old usage: + + OnUpdate=multi:newConnection() + OnUpdate:connect(function(...) + print("Updating",...) + end) + OnUpdate:Fire(1,2,3) + + New usage: notice that connect is no longer needed! Both ways still work! and always will work :) + + OnUpdate=multi:newConnection() + OnUpdate(function(...) + print("Updating",...) + end) + OnUpdate:Fire(1,2,3) +]] +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.queuefinal=function(self) + self:Destroy() + if self.Parent.Mainloop[#self.Parent.Mainloop] then + self.Parent.Mainloop[#self.Parent.Mainloop]:Resume() + 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() then change can be made. Just ensure that Priority_Idle is the greatest and Priority_Core is 1!) +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 and 4 any greater and problems arise +multi.Priority=multi.Priority_Core +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 +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 +function multi:isHeld() + return self.held +end +function multi.executeFunction(name,...) + if type(_G[name])=='function' then + _G[name](...) + else + print('Error: Not a function') + end +end +function multi:waitFor(obj) + self:hold(function() return obj:isActive() end) +end +function multi:reboot(r) + local before=collectgarbage('count') + self.Mainloop={} + self.Tasks={} + self.Tasks2={} + self.Garbage={} + self.Children={} + self.Paused={} + self.Active=true + self.Id=-1 + 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 + 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 +--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 + 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 +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:fromfile(path,int) + int=int or self + local test2={} + local test=bin.load(path) + local tp=test:getBlock('s') + if tp=='event' then + test2=int:newEvent(test:getBlock('f')) + local t=test:getBlock('t') + for i=1,#t do + test2:OnEvent(t[i]) + end + elseif tp=='alarm' then + test2=int:newAlarm(test:getBlock('n')) + elseif tp=='loop' then + test2=int:newLoop(test:getBlock('t')[1]) + elseif tp=='step' or tp=='tstep' then + local func=test:getBlock('t') + local funcE=test:getBlock('t') + local funcS=test:getBlock('t') + local tab=test:getBlock('t') + test2=int:newStep() + table.merge(test2,tab) + test2.funcE=funcE + test2.funcS=funcS + test2.func=func + elseif tp=='trigger' then + test2=int:newTrigger(test:getBlock('f')) + elseif tp=='connector' then + test2=int:newConnection() + test2.func=test:getBlock('t') + elseif tp=='timer' then + test2=int:newTimer() + test2.count=tonumber(test:getBlock('n')) + else + print('Error: The file you selected is not a valid multi file object!') + return false + end + return test2 +end +function multi:benchMark(sec,p) + local temp=self:newLoop(function(t,self) + if self.clock()-self.init>self.sec then + print(self.c..' steps in '..self.sec..' second(s)') + self.tt(self.sec) + 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:tofile(path) + local items=self:getChildren() + io.mkDir(io.getName(path)) + for i=1,#items do + items[i]:tofile(io.getName(path)..'\\item'..item[i]..'.dat') + end + local int=bin.new() + int:addBlock('process') + int:addBlock(io.getName(path)) + int:addBlock(#self.Mainloop) + int:addBlock(self.Active) + int:addBlock(self.Rest) + int:addBlock(self.Jobs) + int:tofile() +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: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(err,Loop[_D]) + 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: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 +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 +function multi:isActive() + return self.Active +end +function multi:getType() + return self.Type +end +function multi:Sleep(n) + self:hold(n) +end +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 +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 alarm=self.Parent:newAlarm(task) + while alarm.Active==true do + if love then + self.Parent:lManager() + else + self.Parent:Do_Order() + end + end + alarm:Destroy() + self:Resume() + self.held=false + elseif type(task)=='function' then + local env=self.Parent:newEvent(task) + env:OnEvent(function(envt) envt:Pause() envt.Active=false end) + while env.Active do + if love then + self.Parent:lManager() + else + self.Parent:Do_Order() + end + end + env:Destroy() + self:Resume() + self.held=false + else + print('Error Data Type!!!') + end +end +function multi:oneTime(func,...) + if not(self.Type=='mainprocess' or self.Type=='process') then + for _k=1,#self.Parent.Tasks2 do + if self.Parent.Tasks2[_k]==func then + return false + end + end + table.insert(self.Parent.Tasks2,func) + func(...) + return true + else + for _k=1,#self.Tasks2 do + if self.Tasks2[_k]==func then + return false + end + end + table.insert(self.Tasks2,func) + func(...) + return true + end +end +function multi:Reset(n) + self:Resume() +end +function multi:isDone() + return self.Active~=true +end +function multi:create(ref) + multi.OnObjectCreated:Fire(ref) +end +--Constructors [CORE] +function multi:newBase(ins) + if not(self.Type=='mainprocess' or self.Type=='process' or self.Type=='queue') then error('Can only create an object on multi or an interface obj') return false end + local c = {} + if self.Type=='process' or self.Type=='queue' then + setmetatable(c, self.Parent) + else + setmetatable(c, self) + end + c.Active=true + c.func={} + c.ender={} + c.Id=0 + c.PId=0 + c.Act=function() end + c.Parent=self + c.held=false + if ins then + table.insert(self.Mainloop,ins,c) + else + table.insert(self.Mainloop,c) + end + return c +end +function multi:newProcess(file) + if not(self.Type=='mainprocess') then error('Can only create an interface on the multi obj') return false end + local c = {} + setmetatable(c, self) + 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.Jobs={} + c.queue={} + c.jobUS=2 + function c:Start() + if self.l then + self.l:Resume() + else + self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end) + end + end + function c:Pause() + if self.l then + self.l:Pause() + end + end + function c:Remove() + self:Destroy() + self.l:Destroy() + end + if file then + self.Cself=c + loadstring('local interface=multi.Cself '..io.open(file,'rb'):read('*all'))() + end + self:create(c) + return c +end +function multi:newQueuer(file) + local c=self:newProcess() + c.Type='queue' + c.last={} + c.funcE={} + function c:OnQueueCompleted(func) + table.insert(self.funcE,func) + end + if file then + self.Cself=c + loadstring('local queue=multi.Cself '..io.open(file,'rb'):read('*all'))() + end + self:create(c) + return c +end +--Constructors [ACTORS] +function multi:newCustomObject(objRef,t) + local c={} + if t=='process' then + if self.Type=='queue' then + c=self:newBase(1) + self.last=c + print("This Custom Object was created on a queue! Ensure that it has a way to end! All objects have a obj:Break() method!") + else + c=self:newBase() + end + 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 + if self.Type=='queue' then + if #self.Mainloop>1 then + c:Pause() + end + c:connectFinal(multi.queuefinal) + end + self:create(c) + return c +end +function multi:newEvent(task) + local c={} + if self.Type=='queue' then + c=self:newBase(1) + self.last=c + else + c=self:newBase() + end + 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:OnEvent(func) + table.insert(self.func,func) + end + function c:tofile(path) + local m=bin.new() + m:addBlock(self.Type) + m:addBlock(self.Task) + m:addBlock(self.func) + m:addBlock(self.Active) + m:tofile(path) + end + if self.Type=='queue' then + if #self.Mainloop>1 then + c:Pause() + end + c:connectFinal(multi.queuefinal) + end + self:create(c) + return c +end +function multi:newAlarm(set) + local c={} + if self.Type=='queue' then + c=self:newBase(1) + self.last=c + else + c=self:newBase() + end + c.Type='alarm' + c.Priority=self.Priority_Low + c.timer=self:newTimer() + c.set=set or 0 + function c:tofile(path) + local m=bin.new() + m:addBlock(self.Type) + m:addBlock(self.set) + m:addBlock(self.Active) + m:tofile(path) + end + 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 + if self.Type=='queue' then + c:Pause() + c:connectFinal(multi.queuefinal) + else + c.timer:Start() + end + self:create(c) + return c +end +function multi:newLoop(func) + local c={} + if self.Type=='queue' then + c=self:newBase(1) + self.last=c + else + c=self:newBase() + end + c.Type='loop' + c.Start=self.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:Act() + for i=1,#self.func do + self.func[i](self.Parent.clock()-self.Start,self) + end + end + function c:OnLoop(func) + table.insert(self.func,func) + end + if self.Type=='queue' then + if #self.Mainloop>1 then + c:Pause() + end + c:connectFinal(multi.queuefinal) + end + self:create(c) + return c +end +function multi:newUpdater(skip) + local c={} + if self.Type=='queue' then + c=self:newBase(1) + self.last=c + else + c=self:newBase() + end + 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 + if self.Type=='queue' then + if #self.Mainloop>1 then + c:Pause() + end + c:connectFinal(multi.queuefinal) + end + self:create(c) + return c +end +function multi:newStep(start,reset,count,skip) + local c={} + if self.Type=='queue' then + c=self:newBase(1) + self.last=c + else + c=self:newBase() + end + 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: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: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 + 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 + if self.Type=='queue' then + if #self.Mainloop>1 then + c:Pause() + end + c:connectFinal(multi.queuefinal) + end + self:create(c) + return c +end +function multi:newTStep(start,reset,count,set) + local c={} + if self.Type=='queue' then + c=self:newBase(1) + self.last=c + else + c=self:newBase() + end + 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: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: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 + 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 + if self.Type=='queue' then + if #self.Mainloop>1 then + c:Pause() + end + c:connectFinal(multi.queuefinal) + 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 +function multi:newThread(name,func) + local c={} + c.ref={} + c.Name=name + c.thread=coroutine.create(func) + c.sleep=1 + 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) + n = tonumber(n) or 0 + ret=coroutine.yield({"_sleep_",n}) + self:syncGlobals(ret) + 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 +-- Constructors [SEMI-ACTORS] +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() + 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] + self.Link:Pause() + self.Link.held=true + return function() return self:getN() end + end + }) + self:create(temp) + return temp +end +function multi:newCondition(func) + local c={['condition']=func} + self:create(c) + return c +end +-- Constructors [NON-ACTORS] +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:newTimer() + local c={} + c.Type='timer' + c.time=0 + c.count=0 + function c:Start() + self.time=os.clock() + end + function c:Get() + return (os.clock()-self.time)+self.count + end + c.Reset=c.Start + function c:Pause() + self.time=self:Get() + end + function c:Resume() + self.time=os.clock()-self.time + end + function c:tofile(path) + local m=bin.new() + self.count=self.count+self:Get() + m:addBlock(self.Type) + m:addBlock(self.count) + m:tofile(path) + end + self:create(c) + return c +end +function multi:newTask(func) + table.insert(self.Tasks,func) +end +function multi:newTrigger(func) + local c={} + c.Type='trigger' + c.trigfunc=func or function() end + function c:Fire(...) + self:trigfunc(self,...) + end + function c:tofile(path) + local m=bin.new() + m:addBlock(self.Type) + m:addBlock(self.trigfunc) + m:tofile(path) + end + self:create(c) + return c +end +function multi:newConnection(protect) + local c={} + setmetatable(c,{__call=function(self,...) self:connect(...) end}) + c.Type='connector' + c.func={} + c.ID=0 + c.protect=protect or true + function c:Fire(...) + local ret={} + for i=#self.func,1,-1 do + if self.protect then + local temp={pcall(self.func[i][1],...)} + if temp[1] then + table.remove(temp,1) + table.insert(ret,temp) + else + print(temp[2]) + end + else + table.insert(ret,{self.func[i][1](...)}) + end + end + return ret + end + function c:bind(t) + self.func=t + end + function c:remove() + self.func={} + end + function c:connect(func) + self.ID=self.ID+1 + table.insert(self.func,1,{func,self.ID}) + return { + Link=self.func, + ID=self.ID, + 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 + } + end + 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() +--Managers +function multi:mainloop() + for i=1,#self.Tasks do + self.Tasks[i](self) + end + rawset(self,'Start',self.clock()) + while self.Active do + self:Do_Order() + end + print("Did you call multi:Stop()? This method should not be used when using multi:mainloop()! You now need to restart the multiManager, by using multi:reboot() and calling multi:mainloop() again or by using multi:uManager()") +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 +--Thread Setup Stuff +multi:setDomainName("Threads") +multi:setDomainName("Globals") +-- Scheduler +multi.scheduler=multi:newUpdater() +multi.scheduler.Type="scheduler" +function multi.scheduler:setStep(n) + self.skip=tonumber(n) or 24 +end +multi.scheduler.Threads=multi:linkDomain("Threads") +multi.scheduler.Globals=multi:linkDomain("Globals") +multi.scheduler:OnUpdate(function(self) + 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 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.Name then + self.Globals[ret.Name]=ret.Value + end + end + end + end +end) +multi.scheduler:setStep() +multi.scheduler:Pause() +multi.OnError=multi:newConnection() diff --git a/game/Libs/README.txt b/game/Libs/README.txt new file mode 100644 index 0000000..02b5fb6 --- /dev/null +++ b/game/Libs/README.txt @@ -0,0 +1,2 @@ +These libraries Namely the MultiManager, bin, and the Library, libraries will be documented because i plan on sharing them +everything else will mostlikely not be documented \ No newline at end of file diff --git a/game/Libs/T1.lua b/game/Libs/T1.lua new file mode 100644 index 0000000..f861efa --- /dev/null +++ b/game/Libs/T1.lua @@ -0,0 +1,598 @@ +require("love.timer") +require("love.system") +require("love.sound") +require("love.physics") +require("love.mouse") +require("love.math") +require("love.keyboard") +require("love.joystick") +require("love.image") +require("love.font") +require("love.filesystem") +require("love.event") +require("love.audio") +require("love.graphics") +require("love.window") +_defaultfont = love.graphics.getFont() +gui = {} +function gui.getTile(i,x,y,w,h)-- returns imagedata + if type(i)=="userdata" then + -- do nothing + 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 +multi = {} +multi.Version="4.0.0" +multi.__index = multi +multi.Mainloop={} +multi.Tasks={} +multi.Tasks2={} +multi.Garbage={} +multi.Children={} +multi.Paused={} +multi.MasterId=0 +multi.Active=true +multi.Id=-1 +multi.Type="MainInt" +multi.Rest=0 +-- System +os.sleep=love.timer.sleep +function multi:newBase(ins) + if not(self.Type=="MainInt" or self.Type=="int") then error("Can only create an object on multi or an interface obj") return false end + local c = {} + if self.Type=="int" then + setmetatable(c, self.Parent) + else + setmetatable(c, self) + end + c.Active=true + c.func={} + c.Id=0 + c.Act=function() end + c.Parent=self + if ins then + table.insert(self.Mainloop,ins,c) + else + table.insert(self.Mainloop,c) + end + self.MasterId=self.MasterId+1 + return c +end +function multi:reboot(r) + self.Mainloop={} + self.Tasks={} + self.Tasks2={} + self.Garbage={} + self.Children={} + self.Paused={} + self.MasterId=0 + self.Active=true + self.Id=-1 + 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 + i={} + end + end + end + end +end +function multi:getChildren() + return self.Mainloop +end +--Processor +function multi:Do_Order() + for _D=#self.Mainloop,1,-1 do + if self.Mainloop[_D]~=nil then + self.Mainloop[_D].Id=_D + self.Mainloop[_D]:Act() + end + if self.Mainloop[_D].rem then + table.remove(self.Mainloop,_D) + end + end + if self.Rest>0 then + os.sleep(self.Rest) + end +end +function multi:benchMark(sec) + local temp=self:newLoop(function(t,self) + if os.clock()-self.init>self.sec then + print(self.c.." steps in "..self.sec.." second(s)") + self.tt(self.sec) + self:Destroy() + else + self.c=self.c+1 + end + end) + function temp:OnBench(func) + self.tt=func + end + self.tt=function() end + temp.sec=sec + temp.init=os.clock() + temp.c=0 + return temp +end +function multi:newInterface() + if not(self.Type=="MainInt") then error("Can only create an interface on the multi obj") return false end + local c = {} + setmetatable(c, self) + c.Parent=self + c.Active=true + c.func={} + c.Id=0 + c.Type="int" + c.Mainloop={} + c.Tasks={} + c.Tasks2={} + c.Garbage={} + c.Children={} + c.Paused={} + c.MasterId=0 + c.Active=true + c.Id=-1 + c.Rest=0 + function c:Start() + if self.l then + self.l:Resume() + else + self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end) + end + end + function c:Stop() + if self.l then + self.l:Pause() + end + end + function c:Remove() + self:Destroy() + self.l:Destroy() + end + return c +end +--Helpers +function multi:FreeMainEvent() + self.func={} +end +function multi:isPaused() + return not(self.Active) +end +function multi:Pause(n) + if self.Type=="int" or self.Type=="MainInt" then + self.Active=false + if not(n) then + local c=self:getChildren() + for i=1,#c do + c[i]:Pause() + end + else + self:hold(n) + end + else + if not(n) then + 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.Id=#self.Parent.Paused + end + else + self:hold(n) + end + end +end +function multi:Resume() + if self.Type=="int" or self.Type=="MainInt" then + self.Active=true + local c=self:getChildren() + for i=1,#c do + c[i]:Resume() + end + else + if self:isPaused() then + self.Active=true + for i=1,#self.Parent.Paused do + if self.Parent.Paused[i]==self then + table.remove(self.Parent.Paused,i) + return + end + end + table.insert(self.Parent.Mainloop,self) + end + end +end +function multi:Destroy() + if self.Type=="int" or self.Type=="MainInt" then + local c=self:getChildren() + for i=1,#c do + c[i]:Destroy() + end + else + self.rem=true + end +end +function multi:hold(task) + self:Pause() + if type(task)=="number" then + local alarm=self:newAlarm(task) + while alarm.Active==true do + if love then + self.Parent.lManager() + else + self.Parent.Do_Order() + end + end + alarm:Destroy() + self:Resume() + elseif type(task)=="function" then + local env=self.Parent:newEvent(task) + env:OnEvent(function(envt) envt:Pause() envt:Stop() end) + while env.Active do + if love then + self.Parent.lManager() + else + self.Parent.Do_Order() + end + end + env:Destroy() + self:Resume() + else + print("Error Data Type!!!") + end +end +function multi:oneTime(func,...) + if not(self.Type=="MainInt" or self.Type=="int") then + for _k=1,#self.Parent.Tasks2 do + if self.Parent.Tasks2[_k]==func then + return false + end + end + table.insert(self.Parent.Tasks2,func) + func(...) + return true + else + for _k=1,#self.Tasks2 do + if self.Tasks2[_k]==func then + return false + end + end + table.insert(self.Tasks2,func) + func(...) + return true + end +end +--Constructors +function multi:newEvent(task) + local c=self:newBase() + c.Type="Event" + c.Task=task or function() end + function c:Act() + if self.Task(self) and self.Active==true then + self:Pause() + for _E=1,#self.func do + self.func[_E](self) + end + end + end + function c:OnEvent(func) + table.insert(self.func,func) + end + return c +end +function multi:newAlarm(set) + local c=self:newBase() + c.Type="Alarm" + c.timer=os.clock() + c.set=set or 0 + function c:Act() + if self.Active==true then + if os.clock()-self.timer>=self.set then + self:Pause() + for i=1,#self.func do + self.func[i](self) + end + end + end + end + function c:Reset(n) + if n then self.set=n end + self.timer=os.clock() + self:Resume() + end + function c:OnRing(func) + table.insert(self.func,func) + end + return c +end +function multi:newTask(func) + table.insert(self.Tasks,func) +end +function multi:newLoop(func) + local c=self:newBase() + c.Type="Loop" + if func then + c.func={func} + end + function c:Act() + if self.Active==true then + for i=1,#self.func do + self.func[i](os.clock()-self.Parent.Start,self) + end + end + end + function c:OnLoop(func) + table.insert(self.func,func) + end + 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.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.Active==true then + for i=1,#self.func do + self.func[i](self.pos,self) + end + self.pos=self.pos+self.count + end + end + end + self.spos=self.spos+1 + if self.spos>=self.skip then + self.spos=0 + end + end + function c:OnStep(func) + table.insert(self.func,1,func) + end + function c:OnEnd(func) + table.insert(self.funcE,func) + 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:OnStep(function(p,s) + if s.count>0 and s.endAt==p then + for fe=1,#s.funcE do + s.funcE[fe](s) + end + s.pos=s.start-1 + elseif s.count<0 and s.endAt==p then + for fe=1,#s.funcE do + s.funcE[fe](s) + end + s.pos=s.start-1 + end + end) + return c +end +function multi:newTStep(start,reset,count,set) + local c=self:newBase() + think=1 + c.Type="TStep" + 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 + function c:Update(start,reset,count,set) + self.start=start or self.start + self.pos=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:Act() + if self.Active then + if os.clock()-self.timer>=self.set then + self:Reset() + for i=1,#self.func do + self.func[i](self.pos,self) + end + if self.endAt==self.pos then + for fe=1,#self.funcE do + self.funcE[fe](self) + end + self.pos=self.start-1 + end + self.pos=self.pos+self.count + end + end + end + function c:OnEnd(func) + table.insert(self.funcE,func) + end + function c:Reset(n) + if n then self.set=n end + self.timer=os.clock() + self:Resume() + end + function c:OnStep(func) + table.insert(self.func,func) + end + return c +end +function multi:newTrigger(func) + local c=self:newBase() + c.Type="Trigger" + c.trigfunc=func or function() end + function c:Fire(...) + self:trigfunc(self,...) + end + return c +end +--Managers +function multi:mainloop() + for i=1,#self.Tasks do + self.Tasks[i](self) + end + self.Start=os.clock() + while self.Active do + self:Do_Order() + end +end +function multi._tFunc(self,dt) + for i=1,#self.Tasks do + self.Tasks[i](self) + end + print("once!") + if dt then + self.pump=true + end + self.pumpvar=dt + self.Start=os.clock() +end +function multi:uManager(dt) + self:oneTime(self._tFunc,self,dt) + self:Do_Order() +end +multi.drawF={} +function multi:dManager() + for ii=1,#multi.drawF do + multi.drawF[ii]() + end +end +function multi:onDraw(func) + table.insert(self.drawF,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 +Thread={} +Thread.Name="Thread 1" +Thread.ChannelThread = love.thread.getChannel("Easy1") +Thread.ChannelMain = love.thread.getChannel("EasyMain") +Thread.Global = {} +function Thread:packTable(G) + function escapeStr(str) + local temp="" + for i=1,#str do + temp=temp.."\\"..string.byte(string.sub(str,i,i)) + end + return temp + end + function ToStr(t) + local dat="{" + for i,v in pairs(t) do + if type(i)=="number" then + i="["..i.."]=" + else + i=i.."=" + end + if type(v)=="string" then + dat=dat..i.."\""..v.."\"," + elseif type(v)=="number" then + dat=dat..i..v.."," + elseif type(v)=="boolean" then + dat=dat..i..tostring(v).."," + elseif type(v)=="table" and not(G==v) then + dat=dat..i..ToStr(v).."," + --elseif type(v)=="table" and G==v then + -- dat=dat..i.."assert(loadstring(\"return self\"))," + elseif type(v)=="function" then + dat=dat..i.."assert(loadstring(\""..escapeStr(string.dump(v)).."\"))," + end + end + return string.sub(dat,1,-2).."}" + end + return "return "..ToStr(G) +end +function Thread:Send(name,var) + arg3="1" + if type(var)=="table" then + var=Thread:packTable(var) + arg3="table" + end + self.ChannelMain:push({name,var,arg3}) +end +function Thread:UnPackChannel() + local c=self.ChannelThread:getCount() + for i=1,c do + local temp=self.ChannelThread:pop() + if temp[1] and temp[2] then + if temp[1]=="func" and type(temp[2])=="string" then + loadstring(temp[2])(temp[3]) + elseif temp[1]=="table" then + _G[temp[3]]=loadstring(temp[2])() + else + _G[temp[1]]=temp[2] + end + end + end + if #multi:getChildren()<2 then + os.sleep(.05) + end +end +function Thread:boost(func,name) + self:Send(name,string.dump(func)) +end +function Thread.mainloop() + Thread:UnPackChannel() +end +Thread.MainThread=false +multi:newLoop():OnLoop(Thread.mainloop) +multi:mainloop() diff --git a/game/Libs/T2.lua b/game/Libs/T2.lua new file mode 100644 index 0000000..44e2fbf --- /dev/null +++ b/game/Libs/T2.lua @@ -0,0 +1,598 @@ +require("love.timer") +require("love.system") +require("love.sound") +require("love.physics") +require("love.mouse") +require("love.math") +require("love.keyboard") +require("love.joystick") +require("love.image") +require("love.font") +require("love.filesystem") +require("love.event") +require("love.audio") +require("love.graphics") +require("love.window") +_defaultfont = love.graphics.getFont() +gui = {} +function gui.getTile(i,x,y,w,h)-- returns imagedata + if type(i)=="userdata" then + -- do nothing + 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 +multi = {} +multi.Version="4.0.0" +multi.__index = multi +multi.Mainloop={} +multi.Tasks={} +multi.Tasks2={} +multi.Garbage={} +multi.Children={} +multi.Paused={} +multi.MasterId=0 +multi.Active=true +multi.Id=-1 +multi.Type="MainInt" +multi.Rest=0 +-- System +os.sleep=love.timer.sleep +function multi:newBase(ins) + if not(self.Type=="MainInt" or self.Type=="int") then error("Can only create an object on multi or an interface obj") return false end + local c = {} + if self.Type=="int" then + setmetatable(c, self.Parent) + else + setmetatable(c, self) + end + c.Active=true + c.func={} + c.Id=0 + c.Act=function() end + c.Parent=self + if ins then + table.insert(self.Mainloop,ins,c) + else + table.insert(self.Mainloop,c) + end + self.MasterId=self.MasterId+1 + return c +end +function multi:reboot(r) + self.Mainloop={} + self.Tasks={} + self.Tasks2={} + self.Garbage={} + self.Children={} + self.Paused={} + self.MasterId=0 + self.Active=true + self.Id=-1 + 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 + i={} + end + end + end + end +end +function multi:getChildren() + return self.Mainloop +end +--Processor +function multi:Do_Order() + for _D=#self.Mainloop,1,-1 do + if self.Mainloop[_D]~=nil then + self.Mainloop[_D].Id=_D + self.Mainloop[_D]:Act() + end + if self.Mainloop[_D].rem then + table.remove(self.Mainloop,_D) + end + end + if self.Rest>0 then + os.sleep(self.Rest) + end +end +function multi:benchMark(sec) + local temp=self:newLoop(function(t,self) + if os.clock()-self.init>self.sec then + print(self.c.." steps in "..self.sec.." second(s)") + self.tt(self.sec) + self:Destroy() + else + self.c=self.c+1 + end + end) + function temp:OnBench(func) + self.tt=func + end + self.tt=function() end + temp.sec=sec + temp.init=os.clock() + temp.c=0 + return temp +end +function multi:newInterface() + if not(self.Type=="MainInt") then error("Can only create an interface on the multi obj") return false end + local c = {} + setmetatable(c, self) + c.Parent=self + c.Active=true + c.func={} + c.Id=0 + c.Type="int" + c.Mainloop={} + c.Tasks={} + c.Tasks2={} + c.Garbage={} + c.Children={} + c.Paused={} + c.MasterId=0 + c.Active=true + c.Id=-1 + c.Rest=0 + function c:Start() + if self.l then + self.l:Resume() + else + self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end) + end + end + function c:Stop() + if self.l then + self.l:Pause() + end + end + function c:Remove() + self:Destroy() + self.l:Destroy() + end + return c +end +--Helpers +function multi:FreeMainEvent() + self.func={} +end +function multi:isPaused() + return not(self.Active) +end +function multi:Pause(n) + if self.Type=="int" or self.Type=="MainInt" then + self.Active=false + if not(n) then + local c=self:getChildren() + for i=1,#c do + c[i]:Pause() + end + else + self:hold(n) + end + else + if not(n) then + 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.Id=#self.Parent.Paused + end + else + self:hold(n) + end + end +end +function multi:Resume() + if self.Type=="int" or self.Type=="MainInt" then + self.Active=true + local c=self:getChildren() + for i=1,#c do + c[i]:Resume() + end + else + if self:isPaused() then + self.Active=true + for i=1,#self.Parent.Paused do + if self.Parent.Paused[i]==self then + table.remove(self.Parent.Paused,i) + return + end + end + table.insert(self.Parent.Mainloop,self) + end + end +end +function multi:Destroy() + if self.Type=="int" or self.Type=="MainInt" then + local c=self:getChildren() + for i=1,#c do + c[i]:Destroy() + end + else + self.rem=true + end +end +function multi:hold(task) + self:Pause() + if type(task)=="number" then + local alarm=self:newAlarm(task) + while alarm.Active==true do + if love then + self.Parent.lManager() + else + self.Parent.Do_Order() + end + end + alarm:Destroy() + self:Resume() + elseif type(task)=="function" then + local env=self.Parent:newEvent(task) + env:OnEvent(function(envt) envt:Pause() envt:Stop() end) + while env.Active do + if love then + self.Parent.lManager() + else + self.Parent.Do_Order() + end + end + env:Destroy() + self:Resume() + else + print("Error Data Type!!!") + end +end +function multi:oneTime(func,...) + if not(self.Type=="MainInt" or self.Type=="int") then + for _k=1,#self.Parent.Tasks2 do + if self.Parent.Tasks2[_k]==func then + return false + end + end + table.insert(self.Parent.Tasks2,func) + func(...) + return true + else + for _k=1,#self.Tasks2 do + if self.Tasks2[_k]==func then + return false + end + end + table.insert(self.Tasks2,func) + func(...) + return true + end +end +--Constructors +function multi:newEvent(task) + local c=self:newBase() + c.Type="Event" + c.Task=task or function() end + function c:Act() + if self.Task(self) and self.Active==true then + self:Pause() + for _E=1,#self.func do + self.func[_E](self) + end + end + end + function c:OnEvent(func) + table.insert(self.func,func) + end + return c +end +function multi:newAlarm(set) + local c=self:newBase() + c.Type="Alarm" + c.timer=os.clock() + c.set=set or 0 + function c:Act() + if self.Active==true then + if os.clock()-self.timer>=self.set then + self:Pause() + for i=1,#self.func do + self.func[i](self) + end + end + end + end + function c:Reset(n) + if n then self.set=n end + self.timer=os.clock() + self:Resume() + end + function c:OnRing(func) + table.insert(self.func,func) + end + return c +end +function multi:newTask(func) + table.insert(self.Tasks,func) +end +function multi:newLoop(func) + local c=self:newBase() + c.Type="Loop" + if func then + c.func={func} + end + function c:Act() + if self.Active==true then + for i=1,#self.func do + self.func[i](os.clock()-self.Parent.Start,self) + end + end + end + function c:OnLoop(func) + table.insert(self.func,func) + end + 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.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.Active==true then + for i=1,#self.func do + self.func[i](self.pos,self) + end + self.pos=self.pos+self.count + end + end + end + self.spos=self.spos+1 + if self.spos>=self.skip then + self.spos=0 + end + end + function c:OnStep(func) + table.insert(self.func,1,func) + end + function c:OnEnd(func) + table.insert(self.funcE,func) + 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:OnStep(function(p,s) + if s.count>0 and s.endAt==p then + for fe=1,#s.funcE do + s.funcE[fe](s) + end + s.pos=s.start-1 + elseif s.count<0 and s.endAt==p then + for fe=1,#s.funcE do + s.funcE[fe](s) + end + s.pos=s.start-1 + end + end) + return c +end +function multi:newTStep(start,reset,count,set) + local c=self:newBase() + think=1 + c.Type="TStep" + 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 + function c:Update(start,reset,count,set) + self.start=start or self.start + self.pos=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:Act() + if self.Active then + if os.clock()-self.timer>=self.set then + self:Reset() + for i=1,#self.func do + self.func[i](self.pos,self) + end + if self.endAt==self.pos then + for fe=1,#self.funcE do + self.funcE[fe](self) + end + self.pos=self.start-1 + end + self.pos=self.pos+self.count + end + end + end + function c:OnEnd(func) + table.insert(self.funcE,func) + end + function c:Reset(n) + if n then self.set=n end + self.timer=os.clock() + self:Resume() + end + function c:OnStep(func) + table.insert(self.func,func) + end + return c +end +function multi:newTrigger(func) + local c=self:newBase() + c.Type="Trigger" + c.trigfunc=func or function() end + function c:Fire(...) + self:trigfunc(self,...) + end + return c +end +--Managers +function multi:mainloop() + for i=1,#self.Tasks do + self.Tasks[i](self) + end + self.Start=os.clock() + while self.Active do + self:Do_Order() + end +end +function multi._tFunc(self,dt) + for i=1,#self.Tasks do + self.Tasks[i](self) + end + print("once!") + if dt then + self.pump=true + end + self.pumpvar=dt + self.Start=os.clock() +end +function multi:uManager(dt) + self:oneTime(self._tFunc,self,dt) + self:Do_Order() +end +multi.drawF={} +function multi:dManager() + for ii=1,#multi.drawF do + multi.drawF[ii]() + end +end +function multi:onDraw(func) + table.insert(self.drawF,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 +Thread={} +Thread.Name="Thread 2" +Thread.ChannelThread = love.thread.getChannel("Easy2") +Thread.ChannelMain = love.thread.getChannel("EasyMain") +Thread.Global = {} +function Thread:packTable(G) + function escapeStr(str) + local temp="" + for i=1,#str do + temp=temp.."\\"..string.byte(string.sub(str,i,i)) + end + return temp + end + function ToStr(t) + local dat="{" + for i,v in pairs(t) do + if type(i)=="number" then + i="["..i.."]=" + else + i=i.."=" + end + if type(v)=="string" then + dat=dat..i.."\""..v.."\"," + elseif type(v)=="number" then + dat=dat..i..v.."," + elseif type(v)=="boolean" then + dat=dat..i..tostring(v).."," + elseif type(v)=="table" and not(G==v) then + dat=dat..i..ToStr(v).."," + --elseif type(v)=="table" and G==v then + -- dat=dat..i.."assert(loadstring(\"return self\"))," + elseif type(v)=="function" then + dat=dat..i.."assert(loadstring(\""..escapeStr(string.dump(v)).."\"))," + end + end + return string.sub(dat,1,-2).."}" + end + return "return "..ToStr(G) +end +function Thread:Send(name,var) + arg3="2" + if type(var)=="table" then + var=Thread:packTable(var) + arg3="table" + end + self.ChannelMain:push({name,var,arg3}) +end +function Thread:UnPackChannel() + local c=self.ChannelThread:getCount() + for i=1,c do + local temp=self.ChannelThread:pop() + if temp[1] and temp[2] then + if temp[1]=="func" and type(temp[2])=="string" then + loadstring(temp[2])(temp[3]) + elseif temp[1]=="table" then + _G[temp[3]]=loadstring(temp[2])() + else + _G[temp[1]]=temp[2] + end + end + end + if #multi:getChildren()<2 then + os.sleep(.05) + end +end +function Thread:boost(func,name) + self:Send(name,string.dump(func)) +end +function Thread.mainloop() + Thread:UnPackChannel() +end +Thread.MainThread=false +multi:newLoop():OnLoop(Thread.mainloop) +multi:mainloop() diff --git a/game/Libs/T3.lua b/game/Libs/T3.lua new file mode 100644 index 0000000..171eff0 --- /dev/null +++ b/game/Libs/T3.lua @@ -0,0 +1,596 @@ +require("love.timer") +require("love.system") +require("love.sound") +require("love.physics") +require("love.mouse") +require("love.math") +require("love.keyboard") +require("love.joystick") +require("love.image") +require("love.font") +require("love.filesystem") +require("love.event") +require("love.audio") +require("love.graphics") +require("love.window") +_defaultfont = love.graphics.getFont() +gui = {} +function gui.getTile(i,x,y,w,h)-- returns imagedata + if type(i)=="userdata" then + -- do nothing + 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 +multi = {} +multi.Version="4.0.0" +multi.__index = multi +multi.Mainloop={} +multi.Tasks={} +multi.Tasks2={} +multi.Garbage={} +multi.Children={} +multi.Paused={} +multi.MasterId=0 +multi.Active=true +multi.Id=-1 +multi.Type="MainInt" +multi.Rest=0 +-- System +os.sleep=love.timer.sleep +function multi:newBase(ins) + if not(self.Type=="MainInt" or self.Type=="int") then error("Can only create an object on multi or an interface obj") return false end + local c = {} + if self.Type=="int" then + setmetatable(c, self.Parent) + else + setmetatable(c, self) + end + c.Active=true + c.func={} + c.Id=0 + c.Act=function() end + c.Parent=self + if ins then + table.insert(self.Mainloop,ins,c) + else + table.insert(self.Mainloop,c) + end + self.MasterId=self.MasterId+1 + return c +end +function multi:reboot(r) + self.Mainloop={} + self.Tasks={} + self.Tasks2={} + self.Garbage={} + self.Children={} + self.Paused={} + self.MasterId=0 + self.Active=true + self.Id=-1 + 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 + i={} + end + end + end + end +end +function multi:getChildren() + return self.Mainloop +end +--Processor +function multi:Do_Order() + for _D=#self.Mainloop,1,-1 do + if self.Mainloop[_D]~=nil then + self.Mainloop[_D].Id=_D + self.Mainloop[_D]:Act() + end + if self.Mainloop[_D].rem then + table.remove(self.Mainloop,_D) + end + end + if self.Rest>0 then + os.sleep(self.Rest) + end +end +function multi:benchMark(sec) + local temp=self:newLoop(function(t,self) + if os.clock()-self.init>self.sec then + print(self.c.." steps in "..self.sec.." second(s)") + self.tt(self.sec) + self:Destroy() + else + self.c=self.c+1 + end + end) + function temp:OnBench(func) + self.tt=func + end + self.tt=function() end + temp.sec=sec + temp.init=os.clock() + temp.c=0 + return temp +end +function multi:newInterface() + if not(self.Type=="MainInt") then error("Can only create an interface on the multi obj") return false end + local c = {} + setmetatable(c, self) + c.Parent=self + c.Active=true + c.func={} + c.Id=0 + c.Type="int" + c.Mainloop={} + c.Tasks={} + c.Tasks2={} + c.Garbage={} + c.Children={} + c.Paused={} + c.MasterId=0 + c.Active=true + c.Id=-1 + c.Rest=0 + function c:Start() + if self.l then + self.l:Resume() + else + self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end) + end + end + function c:Stop() + if self.l then + self.l:Pause() + end + end + function c:Remove() + self:Destroy() + self.l:Destroy() + end + return c +end +--Helpers +function multi:FreeMainEvent() + self.func={} +end +function multi:isPaused() + return not(self.Active) +end +function multi:Pause(n) + if self.Type=="int" or self.Type=="MainInt" then + self.Active=false + if not(n) then + local c=self:getChildren() + for i=1,#c do + c[i]:Pause() + end + else + self:hold(n) + end + else + if not(n) then + 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.Id=#self.Parent.Paused + end + else + self:hold(n) + end + end +end +function multi:Resume() + if self.Type=="int" or self.Type=="MainInt" then + self.Active=true + local c=self:getChildren() + for i=1,#c do + c[i]:Resume() + end + else + if self:isPaused() then + self.Active=true + for i=1,#self.Parent.Paused do + if self.Parent.Paused[i]==self then + table.remove(self.Parent.Paused,i) + return + end + end + table.insert(self.Parent.Mainloop,self) + end + end +end +function multi:Destroy() + if self.Type=="int" or self.Type=="MainInt" then + local c=self:getChildren() + for i=1,#c do + c[i]:Destroy() + end + else + self.rem=true + end +end +function multi:hold(task) + self:Pause() + if type(task)=="number" then + local alarm=self:newAlarm(task) + while alarm.Active==true do + if love then + self.Parent.lManager() + else + self.Parent.Do_Order() + end + end + alarm:Destroy() + self:Resume() + elseif type(task)=="function" then + local env=self.Parent:newEvent(task) + env:OnEvent(function(envt) envt:Pause() envt:Stop() end) + while env.Active do + if love then + self.Parent.lManager() + else + self.Parent.Do_Order() + end + end + env:Destroy() + self:Resume() + else + print("Error Data Type!!!") + end +end +function multi:oneTime(func,...) + if not(self.Type=="MainInt" or self.Type=="int") then + for _k=1,#self.Parent.Tasks2 do + if self.Parent.Tasks2[_k]==func then + return false + end + end + table.insert(self.Parent.Tasks2,func) + func(...) + return true + else + for _k=1,#self.Tasks2 do + if self.Tasks2[_k]==func then + return false + end + end + table.insert(self.Tasks2,func) + func(...) + return true + end +end +--Constructors +function multi:newEvent(task) + local c=self:newBase() + c.Type="Event" + c.Task=task or function() end + function c:Act() + if self.Task(self) and self.Active==true then + self:Pause() + for _E=1,#self.func do + self.func[_E](self) + end + end + end + function c:OnEvent(func) + table.insert(self.func,func) + end + return c +end +function multi:newAlarm(set) + local c=self:newBase() + c.Type="Alarm" + c.timer=os.clock() + c.set=set or 0 + function c:Act() + if self.Active==true then + if os.clock()-self.timer>=self.set then + self:Pause() + for i=1,#self.func do + self.func[i](self) + end + end + end + end + function c:Reset(n) + if n then self.set=n end + self.timer=os.clock() + self:Resume() + end + function c:OnRing(func) + table.insert(self.func,func) + end + return c +end +function multi:newTask(func) + table.insert(self.Tasks,func) +end +function multi:newLoop(func) + local c=self:newBase() + c.Type="Loop" + if func then + c.func={func} + end + function c:Act() + if self.Active==true then + for i=1,#self.func do + self.func[i](os.clock()-self.Parent.Start,self) + end + end + end + function c:OnLoop(func) + table.insert(self.func,func) + end + 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.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.Active==true then + for i=1,#self.func do + self.func[i](self.pos,self) + end + self.pos=self.pos+self.count + end + end + end + self.spos=self.spos+1 + if self.spos>=self.skip then + self.spos=0 + end + end + function c:OnStep(func) + table.insert(self.func,1,func) + end + function c:OnEnd(func) + table.insert(self.funcE,func) + 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:OnStep(function(p,s) + if s.count>0 and s.endAt==p then + for fe=1,#s.funcE do + s.funcE[fe](s) + end + s.pos=s.start-1 + elseif s.count<0 and s.endAt==p then + for fe=1,#s.funcE do + s.funcE[fe](s) + end + s.pos=s.start-1 + end + end) + return c +end +function multi:newTStep(start,reset,count,set) + local c=self:newBase() + think=1 + c.Type="TStep" + 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 + function c:Update(start,reset,count,set) + self.start=start or self.start + self.pos=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:Act() + if self.Active then + if os.clock()-self.timer>=self.set then + self:Reset() + for i=1,#self.func do + self.func[i](self.pos,self) + end + if self.endAt==self.pos then + for fe=1,#self.funcE do + self.funcE[fe](self) + end + self.pos=self.start-1 + end + self.pos=self.pos+self.count + end + end + end + function c:OnEnd(func) + table.insert(self.funcE,func) + end + function c:Reset(n) + if n then self.set=n end + self.timer=os.clock() + self:Resume() + end + function c:OnStep(func) + table.insert(self.func,func) + end + return c +end +function multi:newTrigger(func) + local c=self:newBase() + c.Type="Trigger" + c.trigfunc=func or function() end + function c:Fire(...) + self:trigfunc(self,...) + end + return c +end +--Managers +function multi:mainloop() + for i=1,#self.Tasks do + self.Tasks[i](self) + end + self.Start=os.clock() + while self.Active do + self:Do_Order() + end +end +function multi._tFunc(self,dt) + for i=1,#self.Tasks do + self.Tasks[i](self) + end + print("once!") + if dt then + self.pump=true + end + self.pumpvar=dt + self.Start=os.clock() +end +function multi:uManager(dt) + self:oneTime(self._tFunc,self,dt) + self:Do_Order() +end +multi.drawF={} +function multi:dManager() + for ii=1,#multi.drawF do + multi.drawF[ii]() + end +end +function multi:onDraw(func) + table.insert(self.drawF,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 +Thread={} +Thread.Name="Thread 3" +Thread.ChannelThread = love.thread.getChannel("Easy3") +Thread.ChannelMain = love.thread.getChannel("EasyMain") +Thread.Global = {} +function Thread:packTable(G) + function escapeStr(str) + local temp="" + for i=1,#str do + temp=temp.."\\"..string.byte(string.sub(str,i,i)) + end + return temp + end + function ToStr(t) + local dat="{" + for i,v in pairs(t) do + if type(i)=="number" then + i="["..i.."]=" + else + i=i.."=" + end + if type(v)=="string" then + dat=dat..i.."\""..v.."\"," + elseif type(v)=="number" then + dat=dat..i..v.."," + elseif type(v)=="boolean" then + dat=dat..i..tostring(v).."," + elseif type(v)=="table" and not(G==v) then + dat=dat..i..ToStr(v).."," + --elseif type(v)=="table" and G==v then + -- dat=dat..i.."assert(loadstring(\"return self\"))," + elseif type(v)=="function" then + dat=dat..i.."assert(loadstring(\""..escapeStr(string.dump(v)).."\"))," + end + end + return string.sub(dat,1,-2).."}" + end + return "return "..ToStr(G) +end +function Thread:Send(name,var) + arg3="3" + if type(var)=="table" then + var=Thread:packTable(var) + arg3="table" + end + self.ChannelMain:push({name,var,arg3}) +end +function Thread:UnPackChannel() + local c=self.ChannelThread:getCount() + for i=1,c do + local temp=self.ChannelThread:pop() + if temp[1] and temp[2] then + if temp[1]=="func" and type(temp[2])=="string" then + loadstring(temp[2])(temp[3]) + else + _G[temp[1]]=temp[2] + end + end + end + if #multi:getChildren()<2 then + os.sleep(.05) + end +end +function Thread:boost(func,name) + self:Send(name,string.dump(func)) +end +function Thread.mainloop() + Thread:UnPackChannel() +end +Thread.MainThread=false +multi:newLoop():OnLoop(Thread.mainloop) +multi:mainloop() diff --git a/game/Libs/T4.lua b/game/Libs/T4.lua new file mode 100644 index 0000000..a8d3203 --- /dev/null +++ b/game/Libs/T4.lua @@ -0,0 +1,596 @@ +require("love.timer") +require("love.system") +require("love.sound") +require("love.physics") +require("love.mouse") +require("love.math") +require("love.keyboard") +require("love.joystick") +require("love.image") +require("love.font") +require("love.filesystem") +require("love.event") +require("love.audio") +require("love.graphics") +require("love.window") +_defaultfont = love.graphics.getFont() +gui = {} +function gui.getTile(i,x,y,w,h)-- returns imagedata + if type(i)=="userdata" then + -- do nothing + 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 +multi = {} +multi.Version="4.0.0" +multi.__index = multi +multi.Mainloop={} +multi.Tasks={} +multi.Tasks2={} +multi.Garbage={} +multi.Children={} +multi.Paused={} +multi.MasterId=0 +multi.Active=true +multi.Id=-1 +multi.Type="MainInt" +multi.Rest=0 +-- System +os.sleep=love.timer.sleep +function multi:newBase(ins) + if not(self.Type=="MainInt" or self.Type=="int") then error("Can only create an object on multi or an interface obj") return false end + local c = {} + if self.Type=="int" then + setmetatable(c, self.Parent) + else + setmetatable(c, self) + end + c.Active=true + c.func={} + c.Id=0 + c.Act=function() end + c.Parent=self + if ins then + table.insert(self.Mainloop,ins,c) + else + table.insert(self.Mainloop,c) + end + self.MasterId=self.MasterId+1 + return c +end +function multi:reboot(r) + self.Mainloop={} + self.Tasks={} + self.Tasks2={} + self.Garbage={} + self.Children={} + self.Paused={} + self.MasterId=0 + self.Active=true + self.Id=-1 + 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 + i={} + end + end + end + end +end +function multi:getChildren() + return self.Mainloop +end +--Processor +function multi:Do_Order() + for _D=#self.Mainloop,1,-1 do + if self.Mainloop[_D]~=nil then + self.Mainloop[_D].Id=_D + self.Mainloop[_D]:Act() + end + if self.Mainloop[_D].rem then + table.remove(self.Mainloop,_D) + end + end + if self.Rest>0 then + os.sleep(self.Rest) + end +end +function multi:benchMark(sec) + local temp=self:newLoop(function(t,self) + if os.clock()-self.init>self.sec then + print(self.c.." steps in "..self.sec.." second(s)") + self.tt(self.sec) + self:Destroy() + else + self.c=self.c+1 + end + end) + function temp:OnBench(func) + self.tt=func + end + self.tt=function() end + temp.sec=sec + temp.init=os.clock() + temp.c=0 + return temp +end +function multi:newInterface() + if not(self.Type=="MainInt") then error("Can only create an interface on the multi obj") return false end + local c = {} + setmetatable(c, self) + c.Parent=self + c.Active=true + c.func={} + c.Id=0 + c.Type="int" + c.Mainloop={} + c.Tasks={} + c.Tasks2={} + c.Garbage={} + c.Children={} + c.Paused={} + c.MasterId=0 + c.Active=true + c.Id=-1 + c.Rest=0 + function c:Start() + if self.l then + self.l:Resume() + else + self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end) + end + end + function c:Stop() + if self.l then + self.l:Pause() + end + end + function c:Remove() + self:Destroy() + self.l:Destroy() + end + return c +end +--Helpers +function multi:FreeMainEvent() + self.func={} +end +function multi:isPaused() + return not(self.Active) +end +function multi:Pause(n) + if self.Type=="int" or self.Type=="MainInt" then + self.Active=false + if not(n) then + local c=self:getChildren() + for i=1,#c do + c[i]:Pause() + end + else + self:hold(n) + end + else + if not(n) then + 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.Id=#self.Parent.Paused + end + else + self:hold(n) + end + end +end +function multi:Resume() + if self.Type=="int" or self.Type=="MainInt" then + self.Active=true + local c=self:getChildren() + for i=1,#c do + c[i]:Resume() + end + else + if self:isPaused() then + self.Active=true + for i=1,#self.Parent.Paused do + if self.Parent.Paused[i]==self then + table.remove(self.Parent.Paused,i) + return + end + end + table.insert(self.Parent.Mainloop,self) + end + end +end +function multi:Destroy() + if self.Type=="int" or self.Type=="MainInt" then + local c=self:getChildren() + for i=1,#c do + c[i]:Destroy() + end + else + self.rem=true + end +end +function multi:hold(task) + self:Pause() + if type(task)=="number" then + local alarm=self:newAlarm(task) + while alarm.Active==true do + if love then + self.Parent.lManager() + else + self.Parent.Do_Order() + end + end + alarm:Destroy() + self:Resume() + elseif type(task)=="function" then + local env=self.Parent:newEvent(task) + env:OnEvent(function(envt) envt:Pause() envt:Stop() end) + while env.Active do + if love then + self.Parent.lManager() + else + self.Parent.Do_Order() + end + end + env:Destroy() + self:Resume() + else + print("Error Data Type!!!") + end +end +function multi:oneTime(func,...) + if not(self.Type=="MainInt" or self.Type=="int") then + for _k=1,#self.Parent.Tasks2 do + if self.Parent.Tasks2[_k]==func then + return false + end + end + table.insert(self.Parent.Tasks2,func) + func(...) + return true + else + for _k=1,#self.Tasks2 do + if self.Tasks2[_k]==func then + return false + end + end + table.insert(self.Tasks2,func) + func(...) + return true + end +end +--Constructors +function multi:newEvent(task) + local c=self:newBase() + c.Type="Event" + c.Task=task or function() end + function c:Act() + if self.Task(self) and self.Active==true then + self:Pause() + for _E=1,#self.func do + self.func[_E](self) + end + end + end + function c:OnEvent(func) + table.insert(self.func,func) + end + return c +end +function multi:newAlarm(set) + local c=self:newBase() + c.Type="Alarm" + c.timer=os.clock() + c.set=set or 0 + function c:Act() + if self.Active==true then + if os.clock()-self.timer>=self.set then + self:Pause() + for i=1,#self.func do + self.func[i](self) + end + end + end + end + function c:Reset(n) + if n then self.set=n end + self.timer=os.clock() + self:Resume() + end + function c:OnRing(func) + table.insert(self.func,func) + end + return c +end +function multi:newTask(func) + table.insert(self.Tasks,func) +end +function multi:newLoop(func) + local c=self:newBase() + c.Type="Loop" + if func then + c.func={func} + end + function c:Act() + if self.Active==true then + for i=1,#self.func do + self.func[i](os.clock()-self.Parent.Start,self) + end + end + end + function c:OnLoop(func) + table.insert(self.func,func) + end + 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.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.Active==true then + for i=1,#self.func do + self.func[i](self.pos,self) + end + self.pos=self.pos+self.count + end + end + end + self.spos=self.spos+1 + if self.spos>=self.skip then + self.spos=0 + end + end + function c:OnStep(func) + table.insert(self.func,1,func) + end + function c:OnEnd(func) + table.insert(self.funcE,func) + 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:OnStep(function(p,s) + if s.count>0 and s.endAt==p then + for fe=1,#s.funcE do + s.funcE[fe](s) + end + s.pos=s.start-1 + elseif s.count<0 and s.endAt==p then + for fe=1,#s.funcE do + s.funcE[fe](s) + end + s.pos=s.start-1 + end + end) + return c +end +function multi:newTStep(start,reset,count,set) + local c=self:newBase() + think=1 + c.Type="TStep" + 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 + function c:Update(start,reset,count,set) + self.start=start or self.start + self.pos=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:Act() + if self.Active then + if os.clock()-self.timer>=self.set then + self:Reset() + for i=1,#self.func do + self.func[i](self.pos,self) + end + if self.endAt==self.pos then + for fe=1,#self.funcE do + self.funcE[fe](self) + end + self.pos=self.start-1 + end + self.pos=self.pos+self.count + end + end + end + function c:OnEnd(func) + table.insert(self.funcE,func) + end + function c:Reset(n) + if n then self.set=n end + self.timer=os.clock() + self:Resume() + end + function c:OnStep(func) + table.insert(self.func,func) + end + return c +end +function multi:newTrigger(func) + local c=self:newBase() + c.Type="Trigger" + c.trigfunc=func or function() end + function c:Fire(...) + self:trigfunc(self,...) + end + return c +end +--Managers +function multi:mainloop() + for i=1,#self.Tasks do + self.Tasks[i](self) + end + self.Start=os.clock() + while self.Active do + self:Do_Order() + end +end +function multi._tFunc(self,dt) + for i=1,#self.Tasks do + self.Tasks[i](self) + end + print("once!") + if dt then + self.pump=true + end + self.pumpvar=dt + self.Start=os.clock() +end +function multi:uManager(dt) + self:oneTime(self._tFunc,self,dt) + self:Do_Order() +end +multi.drawF={} +function multi:dManager() + for ii=1,#multi.drawF do + multi.drawF[ii]() + end +end +function multi:onDraw(func) + table.insert(self.drawF,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 +Thread={} +Thread.Name="Thread 4" +Thread.ChannelThread = love.thread.getChannel("Easy4") +Thread.ChannelMain = love.thread.getChannel("EasyMain") +Thread.Global = {} +function Thread:packTable(G) + function escapeStr(str) + local temp="" + for i=1,#str do + temp=temp.."\\"..string.byte(string.sub(str,i,i)) + end + return temp + end + function ToStr(t) + local dat="{" + for i,v in pairs(t) do + if type(i)=="number" then + i="["..i.."]=" + else + i=i.."=" + end + if type(v)=="string" then + dat=dat..i.."\""..v.."\"," + elseif type(v)=="number" then + dat=dat..i..v.."," + elseif type(v)=="boolean" then + dat=dat..i..tostring(v).."," + elseif type(v)=="table" and not(G==v) then + dat=dat..i..ToStr(v).."," + --elseif type(v)=="table" and G==v then + -- dat=dat..i.."assert(loadstring(\"return self\"))," + elseif type(v)=="function" then + dat=dat..i.."assert(loadstring(\""..escapeStr(string.dump(v)).."\"))," + end + end + return string.sub(dat,1,-2).."}" + end + return "return "..ToStr(G) +end +function Thread:Send(name,var) + arg3="4" + if type(var)=="table" then + var=Thread:packTable(var) + arg3="table" + end + self.ChannelMain:push({name,var,arg3}) +end +function Thread:UnPackChannel() + local c=self.ChannelThread:getCount() + for i=1,c do + local temp=self.ChannelThread:pop() + if temp[1] and temp[2] then + if temp[1]=="func" and type(temp[2])=="string" then + loadstring(temp[2])(temp[3]) + else + _G[temp[1]]=temp[2] + end + end + end + if #multi:getChildren()<2 then + os.sleep(.05) + end +end +function Thread:boost(func,name) + self:Send(name,string.dump(func)) +end +function Thread.mainloop() + Thread:UnPackChannel() +end +Thread.MainThread=false +multi:newLoop():OnLoop(Thread.mainloop) +multi:mainloop() diff --git a/game/Libs/ThreadManager.lua b/game/Libs/ThreadManager.lua new file mode 100644 index 0000000..de6434d --- /dev/null +++ b/game/Libs/ThreadManager.lua @@ -0,0 +1,158 @@ +Thread={} +Thread.ChannelT1 = love.thread.getChannel("Easy1") +Thread.ChannelT2 = love.thread.getChannel("Easy2") +Thread.ChannelT3 = love.thread.getChannel("Easy3") +Thread.ChannelT4 = love.thread.getChannel("Easy4") +Thread.ChannelMain = love.thread.getChannel("EasyMain") +Thread.Name = "Thread Main" +Thread.n=0 +Thread.count=1 +function Thread:packTable(G) + function escapeStr(str) + local temp="" + for i=1,#str do + temp=temp.."\\"..string.byte(string.sub(str,i,i)) + end + return temp + end + function ToStr(t) + local dat="{" + for i,v in pairs(t) do + if type(i)=="number" then + i="["..i.."]=" + else + i=i.."=" + end + if type(v)=="string" then + dat=dat..i.."\""..v.."\"," + elseif type(v)=="number" then + dat=dat..i..v.."," + elseif type(v)=="boolean" then + dat=dat..i..tostring(v).."," + elseif type(v)=="table" and not(G==v) then + dat=dat..i..bin.ToStr(v).."," + --elseif type(v)=="table" and G==v then + -- dat=dat..i.."assert(loadstring(\"return self\"))," + elseif type(v)=="function" then + dat=dat..i.."assert(loadstring(\""..escapeStr(string.dump(v)).."\"))," + end + end + return string.sub(dat,1,-2).."}" + end + return ToStr(G) +end +Thread.last={} +function Thread:GetStatus() + print(self.n.." Threads Exist!!!") + for i=1,self.n do + print("\tThread "..i.." Running: "..tostring(self["Thread"..i]:isRunning())) + if not(self["Thread"..i]:isRunning()) then + print("\t\t"..self["Thread"..i]:getError()) + end + end +end +function Thread:Start(n) + local x=love.system.getProcessorCount() + if x>1 then + x=x-1 + else + x=1 + end + n=n or x + if n<1 then + print("Must be atleast 1 thread running!!!") + return + end + if n>4 then + print("Must be no more than 4 threads running!!!") + return + end + for i=1,n do + self["Thread"..i]=love.thread.newThread("Libs/T"..i..".lua") + self["Thread"..i]:start() + end + Thread.n=n +end +function Thread:RestartBroken() + for i=1,self.n do + if self["Thread"..i]:isRunning()==false then + self["Thread"..i]:start() + end + Thread:Boost(Thread.last[1],Thread.last[2]) + end +end +function Thread:Send(name,var,arg3) + if self.n>0 then + if type(var)=="table" then + var=Thread:packTable(var) + arg3=name + name="table" + end + self["ChannelT"..((self.count-1)%self.n)+1]:push({name,var,arg3}) + self.count=self.count+1 + end +end +function Thread:SendAll(name,var,arg3) + if self.n>0 then + for i=1,self.n do + if type(var)=="table" then + var=Thread:packTable(var) + arg3=name + name="table" + end + self["ChannelT"..i]:push({name,var,arg3}) + end + end +end +function Thread:UnPackChannel() + local c=self.ChannelMain:getCount() + for i=1,c do + local temp=self.ChannelMain:pop() + if temp[3]=="table" then + _G[temp[1]]=assert(loadstring(temp[2]))() + else + if Thread.OnDataRecieved then + Thread.OnDataRecieved(temp[1],temp[2],temp[3]) + end + _G[temp[1]]=temp[2] + end + end +end +function Thread:Boost(func,name) + if Thread.last[1]==nil then + return + end + Thread.last={func,name} + name=name or "nil" + if self.n>0 then + self:Send("func",string.dump(func),name) + end +end +function Thread:SendLibs(func,name) + name=name or "nil" + if self.n>0 then + self:SendAll("func",string.dump(func),name) + end +end +function Thread.mainloop() + if Thread.n>0 then + Thread:UnPackChannel() + end +end +Thread.MainThread=true +local loop = multi:newLoop() +loop:OnLoop(Thread.mainloop) +OnThreadError=multi:newConnection() +function love.threaderror(thread, errorstr) + Thread:GetStatus() + Thread:RestartBroken() + Thread:GetStatus() + OnThreadError:Fire(thread,errorstr) +end +multi:newTask(function() + math.randomseed(math.floor(os.time()/2)) + for i=1,Thread.n do + Thread["ChannelT"..i]:push({"randseed",math.random(-1000000,1000000)}) + Thread["ChannelT"..i]:push({"func",string.dump(function() math.randomseed(randseed) end),"randomizing"}) + end +end) diff --git a/game/core/Utils.lua b/game/Libs/Utils.lua similarity index 100% rename from game/core/Utils.lua rename to game/Libs/Utils.lua diff --git a/game/core/bin.lua b/game/Libs/bin.lua similarity index 81% rename from game/core/bin.lua rename to game/Libs/bin.lua index da72b86..3c0a143 100644 --- a/game/core/bin.lua +++ b/game/Libs/bin.lua @@ -6,7 +6,7 @@ +Enhance VFS stuff ]] bin={} -bin.Version={4,5,0} +bin.Version={4,1,0} bin.stage='stable' bin.help=[[ For a list of features do print(bin.Features) @@ -17,8 +17,8 @@ For help do print(bin.help) :D ]] bin.credits=[[ Credits: - Crafted by, Ryan Ward - lzw,bit shift, and b64 conversion are not mine + Everything by me, Ryan Ward + Except the randomGen Stuff I forgot who i took that from, edits by me though :) ]] bin.Features=bin.Version[1]..'.'..bin.Version[2]..'.'..bin.Version[3]..' '..bin.stage..[[ @@ -51,7 +51,6 @@ vfs = bin.loadVFS(path) -- loads a saved .lvfs file --Beta buf = bin:newDataBuffer(s) -- creates a databuffer binobj = bin.bufferToBin(b) -- converts a buffer object to a bin object buf = bin.binToBuffer(b) -- converts a bin object to a buffer obj -buf = bin:getDataBuffer(a,b) -- gets a speical buffer that opperates on a streamed file. It works just like a regular data buffer blockWriter = bin.newNamedBlock(indexSize) -- returns a block writer object index size is the size of the index where labels and pointers are stored blockWriter = bin.newStreamedNamedBlock(indexSize,path) -- returns a streamed version of the above path is the path to write the file blockReader = bin.loadNamedBlock(path) -- returns a block reader object, path is where the file is located @@ -64,8 +63,8 @@ Helpers ------- string = bin.randomName(n,ext) -- creates a random file name if n and ext is nil then a random length is used, and '.tmp' extension is added string = bin.NumtoHEX(n) -- turns number into hex -binobj = bin.HEXtoBin(s)*D -- turns hex data into binobj -string = bin.HEXtoStr(s)*D -- turns hex data into string/text +binobj = bin.HEXtoBin(s) -- turns hex data into binobj +string = bin.HEXtoStr(s) -- turns hex data into string/text string = bin.tohex(s) -- turns string to hex string = bin.fromhex(s) -- turns hex to string string = bin.endianflop(data) -- flips the high order bits to the low order bits and viseversa @@ -158,7 +157,6 @@ string = bitobj:getBin() -- returns 1's & 0's of the bitobj * 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=[[ @@ -285,77 +283,11 @@ Woot!!! Version 3 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.__tostring=function(self) return self.data end bin.__len=function(self) return self:getlength() end bits={} bits.data='' @@ -364,7 +296,6 @@ 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 ------------------------------------------]] @@ -667,16 +598,6 @@ function io.getFullName(name) 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 @@ -980,121 +901,9 @@ function randomGen:newND(a,b,s) 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 @@ -1140,40 +949,11 @@ function bin:find(...) return self.data:find(...) end function bin.fromhex(str) + print(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 @@ -1192,38 +972,22 @@ function bin:streamData(a,b) 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) +function bin.new(data,hex) data=data or "" data=tostring(data) local c = {} setmetatable(c, bin) - if string.sub(data,1,2)=='0x' and hex then + if string.sub(data,1,2)=='0x' and hex==true 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 @@ -1236,7 +1000,6 @@ function bin.stream(file,l) c.workingfile=io.open(file,'rb+') end c.Stream=true - bin.streams[file]=c return c end function bin:streamwrite(d,n) @@ -1250,15 +1013,9 @@ function bin:streamwrite(d,n) 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) + a=tonumber(a) + b=tostring(b) + return bin.load(self.file,a,b).data end function bin:close() if self:canStreamWrite() then @@ -1280,114 +1037,8 @@ 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() @@ -1439,20 +1090,7 @@ function bin:getHash(n) 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) +function bin:newDataBuffer(s) local c={} local mt={ __index=function(t,k,v) @@ -1467,28 +1105,17 @@ function bin:newDataBuffer(s,def) 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 + t.dataS[k]=string.char(v) 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) + s=string.rep("\0",s) else c.maxBuffer=math.huge end @@ -1505,9 +1132,6 @@ function bin:newDataBuffer(s,def) return table.concat(self.dataS,"") end end - function c:getData() - return table.concat(self.dataS,"") - end function c:getBufferTable() return self.dataS end @@ -1520,9 +1144,6 @@ function bin:newDataBuffer(s,def) 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 @@ -2057,7 +1678,7 @@ function bin:addBlock(d,n,e) temp.data=temp.data..'_EOF' temp:flipbits() else - temp=bin.new(bits.numToBytes(d,n)) + temp=bits.new(d):tobytes() if not n then temp.data=temp.data..'_EOF' temp:flipbits() @@ -2369,11 +1990,7 @@ 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 + return self.data end function bin.getLuaVersion() if type(jit)=="table" then @@ -2646,63 +2263,6 @@ function bin.getIndexSize(tab) 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 ------------------------------------------]] @@ -2987,89 +2547,10 @@ 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) +function bits.new(n) 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 + if not t then t={} for i=#n,1,-1 do table.insert(t,bits:conv(string.byte(n,i))) @@ -3099,26 +2580,13 @@ function bits.new(n,s) 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) +function bits.numToBytes(n,fit) 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) + print("Warning: attempting to store a number that takes up more space than allotted!") + return num:sub(1,fit) elseif fit==#num then return num else diff --git a/game/Libs/lovebind.lua b/game/Libs/lovebind.lua new file mode 100644 index 0000000..eca6618 --- /dev/null +++ b/game/Libs/lovebind.lua @@ -0,0 +1,103 @@ +os.sleep=love.timer.sleep +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,l) + error("Sorry streaming is not available when using love2d :(, I am looking for a solution though :)") +end +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/Libs/test.dat b/game/Libs/test.dat new file mode 100644 index 0000000..8b9302a Binary files /dev/null and b/game/Libs/test.dat differ diff --git a/game/core/test.lua b/game/Libs/test.lua similarity index 100% rename from game/core/test.lua rename to game/Libs/test.lua diff --git a/game/audio/Rope_Cracking.mp3 b/game/audio/Rope_Cracking.mp3 new file mode 100644 index 0000000..f78a459 Binary files /dev/null and b/game/audio/Rope_Cracking.mp3 differ diff --git a/game/audio/elevator.ogg b/game/audio/elevator.ogg new file mode 100644 index 0000000..327c55d Binary files /dev/null and b/game/audio/elevator.ogg differ diff --git a/game/audio/elevator_open_close.mp3 b/game/audio/elevator_open_close.mp3 new file mode 100644 index 0000000..21c5ec9 Binary files /dev/null and b/game/audio/elevator_open_close.mp3 differ diff --git a/game/audio/footsteps.ogg b/game/audio/footsteps.ogg new file mode 100644 index 0000000..8c64184 Binary files /dev/null and b/game/audio/footsteps.ogg differ diff --git a/game/bin/init.lua b/game/bin/init.lua index 3728c6f..9b63651 100644 --- a/game/bin/init.lua +++ b/game/bin/init.lua @@ -684,6 +684,9 @@ if love then temp.filepath=file return temp end + function bin.fileExists(name) + return love.filesystem.exists(name) + end function bin:tofile(filename) if not(filename) or self.Stream then return nil end love.filesystem.write(filename,self.data) diff --git a/game/bin/support/utils.lua b/game/bin/support/utils.lua index 957b168..cc6efa6 100644 --- a/game/bin/support/utils.lua +++ b/game/bin/support/utils.lua @@ -70,6 +70,10 @@ function io.dirExists(strFolderName) end end end +function bin.fileExists(name) + local f=io.open(name,"r") + if f~=nil then io.close(f) return true else return false end +end function bin.randomName(n,ext) n=n or math.random(7,15) if ext then diff --git a/game/conf.lua b/game/conf.lua index f9a21e3..80d26f1 100644 --- a/game/conf.lua +++ b/game/conf.lua @@ -1,12 +1,12 @@ function love.conf(t) t.identity = nil -- The name of the save directory (string) - t.version = "0.10.2" -- The LOVE version this game was made for (string) + t.version = "0.10.1" -- The LOVE version this game was made for (string) t.console = true -- Attach a console (boolean, Windows only) - t.window.title = "Chat Client" -- The window title (string) + t.window.title = "game" -- The window title (string) t.window.icon = nil -- Filepath to an image to use as the window's icon (string) - t.window.width = 1280 -- The window width (number) - t.window.height = 720 -- The window height (number) + t.window.width = 1200 -- The window width (number) + t.window.height = 738 -- The window height (number) t.window.borderless = false -- Remove all border visuals from the window (boolean) t.window.resizable = false -- Let the window be user-resizable (boolean) t.window.minwidth = 1 -- Minimum window width if the window is resizable (number) diff --git a/game/core/GuiManager.lua b/game/core/GuiManager.lua deleted file mode 100644 index f86fa69..0000000 --- a/game/core/GuiManager.lua +++ /dev/null @@ -1,4027 +0,0 @@ -utf8 = require("utf8") -_defaultfont = love.graphics.getFont() -gui = {} -gui.__index = gui -gui.TB={} -gui.Version="8.0.0" -- 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 - -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 - -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/gamedata/config.txt b/game/gamedata/config.txt new file mode 100644 index 0000000..4a742b6 --- /dev/null +++ b/game/gamedata/config.txt @@ -0,0 +1,16 @@ +LOAD gamedata/lobby.txt +[CONFIG]{ + //newThread("THREAD") // Starts a thread that handles events and stuff... Just throw this in and things flow nicely + SND_ELEVATOR_BG=loadAudio("audio/elevator.ogg") + SND_ELEVATOR_OPEN_CLOSE=loadAudio("audio/elevator_open_close.mp3") + SND_ROPE_CRACKING=loadAudio("audio/rope_cracking.mp3") + SND_FOOTSTEPS=loadAudio("audio/footsteps.ogg") + JUMP("LOBBY") // Lets start the game Jumping to block lobby in lobby.txt +} +[THREAD]{ + ::threadloop:: + sleep(.001) // No need to put this in, but it is used to help show you whats going on + //Setting up a thread alone allows for events to be process automatically + //All variables are shared between all threads! Functions binded to the external language will be ran in a thread + GOTO("threadloop") +} diff --git a/game/gamedata/lobby.txt b/game/gamedata/lobby.txt new file mode 100644 index 0000000..aaedd32 --- /dev/null +++ b/game/gamedata/lobby.txt @@ -0,0 +1,57 @@ +//SND_ELEVATOR_BG +//SND_ELEVATOR_OPEN_CLOSE +//SND_ROPE_CRACKING +//SND_FOOTSTEPS +[LOBBY]{ + BG("images/elevator-lobby.jpg") + "Abby: Oh no I'm running late!" + "Abby: I hope I make my interview" + playAudio(SND_ELEVATOR_OPEN_CLOSE) + "Abby: Great someone just walked out of the elevator" + playSong(SND_FOOTSTEPS) + "Abby: lets hope i make it" + "Abby: Alright, let me get it this thing" + BG("images/elevator.jpg") + "Abby: ok 10th floor it is" + playAudio(SND_ELEVATOR_OPEN_CLOSE) + playSongLooped(SND_ELEVATOR_BG) + "Abby: Hurry up... I am going to be so late" + "Abby: Wait! What was that?" + playAudio(SND_ROPE_CRACKING) + "That doesn't sound good" + ::choose:: + "What should I do"< + "Cry" JUMP("CRY") + "Call for help" JUMP("HELP") + "Wait it out" JUMP("WAIT") + > +} +[CRY]{ + cry=true // used for future decisions + "Abby: crying is nice, but it won't help any" + GOTOE("choose") +} +[HELP]{ + help=true // used for future decisions + "Abby: Ok let me press this call button" + "..." + "Employee: Hello what is going on?" + "Abby: There is an issue with the elevator! I hear a cracking sound" + "Employee: Hmm... Our sensors say everything is ok" + "Abby: Oh alright... Maybe I am a bit nervous about this interview" + "Employee: No worries, and good luck" + "Abby: Thanks" + JUMP("NOTHING") +} +[WAIT]{ + wait=true // used for future decisions + "Abby: I am sure its nothing" + JUMP("NOTHING") +} +[NOTHING]{ + "RYAN: And it all leads to here eventually" + "What to do try other options"< + "Yes" GOTOE("choose") + "I had enough" QUIT() + > +} \ No newline at end of file diff --git a/game/images/arrow.png b/game/images/arrow.png new file mode 100644 index 0000000..78ad96d Binary files /dev/null and b/game/images/arrow.png differ diff --git a/game/images/elevator-lobby.jpg b/game/images/elevator-lobby.jpg new file mode 100644 index 0000000..a02f601 Binary files /dev/null and b/game/images/elevator-lobby.jpg differ diff --git a/game/images/elevator.jpg b/game/images/elevator.jpg new file mode 100644 index 0000000..baa31f7 Binary files /dev/null and b/game/images/elevator.jpg differ diff --git a/game/images/girl.png b/game/images/girl.png new file mode 100644 index 0000000..24e7a9f Binary files /dev/null and b/game/images/girl.png differ diff --git a/game/init.txt b/game/init.txt new file mode 100644 index 0000000..cd8ec20 --- /dev/null +++ b/game/init.txt @@ -0,0 +1,3 @@ +ENTRY CONFIG +LOAD gamedata/config.txt +//A file without blocks needs at least 1 new line to be properly parsed \ No newline at end of file diff --git a/game/main.lua b/game/main.lua index 9fcbc2a..29435f2 100644 --- a/game/main.lua +++ b/game/main.lua @@ -1,11 +1,309 @@ -love.filesystem.setIdentity("love2dstreamtest") -require("core.Utils") -require("core.Library") +--package.path="/?/init.lua;"..package.path +require("Libs/Library") +--~ require("Libs/Utils") require("bin") -GLOBAL,sThread=require("multi.integration.loveManager").init() -require("core.AudioManager") -require("core.GuiManager") +require("multi.compat.love2d") -- for use with the love2d engine require("parseManager") -gui.ff.Color=Color.Black --- I just added this ---mad confusing +require("Libs/lovebind") +require("GuiManager") +gui.LoadAll("Interface") +function form(link,x,y,w,h,sx,sy,sw,sh) + local x,y,w,h,sx,sy,sw,sh=(link:varExists(x) or tonumber(x)),(link:varExists(y) or tonumber(y)),(link:varExists(w) or tonumber(w)),(link:varExists(h) or tonumber(h)),(link:varExists(sx) or tonumber(sx)),(link:varExists(sy) or tonumber(sy)),(link:varExists(sw) or tonumber(sw)),(link:varExists(sh) or tonumber(sh)) + return x,y,w,h,sx,sy,sw,sh +end +actornum=0 +animnum=0 +rand=randomGen:new(0) +parseManager:define{ + getInput=function(self,msg) + return multi:newFunction(function(mulitobj,self,msg) + inputBox.message.text=msg + inputBox.Visible=true + go.Visible=false + self.handle:Pause() + while _inputvar==nil do + multi:lManager() + end + self.handle:Resume() + local i=_inputvar + _inputvar=nil + inputBox.Visible=false + go.Visible=true + return i + end)(self,msg) + end, + loadAudio=function(self,path) + return love.audio.newSource(path) + end, + loadSong=function(self,path) + return love.audio.newSource(path) + end, + playSongLooped=function(self,item) + item:setLooping(true) + item:play() + end, + playAudio=function(self,item,n) + item:play() + if n then + multi:newAlarm(n):OnRing(function() + item:stop() + end) + end + end, + playSong=function(self,item,n) + item:play() + if n then + multi:newAlarm(n):OnRing(function() + item:stop() + end) + end + end, + sleep=function(self,n) + local num=n + self.handle:hold(num) + end, + fadeSong=function(self,item) + self.handle:Pause() + local handle=self:varExists(item) + local step=multi:newTStep(100,0,-1,.05) + step:OnStep(function(pos,self) + handle:setVolume(pos/100) + end) + while handle:getVolume()~=0 do + multi:lManager() + end + self.handle:Resume() + end, + stopAudio=function(self,item) + item:stop() + end, + stopSong=function(self,item) + if self:varExists(item)==nil then + love.audio.stop() + return + end + item:stop() + end, + pauseAudio=function(self,item) + item:pause() + end, + cls=function(self) + core.chatFrame.textHolder.text="" + end, + BG=function(self,path) + core:SetImage(path) + end, + SHOW=function(self,item) + self:varExists(item).Visible=true + end, + HIDE=function(self,item) + self:varExists(item).Visible=false + end, + createObject=function(self,x,y,w,h,sx,sy,sw,sh) + actornum=actornum+1 + local x,y,w,h,sx,sy,sw,sh=form(self,x,y,w,h,sx,sy,sw,sh) + local obj=workspace:newItem("",nil,"Actor "..actornum, x, y, w, h, sx ,sy ,sw ,sh) + if obj.DPI>=2 then + obj.DPI=obj.DPI-1 + end + print("OBJECT: "..tostring(obj)) + return obj + end, + makeObject=function(self,link,x,y,w,h,sx,sy,sw,sh) + actornum=actornum+1 + local x,y,w,h,sx,sy,sw,sh=form(self,x,y,w,h,sx,sy,sw,sh) + local obj= link:newItem("",nil,"Actor "..actornum, x, y, w, h, sx ,sy ,sw ,sh) + if obj.DPI>=2 then + obj.DPI=obj.DPI-1 + end + return obj + end, + createAnimation=function(self,file,delay,x,y,w,h,sx,sy,sw,sh) + local file,delay=(self:varExists(file) or file),(tonumber(self:varExists(delay)) or tonumber(delay)) + animnum=animnum+1 + local x,y,w,h,sx,sy,sw,sh=form(self,x,y,w,h,sx,sy,sw,sh) + local anim = workspace:newAnim(file,delay, x, y, w, h, sx ,sy ,sw ,sh) + anim:OnAnimEnd(function(link) + link:Reset() + link:Resume() + end) + if anim.DPI>=2 then + anim.DPI=anim.DPI-1 + end + return anim + end, + stopAnimation=function(self,item) + item:Pause() + end, + resumeAnimation=function(self,item) + item:Resume() + end, + resetAnimation=function(self,item) + item:Reset() + end, + setImage=function(self,item,path) + smartPrint(item) + item:SetImage(path) + end, + setText=function(self,item,text) + if type(item)=="string" then + print(actor) + self:pushError("item must be a gui object!") + end + item.text=text + end, + JUMPPLAY=function(self,to,handle) + self.methods.playSong(self,handle) + self.methods.JUMP(self,to) + end, + setPosition=function(self,item,x,y,w,h,sx,sy,sw,sh) + local x,y,w,h,sx,sy,sw,sh=form(self,x,y,w,h,sx,sy,sw,sh) + item:SetDualDim(x,y,w,h,sx,sy,sw,sh) + end, + makeDraggable=function(self,item,db) + item.Draggable=true + if db then + item.dragbut=db + end + end, + centerX=function(self,item) + item:centerX() + end, + centerY=function(self,item) + item:centerY() + end, + centerXY=function(self,item) + item:centerX() + item:centerY() + end, + setVar=function(self,v,t) if t=="n" then return tonumber(v) else return v end end, + destroy=function(self,item) + item:Destroy() + end, + loadImage=function(self,path) + -- + end, + newThread=function(blocklink,block) + multi:newThread(block.." [Thread]",function() + local ThreadTest=parseManager:load(blocklink.chunks[block].path) + ThreadTest.mainENV=blocklink.mainENV + ThreadTest.handle=loop + ThreadTest:define{ + sleep=function(self,n) + thread.sleep(n) + end + } + local t=ThreadTest:next(block) + while true do + if t.Type=="text" then + print(t.text) + t=ThreadTest:next() + else + t=ThreadTest:next() + end + end + end) + end, +} +gui.enableAutoWindowScaling(true) +core=gui:newImageLabel(nil,0,0,0,0,0,0,1,1)--gui:newFullImageLabel("fire.jpg","BG") +workspace=core:newFullFrame() +top=gui:newFrame("",0,0,0,0,0,0,1,1) +workspace.Visibility=0 +top.Visibility=0 +core.chatFrame=core:newFrame("chatFrame",20,-100,-40,80,0,1,1) +core.chatFrame:setRoundness(10,10,360) +core.chatFrame.BorderSize=4 +core.chatFrame.textHolder=core.chatFrame:newTextLabel("","",5,5,-10,-10,0,0,1,1) +core.chatFrame.textHolder.Visibility=0 +core.chatFrame.textHolder.text="" +core.chatFrame.textHolder.TextFormat="left" +test=parseManager:load("init.txt") +table.print(test) +--~ print("DUMP:") +dump=test:dump() +print(dump) +bin.new(dump):tofile("Dump.dat") +test.mainENV["gui"]=workspace +test.mainENV["menu"]=top +go=core.chatFrame.textHolder:newImageButton("images/arrow.png",-25,-25,20,20,1,1) +go:OnReleased(function(b,self) + dialogeHandler:Resume() +end) +dialogeHandler=multi:newLoop(function(self,ti) + t=test:next() + if t.Type=="text" then + core.chatFrame.textHolder.text=t.text + self:Pause() + elseif t.Type=="choice" then + go.Visible=false + local choiceframe=gui:newFrame("",0,0,300,(#t+1)*40-10) + choiceframe:newTextLabel(t.prompt,0,0,0,40,0,0,1).Color=Color.light_blue + for i=1,#t[1] do + local choice=choiceframe:newTextButton(t[1][i],0,i*40,0,40,0,0,1) + choice.Color=Color.Darken(Color.saddle_brown,.15) + choice.index=i + choice:OnReleased(function(b,self) + choicemade=self.index + end) + end + choiceframe:centerX() + choiceframe:centerY() + self:Pause() + while choicemade==nil do + multi:lManager() + end + self:Resume() + go.Visible=true + choiceframe:Destroy() + local cm=choicemade + choicemade=nil + t=test:next(nil,cm) + end +end) +test.handle=dialogeHandler +inputBox=gui:newFrame(0,0,500,160) +inputBox.Visibility=0 +inputBox.header=inputBox:newFrame(0,0,8,28,0,0,1) +inputBox.header.Visibility=0 +inputBox.header.ClipDescendants=true +inputBox.header.helper=inputBox.header:newFrame("",4,4,-8,40,0,0,1) +inputBox.header.helper.BorderSize=4 +inputBox.header.helper:setRoundness(10,20,360) +inputBox.header.helper:ApplyGradient{Color.Brown,Color.Lighten(Color.Brown,.15)} +inputBox.body=inputBox:newFrame("",4,28,0,150,0,0,1) +inputBox.body.BorderSize=4 +inputBox.body:ApplyGradient{Color.tan,Color.Lighten(Color.tan,.3)} +inputBox.X=inputBox.header.helper:newTextButton("X","X",-23,4,15,15,1) +inputBox.X:setRoundness(5,5,360) +inputBox.X:ApplyGradient{Color.red,Color.Lighten(Color.red,.2)} +inputBox.X.Tween=-6 +inputBox.X.XTween=-2 +inputBox.message=inputBox.body:newTextLabel("","Prompt",0,0,0,0,.05,.1,.9,.5) +inputBox.input2=inputBox.body:newTextLabel("","",0,0,0,30,.05,.65,.7) +inputBox.input=inputBox.body:newTextBox("","Enter Text",0,0,0,30,.05,.65,.7) +inputBox.enter=inputBox.body:newTextButton("","GO",0,0,0,30,.8,.65,.15) +inputBox.message.BorderSize=4 +inputBox.input2.BorderSize=4 +inputBox.enter.BorderSize=4 +inputBox.message:setRoundness(5,5,360) +inputBox.input2:setRoundness(5,5,360) +inputBox.input2:ApplyGradient{Color.tan,Color.Lighten(Color.tan,.2)} +inputBox.enter:ApplyGradient{Color.Darken(Color.green,.2),Color.green} +inputBox.enter:setRoundness(5,5,360) +inputBox.enter:OnReleased(function(b,self) + _inputvar=inputBox.input.text + inputBox.Visible=false +end) +inputBox.input:OnEnter(function(self,text) + _inputvar=inputBox.input.text + inputBox.Visible=false +end) +inputBox.input.TextFormat="left" +inputBox.input.XTween=3 +inputBox.input.Visibility=0 +inputBox.input.ClipDescendants=true +inputBox:centerX() +inputBox:centerY() +inputBox.Visible=false +--~ t=test:next() -- lets start this! diff --git a/game/multi/init.lua b/game/multi/init.lua index c824b9e..d8f818b 100644 --- a/game/multi/init.lua +++ b/game/multi/init.lua @@ -1166,7 +1166,7 @@ function multi:newUpdater(skip) end self.pos=self.pos+1 end - function c:setSkip(n) + function c:SetSkip(n) self.skip=n end c.OnUpdate=self.OnMainConnect diff --git a/game/parseManager/AICM.lua b/game/parseManager/AICM.lua deleted file mode 100644 index 23496fa..0000000 --- a/game/parseManager/AICM.lua +++ /dev/null @@ -1,37 +0,0 @@ -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 deleted file mode 100644 index 08ac193..0000000 --- a/game/parseManager/EBIM.lua +++ /dev/null @@ -1,71 +0,0 @@ -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 deleted file mode 100644 index 26fb46f..0000000 --- a/game/parseManager/bytecode.lua +++ /dev/null @@ -1,44 +0,0 @@ --- 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 index af90212..c95feb2 100644 --- a/game/parseManager/init.lua +++ b/game/parseManager/init.lua @@ -1,30 +1,116 @@ -function trim(s) - return s:match'^()%s*$' and '' or s:match'^%s*(.*%S)' -end +require("bin") 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 +parseManager.__index=parseManager +parseManager.chunks={} +parseManager.stats={} +parseManager.stack={} +parseManager.cFuncs={} +parseManager.mainENV={} +parseManager.currentENV=parseManager.mainENV +parseManager.entry="START" +parseManager.methods={} +parseManager.lastCall=nil +parseManager.currentHandle=nil +parseManager.currentHandleName=nil +function readonlytable(tab) + return setmetatable({},{ + __index=tab, + __newindex=function() + error("Attempt to modify read-only table!") + end, + __metatable=false + }) end -function parseManager:debug(txt) - if self.stats.debugging then - self._methods:debug(txt) +function debug(...) + if parseManager.stats.debugging then + print("",...) end end +function parseManager:newENV() + local env={} + function env:getParent() + return getmetatable(self).__index + end + setmetatable(env,{__index=self.currentENV}) + return env +end +function parseManager:setENV(env) + self.currentENV=env +end +function parseManager:defualtENV() + self:setENV(self.mainENV) +end +function parseManager:load(path,c) + local c = c + if not c then + c = {} + setmetatable(c,parseManager) + end + local file + if type(path)=="table" then + if path.Type=="bin" then + file = path + else + error("Currently unsupported path type!") + end + elseif type(path)=="string" then + if bin.fileExists(path) then + file=bin.load(path) + else + error("File: "..path.." does not exist!") + end + end + -- process the data + file.data=file.data:gsub('%b""',function(a) a=a:gsub("//","\2") return a end) + file.data=file.data:gsub("%b''",function(a) a=a:gsub("//","\2") return a end) + file.data=file.data:gsub("//.-\n","\n") + file.data=file.data:gsub('%b""',function(a) a=a:gsub(";","\1") return a end) + file.data=file.data:gsub("%b''",function(a) a=a:gsub(";","\1") return a end) + file.data=file.data:gsub(";\n","\n") + file.data=file.data:gsub(";\r","\r") + file.data=file.data:gsub(";","\n") + file.data=file.data:gsub("\r\n","\n") + file.data=file.data:gsub("\n\n","\n") + file.data=file.data:gsub("\1",";") + file.data=file.data:gsub("\2","//") + file.data=file.data:gsub("\t","") + file:trim() + print(file.data) + for fn in file:gmatch("LOAD (.-)\n") do + debug("L",fn) + self:load(fn,c) + end + for fn in file:gmatch("ENABLE (.-)\n") do + debug("E",fn) + self.stats[string.lower(fn)]=true + end + for fn in file:gmatch("DISABLE (.-)\n") do + debug("D",fn) + self.stats[string.lower(fn)]=false + end + for fn in file:gmatch("ENTRY (.-)\n") do + debug("E",fn) + self.entry=fn + end + for name,data in file:gmatch("%[(.-)[:.-]?%].-{(.-)}") do + local ctype="BLOCK" + if name:find(":") then + ctype=name:match(":(.+)") + name=name:match("(.-):") + end + c.chunks[name]={} + c.chunks[name].type=ctype + c.chunks[name].pos=1 + c.chunks[name].labels={} + c.chunks[name].path=path + c.chunks[name].name=name + parseManager.currentHandleName=name + parseManager.currentHandle=c + c:compile(name,ctype,data) + end + --c.chunks=readonlytable(c.chunks) + return c +end function parseManager.split(s,pat) local pat=pat or "," local res = {} @@ -73,1205 +159,812 @@ function parseManager.split(s,pat) 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" + end + if type(tab[g])=="string" then + tab[g]=tab[g]:gsub("\1","") + end + tab[g]=tostring(tab[g]) + end + return table.concat(tab,sep) end -function parseManager:hasCBlock() - return #self._cblock~=0 -end -function parseManager:combineTruths(t) - --t={1,"a",0,"o",0} - if #t==1 then - return t[1] - end - local v=false - for i=#t,1,-2 do - if t[i-1] then - if t[i-1]=="o" then - v=(t[i] or t[i-2]) - elseif t[i-1]=="a" then - v=(t[i] and t[i-2]) - else - self:pushError("INVALID TRUTH TABLE!!!") - end - t[i-2]=v -- set the next index to the value - end - end - return v -end -function parseManager:setBlock(chunk) - if chunk:find("%-") then - local label=chunk:match("%-(.-)%-") - self._methods.GOTO(self,label) - return - end - if chunk=="__STAY" then return end - if chunk:sub(1,6)=="__SKIP" then local n=tonumber(chunk:sub(7,-1)) if n==-1 then self:pushError("-1 will put the skip command back on its self, creating an infinte pause! use -2 or less to go back 1 or more") return end self.pos=self.pos+n return end - if not(self._chunks[chunk]) then self._methods.GOTO(self,chunk) return end - local test=bin.new(self._chunks[chunk][1]) - test:fullTrim(true) - if self._cblockname~="" then - self.pos=0 - elseif self._cblockname==chunk then - self.pos=-1 - else - self.pos=1 - end - self._cblockname=chunk - self._cblock=bin._lines(test.data) -end -function parseManager:start(chunk,env) - local chunk = self.entrypoint or chunk or self.firstblcok - return self:next(chunk,nil,env) -end ---~ function parseManager:pushError(err) ---~ local file=self._chunks[self._cblockname].file ---~ local d={} ---~ if love then ---~ d=bin.new((love.filesystem.read(file))) ---~ else ---~ d=bin.load(file) ---~ end ---~ local t=d:lines() ---~ local pos=0 ---~ local switch=false ---~ for i=1,#t do ---~ if t[i]:find("["..self._cblockname,1,true) then ---~ switch=true ---~ end ---~ if switch==true and bin._trim(t[i])==self._cblock[self.pos] then ---~ pos=i ---~ break ---~ end ---~ end ---~ print("In Block '"..self._cblockname.."' LIQ: '"..self._cblock[self.pos].."' Filename: "..file.." On line: "..pos..": "..err) ---~ io.read() ---~ os.exit() ---~ end ---~ function parseManager:pushError(err) ---~ print(err) -- print to the console ---~ local file=self._chunks[self._cblockname].file ---~ local d={} ---~ if love then ---~ print(file) ---~ d=bin.new((love.filesystem.read(file))) ---~ else ---~ d=bin.load(file) ---~ end ---~ local _d={} ---~ local t=d:lines() ---~ for i=1,#t do ---~ _d[i]=trim(t[i]) ---~ end ---~ d=table.concat(_d,"\n") ---~ local pos=0 ---~ local cc=d:match("%["..self._cblockname..".*%].*({.-})") ---~ cc=cc:gsub("{.-\n","") ---~ cc=cc:gsub((self._cblock[self.pos]:gsub("%%","%%%%"):gsub("%(","%%%("):gsub("%)","%%%)"):gsub("%[","%%%["):gsub("%]","%%%]"):gsub("%+","%%%+"):gsub("%-","%%%-"):gsub("%*","%%%*"):gsub("%.","%%%."):gsub("%$","%%%$"):gsub("%^","%%%^")).."(.+)","NOPE LOL") ---~ _,b=cc:gsub("^(%-%-.-)\n","\n") ---~ _,c=cc:gsub("%-:.-:%-","\n") ---~ e=b+c ---~ for i=1,#t do ---~ if t[i]:find("["..self._cblockname,1,true) then ---~ pos=i+self.pos ---~ break ---~ end ---~ end ---~ error("In Block '"..self._cblockname.."' LIQ: '"..self._cblock[self.pos].."' Filename: "..file.." On line: "..pos+e..": "..err) ---~ end -function dialogueManager:pushError(err) - print(err) -- print to the console - local file=self._chunks[self._cblockname].file - local d={} - if love then - print(file) - d=bin.new((love.filesystem.read(file))) - elseif type(file)=="table" then - d=file - else - d=bin.load(file) - end - local t=d:lines() - local pos=0 - --Sigh... comments are still a pain to deal with... - local cc=d:match("%["..self._cblockname.."[:.-]?%].-({.-})") - cc=cc:gsub("{.-\n","") - cc=cc:gsub((self._cblock[self.pos]:gsub("%%","%%%%"):gsub("%(","%%%("):gsub("%)","%%%)"):gsub("%[","%%%["):gsub("%]","%%%]"):gsub("%+","%%%+"):gsub("%-","%%%-"):gsub("%*","%%%*"):gsub("%.","%%%."):gsub("%$","%%%$"):gsub("%^","%%%^")).."(.+)","NOPE LOL") - --mlc,a=cc:gsub("%-%-%[%[.-%]%]","\n") - --print(mlc) - --d=#bin._lines(mlc or "") - _,b=cc:gsub("(%-%-.-)\n","\n") - _,c=cc:gsub("%-:.-:%-","\n") - e=b+c - print(a,b,c) - for i=1,#t do - if t[i]:find("["..self._cblockname,1,true) then - pos=i+self.pos - break - end - end - if type(file)=="table" then - filename="runCode" - else - filename=file - end - error("In Block '"..self._cblockname.."' LIQ: '"..self._cblock[self.pos].."' Filename: "..filename.." On line: "..pos+e..": "..err) -end -function parseManager:p() - self.pos=self.pos+1 -end -function parseManager:parseHeader(header,env) - header=header:gsub("(%$%S-%$)",function(a) - local t1,t2=a:match("%$(.-)%[(.-)%]%$") - if t1 and t2 then - if type(env[t1])=="table" then - if t2=="-1" then - return env[t1][#env[t1]] - end - if env[t1][t2] then - return tostring(env[t1][t2]) - else - return tostring(env[t1][tonumber(self:varExists(t2) or t2) or self:varExists(t2)]) - end - end - end - a=a:gsub("%$","") - if type(env[a])=="table" then - if #env[a]==0 then - self:pushError("Invalid Syntax!") - end - return env[a][math.random(1,#env[a])] - end - return tostring(env[a]) - end) - return header -end -function string:split(sep) - local sep, fields = sep or ":", {} - local pattern = string.format("([^%s]+)", sep) - self:gsub(pattern, function(c) fields[#fields+1] = c end) - return fields -end -function parseManager:next(chunk,a,env,dd) - if not env then - env=self.defualtENV - end - if self.stats.topdown and chunk==nil then - chunk=self.firstloadedblock - else - chunk=chunk or "START" - end - if not self:hasCBlock() then - self:setBlock(chunk) - end - local line=self._cblock[self.pos] - if type(a)=="number" then - for i=1,#dd.methods+1 do - self:p() - end - line=dd.methods[a] -- sneaky, but also prevents wrong choices - end - if line==nil then - if self.stats.leaking then - if self._chunks[self._cblockname].next then - self:setBlock(self._chunks[self._cblockname].next) - self:p() - return { - Type="end", - text="leaking", - blocktype=self._chunks[self._cblockname][2] - } - else - self.endData={Type="end",text="Reached end of block!",lastblock=self._cblockname,lastline=self._cblock[self.pos-1],blocktype=self._chunks[self._cblockname][2]} - return self.endData - end - end - return {Type="end",text="Reached end of block!",lastblock=self._cblockname,lastline=self._cblock[self.pos-1],blocktype=self._chunks[self._cblockname][2]} - end - local holder,functest,args=line:match("([%w_]-):([%w_]-)%s*%((.-)%)$") - if not functest then - functest,args=line:match("([%w_]-)%s*%((.-)%)$") - end - if functest then - local funccheck=line:match("([%+%-%*/]+).-%(.-%)") - if funccheck then - functest=nil - end - for i,v in pairs(math) do - if functest==i and type(v)=="function" then - functest=nil - break - end - end - end - line=line:gsub("(.-)%[\"(.-)\"%]=(.+)",function(a,b,c) - return b.."="..c.."->"..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) +function parseManager:dump() + local bytecode = deepcopy(self.chunks) local str="" - for i=1,#self.symbols do - str=self.symbols[i][1]..str + for i,v in pairs(bytecode) do + str=str.."BLOCK: ["..i.."]\n" + for k=1,#v do + if type(v[k].Func)=="table" and v[k].Func.IsALookup==true then + if v[k].Type=="fwor" then + str=str.."\t"..v[k].Func[2].." "..concat(v[k].args,", ").."\n" + elseif v[k].Type=="fwr" then + str=str.."\t"..concat(v[k].vars,", ").." <- "..v[k].Func[2].." "..concat(v[k].args,", ").."\n" + end + elseif v[k].Type=="fwor" then + str=str.."\t"..v[k].Func.." "..concat(v[k].args,", ").."\n" + elseif v[k].Type=="funcblock" then + str=str.."\tFUNCTION: args("..concat(v[k].args,", ")..")\n" + elseif v[k].Type=="return" then + str=str.."\tRETURN: rets("..concat(v[k].RETArgs,", ")..")\n" + elseif v[k].Type=="label" then + str=str.."\t::"..v[k].label.."::\n" + elseif v[k].Type=="fwr" then + str=str.."\t"..concat(v[k].vars,", ").." <- "..v[k].Func.." "..concat(v[k].args,", ").."\n" + elseif v[k].Type=="choice" then + local opt={} + local met={} + local args={} + for i=1,#v[k] do + opt[#opt+1]=v[k][i][1] + met[#met+1]=v[k][i][2].Func + args[#args+1]=concat(v[k][i][2].args," ") + end + str=str.."\tCHOICE["..v[k].prompt.."]$C<"..concat(opt,", ")..">$F<"..concat(met,", ")..">$A<"..concat(args,", ")..">" + elseif v[k].Type=="text" then + str=str.."\tDISP_MSG \""..v[k].text.."\"\n" + elseif v[k].Type=="assign" then + str=str.."\t"..concat(v[k].vars,", ").." <- "..concat(v[k].vals,", ").."\n" + else + str=str.."\tUnknown Code!: "..tostring(v[k].data).."\n" + end + end 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}) +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 - 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) +function parseManager:pushError(err,sym) + error(err.." "..tostring(sym)) +end +local function pieceList(list,self,name) + if #list==0 then + return {} + end + local list=parseManager.split(list) + local L={} + local mathass=1 + for i=1,#list do + if list[i]:match("[%w_]-%[.-%]") then + local dict,sym=list[i]:match("([%w_]-)%[(.-)%]") + if tonumber(sym) then + L[#L+1]={"\1"..dict,tonumber(sym),IsALookup=true} + elseif sym:sub(1,1)=="\"" and sym:sub(-1,-1)=="\"" then + L[#L+1]={"\1"..dict,sym:sub(2,-2),IsALookup=true} 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 + elseif list[i]:sub(1,1)=="[" and list[i]:sub(-1,-1)=="]" then + L[#L+1]=pieceList(list[i]:sub(2,-2),self,name) + elseif tonumber(list[i]) then + L[#L+1]=tonumber(list[i]) + elseif list[i]:sub(1,1)=="\"" and list[i]:sub(-1,-1)=="\"" then + L[#L+1]=list[i]:sub(2,-2) + elseif list[i]:match("[%w_]-%..-") then + local dict,sym=list[i]:match("([%w_]-)%.(.+)") + L[#L+1]={"\1"..dict,sym,IsALookup=true} + elseif list[i]=="true" then + L[#L+1]=true + elseif list[i]=="false" then + L[#L+1]=false + elseif list[i]:match("[%w_]+")==list[i] then + L[#L+1]="\1"..list[i] + elseif list[i]:match("[_%w%+%-/%*%^%(%)%%]+") then + local char="$"..string.char(mathass+64) + self:compileExpr(char,list[i],name) + mathass=mathass+1 + L[#L+1]="\1"..char + else + self:pushError("Invalid Syntax!",list[i]) 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 + return L +end +local function pieceAssign(a,self,name) + local dict,ind=a:match("(.-)%[(.+)%]") + local var + if dict and ind then + if ind:sub(1,1)=="\"" and ind:sub(-1,-1)=="\"" then + var={dict,ind:sub(2,-2)} + elseif tonumber(ind) then + var={dict,tonumber(ind)} + elseif ind:match("[%w_]+")==ind then + var={dict,"\1"..ind} + elseif ind:match("[_%w%+%-/%*%^%(%)%%]+") then + local sym="@A" + self:compileExpr(sym,ind,name) + var={dict,"\1"..sym} + else + self:pushError("Invalid way to index a dictonary/array!",ind) + end + elseif a:match("[%w_]+")==a then + var="\1"..a + elseif a:match("[%w_]-%..-") then + local dict,sym=a:match("([%w_]-)%.(.+)") + var={dict,sym,IsALookup=true} + elseif a:find(",") then + local list = parseManager.split(a) + var={} + for i=1,#list do + table.insert(var,pieceAssign(list[i],self,name)) + end + else + self:pushError("Invalid Syntax, Assignment is invalid!",a) + end + return var +end +function parseManager:compileAssign(assignA,assignB,name) + local listA=parseManager.split(assignA) + local listB=parseManager.split(assignB) + local assign={ + Type="assign", + vars={}, + vals={} + } + for k=1,#listA do + local mathTest=false + debug("VAL: "..listB[k]) + debug("NAME: "..listA[k]) + if listB[k]:sub(1,1)=="[" and listB[k]:sub(-1,-1)=="]" then + if listB[k]:match("%[%]") then + assign.vals[#assign.vals+1]={} + else + assign.vals[#assign.vals+1]=pieceList(listB[k]:sub(2,-2),self,name) + end + elseif listB[k]:match("[%w_]-%[.-%]") then + local dict,sym=listB[k]:match("([%w_]-)%[(.-)%]") + if tonumber(sym) then + assign.vals[#assign.vals+1]={"\1"..dict,tonumber(sym),IsALookup=true} + elseif sym:sub(1,1)=="\"" and sym:sub(-1,-1)=="\"" then + assign.vals[#assign.vals+1]={"\1"..dict,sym:sub(2,-2),IsALookup=true} + end + elseif listB[k]:match("[%w_]-%..-") then + local dict,sym=listB[k]:match("([%w_]-)%.(.+)") + assign.vals[#assign.vals+1]={"\1"..dict,sym,IsALookup=true} + elseif tonumber(listB[k]) then + assign.vals[#assign.vals+1]=tonumber(listB[k]) + elseif listB[k]:sub(1,1)=="\"" and listB[k]:sub(-1,-1)=="\"" then + assign.vals[#assign.vals+1]=listB[k]:sub(2,-2) + elseif listB[k]=="true" then + assign.vals[#assign.vals+1]=true + elseif listB[k]=="false" then + assign.vals[#assign.vals+1]=false + elseif listB[k]:match("[%w_]+")==listB[k] then + assign.vals[#assign.vals+1]="\1"..listB[k] + elseif listB[k]:match("[_%w%+%-/%*%^%(%)%%]+") then + mathTest=true + self:compileExpr(listA[k],listB[k],name) + else + self:pushError("Invalid Systax:",listB[k]) + end + if not mathTest then + assign.vars[#assign.vars+1]=pieceAssign(listA[k],self,name) + end + end + table.insert(self.chunks[name],assign) +end +function parseManager:compileCondition(condition,iff,elsee,name) + self:compileLogic(condition,iff,elsee,name) +end +function parseManager:compileExpr(eql,expr,name) + local cmds={} + expr=expr:gsub("([%W])(%-%d)",function(b,a) + return b.."(0-"..a:match("%d+")..")" + end) + local mathAss=1 + function packFunc(l,o,r) + local l=tonumber(l) or l + local o=tonumber(o) or o + local r=tonumber(r) or r + if type(l)=="string" and l:match("[%w_]") then + l="\1"..l + end + if type(r)=="string" and r:match("[%w_]") then + r="\1"..r + end + if type(o)=="string" and o:match("[%w_]") then + o="\1"..o + end + if l=="@" then + l=r + r="" + end + if type(l)=="string" then + if l:find("\3") then + if type(o)=="number" then + cmds[#cmds+1]={Func=l:match("\3(.+)"),args={o}} + else + if o=="@" then o="" end + if o=="" then o=nil end + cmds[#cmds+1]={Func=l:match("\3(.+)"),o} + end + return + end + end + if l=="@" then -- Fancy movement of math + local n=#cmds + cmds[n]["vars"]={"\1%"..string.char(mathAss+64)} + l="\1%"..string.char(mathAss+64) + mathAss=mathAss+1 + cmds[n+1]["vars"]={"\1%"..string.char(mathAss+64)} + r="\1%"..string.char(mathAss+64) + mathAss=mathAss+1 + end + if r=="@" then -- Fancy movement of math + local n=#cmds + cmds[n]["vars"]={"\1%"..string.char(mathAss+64)} + r="\1%"..string.char(mathAss+64) + mathAss=mathAss+1 + -- cmds[n]["vars"]={"\1%"..string.char(mathAss+64)} + -- l="\1%"..string.char(mathAss+64) + -- mathAss=mathAss+1 + end + if r=="" then + local n=#cmds + cmds[n]["vars"]={"\1%"..string.char(mathAss+64)} + r=l + l="\1%"..string.char(mathAss+64) + mathAss=mathAss+1 + end + if o=="+" then + cmds[#cmds+1]={Func="ADD",args={l,(r or "")}} + elseif o=="-" then + cmds[#cmds+1]={Func="SUB",args={l,(r or "")}} + elseif o=="/" then + cmds[#cmds+1]={Func="DIV",args={l,(r or "")}} + elseif o=="*" then + cmds[#cmds+1]={Func="MUL",args={l,(r or "")}} + elseif o=="^" then + cmds[#cmds+1]={Func="POW",args={l,(r or "")}} + elseif o=="%" then + cmds[#cmds+1]={Func="MOD",args={l,(r or "")}} + else + self:pushError("Something went wrong!",tostring(l)..","..tostring(o)..","..tostring(r)) + end + end + function parseManager:pieceExpr(expr) + local count=0 + for i,v in pairs(self.methods) do + expr=expr:gsub(i.."(%b())",function(a) + a=a:sub(2,-2) + if a:sub(1,1)=="-" then + a="0"..a + end + packFunc("\3"..i,self:pieceExpr(a)) + return "@" + end) + end + for i,v in pairs(self.cFuncs) do + expr=expr:gsub(i.."(%b())",function(a) + a=a:sub(2,-2) + if a:sub(1,1)=="-" then + a="0"..a + end + packFunc("\3"..i,self:pieceExpr(a)) + return "@" + end) + end--self.cFuncs + expr=expr:gsub("%b()",function(a) + return self:pieceExpr(a:sub(2,-2)) + end) + local loop + for l,o,r in expr:gmatch("(.*)([%+%^%-%*/%%])(.*)") do + loop=true + if l:match("[%+%^%-%*/%%]") then + packFunc(self:pieceExpr(l),o,r) + else + packFunc(l,o,r) + end + end + if loop then + return "@" + else + return expr + end + end + if expr:match("[!%$&_%w%+%-/%*%^%(%)%%]+")==expr then + parseManager:pieceExpr(expr) + cmds[#cmds]["vars"]={"\1"..eql} + for i=1,#cmds do + if cmds[i].vars then + cmds[i].Type="fwr" + else + cmds[i].Type="fwor" + end + if not name then + --self:pushError("Unknown Error:",name) + else + table.insert(self.chunks[name],cmds[i]) + end + end + else + --self:pushError("Invalid math Expression!",expr) + end +end +function parseManager:compileFWR(FWR,vars,args,name) + vars=pieceAssign(vars,self,name) + if type(vars)=="string" then + vars={vars} + end + table.insert(self.chunks[name],{ + Type="fwr", + Func=FWR, + vars=vars, + args=pieceList(args,self,name), + }) +end +function parseManager:compileFWOR(FWOR,args,name) + table.insert(self.chunks[name],{ + Type="fwor", + Func=FWOR, + args=pieceList(args,self,name), + }) +end +function parseManager:compileLabel(label,name) + self.chunks[name].labels[label]=#self.chunks[name]+1 -- store this inside the chunk + table.insert(self.chunks[name],{ + Type="label", + pos=#self.chunks[name]+1, + label=label, + }) +end +function parseManager:compileLine(line,name) + table.insert(self.chunks[name],{ + Type="text", + text=line + }) +end +function parseManager:compileLogic(condition,iff,elsee,name) + local cmds={} + local function pieceLogic(conds) + conds=conds.." or 1==0" + conds=conds:gsub(" and ","\4") + conds=conds:gsub(" or ","\5") + conds=conds:gsub("(\".*[\4].*\")",function(a) + return a:gsub("\4"," and ") + end) + conds=conds:gsub("(\".*[\5].*\")",function(a) + return a:gsub("\4"," or ") + end) + local count=0 + local mathass=0 + _conds=conds:gsub("%s*\5".."1==0","") + local cmds={} + for l,eq,r in conds:gmatch("(.-)([=~!><][=]*)(.-)%s*[\4\5]") do + charL=string.char(count+65) + charM=string.char(mathass+65) + count=count+1 + cmds={ + Type="fwr", + Func="COMPARE", + args={[3]=eq}, + vars={"\1!"..charL}, + } + local l,r=(l:gsub("[\4\5\6]*%(","")),(r:gsub("%)","")) + if l=="true" then + cmds.args[1]=true + elseif l=="false" then + cmds.args[1]=false + elseif tonumber(l) then + cmds.args[1]=tonumber(l) + elseif l:match("[%w_]+")==l then + cmds.args[1]="\1"..l + elseif l:match("[_%w%+%-/%*%^%(%)%%]+")==l then + self:compileExpr("&"..charM,l,name) + cmds.args[1]="\1&"..charM + mathass=mathass+1 + elseif l:sub(1,1)=="\"" and l:sub(-1,-1) then + cmds.args[1]=l:sub(2,-2) + else + self:pushError("Invalid Syntax in logical expression!",l) + end + r=r:gsub("%s*\5".."1==0","") + charM=string.char(mathass+65) + if r=="true" then + cmds.args[2]=true + elseif r=="false" then + cmds.args[2]=false + elseif tonumber(r) then + cmds.args[2]=tonumber(r) + elseif r:match("[%w_]+")==r then + cmds.args[2]="\1"..r + elseif r:match("[_%w%+%-/%*%^%(%)%%]+")==r then + self:compileExpr("&"..charM,r,name) + cmds.args[2]="\1&"..charM + mathass=mathass+1 + elseif r:sub(1,1)=="\"" and r:sub(-1,-1) then + cmds.args[2]=r:sub(2,-2) + else + self:pushError("Invalid Syntax in logical expression!",r) + end + l=l:gsub("%%","%%%%");r=r:gsub("%%","%%%%");l=l:gsub("%+","%%%+");r=r:gsub("%+","%%%+");l=l:gsub("%*","%%%*");r=r:gsub("%*","%%%*");l=l:gsub("%-","%%%-");r=r:gsub("%-","%%%-");l=l:gsub("%^","%%%^");r=r:gsub("%^","%%%^");l=l:gsub("%$","%%%$");r=r:gsub("%$","%%%$");l=l:gsub("%.","%%%.");r=r:gsub("%.","%%%.");l=l:gsub("%[","%%%[");r=r:gsub("%[","%%%[");l=l:gsub("%]","%%%]");r=r:gsub("%]","%%%]");l=l:gsub("%?","%%%?");r=r:gsub("%?","%%%?");l=l:gsub("%(","%%%(");r=r:gsub("%(","%%%(");l=l:gsub("%)","%%%)");r=r:gsub("%)","%%%)") + _conds=_conds:gsub(l.."%s*"..eq.."%s*"..r,"!"..charL) + table.insert(self.chunks[name],cmds) + end + _conds=_conds:gsub("\4","*") + _conds=_conds:gsub("\5","+") + if not _conds:find("%*") and not _conds:find("%+") then + cmds.vars[1]="\1L$" + else + self:compileExpr("L$",_conds,name) + end + table.insert(self.chunks[name],{ + Type="fwor", + Func="CSIM", + args={"\1L$"}, + }) + FWORi,argsi=iff:match("^([%w_]+)%s*%((.*)%)") + FWORe,argse=elsee:match("^([%w_]+)%s*%((.*)%)") + self:compileFWOR(FWORi,argsi,name) + self:compileFWOR(FWORe,argse,name) + end + pieceLogic(condition) +end +local function trim1(s) + return (s:gsub("^%s*(.-)%s*$", "%1")) +end +function parseManager:compile(name,ctype,data) + local isFBlock,FBArgs=ctype:match("(f)unction%((.*)%)") + --Check if we are dealing with a FBlock + if isFBlock=="f" then + self.cFuncs[name]=true + -- if self.methods[name] then + -- self:pushError("You cannot create a method with the same name as a standard method or duplicate method names!",name) + -- end + self.methods[name]=function(...) + self:Invoke(name,{},...) + end + self.mainENV[name]=self.methods[name] + table.insert(self.chunks[name],{ + Type="funcblock", + args=pieceList(FBArgs,self,name) + }) + end + debug("COMPILING Block: "..name) + local data=bin.new(data):lines() + local choiceBlock=false + local choice={} + for i=1,#data do + data[i]=trim1(data[i]) + if data[i]~="" then + if data[i]:match(".-<%s*") then + choiceBlock=true + choice={} + j=0 + end + if choiceBlock then + if data[i]:find(">") then + choiceBlock=false + table.insert(self.chunks[name],choice) + else + dat=data[i]:gsub("<","") + if j==0 then + choice.Type="choice" + choice.prompt=dat:sub(2,-2) + j=1 + else + local a,b=dat:match("\"(.-)\"%s*(.+)") + local f,ag=b:match("^([%w_]+)%s*%((.*)%)") + if ag~="" then + choice[#choice+1]={a,{ + Type="fwor", + Func=f, + args=pieceList(ag,self,name), + }} + else + choice[#choice+1]={a,{ + Type="fwor", + Func=f, + args={}, + }} + end + end + end + else + local cmd={} + local Return,RETArgs=data[i]:match("(return)%s*(.*)$") + local line=data[i]:match("^\"(.+)\"") + local assignA,assignB=data[i]:match("^([%w,%[%]\"_%(%)%+%-%*%%%./]+)%s*=%s*(.+)") + local vars,FWR,args=data[i]:match("([\"%[%]%w_,]+)%s*=%s*([%w_]+)%s*%((.*)%)$") + local FWOR + if not args then + FWOR,args=data[i]:match("^([%w_]+)%s*%((.*)%)$") + end + local label=data[i]:match("::(.*)::") + local condition,iff,elsee=data[i]:match("if%s*(.+)%s*then%s*(.-%))%s*|%s*(.+%))") + ------ + local vars2,FWR2,args2=data[i]:match("([%[%]\"%w_,]+)%s*=%s*([%.:%w_]+)%s*%((.*)%)$") + if not args2 then + FWOR2,args2=data[i]:match("^([%.:%w_]+)%s*%((.*)%)$") + end + ------ + if line then + self:compileLine(line,name) + elseif condition then + self:compileCondition(condition,iff,elsee,name) + elseif FWR then + self:compileFWR(FWR,vars,args,name) + elseif FWOR then + self:compileFWOR(FWOR,args,name) + elseif FWR2 then + local dict,dot,sym=FWR2:match("([%w_]-)([%.:])(.+)") + if dot==":" then + args2=dict..","..args2 + end + self:compileFWR({dict,sym,IsALookup=true},vars2,args2,name) + elseif FWOR2 then + local dict,dot,sym=FWOR2:match("([%w_]-)([%.:])(.+)") + if dot==":" then + args2=dict..","..args2 + end + self:compileFWOR({dict,sym,IsALookup=true},args2,name) + elseif assignA then + self:compileAssign(assignA,assignB,name) + elseif label then + self:compileLabel(label,name) + elseif Return and isFBlock then + table.insert(self.chunks[name],{ + Type="return", + RETArgs=pieceList(RETArgs,self,name) + }) + elseif Return and not(isFBlock) then + self:pushError("Attempt to call return in a non function block!",data[i]) + else + table.insert(self.chunks[name],{ + Type="customdata", + data=data[i], + }) + end + end + end + end +end +function parseManager:testDict(dict) + if type(dict[1])=="string" then + if dict[1]:sub(1,1)=="\1" and dict.IsALookup then + return true + end + else + return + end +end +function parseManager:dataToValue(name,envF) -- includes \1\ + envF=envF or self.currentENV + local tab=name + if type(name)=="string" then + if name:sub(1,1)=="\1" then + return self:parseHeader(envF[name:sub(2)]) + else + return self:parseHeader(name) + end + elseif type(name)=="table" then + if name.__index then + return name + end + if self:testDict(name) then + return envF[name[1]:sub(2,-1)][self:dataToValue(name[2])] + else + tab={} + for i=1,#name do + tab[i]=self:dataToValue(name[i],envF) + end + end + end + return tab or {} +end +function parseManager:define(t) + for i,v in pairs(t) do + self.methods[i]=v + end +end +function push(s,n) + table.insert(s,n) +end +function pop(s) + return table.remove(s) +end +function peek(s) + return s[#s] +end +function parseManager:Invoke(func,vars,...) + local name=func + local func=self.chunks[func] + if func then + if func.type:sub(1,1)=="f" then + local returndata={} + self.fArgs={...} + if #self.fArgs==0 then + self.fArgs={self.lastCall} + end + push(self.stack,{chunk=self.currentChunk,pos=self.currentChunk.pos,env=self.currentENV,vars=vars}) + self.methods.JUMP(self,name) + return + else + self:pushError("Attempt to call a non function block!",name) + end + else + self:pushError("Attempt to call a non existing function!",name) + end +end +function parseManager:parseHeader(data) + if type(data)=="string" then + data=data:gsub("%$([%w_:%.%[%]\"']+)%$",function(dat) + debug("PARSE: "..dat) + if dat:find(":") then + -- for later use + elseif dat:find("%[") then + -- for dicts + else + -- regular strings + debug("PARSE DATA: "..tostring(self.currentENV[dat])) + if self.currentENV[dat]~=nil then + if type(self.currentENV[dat])=="table" then + local str="" + for i=1,#self.currentENV[dat] do + str=str..tostring(self.currentENV[dat][i]).."," + end + str=str:sub(1,-2) + return "["..str.."]" + else + return tostring(self.currentENV[dat]) + end + else + return "nil" + end 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) + return data +end +function parseManager:pairAssign(vars,vals,envF) + for i=1,#vars do + debug("ASSIGN NAME: "..tostring(vars[i])) + debug("ASSIGN DATA: "..tostring(self:dataToValue(vals[i],envF))) + if type(vars[i])=="table" then + if type(self.currentENV[vars[i][1]])~="table" then + self:pushError("Attempt to index a non table object:",vars[i][1].."[\""..vars[i][2].."\"]") + end + self.currentENV[vars[i][1]][self:dataToValue(vars[i][2])]=self:dataToValue(vals[i],envF) else - if count==1 then - v=helper(o,r,l) + self.currentENV[vars[i]:sub(2,-1)]=self:dataToValue(vals[i],envF) + end + end +end +function parseManager:next(block,choice) + if self.entry then + block = block or self.entry + self.entry = nil + end + local chunk = self.currentChunk or self.chunks[block] or self.chunks["START"] + self.currentChunk=chunk + if choice then + local c=self.choiceData[choice][2] + local args=self:dataToValue(c.args) + if not self.methods[c.Func] then + self.lastCall=self:Invoke(c.Func,"lastCall",unpack(args)) + else + self.lastCall=self.methods[c.Func](self,unpack(args)) + end + return {Type="method"} + end + local ret + local data=chunk[chunk.pos] + if not data then return end + if data.Type=="label" then + chunk.pos=chunk.pos+1 + data=chunk[chunk.pos] + end + chunk.pos=chunk.pos+1 + debug("TYPE: "..data.Type) + if data.Type=="text" then + self.lastCall=nil + return {Type="text",text=self:parseHeader(data.text)} + elseif data.Type=="funcblock" then + local env=self.currentENV + self.currentENV=self:newENV() + self:pairAssign(data.args,self.fArgs,env) + return {Type="FBLOCK"} + elseif data.Type=="return" then + local obj=pop(self.stack) + local chunk=obj.chunk + local pos=obj.pos + local env=obj.env + local vars=obj.vars + local name=chunk.name + local env=self.currentENV + chunk.pos=pos + self.currentENV=env + self:pairAssign(vars,data.RETArgs,env) + self.currentChunk=chunk + return {Type="method"} + elseif data.Type=="fwr" then + local args=self:dataToValue(data.args) + local rets={} + local Func + local Ext=false + if type(data.Func)=="table" then + Ext=true + Func=self.currentENV[data.Func[1]][data.Func[2]] + else + Func=self.methods[data.Func] + end + if Ext then + rets={Func(unpack(args))} + else + if type(Func)~="function" then + rets={self:Invoke(data.Func,data.vars,unpack(args))} + return {Type="method"} + else + rets={Func(self,unpack(args))} end 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) + if #rets~=0 then + self:pairAssign(data.vars,rets) end - -- Time to collect local vars to populate we will use these below + self.lastCall=nil + return {Type="method"} + elseif data.Type=="fwor" then + local args=self:dataToValue(data.args) + local Func + local Ext=false + if type(data.Func)=="table" then + Ext=true + Func=self.currentENV[data.Func[1]][data.Func[2]] + else + Func=self.methods[data.Func] + end + if Ext then + self.lastCall=Func(unpack(args)) + else + if type(Func)~="function" then + self.lastCall=self:Invoke(data.Func,"lastCall",unpack(args)) + return {Type="method"} + else + self.lastCall=Func(self,unpack(args)) + end + end + return {Type="method"} + elseif data.Type=="choice" then + self.choiceData=data + local CList={} + for i=1,#data do + CList[#CList+1]=data[i][1] + end + self.lastCall=nil + return {Type="choice",prompt=data.prompt,CList} + elseif data.Type=="assign" then + self:pairAssign(data.vars,data.vals) + self.lastCall=nil + return {Type="assign"} + else + self.lastCall=nil + return {Type="Custom Syntax"} 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 + return rets 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) +require("parseManager.standardDefine") diff --git a/game/parseManager/interpreter.lua b/game/parseManager/interpreter.lua deleted file mode 100644 index e4a5b84..0000000 --- a/game/parseManager/interpreter.lua +++ /dev/null @@ -1,10 +0,0 @@ -engine={} -function engine:init(bytecodeFile) - self.code=bin.load(bytecodeFile).data -end ---[[OP-CODES - -]] -function engine:run(assessors) - -- -end diff --git a/game/parseManager/standardDefine.lua b/game/parseManager/standardDefine.lua new file mode 100644 index 0000000..5bd23d0 --- /dev/null +++ b/game/parseManager/standardDefine.lua @@ -0,0 +1,310 @@ +parseManager:define{ + print=function(self,...) + print(...) + end, + error=function(self,msg) + self:pushError(msg,"\2") + end, + QUIT=function() + os.exit() + end, + JUMP=function(self,block) + if self.chunks[block] then + self.chunks[block].pos=1 + self.currentChunk=self.chunks[block] + else + self:pushError("Attempt to jump to a non existing block:","\2") + end + end, + SKIP=function(self,n) + if type(n)~="number" then self:pushError("Number expected got: "..type(n),"SKIP( ? )") end + self.currentChunk.pos=self.currentChunk.pos+n + end, + GOTO=function(self,label) + if self.currentChunk.labels[label] then + self.currentChunk.pos=self.currentChunk.labels[label] + else + self:pushError("Attempt to goto a non existing label:","\2") + end + end, + GOTOE=function(self,label) + local chunks=self.chunks + for i,v in pairs(chunks) do + if chunks[i].labels[label] then + self.currentChunk=chunks[i] + self.currentChunk.pos=chunks[i].labels[label] + return + end + end + self:pushError("Attempt to goto a non existing label:","\2") + end, + ADD=function(self,a,b) + if type(self.lastCall)=="number" and type(a)=="number" then + return self.lastCall+a + elseif type(a)=="number" and type(b)=="number" then + return a+b + else + self:pushError("Invalid Arguments!","ADD("..tostring(a)..","..tostring(b)..")") + end + end, + SUB=function(self,a,b) + if type(self.lastCall)=="number" and type(a)=="number" then + return self.lastCall-a + elseif type(a)=="number" and type(b)=="number" then + return a-b + else + self:pushError("Invalid Arguments!","SUB("..tostring(a)..","..tostring(b)..")") + end + end, + MUL=function(self,a,b) + if type(self.lastCall)=="number" and type(a)=="number" then + return self.lastCall*a + elseif type(a)=="number" and type(b)=="number" then + return a*b + else + self:pushError("Invalid Arguments!","MUL("..tostring(a)..","..tostring(b)..")") + end + end, + DIV=function(self,a,b) + if type(self.lastCall)=="number" and type(a)=="number" then + return self.lastCall/a + elseif type(a)=="number" and type(b)=="number" then + return a/b + else + self:pushError("Invalid Arguments!","DIV("..tostring(a)..","..tostring(b)..")") + end + end, + POW=function(self,a,b) + if type(self.lastCall)=="number" and type(a)=="number" then + return self.lastCall^a + elseif type(a)=="number" and type(b)=="number" then + return a^b + else + self:pushError("Invalid Arguments!","POW("..tostring(a)..","..tostring(b)..")") + end + end, + sqrt=function(self,a) + if type(self.lastCall)=="number" then + return math.sqrt(self.lastCall) + elseif type(a)=="number" then + return math.sqrt(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + cos=function(self,a) + if type(self.lastCall)=="number" then + return math.cos(self.lastCall) + elseif type(a)=="number" then + return math.cos(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + sin=function(self,a) + if type(self.lastCall)=="number" then + return math.sin(self.lastCall) + elseif type(a)=="number" then + return math.sin(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + tan=function(self,a) + if type(self.lastCall)=="number" then + return math.tan(self.lastCall) + elseif type(a)=="number" then + return math.tan(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + log=function(self,a) + if type(self.lastCall)=="number" then + return math.log(self.lastCall) + elseif type(a)=="number" then + return math.log(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + acos=function(self,a) + if type(self.lastCall)=="number" then + return math.acos(self.lastCall) + elseif type(a)=="number" then + return math.acos(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + tanh=function(self,a) + if type(self.lastCall)=="number" then + return math.tanh(self.lastCall) + elseif type(a)=="number" then + return math.tanh(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + deg=function(self,a) + if type(self.lastCall)=="number" then + return math.deg(self.lastCall) + elseif type(a)=="number" then + return math.deg(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + cosh=function(self,a) + if type(self.lastCall)=="number" then + return math.cosh(self.lastCall) + elseif type(a)=="number" then + return math.cosh(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + sinh=function(self,a) + if type(self.lastCall)=="number" then + return math.sinh(self.lastCall) + elseif type(a)=="number" then + return math.sinh(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + randomseed=function(self,a) + if type(self.lastCall)=="number" then + return math.randomseed(self.lastCall) + elseif type(a)=="number" then + return math.randomseed(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + ceil=function(self,a) + if type(self.lastCall)=="number" then + return math.ceil(self.lastCall) + elseif type(a)=="number" then + return math.ceil(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + floor=function(self,a) + if type(self.lastCall)=="number" then + return math.floor(self.lastCall) + elseif type(a)=="number" then + return math.floor(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + rad=function(self,a) + if type(self.lastCall)=="number" then + return math.rad(self.lastCall) + elseif type(a)=="number" then + return math.rad(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + abs=function(self,a) + if type(self.lastCall)=="number" then + return math.abs(self.lastCall) + elseif type(a)=="number" then + return math.abs(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + asin=function(self,a) + if type(self.lastCall)=="number" then + return math.asin(self.lastCall) + elseif type(a)=="number" then + return math.asin(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + log10=function(self,a) + if type(self.lastCall)=="number" then + return math.log10(self.lastCall) + elseif type(a)=="number" then + return math.log10(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + atan2=function(self,a) + if type(self.lastCall)=="number" then + return math.atan2(self.lastCall) + elseif type(a)=="number" then + return math.atan2(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + exp=function(self,a) + if type(self.lastCall)=="number" then + return math.exp(self.lastCall) + elseif type(a)=="number" then + return math.exp(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + atan=function(self,a) + if type(self.lastCall)=="number" then + return math.atan(self.lastCall) + elseif type(a)=="number" then + return math.atan(a) + else + self:pushError("Invalid Arguments!","\2") + end + end, + max=function(self,a,b) + if type(self.lastCall)=="number" and type(a)=="number" then + return max(self.lastCall,a) + elseif type(a)=="number" and type(b)=="number" then + return max(a,b) + else + self:pushError("Invalid Arguments!","\2") + end + end, + mod=function(self,a,b) + if type(self.lastCall)=="number" and type(a)=="number" then + return mod(self.lastCall,a) + elseif type(a)=="number" and type(b)=="number" then + return mod(a,b) + else + self:pushError("Invalid Arguments!","\2") + end + end, + COMPARE=function(self,v1,v2,sym) + if sym==nil then self:pushError("Unexpected Error has occured!",":(") end + if sym=="==" then + if v1==v2 then return 1 else return 0 end + elseif sym==">=" then + if v1>=v2 then return 1 else return 0 end + elseif sym=="<=" then + if v1<=v2 then return 1 else return 0 end + elseif sym==">" then + if v1>v2 then return 1 else return 0 end + elseif sym=="<" then + if v1 + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code +keep intact all notices of the absence of any warranty and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/love.dll b/love.dll new file mode 100644 index 0000000..60c1016 Binary files /dev/null and b/love.dll differ diff --git a/love.exe b/love.exe new file mode 100644 index 0000000..75b2afc Binary files /dev/null and b/love.exe differ diff --git a/love.ico b/love.ico new file mode 100644 index 0000000..b703c98 Binary files /dev/null and b/love.ico differ diff --git a/lovec.exe b/lovec.exe new file mode 100644 index 0000000..d6ea63e Binary files /dev/null and b/lovec.exe differ diff --git a/lua51.dll b/lua51.dll new file mode 100644 index 0000000..2338fcf Binary files /dev/null and b/lua51.dll differ diff --git a/mpg123.dll b/mpg123.dll new file mode 100644 index 0000000..e93412c Binary files /dev/null and b/mpg123.dll differ diff --git a/msvcp120.dll b/msvcp120.dll new file mode 100644 index 0000000..4ea1efa Binary files /dev/null and b/msvcp120.dll differ diff --git a/msvcr120.dll b/msvcr120.dll new file mode 100644 index 0000000..d711c92 Binary files /dev/null and b/msvcr120.dll differ diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..6bdf782 --- /dev/null +++ b/readme.txt @@ -0,0 +1,96 @@ +LÖVE is an *awesome* framework you can use to make 2D games in Lua. It's free, open-source, and works on Windows, Mac OS X, Linux, Android, and iOS. + +[![Build Status: Windows](https://ci.appveyor.com/api/projects/status/u1a69u5o5ej1pus4?svg=true)](https://ci.appveyor.com/project/AlexSzpakowski/love) + +Documentation +------------- + +We use our [wiki][wiki] for documentation. +If you need further help, feel free to ask on our [forums][forums], and last but not least there's the irc channel [#love on OFTC][irc]. + +Compilation +----------- + +###Windows +Follow the instructions at the [megasource][megasource] repository page. + +###*nix +Run `platform/unix/automagic` from the repository root, then run ./configure and make. + + $ platform/unix/automagic + $ ./configure + $ make + +###Mac OS X +Download the required frameworks from [here][dependencies] and place them in `/Library/Frameworks/`. + +Then use the Xcode project found at `platform/xcode/love.xcodeproj` to build the `love-macosx` target. + +###iOS +Download the required libraries from [here][dependencies-ios] and place the `include` and `libraries` folders +into the `platform/xcode/ios` folder. + +Then use the Xcode project found at `platform/xcode/love.xcodeproj` to build the `love-ios` target. + +See `readme-iOS.rtf` for more information. + +###Android +Visit the [Android build repository][android-repository] for build instructions. + +Repository information +---------------------- + +We use the 'default' branch for development, and therefore it should not be considered stable. +Also used is the 'minor' branch, which is used for features in the next minor version and it is +not our development target (which would be the next revision - version numbers are formatted major.minor.revision.) + +We tag all our releases (since we started using mercurial), and have binary downloads available for them. + +Experimental changes are developed in the separate [love-experiments][love-experiments] repository. + +Contributing +------------ + +The best places to contribute are through the Bitbucket issue tracker and the official IRC channel. +For code contributions, pull requests and patches are welcome. Be sure to read the [source code style guide][codestyle]. + +Builds +------ + +Releases are found in the 'downloads' section on bitbucket, are linked on [the site][site], +and there's a ppa for ubuntu, [ppa:bartbes/love-stable][stableppa]. + +There are also unstable/nightly builds: + +- Most can be found [here][builds]. +- For ubuntu linux they are in [ppa:bartbes/love-unstable][unstableppa] +- For arch linux there's [love-hg][aur] in the AUR. + +Dependencies +------------ + +- SDL2 +- OpenGL 2.1+ / OpenGL ES 2+ +- OpenAL +- Lua / LuaJIT / LLVM-lua +- FreeType +- PhysicsFS +- ModPlug +- mpg123 +- Vorbisfile +- Theora + +[site]: http://love2d.org +[wiki]: http://love2d.org/wiki +[forums]: http://love2d.org/forums +[irc]: irc://irc.oftc.net/love +[dependencies]: http://love2d.org/sdk +[dependencies-ios]: https://bitbucket.org/rude/love/downloads/love-0.10.0-ios-libraries.zip +[megasource]: https://bitbucket.org/rude/megasource +[builds]: http://love2d.org/builds +[stableppa]: https://launchpad.net/~bartbes/+archive/love-stable +[unstableppa]: https://launchpad.net/~bartbes/+archive/love-unstable +[aur]: http://aur.archlinux.org/packages/love-hg +[love-experiments]: https://bitbucket.org/bartbes/love-experiments +[codestyle]: https://love2d.org/wiki/Code_Style +[android-repository]: https://bitbucket.org/MartinFelis/love-android-sdl2