Compare commits

..

No commits in common. "e46bc230a6ecef40329d64bcb32ac1c73557f8f9" and "9513a5c4717a0bc7a5ab24a293791df0136fe31c" have entirely different histories.

17 changed files with 208 additions and 1023 deletions

5
.gitignore vendored
View file

@ -1,5 +0,0 @@
dev
build/
games/*
!games/.gitkeep

View file

@ -1,37 +0,0 @@
return function(ll)
ll.mdir = nil
ll.mgme = nil
local ffi = require 'ffi'
ffi.cdef [[
int PHYSFS_mount(const char *, const char *, int);
int PHYSFS_unmount(const char *);
]]
local baseReq = '?.lua;?/init.lua;'
function ll.mount(gme)
local mdir = gme.base .. gme.dir
ll.mgme = gme
love.filesystem.setRequirePath(''
.. mdir .. '/?.lua;'
.. mdir .. '/?/init.lua;'
.. baseReq
)
-- FIXME: Bug may appear in Linux. Recompile Love2D or use official PPA.
if ffi.C.PHYSFS_mount(mdir, '/', 0) == 0
then error('Cannot mount '..mdir)
love.filesystem.setRequirePath(baseReq)
else ll.mdir = mdir
end
end
function ll.umount()
if ll.mdir ~= nil then
ffi.C.PHYSFS_unmount(ll.mdir)
ll.mdir = nil
end
end
end

View file

@ -1,20 +0,0 @@
return function(ll)
function ll.fsIsAbs(f)
f = f:sub(1, 1)
return f == '/' or f == '\\'
end
function ll.fsIsRel(f)
return not ll.fsIsAbs(f)
end
function ll.fsFile(f)
return f:match '([^/\\]*)[/\\]*$'
end
function ll.fsDir(f)
return f:match '^(.*)[/\\]+[^/\\]*[/\\]*$'
end
end

View file

@ -1,100 +0,0 @@
return function(ll)
ll.games = {}
local function parse(conf)
local r = {}
local k, v
local buf = ''
local t = 'str'
local esc = false
local prg = true
local i = 1
repeat
local ch = conf:sub(i, i)
if ch == '\\'
then esc = true
elseif ch == '#' then
repeat i = i + 1
ch = conf:sub(i, i)
until ch == '' or ch == '\n' or ch == '\r'
elseif ch == '[' then
buf = buf:match '%s*(.*)%s*'
assert(#buf == 0, 'Unexpected array usage')
t = 'arr'
prg = true
v = {}
elseif ch == ''
or (ch == '=' and not k)
or (ch == ']' and t == 'arr')
or (ch == ';' and t == 'arr')
or ch == '\n' or ch == '\r' then
buf = buf:match '^%s*(.-)%s*$'
if ch == '=' then
assert(t == 'str', 'Cannot use other types than string for key')
end
if t == 'str'
or (t == 'arr' and ch == ']')
then prg = false end
if not prg or ch == ';' then
if #buf ~= 0 then
if k then
if t == 'str'
then v = buf
elseif t == 'arr'
then table.insert(v, buf)
else error 'wut?' end
else k = buf
end
buf = ''
elseif ch ~= ''
and ch ~= '\r'
and ch ~= '\n'
then error 'empty buffer'
end
end
if k and v and not prg then
r[k] = v
k = nil
v = nil
buf = ''
t = 'str'
end
elseif esc then
buf = buf .. ch
esc = false
else buf = buf .. ch
end
i = i + 1
until i >= #conf + 1
return r
end
function ll.gameNew(conf, file, base, dir)
local cfg = parse(conf or '')
local gme = {
name = cfg.name or dir or 'No name',
desc = cfg.desc or 'No description provided.',
base = base,
dir = dir,
main = cfg.main or 'main.lua',
screens = cfg.screens or cfg.pics or nil,
scrcur = 1,
scrprv = 1,
dat = nil,
}
return gme
end
end

View file

@ -1,81 +0,0 @@
return function(ll)
local mx, my, mb, mpb
local dir, sc1, sc2, sclm
-- d - direction (h, v, x, y, *)
-- c1 - coordinate before card (mouse) (be left or top)
-- c2 - coordinate after card (mouse) (be right or bottom)
-- clm - other coordinate limit (mouse) (set -1 to disable)
function ll.kbInit(d, c1, c2, clim)
if d == 'h' or d == 'v' or d == '*'
then dir = d
elseif d == 'y'
then dir = 'v'
elseif d == 'x'
then dir = 'h'
else error 'Direction must be *, h (x) or v (y)'
end
c1, c2 =
tonumber(c1) or 0,
tonumber(c2) or 0
sc1, sc2, sclm =
math.min(c1, c2),
math.max(c1, c2),
tonumber(clim) or -1
end
-- returns: <, >, o, m, nil
-- ^ and v if dir is *
function ll.kbGet()
assert(dir, 'Call ll.kbInit(dir, coord1, coord2, coordlimit) before')
mx, my = love.mouse.getPosition()
mpb = mb
if love.mouse.isDown(1) then mb = 1
else mb = 0
end
if love.keyboard.isScancodeDown('up', 'w')
then return dir == '*' and '^' or '<'
elseif love.keyboard.isScancodeDown('left', 'a')
then return '<'
elseif love.keyboard.isScancodeDown('down', 's')
then return dir == '*' and 'v' or '>'
elseif love.keyboard.isScancodeDown('right', 'd')
then return '>'
elseif love.keyboard.isScancodeDown('return', 'space')
then return 'o'
elseif love.keyboard.isDown 'menu'
then return 'm'
elseif mb == 0 and mpb == 1 then -- unpressed
if dir == 'h' then
if sclm < 0 or my <= sclm then
if mx <= sc1
then return '<'
elseif mx >= sc2
then return '>'
else return 'o'
end
end
else
if sclm < 0 or mx <= sclm then
if my <= sc1
then return '<'
elseif my >= sc2
then return '>'
else return 'o'
end
end
end
end
end
end

View file

@ -1,51 +0,0 @@
return function(ll)
function ll.addGame(file, cont)
local dir = ll.fsDir(file)
file = ll.fsFile(file)
local ext = file:match '%.(%w+)$'
print(file, ext, dir)
return 'NO!', nil
end
function ll.gameAdd(conf, file, base, dir)
local gme = ll.gameNew(conf, file, base, dir)
gme.dat = {}
if gme.screens and gme.screens[1] then
gme.dat.scr = {}
for i = 1, #gme.screens do
table.insert(gme.dat.scr, love.graphics.newImage(ll.cfg.root .. gme.dir ..'/'.. gme.screens[i]))
end
end
table.insert(ll.games, gme)
return gme
end
local lfs = love.filesystem
local info = lfs.getInfo
for _, dir in pairs(love.filesystem.getDirectoryItems(ll.cfg.root)) do
local isDir
if info
then isDir = info(ll.cfg.root .. dir).type == 'directory'
else isDir = lfs.isDirectory(ll.cfg.root .. dir)
end
if isDir then
local file = ll.cfg.root .. dir..'/'.. 'info.ll'
local realDir = love.filesystem.getRealDirectory(file)
or love.filesystem.getRealDirectory(ll.cfg.root .. dir..'/main.lua')
if realDir
then ll.gameAdd(
love.filesystem.read(file),
file,
realDir ..'/'.. ll.cfg.root,
dir
)
end
end
end
end

View file

@ -1,27 +0,0 @@
local ll = {}
ll.cfg = {
root = 'games/',
}
require 'lib.fs' (ll)
require 'lib.game' (ll)
require 'lib.chroot' (ll)
require 'lib.load' (ll)
require 'lib.keyb' (ll)
function ll.home()
ll.umount()
love.event.push('quit', 'restart')
end
ll.dt = false
function ll.devtools()
if not ll.dt then
ll.dt = true
__LL = ll
pcall(function() require 'dev.tools' end)
end
end
return ll

View file

@ -1,17 +1,8 @@
-- Minimal Love Loader API
-- Version 2.1
-- (c) Er2 2022 <er2@dismail.de>
-- Zlib License
-- minimal Love Loader API
if not llUsed then
COLDIV = love.getVersion() == 0 and 1 or 255
MOBILE = love.system.getOS() == 'Android'
or love.system.getOS() == 'iOS'
if MOBILE
then love.window.setFullscreen(true)
end
function love.resize(x, y)
W, H = x, y

View file

@ -1,17 +0,0 @@
return {
entry = 'main.lua',
output = 'build/main.lua',
plug = {
require 'plug.minify' {
extGlob = {
'love',
'llUsed',
'llHome',
'resize',
'COLDIV',
'MOBILE',
'W', 'H',
}
},
}
}

238
main.lua
View file

@ -1,71 +1,219 @@
local ll = require 'lib.main'
error = love.errhand or love.errorhandler
function splash()
love.graphics.setColor(255, 255, 255, 100 / COLDIV)
if ll.mgme.screens and ll.mgme.screens[1] then
local img = love.graphics.newImage(ll.mgme.screens[1])
love.graphics.draw(img, 0, 0, 0, W / img:getWidth(), H / img:getHeight())
end
love.graphics.setColor(255, 255, 255, 255)
love.graphics.print('Loading '..ll.mgme.name, W / 2, H / 2)
local root = 'games/'
-- games library and selection
local gms = {}
local sel = 1
local sgme
-- some internals
local cx, cy, cw, ch
local f, bf
local ffi = require 'ffi'
local fd
ffi.cdef [[
int PHYSFS_mount(const char *, const char *, int);
int PHYSFS_unmount(const char *);
]]
local function llResz()
cw, ch = W / 1.25, H / 1.25
cx, cy = (W - cw) / 2, (H - ch) / 2
local th = math.min(W, H) / 8
f = love.graphics.newFont(th / 3)
bf = love.graphics.newFont(th / 2)
end
ll.skin = require 'skins.psp' (ll)
resize = llResz
require 'll-min'
llUsed = true
if love.errorhandler
then love.errorhandler = error
else love.errhand = error
local function chroot(dir, main)
fd = love.filesystem.getSource() .. dir
love.filesystem.setRequirePath(
'?.lua;?/init.lua;'
.. dir .. '/?.lua;'
.. dir .. '/?/init.lua;'
)
-- FIXME: Bug in Linux (Debian)
ffi.C.PHYSFS_mount(fd, '/', 0);
if main then
load(love.filesystem.read(dir ..'/'.. main), main)()
end
end
local function escChroot()
if fd then
ffi.C.PHYSFS_unmount(fd);
fd = nil
end
end
local function gmeNew(cont, dir, file)
local gme = {
name = 'No name',
desc = 'No description provided.',
dir = dir,
main = 'main.lua',
pics = nil,
psel = 2,
ppsl = 1,
}
local fi = false
cont = cont or ''
cont = cont:gsub('[^\\]#[^\n]*', '')
for v in cont:gmatch '([^\n]+)' do
local k, v = v:match '^%s*([%w_]+)%s*=%s*(.*)%s*$'
if k == 'name'
or k == 'desc'
or k == 'main'
then gme[k] = v
fi = true
elseif k == 'pic' then
gme.pics = gme.pics or {}
table.insert(gme.pics, v)
fi = true
elseif k == 'pics' then
local t = {}
v = v:sub(2, -2)
for v in v:gmatch '%s*([^;]+%a+)%s*;?'
do table.insert(t, v) end
gme[k] = t
fi = true
elseif k
then error('unknown field "'.. k ..'" in "'.. file ..'"')
end
end
if gme.pics then
for k, v in pairs(gme.pics) do
gme.pics[k] = love.graphics.newImage(root .. dir ..'/'.. v)
end
gme.psel = math.min(2, #gme.pics)
end
if not fi then
gme.name = dir
end
table.insert(gms, gme)
end
for _, v in pairs(love.filesystem.getDirectoryItems(root)) do
local file = v..'/'.. 'info.ll'
gmeNew(love.filesystem.read(root .. file), v, file)
end
local pf, mx, mb, mpb
local pcht = 60 * 5
local pchat = math.floor(1 / pcht * 2 * 255 + 0.5)
local pchv, pcha = 0, 0
local function llUpdate()
mx = love.mouse.getX()
mpb = mb
mb = 0
if love.mouse.isDown(1) then mb = 1
end
if mpb == 1 and mb == 0 then
if mx <= cx then
sel = sel - 1
if sel < 1 then sel = #gms end
elseif mx >= cx + cw then
sel = sel + 1
if sel > #gms then sel = 1 end
else sgme = gms[sel]
end
end
pchv = pchv + 1
if pchv >= pcht then
pchv, pcha = 0, 0
for _, v in pairs(gms) do
if v.pics then
v.ppsl = v.psel
v.psel = v.psel + 1
if v.psel > #v.pics
then v.psel = 1 end
end
end
else pcha = math.min(255, pcha + pchat)
end
end
local function llDraw()
love.graphics.polygon('fill',
8, H / 2,
32, H / 2 - 32,
32, H / 2 + 32)
love.graphics.polygon('fill',
W - 8, H / 2,
W - 32, H / 2 - 32,
W - 32, H / 2 + 32)
local oy, t = 0, ''
local gme = gms[sel]
if gme then
local ph = ch / 1.5
if gme.pics then
local p, n = gme.pics[gme.ppsl], gme.pics[gme.psel]
love.graphics.draw(p, cx, cy, 0, cw / p:getWidth(), ph / p:getHeight())
love.graphics.setColor(255, 255, 255, pcha / COLDIV)
love.graphics.draw(n, cx, cy, 0, cw / n:getWidth(), ph / n:getHeight())
love.graphics.setColor(255, 255, 255, 255)
end
love.graphics.rectangle('line', cx, cy, cw, ph)
love.graphics.rectangle('line', cx, cy, cw, ch)
oy = cy + ph
love.graphics.setFont(bf)
love.graphics.print(gme.name, cx, oy)
oy = oy + bf:getHeight(gme.name)
love.graphics.setFont(f)
love.graphics.print(gme.desc, cx, oy)
else oy = H / 2
t = 'No games'
love.graphics.setFont(bf)
love.graphics.print(t, (W - bf:getWidth(t)) / 2, oy)
oy = oy + bf:getHeight(t)
love.graphics.setFont(f)
t = 'There is no projects/games to run'
love.graphics.print(t, (W - f:getWidth(t)) / 2, oy)
end
end
function llHome()
escChroot()
love.event.push('quit', 'restart')
end
local brk = false
while not brk and not ll.mdir do
while not brk and not sgme do
-- event handling
love.event.pump()
for n, a,b,c in love.event.poll() do
if n == 'quit'
or (n == 'keypressed' and a == 'escape')
then ll.umount()
for n, a,b,c,d,e,f in love.event.poll() do
if n == 'quit' then
escChroot()
love.event.push('quit')
brk = true; break
end
love.handlers[n](a,b,c)
love.handlers[n](a,b,c,d,e,f)
end
-- update and drawing
ll.skin.update()
llUpdate()
love.graphics.origin()
love.graphics.clear(0, 0, 0)
ll.skin.draw()
llDraw()
love.graphics.present()
love.timer.sleep(0.001)
end
if ll.mdir then
if sgme then
love.graphics.setNewFont()
resize = nil
love.graphics.clear(0, 0, 0)
splash()
love.graphics.present()
if ll.skin.lovecb then
for _, v in pairs(ll.skin.lovecb)
do love[v] = nil
end
end
love.filesystem.setIdentity(ll.mgme.dir)
local f, err = load(love.filesystem.read(ll.mgme.main), ll.mgme.name)
if not f then error(err)
else xpcall(f, function(e)
error(e)
llHome()
end)
end
love.resize(love.graphics.getDimensions())
chroot(root .. sgme.dir, sgme.main)
end

View file

@ -2,99 +2,31 @@
Custom menu for selecting game from multiple for Love2D.
![PSP Style](./scr/psp.png)
[Other screenshots](./scr)
# How it works?
Just place games into `games` folder! (like `this_folder/games/game/main.lua`)
If simple: just place games in `games` folder with structure like `games/yourgame/main.lua`
Technically, this creates the loop until game wasn't selected or user wants to exit
with custom event handling and redrawing.
If technically: creates local variables functions and variables.
Creates the loop until game wasn't selected with manual event handling and redrawing.
# LibLL
# Things left or API
Love Loader from 2.0 includes backend API to simplify creating custom skins.
We are not keep environment super clear (except local variables ;))
so there are some variables can be used in game:
It have not so many functions and fields:
`W` and `H` variables: width and height of the screen, controlled by love.resize function.
- `ll.games` - field for games, which have this structure:
```lua
{
name = 'string', -- Friendly name for game or placeholder
desc = 'string', -- Description for game or placeholder
base = 'string', -- base directory used in game mounting, must end with `/`
dir = 'string', -- directory name, used if no name was defined
main = 'string', -- main file to execute or `main.lua`
screens = {'array of', 'path to screenshots'},
scrcur = 1, --[[number]] -- current index from screenshots
scrprv = 1, --[[number]] -- previous index from screenshots
dat = nil, --[[any]] -- maybe platform-dependent data to reduce operations
}
```
`love.resize` and optional `resize` payload: functions called when screen size when changed and at boot.
- `ll.mdir` - string or nil, contains full mounted directory.
`love.event.quit`: function to quit to menu screen
- `ll.mgme` - game or nil, contains mounted game.
`COLDIV`: color divider (1 or 255) to setColor function
- `ll.gameNew(configuration --[[string]], fileName --[[string, not used]], base --[[string]], directory --[[string]])`
`llUsed`: is Love Loader used
Creates game object (defined above) and returns it.
`llHome`: function to quit to menu screen
- `ll.gameAdd(conf, file, base, dir)` - same as `ll.gameNew` with insertion into `ll.games`.
- `ll.addGame(fileName, fileContent)` - function for file dropping, reserved for v3.0.
- `ll.mount(game)` - mounts game.
Can throw an error.
Sets `ll.mdir` and `ll.mgme`.
- `ll.umount()` - unmounts game if can.
Unsets `ll.mdir` and `ll.mgme`.
- `ll.home()` - calls `llHome`
- `ll.dt` - is developer tools enabled?
- `__LL` - global variable of Love Loader instance when developer tools enabled.
- `ll.devtools()` - enable developer tools.
- `ll.fsIsAbs(file)` - is file absolute (/file)?
- `ll.fsIsRel(file)` - is file relative, inverted result of ll.fsIsAbs (./file).
- `ll.fsDir(path)` - get directory name (2 from /1/2/3.file).
- `ll.fsFile(path)` - get file (including dividers after) (2 from /1/2/).
- `ll.kbInit(direction --[[string: *, h, v, x, y]], c1 --[[number, coordinate before card for mouse (left/top)]], c2 --[[number, coordinate after card for mouse (right/bottom)]], clim --[[other coordinate limit for mouse or -1 to disable]])` - initialize keyboard module for skins.
- `ll.kbGet() --[[nil, string: <, >, o, m, ^ anv v if direction is *]]` - get key pressed.
# API
To reduce things to do for game developers, this loader creates some global variables to use.
You can also use it without Love Loader (or if your game can distribute without loader) by including `ll-min.lua` file.
`W` and `H`: width and height of the screen which controls by custom love.resize function.
`love.resize` and optional `resize` payload: functions called when screen size was changed and on booting.
`love.event.quit`: function to exit to main screen.
`llHome`: function called by `love.event.quit` (broken for now).
`llUsed`: is Love Loader (not minimal API) used.
`COLDIV`: color divider (1 or 255) to `love.graphics.setColor` function.
`MOBILE`: is this device runs Android or iOS?
They also can be used without Love Loader if load `ll-min.lua`
# Fill game information
@ -108,6 +40,5 @@ name = New awesome game using Love Loader
desc = Some descripion about the game.
# main = optional main file instead of `main.lua`
pic = screen.png
pics = [ screen.png; screen2.png ] # wow arrays
pics = [ screen.png; screen2.png ] # wow array
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View file

@ -1,190 +0,0 @@
return function(ll)
-- Basic cmd-like style UI
-- FIXME: Console scrolling
local cw, ch, ctw, cth
local ct = 'Love Loader v2.0\n(c) Er2 2022\tZlib License\n\n'
local cce = false
local buf = ''
local mb, mpb, mt = 0, 0, 0
local function ccp()
local argv = {}
for v in buf:gmatch '%S+'
do table.insert(argv, v)
end
local cmd = (argv[1] or ''):lower()
if cmd == '' then return '' -- nothing
elseif cmd == 'help' then return 'Available commands:'
.. '\nhelp\t\tThis command'
.. '\nls\t\tList of games'
.. '\ndir\t\tSame as ls'
.. '\ncat\t<path>\tInformation about game'
.. '\ninfo\t<path>\tSame as cat'
.. '\nrun\t<path>\tStart game'
.. '\nmount\t<path>\tSame as run'
.. '\nchroot\t<path>\tSame as run'
.. '\nclear\t\tClear screen'
.. '\neval\t<code>\tExecute code'
elseif cmd == 'clear' then
ct = ''
return ''
elseif cmd == 'eval' then
local code = buf:match '^%S+%s+(.*)'
local f, err = load(code, 'test.lua')
if not f then return err
else return tostring(f() or 'nil')
end
elseif cmd == 'ls'
or cmd == 'dir' then
local r = ''
if #ll.games == 0 then
return ('%s: No games found. Add some to the library.'):format(argv[1])
end
for i = 1, #ll.games do
local v = ll.games[i]
r = r .. ('%s\t(%s)\t - %s\n'):format(v.dir, v.name, v.desc)
end
return r .. ('\nTotal: %3d games\n'):format(#ll.games)
elseif cmd == 'cat'
or cmd == 'info' then
if not argv[2]
then return ('%s: Game directory missing'):format(argv[1])
end
local r = ''
for _, v in pairs(ll.games) do
if argv[2] == v.dir
or argv[2] == v.base .. v.dir
then r = r..
( '\nFriendly name:\t%s'
..'\nDescription:\t%s'
..'\nLocation:\t%s%s'
..'\nMain file:\t%s'
..'\n\n\t\tScreenshots are not supported yet.'
..'\n'):format(v.name, v.desc, v.base, v.dir, v.main)
end
end
if r == '' then r = 'Not found' end
return r
elseif cmd == 'run'
or cmd == 'mount'
or cmd == 'chroot' then
local gme
for _, v in pairs(ll.games) do
if argv[2] == v.dir
or argv[2] == v.base .. v.dir
then if gme then
return 'Error: multiple paths found, use full location'
end
gme = v end
end
if gme
then ll.mount(gme)
love.keyboard.setTextInput(false)
return ''
else return 'Not found'
end
else return 'Unknown command "'.. cmd .. '"'
end
end
local function update()
mpb = mb
if love.mouse.isDown(1) then mb = 1
if mpb ~= 1
then mt = os.time()
end
else mb = 0
end
if mb == 0 and mpb == 1
and os.time() - mt <= 1 then
if love.system.getOS() == 'Android' then
love.keyboard.setTextInput(
not love.keyboard.hasTextInput(),
0, H, W, ch)
end
end
if not cce then
cce = true
local r = ccp()
if #r ~= 0 then ct = ct.. '\n'.. r end
ct = ct.. '\n> '
buf = ''
end
end
local utf8 = require 'utf8'
local function draw()
love.graphics.setColor(255, 255, 255)
local x, y = 0, 0
for p, cde in utf8.codes(ct) do
local chr = utf8.char(cde)
if chr == '\n'
then x, y = 0, y + 1
elseif chr == '\r'
then x = 0
elseif chr == '\t'
then x = x + 8 - (x % 8)
elseif chr == '\v'
then y = y + 1
else love.graphics.print(chr, x * cw, y * ch)
if x >= ctw
then x, y = x - ctw, y + 1
else x = x + 1
end
end
end
if os.time() % 2 == 0
then love.graphics.rectangle('fill', x * cw, y * ch, cw, ch)
end
end
function resize()
local f = love.graphics.newFont(math.min(W, H) / 32)
love.graphics.setFont(f)
cw, ch = f:getWidth 'm', f:getHeight 'A'
ctw, cth =
math.floor(W / cw) - 1,
math.floor(H / ch) - 1
love.keyboard.setTextInput(true, 0, H, W, ch)
end
function love.textinput(txt)
ct = ct.. txt
buf = buf.. txt
end
function love.keypressed(k)
if k == 'backspace' then
local off = utf8.offset(buf, -1)
if off then
buf = buf:sub(1, off - 1)
off = utf8.offset(ct, -1)
if off
then ct = ct:sub(1, off - 1)
end
end
elseif k == 'return'
then cce = false
end
end
love.keyboard.setKeyRepeat(true)
love.window.setMode(800, 600, {resizable = true})
return {
update = update,
draw = draw,
lovecb = {
'textinput',
'keypressed',
},
}
end

View file

@ -1,198 +0,0 @@
return function(ll)
ll.cfg.pcht = ll.cfg.pcht or 60 * 5
local pikchv, pikcha = 0, 0
local pikchao = math.floor(1 / ll.cfg.pcht * 2 * 255 + 0.5)
local cx, cy, cw, ch
local f, bf
local sel = 1
local cdir
function resize()
cw = W / 1.25
ch = H / 1.25
cx = (W - cw) / 2
cy = (H - ch) / 2
local th = math.min(W, H) / 8
f = love.graphics.newFont(th / 3)
bf = love.graphics.newFont(th / 2)
ll.kbInit('h', cx, cx + cw)
end
local function update()
local sdi = ll.kbGet()
if cdir ~= sdi then
cdir = sdi
if sdi == '<'
then sel = sel - 1
elseif sdi == '>'
then sel = sel + 1
elseif sdi == 'o' and ll.games[sel]
then ll.mount(ll.games[sel])
elseif sdi == 'm'
and love.mouse.getX() >= W - 8
then ll.devtools()
end
if sel < 1 then sel = #ll.games end
if sel > #ll.games then sel = 1 end
end
pikchv = pikchv + 1
if pikchv >= ll.cfg.pcht then
pikchv = 0
pikcha = 0
for _, v in pairs(ll.games) do
if v.dat.scr then
v.scrprv = v.scrcur
v.scrcur = v.scrcur + 1
if v.scrcur > #v.dat.scr
then v.scrcur = 1
end
end
end
else pikcha = math.min(255, pikcha + pikchao)
end
end
local tm = 0
local function draw()
love.graphics.setColor(0 / COLDIV, 50 / COLDIV, 75 / COLDIV)
love.graphics.rectangle('fill', 0, 0, W, H)
love.graphics.setColor(255, 255, 255, 100 / COLDIV)
love.graphics.setLineWidth(8)
love.graphics.setFont(bf)
local t = 'Love Loader'
local tw, th = bf:getWidth(t), bf:getHeight(t)
love.graphics.print(t, W - tw - 8, H - th)
tm = (tm + 0.02) % 6.28
local c, pc, ps = tm, math.cos(tm), math.sin(tm)
local oy = H / 2
for x = 0, W + 8, 8 do
c = c + 0.1
local c, s = math.cos(c), math.sin(c)
local cy, ncy, sy, nsy =
pc * H / 12,
c * H / 12,
ps * H / 12,
s * H / 12
love.graphics.line(x - 8, sy + oy, x-1, nsy + oy)
love.graphics.line(x - 8, sy/2 + oy, x-1, nsy/2 + oy)
love.graphics.line(x - 8, cy/1.5 + oy, x-1, ncy/1.5 + oy)
love.graphics.line(x - 8, cy*1.5 + oy, x-1, ncy*1.5 + oy)
pc, ps = c, s
end
love.graphics.setColor(255, 255, 255, 255)
love.graphics.setLineWidth(1)
local oy, t = 0, ''
local gme = ll.games[sel]
if gme then
love.graphics.polygon('fill',
8, H / 2,
32, H / 2 - 32,
32, H / 2 + 32)
love.graphics.polygon('fill',
W - 8, H / 2,
W - 32, H / 2 - 32,
W - 32, H / 2 + 32)
love.graphics.stencil(function()
love.graphics.rectangle('fill', cx, cy, cw, ch, 16)
end)
love.graphics.setStencilTest('greater', 0)
love.graphics.setColor(50 / COLDIV, 50 / COLDIV, 50 / COLDIV, 100 / COLDIV)
love.graphics.rectangle('fill', cx, cy, cw, ch)
love.graphics.setColor(255, 255, 255, 255)
if gme.dat.scr then
local p, n = gme.dat.scr[gme.scrprv], gme.dat.scr[gme.scrcur]
love.graphics.draw(p, cx, cy, 0, cw / p:getWidth(), ch / p:getHeight())
love.graphics.setColor(255, 255, 255, pikcha / COLDIV)
love.graphics.draw(n, cx, cy, 0, cw / n:getWidth(), ch / n:getHeight())
love.graphics.setColor(0, 0, 0, 150 / COLDIV)
love.graphics.rectangle('fill', cx, cy, cw, ch)
love.graphics.setColor(255, 255, 255, 255)
end
oy = cy + ch / 1.25
love.graphics.setFont(bf)
love.graphics.print(gme.name, cx + 16, oy)
oy = oy + bf:getHeight(gme.name)
love.graphics.setFont(f)
love.graphics.print(gme.desc, cx + 16, oy)
love.graphics.setStencilTest()
love.graphics.rectangle('line', cx, cy, cw, ch, 16)
elseif ll.games[1] then
sel = 1
love.graphics.setColor(255, 255, 255, 255)
love.graphics.print('Sorry :)', W / 2, H / 2)
else love.graphics.setColor(255, 255, 255, 255)
oy = H / 2.5
t = 'No games'
love.graphics.setFont(bf)
love.graphics.print(t, (W - bf:getWidth(t)) / 2, oy)
oy = oy + bf:getHeight(t)
love.graphics.setFont(f)
t = 'There are no projects/games to run'
love.graphics.print(t, (W - f:getWidth(t)) / 2, oy)
end
end
function error(msg)
msg = tostring(msg)
love.graphics.reset()
love.graphics.origin()
local bf = love.graphics.newFont(64)
local f = love.graphics.setNewFont(16)
local perc = 0
local q
repeat
perc = math.min(100, perc + 0.1 * math.random(50))
love.graphics.clear(17/COLDIV, 113/COLDIV, 172/COLDIV)
love.graphics.setColor(255, 255, 255)
love.graphics.setFont(bf)
love.graphics.print(':(', 64, 16)
love.graphics.setFont(f)
love.graphics.print(('%d%% complete'):format(perc), 64, 100)
love.graphics.printf(msg, 64, 132, W - 64)
love.graphics.print('(c) Love Loader and Er2', 8, H - 16 - 8)
love.graphics.present()
love.event.pump()
for n, a,b,c in love.event.poll() do
if n == 'quit'
or n == 'mousereleased'
or (n == 'keypressed' and a == 'escape')
then q = true end
end
love.timer.sleep(0.5)
until q or perc == 100
-- Unfortunately, we can't restart Love in error handler
llHome() -- but can outside of love.errorhandler
return function() return 1 end
end
return {
update = update,
draw = draw,
}
end

View file

@ -1,159 +0,0 @@
return function(ll)
-- New UI from Sony PSP
local sel = 1
local psel
local cx, cy, cw, ch, cg
local css, rcss = 2, 0
local f, bf
ll.cfg.pcht = ll.cfg.pcht or 60 * 5
local pikchv, pikcha = 0, 0
local pikchao = math.floor(1 / ll.cfg.pcht * 2 * 255 + 0.5)
local logger = ''
local chc = '<>><m><'
function resize()
r = math.min(W, H) / 30
cg = H / 64
cw = W / 5
ch = (H - cg) / 6
cx = W / 10
cy = -H / 2
f = love.graphics.setNewFont(math.min(W, H) / 30)
bf = love.graphics.newFont(math.min(W, H) / 20)
ll.kbInit('v', H / 2 - ch, H / 2 + ch + cg, cx + cw * 2)
end
love.window.setMode(800, 600, {resizable = true})
local sdir
local function update()
local ty = H / 2 - (ch + cg) * sel
cy = cy + (ty - cy) * 0.1
css = css + (2 - css) * 0.2
rcss = 2 - css + 1
local sdi = ll.kbGet()
if sdi ~= sdir then
if sdi
then rcss = css
css = 1
psel = sel
logger = logger .. sdi
if logger == chc then
resize()
ll.devtools()
end
end
sdir = sdi
if sdi == '<'
then sel = sel - 1
elseif sdi == '>'
then sel = sel + 1
elseif sdi == 'o' and ll.games[sel]
then ll.mount(ll.games[sel])
end
if sel < 1 then sel = #ll.games end
if sel > #ll.games then sel = 1 end
end
pikchv = pikchv + 1
if pikchv >= ll.cfg.pcht then
pikchv = 0
pikcha = 0
for _, v in pairs(ll.games) do
if v.dat.scr then
v.scrprv = v.scrcur
v.scrcur = v.scrcur + 1
if v.scrcur > #v.dat.scr
then v.scrcur = 1
end
end
end
else pikcha = math.min(255, pikcha + pikchao)
end
end
local function scrCard(gme, x, y, w, h, a)
if not gme.dat.scr then return end
love.graphics.setColor(255, 255, 255, a / COLDIV)
local p, n = gme.dat.scr[gme.scrprv], gme.dat.scr[gme.scrcur]
love.graphics.draw(p, x, y, 0, w / p:getWidth(), h / p:getHeight())
love.graphics.setColor(255, 255, 255, math.min(a, pikcha) / COLDIV)
love.graphics.draw(n, x, y, 0, w / n:getWidth(), h / n:getHeight())
love.graphics.setColor(0, 0, 0, 150 / COLDIV)
love.graphics.rectangle('fill', x, y, w, h)
end
local function draw()
love.graphics.setColor(0 / COLDIV, 50 / COLDIV, 75 / COLDIV)
love.graphics.rectangle('fill', 0, 0, W, H)
if ll.games[sel] then
local cur = ll.games[sel]
scrCard(cur, 0, 0, W, H, (css - 1) * 255)
love.graphics.setColor(255, 255, 255, 255)
love.graphics.setFont(bf)
love.graphics.printf(cur.desc, cx + cw * 2, cx, W - (cx + cw * 2))
else love.graphics.setColor(255, 255, 255, 255)
sel = #ll.games
end
love.graphics.setFont(f)
local oy = 0
for k, v in pairs(ll.games) do
local x, w, h, g = cx, cw, ch, cg
if k == sel then
x = cx / css
w = cw * css
h = ch * css
g = cg * 3
oy = oy + cg * css
elseif k == psel then
x = cx / rcss
w = cw * rcss
h = ch * rcss
oy = oy + cg * rcss
end
love.graphics.stencil(function()
love.graphics.rectangle('fill', x, cy + oy, w, h, r)
end)
love.graphics.setStencilTest('greater', 0)
love.graphics.setColor(50 / COLDIV, 50 / COLDIV, 50 / COLDIV, 100 / COLDIV)
love.graphics.rectangle('fill', x, cy + oy, w, h)
love.graphics.setColor(255, 255, 255, 255)
scrCard(v, x, cy + oy, w, h, 255)
love.graphics.setColor(255, 255, 255, 255)
local th = f:getHeight(v.name)
love.graphics.print(v.name, x + cg, cy + oy + h - th - cg)
love.graphics.setStencilTest()
love.graphics.rectangle('line', x, cy + oy, w, h, r)
oy = oy + h + g
end
if #ll.games == 0 then
love.graphics.print('No games', cx, cy - ch)
love.graphics.setFont(bf)
love.graphics.print('Add some to the library', cx, cy)
end
end
return {
update = update,
draw = draw,
}
end