Files
birth1mark 29a17766a1 Add in-app Lexaloffle BBS Store and cartridge downloader
- Added integrated 🌐 BBS Store tab to arcade BIOS interface (DefaultCart.h)
- Implemented C++ Lua API bindings: __bbs_listfeatured, __bbs_download, __bbs_isdownloaded, __refreshcarts
- Curated top-rated community games catalog with 1-click download & play
- Added custom BBS Cartridge ID downloader with on-screen character picker
- Added robust magic-byte verification (PNG/p8) on downloaded cartridges
- Updated README.md and ARCHITECTURE.md documentation
2026-10-22 19:12:10 +01:00

1610 lines
35 KiB
C++

#include <string>
#include <vector>
#include <tuple>
#include <cstdio>
using namespace std;
#include "picoluaapi.h"
#include "graphics.h"
#include "Input.h"
#include "vm.h"
#include "logger.h"
#include "printHelper.h"
#include "emojiconversion.h"
//extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
//}
Graphics* _graphicsForLuaApi;
Input* _inputForLuaApi;
Vm* _vmForLuaApi;
Audio* _audioForLuaApi;
PicoRam* _ramForLuaApi;
void initPicoApi(PicoRam* memory, Graphics* graphics, Input* input, Vm* vm, Audio* audio){
_graphicsForLuaApi = graphics;
_inputForLuaApi = input;
_vmForLuaApi = vm;
_audioForLuaApi = audio;
_ramForLuaApi = memory;
initPrintHelper(_ramForLuaApi, _graphicsForLuaApi, _vmForLuaApi, _audioForLuaApi);
}
int noop(const char * name) {
//todo log name of unimplemented functions?
return 0;
}
int noopreturns(lua_State *L, const char * name) {
//todo log name of unimplemented functions?
lua_pushnumber(L, 0);
return 1;
}
/*functions to expose to lua*/
//Graphics
int cls(lua_State *L){
if (lua_gettop(L) == 0) {
_graphicsForLuaApi->cls();
}
else {
int c = lua_tonumber(L,1);
_graphicsForLuaApi->cls(c);
}
return 0;
}
int pset(lua_State *L){
int x = lua_tonumber(L,1);
int y = lua_tonumber(L,2);
if (lua_gettop(L) <= 2) {
_graphicsForLuaApi->pset(x, y);
return 0;
}
int c = lua_tonumber(L,3);
_graphicsForLuaApi->pset(x, y, (uint8_t)c);
return 0;
}
int pget(lua_State *L){
fix32 x = lua_tonumber(L,1);
fix32 y = lua_tonumber(L,2);
uint8_t color = _graphicsForLuaApi->pget((int)x, (int)y);
lua_pushinteger(L, color);
return 1;
}
int color(lua_State *L){
uint8_t prev = 0;
int16_t c = 0;
if (lua_gettop(L) > 0) {
c = lua_tonumber(L,1);
prev = _graphicsForLuaApi->color(c);
}
else {
prev = _graphicsForLuaApi->color();
}
lua_pushinteger(L, prev);
return 1;
}
int line (lua_State *L){
if (lua_gettop(L) == 0) {
_graphicsForLuaApi->line();
}
else if (lua_gettop(L) == 1) {
fix32 c = lua_tonumber(L,1);
_graphicsForLuaApi->line(c);
}
else if (lua_gettop(L) == 2) {
int x1 = lua_tonumber(L,1);
int y1 = lua_tonumber(L,2);
_graphicsForLuaApi->line(x1, y1);
}
else if (lua_gettop(L) == 3) {
int x1 = lua_tonumber(L,1);
int y1 = lua_tonumber(L,2);
int16_t c = lua_tonumber(L,3);
_graphicsForLuaApi->line(x1, y1, c);
}
else if (lua_gettop(L) == 4) {
int x1 = lua_tonumber(L,1);
int y1 = lua_tonumber(L,2);
int x2 = lua_tonumber(L,3);
int y2 = lua_tonumber(L,4);
_graphicsForLuaApi->line(x1, y1, x2, y2);
}
else {
int x1 = lua_tonumber(L,1);
int y1 = lua_tonumber(L,2);
int x2 = lua_tonumber(L,3);
int y2 = lua_tonumber(L,4);
int16_t c = lua_tonumber(L,5);
_graphicsForLuaApi->line(x1, y1, x2, y2, c);
}
return 0;
}
int tline (lua_State *L){
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
fix32 mx = 0, my = 0, mdx = fix32::frombits(0x2000), mdy = 0;
if (lua_gettop(L) >= 6) {
x0 = lua_tonumber(L,1);
y0 = lua_tonumber(L,2);
x1 = lua_tonumber(L,3);
y1 = lua_tonumber(L,4);
mx = lua_tonumber(L,5);
my = lua_tonumber(L,6);
}
if (lua_gettop(L) > 7){
mdx = lua_tonumber(L,7);
mdy = lua_tonumber(L,8);
}
_graphicsForLuaApi->tline(x0, y0, x1, y1, mx, my, mdx, mdy);
return 0;
}
int circ(lua_State *L){
int ox = lua_tonumber(L,1);
int oy = lua_tonumber(L,2);
if (lua_gettop(L) == 2) {
_graphicsForLuaApi->circ(ox, oy);
}
else if (lua_gettop(L) == 3){
int r = lua_tonumber(L,3);
_graphicsForLuaApi->circ(ox, oy, r);
}
else if (lua_gettop(L) > 3){
int r = lua_tonumber(L,3);
int16_t c = lua_tonumber(L,4);
_graphicsForLuaApi->circ(ox, oy, r, c);
}
return 0;
}
int circfill(lua_State *L){
int ox = lua_tonumber(L,1);
int oy = lua_tonumber(L,2);
if (lua_gettop(L) == 2) {
_graphicsForLuaApi->circfill(ox, oy);
}
else if (lua_gettop(L) == 3){
int r = lua_tonumber(L,3);
_graphicsForLuaApi->circfill(ox, oy, r);
}
else if (lua_gettop(L) > 3){
int r = lua_tonumber(L,3);
int16_t c = lua_tonumber(L,4);
_graphicsForLuaApi->circfill(ox, oy, r, c);
}
return 0;
}
int oval(lua_State *L){
if (lua_gettop(L) >= 4) {
int x1 = lua_tonumber(L,1);
int y1 = lua_tonumber(L,2);
int x2 = lua_tonumber(L,3);
int y2 = lua_tonumber(L,4);
if (lua_gettop(L) == 4){
_graphicsForLuaApi->oval(x1, y1, x2, y2);
}
else {
int16_t c = lua_tonumber(L,5);
_graphicsForLuaApi->oval(x1, y1, x2, y2, c);
}
}
return 0;
}
int ovalfill(lua_State *L){
if (lua_gettop(L) >= 4) {
int x1 = lua_tonumber(L,1);
int y1 = lua_tonumber(L,2);
int x2 = lua_tonumber(L,3);
int y2 = lua_tonumber(L,4);
if (lua_gettop(L) == 4){
_graphicsForLuaApi->ovalfill(x1, y1, x2, y2);
}
else {
int16_t c = lua_tonumber(L,5);
_graphicsForLuaApi->ovalfill(x1, y1, x2, y2, c);
}
}
return 0;
}
int rect(lua_State *L){
if (lua_gettop(L) >= 4) {
int x1 = lua_tonumber(L,1);
int y1 = lua_tonumber(L,2);
int x2 = lua_tonumber(L,3);
int y2 = lua_tonumber(L,4);
if (lua_gettop(L) == 4){
_graphicsForLuaApi->rect(x1, y1, x2, y2);
}
else {
int16_t c = lua_tonumber(L,5);
_graphicsForLuaApi->rect(x1, y1, x2, y2, c);
}
}
return 0;
}
int rectfill(lua_State *L){
if (lua_gettop(L) >= 4) {
int x1 = lua_tonumber(L,1);
int y1 = lua_tonumber(L,2);
int x2 = lua_tonumber(L,3);
int y2 = lua_tonumber(L,4);
if (lua_gettop(L) == 4){
_graphicsForLuaApi->rectfill(x1, y1, x2, y2);
}
else {
int16_t c = lua_tonumber(L,5);
_graphicsForLuaApi->rectfill(x1, y1, x2, y2, c);
}
}
return 0;
}
int rrect(lua_State *L){
if (lua_gettop(L) >= 5) {
int x = lua_tonumber(L,1);
int y = lua_tonumber(L,2);
int w = lua_tonumber(L,3);
int h = lua_tonumber(L,4);
int r = lua_tonumber(L,5);
if (lua_gettop(L) == 5){
_graphicsForLuaApi->rrect(x, y, w, h, r);
}
else {
int16_t c = lua_tonumber(L,6);
_graphicsForLuaApi->rrect(x, y, w, h, r, c);
}
}
return 0;
}
int rrectfill(lua_State *L){
if (lua_gettop(L) >= 5) {
int x = lua_tonumber(L,1);
int y = lua_tonumber(L,2);
int w = lua_tonumber(L,3);
int h = lua_tonumber(L,4);
int r = lua_tonumber(L,5);
if (lua_gettop(L) == 5){
_graphicsForLuaApi->rrectfill(x, y, w, h, r);
}
else {
int16_t c = lua_tonumber(L,6);
_graphicsForLuaApi->rrectfill(x, y, w, h, r, c);
}
}
return 0;
}
int print(lua_State *L){
int numArgs = lua_gettop(L);
if (numArgs == 0){
return 0;
}
const char * charArray = "";
size_t len = 0;
int newx = 0;
//todo: handle other cases, maybe move this somewhere else
//learned this from zepto8 https://github.com/samhocevar/zepto8/blob/27f83fe0626d4823fe2a33568d8310d8def84ae9/src/pico8/vm.cpp
if (lua_isnil(L, 1)){
charArray = "[nil]";
len = 5;
}
else if (lua_isstring(L, 1)){
charArray = lua_tolstring(L, 1, &len);
}
else if (lua_isnumber(L, 1)){
charArray = lua_tolstring(L, 1, &len);
}
else if (lua_isboolean(L, 1)){
int boolVal = lua_toboolean(L, 1);
charArray = boolVal ? "true" : "false";
len = boolVal ? 4 : 5;
}
else if (lua_isfunction(L, 1)){
charArray = "[function]";
len = 10;
}
std::string str = std::string(charArray, len);
if (numArgs < 2) {
newx = print(str);
}
else if (numArgs == 2) {
int16_t c = lua_tonumber(L,2);
_graphicsForLuaApi->color(c);
newx = print(str);
}
else if (numArgs == 3) {
int x = lua_tonumber(L,2);
int y = lua_tonumber(L,3);
newx = print(str, x, y);
}
else {
int x = lua_tonumber(L,2);
int y = lua_tonumber(L,3);
int16_t c = lua_tonumber(L,4);
newx = print(str, x, y, c);
}
lua_pushinteger(L, newx);
return 1;
}
int spr(lua_State *L) {
if (lua_gettop(L) < 3) {
return 0;
}
int n = lua_tonumber(L,1);
int x = lua_tonumber(L,2);
int y = lua_tonumber(L,3);
fix32 w = 1.0;
fix32 h = 1.0;
bool flip_x = false;
bool flip_y = false;
if (lua_gettop(L) > 3){
w = lua_tonumber(L,4);
}
if (lua_gettop(L) > 4) {
h = lua_tonumber(L,5);
}
if (lua_gettop(L) > 5) {
flip_x = lua_toboolean(L,6);
}
if (lua_gettop(L) > 6) {
flip_y = lua_toboolean(L,7);
}
_graphicsForLuaApi->spr(n, x, y, w, h, flip_x, flip_y);
return 0;
}
int sspr(lua_State *L) {
if (lua_gettop(L) < 6) {
return 0;
}
int sx = lua_tonumber(L,1);
int sy = lua_tonumber(L,2);
int sw = lua_tonumber(L,3);
int sh = lua_tonumber(L,4);
int dx = lua_tonumber(L,5);
int dy = lua_tonumber(L,6);
int dw = sw;
int dh = sh;
bool flip_x = false;
bool flip_y = false;
if (lua_gettop(L) > 6){
dw = lua_tonumber(L,7);
}
if (lua_gettop(L) > 7){
dh = lua_tonumber(L,8);
}
if (lua_gettop(L) > 8){
flip_x = lua_toboolean(L,9);
}
if (lua_gettop(L) > 9){
flip_y = lua_toboolean(L,10);
}
_graphicsForLuaApi->sspr(
sx,
sy,
sw,
sh,
dx,
dy,
dw,
dh,
flip_x,
flip_y);
return 0;
}
int fget(lua_State *L) {
fix32 n = lua_tonumber(L,1);
if (lua_gettop(L) == 1) {
uint8_t result = _graphicsForLuaApi->fget((uint8_t)n);
lua_pushinteger(L, result);
}
else {
fix32 f = lua_tonumber(L,2);
bool result = _graphicsForLuaApi->fget((uint8_t)n, (uint8_t)f);
lua_pushboolean(L, result);
}
return 1;
}
int fset(lua_State *L) {
fix32 n = lua_tonumber(L,1);
if (lua_gettop(L) > 2) {
fix32 f = lua_tonumber(L,2);
bool v = lua_toboolean(L,3);
_graphicsForLuaApi->fset((uint8_t)n, (uint8_t)f, v);
}
else {
fix32 v = lua_tonumber(L,2);
_graphicsForLuaApi->fset((uint8_t)n, (uint8_t)v);
}
return 0;
}
int sget(lua_State *L) {
int x = lua_tonumber(L,1);
int y = lua_tonumber(L,2);
uint8_t result = _graphicsForLuaApi->sget((uint8_t)x, (uint8_t)y);
lua_pushinteger(L, result);
return 1;
}
int sset(lua_State *L) {
int x = lua_tonumber(L,1);
int y = lua_tonumber(L,2);
int16_t c = lua_tonumber(L,3);
_graphicsForLuaApi->sset(x, y, c);
return 0;
}
int camera(lua_State *L) {
int16_t x = 0;
int16_t y = 0;
if (lua_gettop(L) > 0) {
x = lua_tointeger(L,1);
}
if (lua_gettop(L) > 1) {
y = lua_tointeger(L,2);
}
auto prev = _graphicsForLuaApi->camera(x, y);
lua_pushnumber(L, get<0>(prev));
lua_pushnumber(L, get<1>(prev));
return 2;
}
int clip(lua_State *L) {
std::tuple<uint8_t, uint8_t, uint8_t, uint8_t> prev;
if (lua_gettop(L) >= 4) {
int x = lua_tonumber(L,1);
int y = lua_tonumber(L,2);
int w = lua_tonumber(L,3);
int h = lua_tonumber(L,4);
prev = _graphicsForLuaApi->clip(x, y, w, h);
}
else {
prev = _graphicsForLuaApi->clip();
}
lua_pushnumber(L, get<0>(prev));
lua_pushnumber(L, get<1>(prev));
lua_pushnumber(L, get<2>(prev));
lua_pushnumber(L, get<3>(prev));
return 4;
}
int mget(lua_State *L) {
int celx = lua_tonumber(L,1);
int cely = lua_tonumber(L,2);
uint8_t result = _graphicsForLuaApi->mget(celx, cely);
lua_pushnumber(L, result);
return 1;
}
int mset(lua_State *L) {
int celx = lua_tonumber(L,1);
int cely = lua_tonumber(L,2);
int16_t snum = lua_tonumber(L, 3);
_graphicsForLuaApi->mset(celx, cely, snum);
return 0;
}
int gfx_map(lua_State *L) {
const bool bigMap = _ramForLuaApi->hwState.mapMemMapping >= 0x80;
const int bigMapLocation = _ramForLuaApi->hwState.mapMemMapping << 8;
const int mapSize = bigMap
? 0x10000 - bigMapLocation
: 8192;
const int mapW = _ramForLuaApi->hwState.widthOfTheMap == 0 ? 256 : _ramForLuaApi->hwState.widthOfTheMap;
const int mapH = mapSize / mapW;
int celx = 0, cely = 0, sx = 0, sy = 0, celw = mapW, celh = mapH, argc;
argc = lua_gettop(L);
if (argc > 0) {
celx = lua_tonumber(L,1);
}
if (argc > 1) {
cely = lua_tonumber(L,2);
}
if (argc > 2) {
sx = lua_tonumber(L,3);
}
if (argc > 3) {
sy = lua_tonumber(L,4);
}
if (argc > 4) {
celw = lua_tonumber(L,5);
}
if (argc > 5) {
celh = lua_tonumber(L,6);
}
int16_t layer = 0;
if (argc > 6){
layer = lua_tonumber(L,7);
}
_graphicsForLuaApi->map(celx, cely, sx, sy, celw, celh, layer);
return 0;
}
int pal(lua_State *L) {
int numArgs = lua_gettop(L);
if (numArgs == 0) {
_graphicsForLuaApi->pal();
return 0;
}
int16_t p = 0;
int16_t c0 = 0;
int16_t c1 = 0;
if (lua_istable(L, 1)){
if (numArgs > 1) {
p = lua_tonumber(L,2);
}
/* table is in the stack at index 't' */
lua_pushnil(L); /* first key */
while (lua_next(L, 1) != 0) {
if (lua_isnumber(L, -2) && lua_isnumber(L, -1)) {
c0 = lua_tonumber(L, -2);
c1 = lua_tonumber(L, -1);
_graphicsForLuaApi->pal(c0, c1, p);
}
lua_pop(L, 1);
}
return 0;
} else if (numArgs == 1) {
p = lua_tonumber(L, 1);
_graphicsForLuaApi->pal(p);
return 0;
}
c0 = lua_tonumber(L,1);
c1 = c0;
if (lua_gettop(L) > 1) {
c1 = lua_tonumber(L,2);
}
if (lua_gettop(L) > 2){
p = lua_tonumber(L,3);
}
uint8_t prev =_graphicsForLuaApi->pal(c0, c1, p);
lua_pushnumber(L, prev);
return 1;
}
int palt(lua_State *L) {
int16_t prev = 0;
//only 0th color is set to transparent if called with no args
int16_t c = 0;
c |= 1UL << 15;
if (lua_gettop(L) < 2) {
if (lua_gettop(L) == 1){
c = lua_tonumber(L,1);
}
//c is a bitfield of what colors should be transparent
for (int i = 0; i < 16; i++){
//get single bit
bool bit = (c >> (15 - i)) & 1U;
auto singlePrev = _graphicsForLuaApi->palt(i, bit);
//update prev single bit
if (singlePrev) {
prev |= 1UL << (15 - i);
}
}
}
else {
c = lua_tonumber(L,1);
bool t = lua_toboolean(L,2);
prev = _graphicsForLuaApi->palt(c, t);
}
lua_pushnumber(L, prev);
return 1;
}
int cursor(lua_State *L) {
int x = lua_tonumber(L,1);
int y = lua_tonumber(L,2);
std::tuple<uint8_t, uint8_t> prev;
if (lua_gettop(L) < 3) {
prev = _graphicsForLuaApi->cursor(x, y);
}
else{
int16_t c = lua_tonumber(L,3);
prev =_graphicsForLuaApi->cursor(x, y, c);
}
lua_pushnumber(L, get<0>(prev));
lua_pushnumber(L, get<1>(prev));
return 2;
}
int fillp(lua_State *L) {
fix32 pat = 0;
if (lua_gettop(L) > 0) {
pat = lua_tonumber(L, 1);
}
fix32 prev = _graphicsForLuaApi->fillp(pat);
lua_pushnumber(L, prev);
return 1;
}
// int flip(lua_State *L) {
// _vmForLuaApi->vm_flip();
// return 0;
// }
//Input
//input api
int btn(lua_State *L){
int numArgs = lua_gettop(L);
if (numArgs == 0) {
uint8_t btnstate = _inputForLuaApi->btn();
lua_pushnumber(L, btnstate);
}
else {
fix32 i = lua_tonumber(L,1);
int p = 0;
if (numArgs > 1){
p = lua_tonumber(L,2);
};
bool pressed = _inputForLuaApi->btn((int)i, p);
lua_pushboolean(L, pressed);
}
return 1;
}
int btnp(lua_State *L){
int numArgs = lua_gettop(L);
if (numArgs == 0) {
uint8_t btnpstate = _inputForLuaApi->btnp();
lua_pushnumber(L, btnpstate);
}
else {
fix32 i = lua_tonumber(L,1);
int p = 0;
if (numArgs > 1){
p = lua_tonumber(L,2);
};
bool pressed = _inputForLuaApi->btnp((int)i, p);
lua_pushboolean(L, pressed);
}
return 1;
}
//System
int time(lua_State *L) {
int frameCount = _vmForLuaApi->GetFrameCount();
int targetFps = _vmForLuaApi->GetTargetFps();
fix32 seconds = (fix32)frameCount / (fix32)targetFps;
lua_pushnumber(L, seconds);
return 1;
}
int stat(lua_State *L) {
int n = (int)lua_tonumber(L, 1);
switch(n){
//0 memory usage
case 0:
//TODO: get from z8lua
lua_pushnumber(L, 1);
return 1;
break;
//cpu usage
case 1:
// stubbed to return 50%
lua_pushnumber(L, 0.5);
return 1;
break;
//cpu usage (without system calls)
case 2:
// stubbed to return 50%
lua_pushnumber(L, 0.5);
return 1;
break;
//clipboard contents
case 4:
// no clipboard support currently
lua_pushstring(L, "");
return 1;
break;
//version
case 5:
// no clipboard support currently
lua_pushnumber(L, 22);
return 1;
break;
//argument
case 6:
// no args or loading other cards currently supported
lua_pushstring(L, _vmForLuaApi->getCartParam().c_str());
return 1;
break;
//frame rate
case 7:
lua_pushnumber(L, _vmForLuaApi->getFps());
return 1;
break;
//target framerate
case 8:
//lua_pushnumber(L, _vmForLuaApi->getTargetFps());
lua_pushnumber(L, _vmForLuaApi->getFps());
return 1;
break;
//16-19 audio sfx currently playing
case 16:
case 46:
lua_pushnumber(L, _audioForLuaApi->getCurrentSfxId(0));
return 1;
break;
case 17:
case 47:
lua_pushnumber(L, _audioForLuaApi->getCurrentSfxId(1));
return 1;
break;
case 18:
case 48:
lua_pushnumber(L, _audioForLuaApi->getCurrentSfxId(2));
return 1;
break;
case 19:
case 49:
lua_pushnumber(L, _audioForLuaApi->getCurrentSfxId(3));
return 1;
break;
//20-23 note idx of sfx currently playing
case 20:
case 50:
lua_pushnumber(L, _audioForLuaApi->getCurrentNoteNumber(0));
return 1;
break;
case 21:
case 51:
lua_pushnumber(L, _audioForLuaApi->getCurrentNoteNumber(1));
return 1;
break;
case 22:
case 52:
lua_pushnumber(L, _audioForLuaApi->getCurrentNoteNumber(2));
return 1;
break;
case 23:
case 53:
lua_pushnumber(L, _audioForLuaApi->getCurrentNoteNumber(3));
return 1;
break;
//current music pattern
case 24:
case 54:
lua_pushnumber(L, _audioForLuaApi->getCurrentMusic());
return 1;
break;
//current music count
case 25:
case 55:
lua_pushnumber(L, _audioForLuaApi->getMusicPatternCount());
return 1;
break;
//current music tick count
case 56:
case 26:
lua_pushnumber(L, _audioForLuaApi->getMusicTickCount());
return 1;
break;
//if SDL scancode is pressed. always false for now
case 28:
lua_pushboolean(L, false);
return 1;
break;
//unknown. appears to always be 0
case 29:
lua_pushnumber(L, 0);
return 1;
break;
//was a key pressed
case 30:
lua_pushboolean(L, _inputForLuaApi->getKeyDown());
return 1;
break;
//string of key pressed
case 31:
lua_pushstring(L, _inputForLuaApi->getKey());
return 1;
break;
//mouse x
case 32:
lua_pushnumber(L, _inputForLuaApi->getMouseX());
return 1;
break;
//mouse y
case 33:
lua_pushnumber(L, _inputForLuaApi->getMouseY());
return 1;
break;
//mouse btn state
case 34:
lua_pushnumber(L, _inputForLuaApi->getMouseBtnState());
return 1;
break;
//Current Year
case 90:
lua_pushnumber(L, _vmForLuaApi->getYear());
return 1;
break;
//Current month
case 91:
lua_pushnumber(L, _vmForLuaApi->getMonth());
return 1;
break;
//Current day
case 92:
lua_pushnumber(L, _vmForLuaApi->getDay());
return 1;
break;
//Current Hour
case 93:
lua_pushnumber(L, _vmForLuaApi->getHour());
return 1;
break;
//Current Minute
case 94:
lua_pushnumber(L, _vmForLuaApi->getMinute());
return 1;
break;
//Current second
case 95:
lua_pushnumber(L, _vmForLuaApi->getSecond());
return 1;
break;
case 100:
lua_pushstring(L, _vmForLuaApi->getCartBreadcrumb().c_str());
return 1;
//101 and 102 are something to do with the bbs -
case 101:
lua_pushnil(L);
return 1;
case 102:
lua_pushnumber(L, 0);
return 1;
//unknown? used by serial carts
case 108:
lua_pushnumber(L, 32);
return 1;
break;
//bytestream availability (dropped file or image. not supported)
case 120:
lua_pushboolean(L, false);
return 1;
break;
case 121:
lua_pushboolean(L, false);
return 1;
break;
case 122:
lua_pushboolean(L, false);
return 1;
break;
}
return noopreturns(L, "stat");
}
//Audio
int music(lua_State *L) {
int n = lua_tonumber(L,1);
int fadems = 0;
if (lua_gettop(L) > 1) {
fadems = (int)lua_tonumber(L, 2);
}
int channelmask = 0;
if (lua_gettop(L) > 2) {
channelmask = (int)lua_tonumber(L, 3);
}
_audioForLuaApi->api_music(n, fadems, channelmask);
return 0;
}
int sfx(lua_State *L) {
fix32 n = lua_tonumber(L,1);
int channel = -1;
if (lua_gettop(L) > 1) {
channel = (int)lua_tonumber(L, 2);
}
int offset = 0;
if (lua_gettop(L) > 2) {
offset = (int)lua_tonumber(L, 3);
}
int length = -1;
if (lua_gettop(L) > 3) {
length = (int)lua_tonumber(L, 4);
}
int result = _audioForLuaApi->api_sfx((int)n, channel, offset, length);
lua_pushnumber(L, result);
return 1;
}
//Memory
int cstore(lua_State *L) {
//this is supposed to copy data from ram to the file.
//for now, not implementing this
return noop("cstore");
}
int api_memcpy(lua_State *L) {
uint16_t dest = (uint16_t)lua_tointeger(L,1);
uint16_t src = (uint16_t)lua_tointeger(L,2);
uint16_t len = (uint16_t)lua_tointeger(L,3);
_vmForLuaApi->vm_memcpy(dest, src, len);
return 0;
}
int api_memset(lua_State *L) {
uint16_t dest = (uint16_t)lua_tointeger(L,1);
uint16_t val = (uint16_t)lua_tointeger(L,2);
uint16_t len = (uint16_t)lua_tointeger(L,3);
_vmForLuaApi->vm_memset(dest, val, len);
return 0;
}
int peek(lua_State *L) {
int numArgs = lua_gettop(L);
int numToReturn = 1;
uint16_t addr = (uint16_t)lua_tointeger(L,1);
if (numArgs > 1) {
int tmpNumToReturn = lua_tonumber(L,2);
//pico 8 docs say up to 8192 - clamp to this limit
if (tmpNumToReturn > 0) {
numToReturn = tmpNumToReturn > 8192 ? 8192 : tmpNumToReturn;
}
}
// Ensure Lua stack has enough space for the values we're about to push
lua_checkstack(L, numToReturn);
for(int i = 0; i < numToReturn; i++) {
uint8_t val = _vmForLuaApi->vm_peek(addr + i);
lua_pushinteger(L, val);
}
return numToReturn;
}
int poke(lua_State *L) {
int numArgs = lua_gettop(L);
uint16_t dest = (uint16_t)lua_tointeger(L,1);
uint8_t val = 0;
if (numArgs > 1) {
val = lua_tonumber(L,2);
}
_vmForLuaApi->vm_poke(dest, val);
if (numArgs > 2) {
//pico 8 docs say up to 8192
int effectiveNumArgs = numArgs - 2;
if (effectiveNumArgs > 8192) {
effectiveNumArgs = 8192;
}
for(int i = 1; i <= effectiveNumArgs; i++) {
val = lua_tonumber(L, 2 + i);
_vmForLuaApi->vm_poke(dest + i, val);
}
}
return 0;
}
int peek2(lua_State *L) {
uint16_t addr = (uint16_t)lua_tointeger(L,1);
int16_t val = _vmForLuaApi->vm_peek2(addr);
lua_pushinteger(L, val);
return 1;
}
int poke2(lua_State *L) {
int numArgs = lua_gettop(L);
uint16_t dest = (uint16_t)lua_tointeger(L,1);
int val = 0;
if (numArgs > 1) {
val = lua_tonumber(L,2);
}
_vmForLuaApi->vm_poke2(dest, (int16_t)val);
if (numArgs > 2) {
for(int i = 1; i <= (numArgs - 2); i++) {
val = lua_tonumber(L, 2 + i);
_vmForLuaApi->vm_poke2(dest + i, (int16_t)val);
}
}
return 0;
}
int peek4(lua_State *L) {
uint16_t addr = (uint16_t)lua_tointeger(L,1);
fix32 val = _vmForLuaApi->vm_peek4(addr);
lua_pushnumber(L, val);
return 1;
}
int poke4(lua_State *L) {
int numArgs = lua_gettop(L);
uint16_t dest = (uint16_t)lua_tointeger(L,1);
fix32 val = 0;
if (numArgs > 1) {
val = lua_tonumber(L,2);
}
_vmForLuaApi->vm_poke4(dest, val);
if (numArgs > 2) {
for(int i = 1; i <= (numArgs - 2); i++) {
val = lua_tonumber(L, 2 + i);
_vmForLuaApi->vm_poke4(dest + i, val);
}
}
return 0;
}
int reload(lua_State *L) {
uint16_t dest = 0;
uint16_t src = 0;
uint16_t len = 0x4300;
const char * str = "";
if (lua_gettop(L) > 0) {
dest = (uint16_t)lua_tointeger(L,1);
}
if (lua_gettop(L) > 1) {
src = (uint16_t)lua_tointeger(L,2);
}
if (lua_gettop(L) > 2) {
len = (uint16_t)lua_tointeger(L,3);
}
if (lua_gettop(L) > 3) {
str = lua_tolstring(L, 4, nullptr);
if (str == nullptr) {
str = "";
}
}
_vmForLuaApi->vm_reload(dest, src, len, str);
return 0;
}
//cart data
int cartdata(lua_State *L) {
bool result = false;
if (lua_gettop(L) > 0 && lua_isstring(L, 1)) {
std::string key = lua_tolstring(L, 1, nullptr);
result = _vmForLuaApi->vm_cartdata(key);
}
lua_pushboolean(L, result);
return 1;
}
int dget(lua_State *L) {
int addr = lua_tonumber(L,1);
fix32 val = _vmForLuaApi->vm_dget(addr);
lua_pushnumber(L, val);
return 1;
}
int dset(lua_State *L) {
int dest = lua_tonumber(L,1);
fix32 val = lua_tonumber(L,2);
_vmForLuaApi->vm_dset(dest, val);
return 0;
}
int printh(lua_State *L) {
if (lua_isstring(L, 1)){
const char * str = "";
str = lua_tolstring(L, 1, nullptr);
std::string utf8str = charset::pico8_to_utf8(str);
printf("%s\n", utf8str.c_str());
}
return 0;
}
int rnd(lua_State *L) {
if (lua_gettop(L) == 0) {
fix32 val = _vmForLuaApi->api_rnd();
lua_pushnumber(L, val);
}
else {
if (lua_istable(L, 1)){
size_t len = lua_rawlen(L,1);
fix32 range = (fix32)len;
int idx = (int)(_vmForLuaApi->api_rnd(range)) + 1;
lua_rawgeti(L, 1, idx);
}
else {
fix32 range = lua_tonumber(L,1);
fix32 val = _vmForLuaApi->api_rnd(range);
lua_pushnumber(L, val);
}
}
return 1;
}
int srand(lua_State *L) {
fix32 seed = lua_tonumber(L,1);
_vmForLuaApi->api_srand(seed);
return 0;
}
int _update_buttons(lua_State *L) {
_vmForLuaApi->update_buttons();
return 0;
}
int run(lua_State *L) {
_vmForLuaApi->vm_run();
return 0;
}
int extcmd(lua_State *L){
const char * str = "";
if (lua_isstring(L, 1)){
str = lua_tolstring(L, 1, nullptr);
}
_vmForLuaApi->vm_extcmd(str);
return 0;
}
int load(lua_State *L) {
const char* filename = "";
const char* breadcrumb = "";
const char* param = "";
int argC = lua_gettop(L);
if (argC > 0 && lua_isstring(L, 1)){
filename = lua_tolstring(L, 1, nullptr);
if (argC > 1 && lua_isstring(L, 2)){
breadcrumb = lua_tolstring(L, 2, nullptr);
}
if (argC > 2 && lua_isstring(L, 3)){
param = lua_tolstring(L, 3, nullptr);
}
bool result = _vmForLuaApi->vm_load(filename, breadcrumb, param);
if (result) {
//todo: abort current cart?
}
lua_pushboolean(L, result);
return 1;
}
return 0;
}
int reset(lua_State *L) {
_vmForLuaApi->vm_reset();
return 0;
}
int setFps(lua_State *L){
//_vmForLuaApi->setTargetFps(lua_tointeger(L, 1));
return 0;
}
int listcarts(lua_State *L) {
//get cart list from VM (who should get it from host)
vector<string> carts = _vmForLuaApi->GetCartList();
lua_createtable(L, carts.size(), 0);
int newTable = lua_gettop(L);
int index = 1;
for(size_t i = 0; i < carts.size(); i++){
lua_pushstring(L, carts[i].c_str());
lua_rawseti(L, newTable, index);
++index;
}
return 1;
}
int listdirs(lua_State *L) {
vector<string> dirs = _vmForLuaApi->GetDirList();
lua_createtable(L, dirs.size(), 0);
int newTable = lua_gettop(L);
int index = 1;
for(size_t i = 0; i < dirs.size(); i++){
lua_pushstring(L, dirs[i].c_str());
lua_rawseti(L, newTable, index);
++index;
}
return 1;
}
int cd(lua_State *L) {
const char* dir = "";
if (lua_gettop(L) > 0 && lua_isstring(L, 1)){
dir = lua_tolstring(L, 1, nullptr);
}
bool result = _vmForLuaApi->ChangeDirectory(dir);
lua_pushboolean(L, result);
return 1;
}
int pwd(lua_State *L) {
string dir = _vmForLuaApi->GetCurrentDirectory();
lua_pushstring(L, dir.c_str());
return 1;
}
int refreshcarts(lua_State *L) {
_vmForLuaApi->RefreshCartList();
return 0;
}
int bbs_listfeatured(lua_State *L) {
vector<BBSCartItem> carts = _vmForLuaApi->GetBBSFeaturedCarts();
lua_createtable(L, (int)carts.size(), 0);
int top = lua_gettop(L);
for (size_t i = 0; i < carts.size(); i++) {
lua_createtable(L, 0, 7);
lua_pushstring(L, carts[i].id.c_str());
lua_setfield(L, -2, "id");
lua_pushstring(L, carts[i].title.c_str());
lua_setfield(L, -2, "title");
lua_pushstring(L, carts[i].author.c_str());
lua_setfield(L, -2, "author");
lua_pushstring(L, carts[i].category.c_str());
lua_setfield(L, -2, "cat");
lua_pushstring(L, carts[i].filename.c_str());
lua_setfield(L, -2, "file");
lua_pushstring(L, carts[i].url.c_str());
lua_setfield(L, -2, "url");
lua_pushboolean(L, carts[i].downloaded);
lua_setfield(L, -2, "downloaded");
lua_rawseti(L, top, (int)i + 1);
}
return 1;
}
int bbs_download(lua_State *L) {
int argC = lua_gettop(L);
if (argC >= 2 && lua_isstring(L, 1) && lua_isstring(L, 2)) {
string lid = lua_tostring(L, 1);
string filename = lua_tostring(L, 2);
bool res = _vmForLuaApi->DownloadBBSCart(lid, filename);
lua_pushboolean(L, res);
return 1;
}
lua_pushboolean(L, false);
return 1;
}
int bbs_isdownloaded(lua_State *L) {
int argC = lua_gettop(L);
if (argC >= 1 && lua_isstring(L, 1)) {
string filename = lua_tostring(L, 1);
bool res = _vmForLuaApi->IsBBSCartDownloaded(filename);
lua_pushboolean(L, res);
return 1;
}
lua_pushboolean(L, false);
return 1;
}
int getbioserror(lua_State *L) {
string error = _vmForLuaApi->GetBiosError();
lua_pushstring(L, error.c_str());
return 1;
}
int loaddefaultcart(lua_State *L) {
_vmForLuaApi->QueueCartChange("__FAKE08-DEFAULT.p8");
return 0;
}
int loadsettingscart(lua_State *L) {
_vmForLuaApi->QueueCartChange("__FAKE08-SETTINGS.p8");
return 0;
}
int togglepausemenu(lua_State *L) {
_vmForLuaApi->togglePauseMenu();
return 0;
}
int ispaused(lua_State *L) {
lua_pushboolean(L, _vmForLuaApi->IsPaused());
return 1;
}
int resetcart(lua_State *L) {
_vmForLuaApi->QueueCartChange(_vmForLuaApi->CurrentCartFilename());
return 0;
}
int getsetting(lua_State *L) {
//get setting from host
const char * str = "";
if (lua_isstring(L, 1)){
str = lua_tolstring(L, 1, nullptr);
}
Logger_Write("loading setting ");
Logger_Write(str);
Logger_Write("\n");
//std::string sname = str;
int val = _vmForLuaApi->getSetting(str);
lua_pushnumber(L, val);
return 1;
}
int setsetting(lua_State *L) {
//get setting from host
const char * str = "";
if (lua_isstring(L, 1)){
str = lua_tolstring(L, 1, nullptr);
}
Logger_Write("setting setting ");
Logger_Write(str);
Logger_Write("\n");
int sval = lua_tonumber(L,2);
_vmForLuaApi->setSetting(str,sval);
return 1;
}
int installpackins(lua_State *L) {
#if LOAD_PACK_INS
_vmForLuaApi->installPackins();
#endif
return 1;
}
int loadlabel(lua_State *L) {
const char * cartname = "";
if (lua_isstring(L, 1)){
cartname = lua_tolstring(L, 1, nullptr);
}
std::string filename = cartname;
bool mini = lua_toboolean(L,2);
int minioffset = lua_tonumber(L,3);
_vmForLuaApi->loadLabel(filename, mini, minioffset);
return 1;
}
int getlualine(lua_State *L) {
const char * cartname = "";
if (lua_isstring(L, 1)){
cartname = lua_tolstring(L, 1, nullptr);
}
std::string filename = cartname;
int linenumber = lua_tonumber(L,2);
std::string resultstring = _vmForLuaApi->getLuaLine(filename, linenumber);
lua_pushstring(L, resultstring.c_str());
return 1;
}