2017-09-26 08:59:34 +02:00
|
|
|
// MIT License
|
|
|
|
|
|
|
|
// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com
|
|
|
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
|
|
// copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
// SOFTWARE.
|
|
|
|
|
|
|
|
#include "console.h"
|
|
|
|
#include "fs.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "net.h"
|
|
|
|
#include "ext/gif.h"
|
|
|
|
#include "ext/file_dialog.h"
|
|
|
|
|
|
|
|
#include <zlib.h>
|
|
|
|
|
2017-10-20 09:37:30 +02:00
|
|
|
#define CONSOLE_CURSOR_COLOR ((tic_color_red))
|
|
|
|
#define CONSOLE_BACK_TEXT_COLOR ((tic_color_dark_gray))
|
|
|
|
#define CONSOLE_FRONT_TEXT_COLOR ((tic_color_white))
|
|
|
|
#define CONSOLE_ERROR_TEXT_COLOR ((tic_color_red))
|
2017-09-26 08:59:34 +02:00
|
|
|
#define CONSOLE_CURSOR_BLINK_PERIOD (TIC_FRAMERATE)
|
|
|
|
#define CONSOLE_CURSOR_DELAY (TIC_FRAMERATE / 2)
|
|
|
|
#define CONSOLE_BUFFER_WIDTH (STUDIO_TEXT_BUFFER_WIDTH)
|
|
|
|
#define CONSOLE_BUFFER_HEIGHT (STUDIO_TEXT_BUFFER_HEIGHT)
|
|
|
|
#define CONSOLE_BUFFER_SCREENS 64
|
|
|
|
#define CONSOLE_BUFFER_SIZE (CONSOLE_BUFFER_WIDTH * CONSOLE_BUFFER_HEIGHT * CONSOLE_BUFFER_SCREENS)
|
|
|
|
|
2017-11-20 07:14:37 +01:00
|
|
|
#if defined(__WINDOWS__) || defined(__LINUX__) || defined(__MACOSX__)
|
2017-09-26 08:59:34 +02:00
|
|
|
#define CAN_EXPORT 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(__WINDOWS__)
|
|
|
|
static const char* ExeExt = ".exe";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static struct
|
|
|
|
{
|
|
|
|
char prefix[32];
|
|
|
|
bool yes;
|
|
|
|
bool menu;
|
|
|
|
tic_cartridge file;
|
|
|
|
} embed =
|
|
|
|
{
|
|
|
|
.prefix = "C8B39163816B47209E721136D37B8031",
|
|
|
|
.yes = false,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char DefaultLuaTicPath[] = TIC_LOCAL "default.tic";
|
|
|
|
static const char DefaultMoonTicPath[] = TIC_LOCAL "default_moon.tic";
|
|
|
|
static const char DefaultJSTicPath[] = TIC_LOCAL "default_js.tic";
|
|
|
|
|
2017-11-10 17:40:44 +01:00
|
|
|
static const char* getName(const char* name, const char* ext)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
static char path[FILENAME_MAX];
|
|
|
|
|
|
|
|
strcpy(path, name);
|
|
|
|
|
|
|
|
size_t ps = strlen(path);
|
2017-11-10 17:40:44 +01:00
|
|
|
size_t es = strlen(ext);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-11-10 17:40:44 +01:00
|
|
|
if(!(ps > es && strstr(path, ext) + es == path + ps))
|
|
|
|
strcat(path, ext);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2017-11-10 17:40:44 +01:00
|
|
|
static const char* getCartName(const char* name)
|
|
|
|
{
|
2017-11-19 15:44:01 +01:00
|
|
|
return getName(name, CART_EXT);
|
2017-11-10 17:40:44 +01:00
|
|
|
}
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
static void scrollBuffer(char* buffer)
|
|
|
|
{
|
|
|
|
memmove(buffer, buffer + CONSOLE_BUFFER_WIDTH, CONSOLE_BUFFER_SIZE - CONSOLE_BUFFER_WIDTH);
|
|
|
|
memset(buffer + CONSOLE_BUFFER_SIZE - CONSOLE_BUFFER_WIDTH, 0, CONSOLE_BUFFER_WIDTH);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void scrollConsole(Console* console)
|
|
|
|
{
|
|
|
|
while(console->cursor.y >= CONSOLE_BUFFER_HEIGHT * CONSOLE_BUFFER_SCREENS)
|
|
|
|
{
|
|
|
|
scrollBuffer(console->buffer);
|
|
|
|
scrollBuffer((char*)console->colorBuffer);
|
|
|
|
|
|
|
|
console->cursor.y--;
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 minScroll = console->cursor.y - CONSOLE_BUFFER_HEIGHT + 1;
|
|
|
|
if(console->scroll.pos < minScroll)
|
|
|
|
console->scroll.pos = minScroll;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void consolePrint(Console* console, const char* text, u8 color)
|
|
|
|
{
|
|
|
|
printf("%s", text);
|
|
|
|
|
|
|
|
const char* textPointer = text;
|
|
|
|
const char* endText = textPointer + strlen(text);
|
|
|
|
|
|
|
|
while(textPointer != endText)
|
|
|
|
{
|
|
|
|
char symbol = *textPointer++;
|
|
|
|
|
|
|
|
scrollConsole(console);
|
|
|
|
|
|
|
|
if(symbol == '\n')
|
|
|
|
{
|
|
|
|
console->cursor.x = 0;
|
|
|
|
console->cursor.y++;
|
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
else
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
s32 offset = console->cursor.x + console->cursor.y * CONSOLE_BUFFER_WIDTH;
|
|
|
|
*(console->buffer + offset) = symbol;
|
|
|
|
*(console->colorBuffer + offset) = color;
|
|
|
|
|
|
|
|
console->cursor.x++;
|
|
|
|
|
|
|
|
if(console->cursor.x >= CONSOLE_BUFFER_WIDTH)
|
|
|
|
{
|
|
|
|
console->cursor.x = 0;
|
|
|
|
console->cursor.y++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printBack(Console* console, const char* text)
|
|
|
|
{
|
|
|
|
consolePrint(console, text, CONSOLE_BACK_TEXT_COLOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printFront(Console* console, const char* text)
|
|
|
|
{
|
|
|
|
consolePrint(console, text, CONSOLE_FRONT_TEXT_COLOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printError(Console* console, const char* text)
|
|
|
|
{
|
|
|
|
consolePrint(console, text, CONSOLE_ERROR_TEXT_COLOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printLine(Console* console)
|
|
|
|
{
|
|
|
|
consolePrint(console, "\n", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void commandDoneLine(Console* console, bool newLine)
|
|
|
|
{
|
|
|
|
if(newLine)
|
|
|
|
printLine(console);
|
|
|
|
|
|
|
|
if(strlen(fsGetDir(console->fs)))
|
|
|
|
printBack(console, fsGetDir(console->fs));
|
|
|
|
|
|
|
|
printFront(console, ">");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void commandDone(Console* console)
|
|
|
|
{
|
|
|
|
commandDoneLine(console, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drawCursor(Console* console, s32 x, s32 y, u8 symbol)
|
|
|
|
{
|
|
|
|
bool inverse = console->cursor.delay || console->tickCounter % CONSOLE_CURSOR_BLINK_PERIOD < CONSOLE_CURSOR_BLINK_PERIOD / 2;
|
|
|
|
|
|
|
|
if(inverse)
|
|
|
|
console->tic->api.rect(console->tic, x-1, y-1, TIC_FONT_WIDTH+1, TIC_FONT_HEIGHT+1, CONSOLE_CURSOR_COLOR);
|
2017-10-16 05:03:05 +02:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
console->tic->api.draw_char(console->tic, symbol, x, y, inverse ? TIC_COLOR_BG : CONSOLE_FRONT_TEXT_COLOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drawConsoleText(Console* console)
|
|
|
|
{
|
|
|
|
char* pointer = console->buffer + console->scroll.pos * CONSOLE_BUFFER_WIDTH;
|
|
|
|
u8* colorPointer = console->colorBuffer + console->scroll.pos * CONSOLE_BUFFER_WIDTH;
|
|
|
|
|
|
|
|
const char* end = console->buffer + CONSOLE_BUFFER_SIZE;
|
|
|
|
s32 x = 0;
|
|
|
|
s32 y = 0;
|
|
|
|
|
|
|
|
while(pointer < end)
|
|
|
|
{
|
|
|
|
char symbol = *pointer++;
|
|
|
|
u8 color = *colorPointer++;
|
|
|
|
|
|
|
|
if(symbol)
|
|
|
|
console->tic->api.draw_char(console->tic, symbol, x * STUDIO_TEXT_WIDTH, y * STUDIO_TEXT_HEIGHT, color);
|
|
|
|
|
|
|
|
if(++x == CONSOLE_BUFFER_WIDTH)
|
|
|
|
{
|
|
|
|
y++;
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drawConsoleInputText(Console* console)
|
|
|
|
{
|
|
|
|
s32 x = console->cursor.x * STUDIO_TEXT_WIDTH;
|
|
|
|
s32 y = (console->cursor.y - console->scroll.pos) * STUDIO_TEXT_HEIGHT;
|
|
|
|
|
|
|
|
const char* pointer = console->inputBuffer;
|
|
|
|
const char* end = pointer + strlen(console->inputBuffer);
|
|
|
|
s32 index = 0;
|
|
|
|
|
|
|
|
while(pointer != end)
|
|
|
|
{
|
|
|
|
char symbol = *pointer++;
|
|
|
|
|
|
|
|
if(console->inputPosition == index)
|
|
|
|
drawCursor(console, x, y, symbol);
|
|
|
|
else
|
|
|
|
console->tic->api.draw_char(console->tic, symbol, x, y, CONSOLE_FRONT_TEXT_COLOR);
|
|
|
|
|
|
|
|
index++;
|
|
|
|
|
|
|
|
x += STUDIO_TEXT_WIDTH;
|
|
|
|
if(x == (CONSOLE_BUFFER_WIDTH * STUDIO_TEXT_WIDTH))
|
|
|
|
{
|
|
|
|
y += STUDIO_TEXT_HEIGHT;
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if(console->inputPosition == index)
|
|
|
|
drawCursor(console, x, y, ' ');
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void processConsoleHome(Console* console)
|
|
|
|
{
|
|
|
|
console->inputPosition = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void processConsoleEnd(Console* console)
|
|
|
|
{
|
|
|
|
console->inputPosition = strlen(console->inputBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void processConsoleDel(Console* console)
|
|
|
|
{
|
|
|
|
char* pos = console->inputBuffer + console->inputPosition;
|
|
|
|
size_t size = strlen(pos);
|
2017-10-16 05:03:05 +02:00
|
|
|
memmove(pos, pos + 1, size);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void processConsoleBackspace(Console* console)
|
|
|
|
{
|
|
|
|
if(console->inputPosition > 0)
|
|
|
|
{
|
|
|
|
console->inputPosition--;
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
processConsoleDel(console);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleHelpCommand(Console* console, const char* param);
|
|
|
|
|
|
|
|
static void onConsoleExitCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
exitStudio();
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static s32 writeGifData(const tic_mem* tic, u8* dst, const u8* src, s32 width, s32 height)
|
|
|
|
{
|
|
|
|
s32 size = 0;
|
|
|
|
gif_color* palette = (gif_color*)SDL_malloc(sizeof(gif_color) * TIC_PALETTE_SIZE);
|
|
|
|
|
|
|
|
if(palette)
|
|
|
|
{
|
2017-12-13 17:54:00 +01:00
|
|
|
const tic_rgb* pal = tic->cart.bank.palette.colors;
|
2017-09-26 08:59:34 +02:00
|
|
|
for(s32 i = 0; i < TIC_PALETTE_SIZE; i++, pal++)
|
|
|
|
palette[i].r = pal->r, palette[i].g = pal->g, palette[i].b = pal->b;
|
|
|
|
|
|
|
|
gif_write_data(dst, &size, width, height, src, palette, TIC_PALETTE_BPP);
|
|
|
|
|
|
|
|
SDL_free(palette);
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void loadCart(tic_mem* tic, tic_cartridge* cart, const u8* buffer, s32 size, bool palette)
|
|
|
|
{
|
2017-12-13 17:54:00 +01:00
|
|
|
tic->api.load(cart, sizeof(tic_cartridge), buffer, size, palette);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
if(!palette)
|
2017-12-13 17:54:00 +01:00
|
|
|
memcpy(cart->bank.palette.data, tic->config.palette.data, sizeof(tic_palette));
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool loadRom(tic_mem* tic, const void* data, s32 size, bool palette)
|
|
|
|
{
|
|
|
|
loadCart(tic, &tic->cart, data, size, palette);
|
|
|
|
tic->api.reset(tic);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool onConsoleLoadSectionCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
if(param)
|
|
|
|
{
|
2017-10-16 05:03:05 +02:00
|
|
|
static const char* Sections[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-12-13 17:54:00 +01:00
|
|
|
"cover",
|
2017-09-26 08:59:34 +02:00
|
|
|
"sprites",
|
|
|
|
"map",
|
|
|
|
"code",
|
|
|
|
"sfx",
|
|
|
|
"music",
|
|
|
|
"palette",
|
|
|
|
};
|
|
|
|
|
|
|
|
char buf[64] = {0};
|
|
|
|
|
|
|
|
for(s32 i = 0; i < COUNT_OF(Sections); i++)
|
|
|
|
{
|
2017-11-19 15:44:01 +01:00
|
|
|
sprintf(buf, "%s %s", CART_EXT, Sections[i]);
|
2017-09-26 08:59:34 +02:00
|
|
|
char* pos = SDL_strstr(param, buf);
|
|
|
|
|
|
|
|
if(pos)
|
|
|
|
{
|
2017-11-19 15:44:01 +01:00
|
|
|
pos[sizeof(CART_EXT) - 1] = 0;
|
2017-11-10 17:40:44 +01:00
|
|
|
const char* name = getCartName(param);
|
2017-09-26 08:59:34 +02:00
|
|
|
s32 size = 0;
|
|
|
|
void* data = fsLoadFile(console->fs, name, &size);
|
|
|
|
|
|
|
|
if(data)
|
|
|
|
{
|
|
|
|
tic_cartridge* cart = (tic_cartridge*)SDL_malloc(sizeof(tic_cartridge));
|
|
|
|
|
|
|
|
if(cart)
|
|
|
|
{
|
|
|
|
loadCart(console->tic, cart, data, size, true);
|
|
|
|
tic_mem* tic = console->tic;
|
|
|
|
|
|
|
|
switch(i)
|
|
|
|
{
|
2017-12-13 17:54:00 +01:00
|
|
|
case 0: memcpy(&tic->cart.cover, &cart->cover, sizeof cart->cover); break;
|
|
|
|
case 1: memcpy(&tic->cart.bank.tiles, &cart->bank.tiles, sizeof(tic_tiles)*2); break;
|
|
|
|
case 2: memcpy(&tic->cart.bank.map, &cart->bank.map, sizeof(tic_map)); break;
|
|
|
|
case 3: memcpy(&tic->cart.bank.code, &cart->bank.code, sizeof(tic_code)); break;
|
|
|
|
case 4: memcpy(&tic->cart.bank.sfx, &cart->bank.sfx, sizeof(tic_sfx)); break;
|
|
|
|
case 5: memcpy(&tic->cart.bank.music, &cart->bank.music, sizeof(tic_music)); break;
|
|
|
|
case 6: memcpy(&tic->cart.bank.palette, &cart->bank.palette, sizeof(tic_palette)); break;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
studioRomLoaded();
|
|
|
|
|
|
|
|
printLine(console);
|
|
|
|
printFront(console, Sections[i]);
|
|
|
|
printBack(console, " loaded from ");
|
|
|
|
printFront(console, name);
|
|
|
|
printLine(console);
|
|
|
|
|
|
|
|
SDL_free(cart);
|
|
|
|
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_free(data);
|
|
|
|
}
|
|
|
|
else printBack(console, "\ncart loading error");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void* getDemoCart(Console* console, tic_script_lang script, s32* size)
|
|
|
|
{
|
|
|
|
char path[FILENAME_MAX] = {0};
|
|
|
|
|
|
|
|
{
|
|
|
|
switch(script)
|
|
|
|
{
|
|
|
|
case tic_script_lua:
|
|
|
|
strcpy(path, DefaultLuaTicPath);
|
|
|
|
break;
|
|
|
|
case tic_script_moon:
|
|
|
|
strcpy(path, DefaultMoonTicPath);
|
|
|
|
break;
|
|
|
|
case tic_script_js:
|
|
|
|
strcpy(path, DefaultJSTicPath);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* data = fsLoadRootFile(console->fs, path, size);
|
|
|
|
|
|
|
|
if(data && *size)
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 LuaDemoRom[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/luademo.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 JsDemoRom[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/jsdemo.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 MoonDemoRom[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/moondemo.tic.dat"
|
|
|
|
};
|
2017-10-16 05:03:05 +02:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
const u8* demo = NULL;
|
|
|
|
s32 romSize = 0;
|
|
|
|
|
|
|
|
switch(script)
|
|
|
|
{
|
|
|
|
case tic_script_lua:
|
|
|
|
demo = LuaDemoRom;
|
|
|
|
romSize = sizeof LuaDemoRom;
|
|
|
|
break;
|
|
|
|
case tic_script_moon:
|
|
|
|
demo = MoonDemoRom;
|
|
|
|
romSize = sizeof MoonDemoRom;
|
|
|
|
break;
|
|
|
|
case tic_script_js:
|
|
|
|
demo = JsDemoRom;
|
|
|
|
romSize = sizeof JsDemoRom;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
u8* data = NULL;
|
|
|
|
*size = unzip(&data, demo, romSize);
|
|
|
|
|
|
|
|
if(data)
|
|
|
|
{
|
|
|
|
fsSaveRootFile(console->fs, path, data, *size, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2017-11-27 18:43:03 +01:00
|
|
|
static void setCartName(Console* console, const char* name)
|
|
|
|
{
|
|
|
|
if(name != console->romName)
|
|
|
|
strcpy(console->romName, name);
|
|
|
|
}
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
static void onConsoleLoadDemoCommandConfirmed(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
void* data = NULL;
|
|
|
|
s32 size = 0;
|
|
|
|
|
|
|
|
console->showGameMenu = false;
|
2017-10-16 05:03:05 +02:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
if(strcmp(param, DefaultLuaTicPath) == 0)
|
|
|
|
data = getDemoCart(console, tic_script_lua, &size);
|
|
|
|
else if(strcmp(param, DefaultMoonTicPath) == 0)
|
|
|
|
data = getDemoCart(console, tic_script_moon, &size);
|
|
|
|
else if(strcmp(param, DefaultJSTicPath) == 0)
|
|
|
|
data = getDemoCart(console, tic_script_js, &size);
|
|
|
|
|
2017-11-10 17:40:44 +01:00
|
|
|
const char* name = getCartName(param);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-11-27 18:46:32 +01:00
|
|
|
setCartName(console, name);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
loadRom(console->tic, data, size, true);
|
|
|
|
|
|
|
|
studioRomLoaded();
|
|
|
|
|
|
|
|
printBack(console, "\ncart ");
|
|
|
|
printFront(console, console->romName);
|
|
|
|
printBack(console, " loaded!\n");
|
|
|
|
|
|
|
|
SDL_free(data);
|
|
|
|
}
|
|
|
|
|
2017-11-09 18:34:03 +01:00
|
|
|
static void onCartLoaded(Console* console, const char* name)
|
|
|
|
{
|
2017-11-27 18:46:32 +01:00
|
|
|
setCartName(console, name);
|
2017-11-09 18:34:03 +01:00
|
|
|
|
|
|
|
studioRomLoaded();
|
|
|
|
|
|
|
|
printBack(console, "\ncart ");
|
|
|
|
printFront(console, console->romName);
|
|
|
|
printBack(console, " loaded!\nuse ");
|
|
|
|
printFront(console, "RUN");
|
|
|
|
printBack(console, " command to run it\n");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
static bool hasExt(const char* name, const char* ext)
|
|
|
|
{
|
|
|
|
return strcmp(name + strlen(name) - strlen(ext), ext) == 0;
|
|
|
|
}
|
|
|
|
|
2017-11-24 10:09:25 +01:00
|
|
|
#if defined(TIC80_PRO)
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
static bool hasProjectExt(const char* name)
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
2017-11-23 13:26:39 +01:00
|
|
|
return hasExt(name, PROJECT_LUA_EXT) || hasExt(name, PROJECT_MOON_EXT) || hasExt(name, PROJECT_JS_EXT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char* projectComment(const char* name)
|
|
|
|
{
|
|
|
|
return hasExt(name, PROJECT_JS_EXT) ? "//" : "--";
|
2017-11-19 16:41:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void buf2str(const void* data, s32 size, char* ptr, bool flip)
|
|
|
|
{
|
|
|
|
enum {Len = 2};
|
|
|
|
|
|
|
|
for(s32 i = 0; i < size; i++, ptr+=Len)
|
|
|
|
{
|
|
|
|
sprintf(ptr, "%02x", ((u8*)data)[i]);
|
|
|
|
|
|
|
|
if(flip)
|
|
|
|
{
|
|
|
|
char tmp = ptr[0];
|
|
|
|
ptr[0] = ptr[1];
|
|
|
|
ptr[1] = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool bufferEmpty(const u8* data, s32 size)
|
|
|
|
{
|
|
|
|
for(s32 i = 0; i < size; i++)
|
|
|
|
if(*data++)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-11-23 11:19:31 +01:00
|
|
|
static char* saveTextSection(char* ptr, const char* data)
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
|
|
|
if(strlen(data) == 0)
|
|
|
|
return ptr;
|
|
|
|
|
2017-11-23 11:19:31 +01:00
|
|
|
sprintf(ptr, "%s\n", data);
|
2017-11-19 16:41:39 +01:00
|
|
|
ptr += strlen(ptr);
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
static char* saveBinaryBuffer(char* ptr, const char* comment, const void* data, s32 size, s32 row, bool flip)
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
|
|
|
if(bufferEmpty(data, size))
|
|
|
|
return ptr;
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
sprintf(ptr, "%s %03i:", comment, row);
|
2017-11-19 16:41:39 +01:00
|
|
|
ptr += strlen(ptr);
|
|
|
|
|
|
|
|
buf2str(data, size, ptr, flip);
|
|
|
|
ptr += strlen(ptr);
|
|
|
|
|
|
|
|
sprintf(ptr, "\n");
|
|
|
|
ptr += strlen(ptr);
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
static char* saveBinarySection(char* ptr, const char* comment, const char* tag, s32 count, const void* data, s32 size, bool flip)
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
|
|
|
if(bufferEmpty(data, size * count))
|
|
|
|
return ptr;
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
sprintf(ptr, "%s <%s>\n", comment, tag);
|
2017-11-19 16:41:39 +01:00
|
|
|
ptr += strlen(ptr);
|
|
|
|
|
|
|
|
for(s32 i = 0; i < count; i++, data = (u8*)data + size)
|
2017-11-23 13:26:39 +01:00
|
|
|
ptr = saveBinaryBuffer(ptr, comment, data, size, i, flip);
|
2017-11-19 16:41:39 +01:00
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
sprintf(ptr, "%s </%s>\n\n", comment, tag);
|
2017-11-19 16:41:39 +01:00
|
|
|
ptr += strlen(ptr);
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {char* tag; s32 count; s32 offset; s32 size; bool flip;} BinarySection;
|
|
|
|
static const BinarySection BinarySections[] =
|
|
|
|
{
|
2017-12-13 17:54:00 +01:00
|
|
|
{"PALETTE", 1, offsetof(tic_cartridge, bank.palette.data), sizeof(tic_palette), false},
|
2017-12-11 09:59:14 +01:00
|
|
|
{"TILES", TIC_BANK_SPRITES, offsetof(tic_cartridge, bank.tiles), sizeof(tic_tile), true},
|
|
|
|
{"SPRITES", TIC_BANK_SPRITES, offsetof(tic_cartridge, bank.sprites), sizeof(tic_tile), true},
|
|
|
|
{"MAP", TIC_MAP_HEIGHT, offsetof(tic_cartridge, bank.map), TIC_MAP_WIDTH, true},
|
|
|
|
{"WAVES", ENVELOPES_COUNT, offsetof(tic_cartridge, bank.sfx.waveform.envelopes), sizeof(tic_waveform), true},
|
|
|
|
{"SFX", SFX_COUNT, offsetof(tic_cartridge, bank.sfx.data), sizeof(tic_sound_effect), true},
|
|
|
|
{"PATTERNS", MUSIC_PATTERNS, offsetof(tic_cartridge, bank.music.patterns), sizeof(tic_track_pattern), true},
|
|
|
|
{"TRACKS", MUSIC_TRACKS, offsetof(tic_cartridge, bank.music.tracks), sizeof(tic_track), true},
|
2017-11-19 16:41:39 +01:00
|
|
|
};
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
static s32 saveProject(Console* console, void* buffer, const char* comment)
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
|
|
|
tic_mem* tic = console->tic;
|
|
|
|
|
|
|
|
char* stream = buffer;
|
2017-12-13 17:54:00 +01:00
|
|
|
char* ptr = saveTextSection(stream, tic->cart.bank.code.data);
|
2017-11-19 16:41:39 +01:00
|
|
|
|
|
|
|
for(s32 i = 0; i < COUNT_OF(BinarySections); i++)
|
|
|
|
{
|
|
|
|
const BinarySection* section = &BinarySections[i];
|
2017-11-23 13:26:39 +01:00
|
|
|
ptr = saveBinarySection(ptr, comment, section->tag, section->count, (u8*)&tic->cart + section->offset, section->size, section->flip);
|
2017-11-19 16:41:39 +01:00
|
|
|
}
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
saveBinarySection(ptr, comment, "COVER", 1, &tic->cart.cover, tic->cart.cover.size + sizeof(s32), true);
|
2017-11-19 16:41:39 +01:00
|
|
|
|
|
|
|
return strlen(stream);
|
|
|
|
}
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
static bool loadTextSection(const char* project, const char* comment, void* dst, s32 size)
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
2017-11-22 08:20:12 +01:00
|
|
|
bool done = false;
|
2017-11-19 16:41:39 +01:00
|
|
|
|
2017-11-23 11:19:31 +01:00
|
|
|
const char* start = project;
|
|
|
|
const char* end = project + strlen(project);
|
|
|
|
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
2017-11-23 11:19:31 +01:00
|
|
|
char tagbuf[64];
|
2017-11-19 16:41:39 +01:00
|
|
|
|
2017-11-23 11:19:31 +01:00
|
|
|
for(s32 i = 0; i < COUNT_OF(BinarySections); i++)
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
2017-11-23 13:26:39 +01:00
|
|
|
sprintf(tagbuf, "\n%s <%s>\n", comment, BinarySections[i].tag);
|
2017-11-19 16:41:39 +01:00
|
|
|
|
2017-11-23 11:19:31 +01:00
|
|
|
const char* ptr = SDL_strstr(project, tagbuf);
|
|
|
|
|
|
|
|
if(ptr && ptr < end)
|
|
|
|
end = ptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(end > start)
|
|
|
|
{
|
|
|
|
SDL_memcpy(dst, start, SDL_min(size, end - start));
|
|
|
|
done = true;
|
2017-11-19 16:41:39 +01:00
|
|
|
}
|
2017-11-22 08:20:12 +01:00
|
|
|
|
|
|
|
return done;
|
2017-11-19 16:41:39 +01:00
|
|
|
}
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
static bool loadBinarySection(const char* project, const char* comment, const char* tag, s32 count, void* dst, s32 size, bool flip)
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
|
|
|
char tagbuf[64];
|
2017-11-23 13:26:39 +01:00
|
|
|
sprintf(tagbuf, "%s <%s>\n", comment, tag);
|
2017-11-19 16:41:39 +01:00
|
|
|
|
|
|
|
const char* start = SDL_strstr(project, tagbuf);
|
2017-11-22 08:20:12 +01:00
|
|
|
bool done = false;
|
2017-11-19 16:41:39 +01:00
|
|
|
|
|
|
|
if(start)
|
|
|
|
{
|
|
|
|
start += strlen(tagbuf);
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
sprintf(tagbuf, "\n%s </%s>", comment, tag);
|
2017-11-19 16:41:39 +01:00
|
|
|
const char* end = SDL_strstr(start, tagbuf);
|
|
|
|
|
|
|
|
if(end > start)
|
|
|
|
{
|
|
|
|
const char* ptr = start;
|
|
|
|
|
|
|
|
if(size > 0)
|
|
|
|
{
|
|
|
|
while(ptr < end)
|
|
|
|
{
|
|
|
|
static char lineStr[] = "999";
|
|
|
|
memcpy(lineStr, ptr + sizeof("-- ") - 1, sizeof lineStr - 1);
|
|
|
|
|
|
|
|
s32 index = SDL_atoi(lineStr);
|
|
|
|
|
|
|
|
if(index < count)
|
|
|
|
{
|
|
|
|
ptr += sizeof("-- 999:") - 1;
|
|
|
|
str2buf(ptr, size*2, (u8*)dst + size*index, flip);
|
|
|
|
ptr += size*2 + 1;
|
|
|
|
}
|
2017-11-30 14:50:21 +01:00
|
|
|
else break;
|
2017-11-19 16:41:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ptr += sizeof("-- 999:") - 1;
|
|
|
|
str2buf(ptr, end - ptr, (u8*)dst, flip);
|
|
|
|
}
|
2017-11-22 08:20:12 +01:00
|
|
|
|
|
|
|
done = true;
|
2017-11-19 16:41:39 +01:00
|
|
|
}
|
|
|
|
}
|
2017-11-22 08:20:12 +01:00
|
|
|
|
|
|
|
return done;
|
2017-11-19 16:41:39 +01:00
|
|
|
}
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
static bool loadProject(Console* console, const char* name, const char* data, s32 size, tic_cartridge* dst)
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
|
|
|
tic_mem* tic = console->tic;
|
|
|
|
|
|
|
|
char* project = (char*)SDL_malloc(size+1);
|
|
|
|
|
|
|
|
bool done = false;
|
|
|
|
|
|
|
|
if(project)
|
|
|
|
{
|
|
|
|
SDL_memcpy(project, data, size);
|
|
|
|
project[size] = '\0';
|
|
|
|
|
|
|
|
// remove all the '\r' chars
|
|
|
|
{
|
|
|
|
char *s, *d;
|
|
|
|
for(s = d = project; (*d = *s); d += (*s++ != '\r'));
|
|
|
|
}
|
|
|
|
|
|
|
|
tic_cartridge* cart = (tic_cartridge*)SDL_malloc(sizeof(tic_cartridge));
|
|
|
|
|
|
|
|
if(cart)
|
|
|
|
{
|
|
|
|
SDL_memset(cart, 0, sizeof(tic_cartridge));
|
2017-12-13 17:54:00 +01:00
|
|
|
SDL_memcpy(&cart->bank.palette, &tic->config.palette.data, sizeof(tic_palette));
|
2017-11-19 16:41:39 +01:00
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
const char* comment = projectComment(name);
|
|
|
|
|
2017-12-13 17:54:00 +01:00
|
|
|
if(loadTextSection(project, comment, cart->bank.code.data, sizeof(tic_code)))
|
2017-11-22 08:20:12 +01:00
|
|
|
done = true;
|
2017-11-19 16:41:39 +01:00
|
|
|
|
|
|
|
for(s32 i = 0; i < COUNT_OF(BinarySections); i++)
|
|
|
|
{
|
|
|
|
const BinarySection* section = &BinarySections[i];
|
2017-11-23 13:26:39 +01:00
|
|
|
if(loadBinarySection(project, comment, section->tag, section->count, (u8*)cart + section->offset, section->size, section->flip))
|
2017-11-22 08:20:12 +01:00
|
|
|
done = true;
|
2017-11-19 16:41:39 +01:00
|
|
|
}
|
|
|
|
|
2017-11-23 13:26:39 +01:00
|
|
|
if(loadBinarySection(project, comment, "COVER", 1, &cart->cover, -1, true))
|
2017-11-22 08:20:12 +01:00
|
|
|
done = true;
|
2017-11-19 16:41:39 +01:00
|
|
|
|
|
|
|
SDL_memcpy(dst, cart, sizeof(tic_cartridge));
|
|
|
|
|
|
|
|
SDL_free(cart);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_free(project);
|
|
|
|
}
|
|
|
|
|
|
|
|
return done;
|
|
|
|
}
|
|
|
|
|
2017-11-21 17:47:36 +01:00
|
|
|
static void updateProject(Console* console)
|
|
|
|
{
|
|
|
|
tic_mem* tic = console->tic;
|
|
|
|
|
2017-11-23 21:19:53 +01:00
|
|
|
if(strlen(console->romName) && hasProjectExt(console->romName))
|
2017-11-21 17:47:36 +01:00
|
|
|
{
|
|
|
|
s32 size = 0;
|
|
|
|
void* data = fsLoadFile(console->fs, console->romName, &size);
|
|
|
|
|
|
|
|
if(data)
|
|
|
|
{
|
2017-11-22 08:20:12 +01:00
|
|
|
tic_cartridge* cart = SDL_malloc(sizeof(tic_cartridge));
|
|
|
|
|
|
|
|
if(cart)
|
|
|
|
{
|
2017-11-23 13:26:39 +01:00
|
|
|
if(loadProject(console, console->romName, data, size, cart))
|
2017-11-22 08:20:12 +01:00
|
|
|
{
|
|
|
|
SDL_memcpy(&tic->cart, cart, sizeof(tic_cartridge));
|
|
|
|
|
|
|
|
studioRomLoaded();
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_free(cart);
|
|
|
|
}
|
2017-11-21 17:47:36 +01:00
|
|
|
SDL_free(data);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-19 16:41:39 +01:00
|
|
|
#endif
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
static void onConsoleLoadCommandConfirmed(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(onConsoleLoadSectionCommand(console, param)) return;
|
|
|
|
|
|
|
|
if(param)
|
|
|
|
{
|
|
|
|
s32 size = 0;
|
2017-11-10 17:40:44 +01:00
|
|
|
const char* name = getCartName(param);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
void* data = strcmp(name, CONFIG_TIC_PATH) == 0
|
2017-09-26 08:59:34 +02:00
|
|
|
? fsLoadRootFile(console->fs, name, &size)
|
|
|
|
: fsLoadFile(console->fs, name, &size);
|
|
|
|
|
|
|
|
if(data)
|
|
|
|
{
|
|
|
|
console->showGameMenu = fsIsInPublicDir(console->fs);
|
|
|
|
|
|
|
|
loadRom(console->tic, data, size, true);
|
|
|
|
|
2017-11-09 18:34:03 +01:00
|
|
|
onCartLoaded(console, name);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
SDL_free(data);
|
|
|
|
}
|
2017-11-19 16:41:39 +01:00
|
|
|
else
|
2017-11-09 18:34:03 +01:00
|
|
|
{
|
2017-11-19 16:41:39 +01:00
|
|
|
#if defined(TIC80_PRO)
|
2017-11-23 13:26:39 +01:00
|
|
|
const char* name = getName(param, PROJECT_LUA_EXT);
|
|
|
|
|
|
|
|
if(!fsExistsFile(console->fs, name))
|
|
|
|
name = getName(param, PROJECT_MOON_EXT);
|
|
|
|
|
|
|
|
if(!fsExistsFile(console->fs, name))
|
|
|
|
name = getName(param, PROJECT_JS_EXT);
|
2017-11-19 16:41:39 +01:00
|
|
|
|
|
|
|
void* data = fsLoadFile(console->fs, name, &size);
|
|
|
|
|
|
|
|
if(data)
|
|
|
|
{
|
2017-11-23 13:26:39 +01:00
|
|
|
loadProject(console, name, data, size, &console->tic->cart);
|
2017-11-19 16:41:39 +01:00
|
|
|
onCartLoaded(console, name);
|
|
|
|
|
|
|
|
SDL_free(data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printBack(console, "\ncart loading error");
|
|
|
|
}
|
|
|
|
#else
|
2017-11-09 18:34:03 +01:00
|
|
|
printBack(console, "\ncart loading error");
|
2017-11-19 16:41:39 +01:00
|
|
|
#endif
|
2017-11-09 18:34:03 +01:00
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
else printBack(console, "\ncart name is missing");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef void(*ConfirmCallback)(Console* console, const char* param);
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
Console* console;
|
|
|
|
char* param;
|
|
|
|
ConfirmCallback callback;
|
|
|
|
|
|
|
|
} CommandConfirmData;
|
|
|
|
|
|
|
|
static void onConfirm(bool yes, void* data)
|
|
|
|
{
|
|
|
|
CommandConfirmData* confirmData = (CommandConfirmData*)data;
|
|
|
|
|
|
|
|
if(yes)
|
|
|
|
{
|
|
|
|
confirmData->callback(confirmData->console, confirmData->param);
|
|
|
|
}
|
|
|
|
else commandDone(confirmData->console);
|
|
|
|
|
|
|
|
if(confirmData->param)
|
|
|
|
SDL_free(confirmData->param);
|
|
|
|
|
|
|
|
SDL_free(confirmData);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void confirmCommand(Console* console, const char** text, s32 rows, const char* param, ConfirmCallback callback)
|
|
|
|
{
|
|
|
|
CommandConfirmData* data = SDL_malloc(sizeof(CommandConfirmData));
|
|
|
|
data->console = console;
|
|
|
|
data->param = param ? SDL_strdup(param) : NULL;
|
|
|
|
data->callback = callback;
|
|
|
|
|
|
|
|
showDialog(text, rows, onConfirm, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleLoadDemoCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(studioCartChanged())
|
|
|
|
{
|
2017-10-16 05:03:05 +02:00
|
|
|
static const char* Rows[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
"YOU HAVE",
|
|
|
|
"UNSAVED CHANGES",
|
|
|
|
"",
|
|
|
|
"DO YOU REALLY WANT",
|
|
|
|
"TO LOAD CART?",
|
|
|
|
};
|
|
|
|
|
|
|
|
confirmCommand(console, Rows, COUNT_OF(Rows), param, onConsoleLoadDemoCommandConfirmed);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
onConsoleLoadDemoCommandConfirmed(console, param);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleLoadCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(studioCartChanged())
|
|
|
|
{
|
2017-10-16 05:03:05 +02:00
|
|
|
static const char* Rows[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
"YOU HAVE",
|
|
|
|
"UNSAVED CHANGES",
|
|
|
|
"",
|
|
|
|
"DO YOU REALLY WANT",
|
|
|
|
"TO LOAD CART?",
|
|
|
|
};
|
|
|
|
|
|
|
|
confirmCommand(console, Rows, COUNT_OF(Rows), param, onConsoleLoadCommandConfirmed);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
onConsoleLoadCommandConfirmed(console, param);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void loadDemo(Console* console, tic_script_lang script)
|
|
|
|
{
|
|
|
|
s32 size = 0;
|
|
|
|
u8* data = getDemoCart(console, script, &size);
|
|
|
|
|
|
|
|
if(data)
|
|
|
|
{
|
|
|
|
loadRom(console->tic, data, size, false);
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
SDL_free(data);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SDL_memset(console->romName, 0, sizeof console->romName);
|
|
|
|
|
|
|
|
studioRomLoaded();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleNewCommandConfirmed(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(param && strlen(param))
|
|
|
|
{
|
|
|
|
if(strcmp(param, "lua") == 0)
|
|
|
|
loadDemo(console, tic_script_lua);
|
|
|
|
else if(strcmp(param, "moon") == 0 || strcmp(param, "moonscript") == 0)
|
|
|
|
loadDemo(console, tic_script_moon);
|
|
|
|
else if(strcmp(param, "js") == 0 || strcmp(param, "javascript") == 0)
|
|
|
|
loadDemo(console, tic_script_js);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printError(console, "\nunknown parameter: ");
|
|
|
|
printError(console, param);
|
|
|
|
commandDone(console);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else loadDemo(console, tic_script_lua);
|
|
|
|
|
|
|
|
printBack(console, "\nnew cart is created");
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleNewCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(studioCartChanged())
|
|
|
|
{
|
2017-10-16 05:03:05 +02:00
|
|
|
static const char* Rows[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
"YOU HAVE",
|
|
|
|
"UNSAVED CHANGES",
|
|
|
|
"",
|
|
|
|
"DO YOU REALLY WANT",
|
|
|
|
"TO CREATE NEW CART?",
|
|
|
|
};
|
|
|
|
|
|
|
|
confirmCommand(console, Rows, COUNT_OF(Rows), param, onConsoleNewCommandConfirmed);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
onConsoleNewCommandConfirmed(console, param);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
s32 count;
|
|
|
|
Console* console;
|
|
|
|
} PrintFileNameData;
|
|
|
|
|
|
|
|
static bool printFilename(const char* name, const char* info, s32 id, void* data, bool dir)
|
|
|
|
{
|
2017-11-09 18:34:03 +01:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
PrintFileNameData* printData = data;
|
|
|
|
Console* console = printData->console;
|
|
|
|
|
|
|
|
printLine(console);
|
|
|
|
|
|
|
|
if(dir)
|
|
|
|
{
|
2017-11-09 18:34:03 +01:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
printBack(console, "[");
|
|
|
|
printBack(console, name);
|
|
|
|
printBack(console, "]");
|
|
|
|
}
|
|
|
|
else printFront(console, name);
|
|
|
|
|
|
|
|
if(!dir)
|
|
|
|
printData->count++;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleChangeDirectory(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(param && strlen(param))
|
|
|
|
{
|
|
|
|
if(strcmp(param, "/") == 0)
|
|
|
|
{
|
|
|
|
fsHomeDir(console->fs);
|
|
|
|
}
|
|
|
|
else if(strcmp(param, "..") == 0)
|
|
|
|
{
|
|
|
|
fsDirBack(console->fs);
|
|
|
|
}
|
|
|
|
else if(fsIsDir(console->fs, param))
|
|
|
|
{
|
|
|
|
fsChangeDir(console->fs, param);
|
|
|
|
}
|
|
|
|
else printBack(console, "\ndir doesn't exist");
|
|
|
|
}
|
|
|
|
else printBack(console, "\ninvalid dir name");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleMakeDirectory(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(param && strlen(param))
|
|
|
|
fsMakeDir(console->fs, param);
|
|
|
|
else printBack(console, "\ninvalid dir name");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleDirCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
PrintFileNameData data = {0, console};
|
|
|
|
|
|
|
|
printLine(console);
|
|
|
|
|
|
|
|
fsEnumFiles(console->fs, printFilename, &data);
|
|
|
|
|
|
|
|
if(data.count == 0)
|
|
|
|
{
|
|
|
|
printBack(console, "\n\nuse ");
|
|
|
|
printFront(console, "ADD");
|
|
|
|
printBack(console, " or ");
|
|
|
|
printFront(console, "DEMO");
|
|
|
|
printBack(console, " command to add carts");
|
|
|
|
}
|
|
|
|
|
|
|
|
printLine(console);
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CAN_EXPORT
|
|
|
|
|
|
|
|
static void onConsoleFolderCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
fsOpenWorkingFolder(console->fs);
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void onConsoleClsCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
memset(console->buffer, 0, CONSOLE_BUFFER_SIZE);
|
|
|
|
memset(console->colorBuffer, TIC_COLOR_BG, CONSOLE_BUFFER_SIZE);
|
|
|
|
console->scroll.pos = 0;
|
|
|
|
console->cursor.x = console->cursor.y = 0;
|
|
|
|
|
|
|
|
commandDoneLine(console, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void installDemoCart(FileSystem* fs, const char* name, const void* cart, s32 size)
|
|
|
|
{
|
|
|
|
u8* data = NULL;
|
|
|
|
s32 dataSize = unzip(&data, cart, size);
|
|
|
|
fsSaveFile(fs, name, data, dataSize, true);
|
|
|
|
SDL_free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleInstallDemosCommand(Console* console, const char* param)
|
|
|
|
{
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 DemoFire[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/fire.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 DemoP3D[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/p3d.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 DemoSFX[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/sfx.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 DemoPalette[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/palette.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 DemoFont[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/font.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 DemoMusic[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/music.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 GameQuest[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/quest.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const u8 GameTetris[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#include "../bin/assets/tetris.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-11-20 10:09:21 +01:00
|
|
|
static const u8 Benchmark[] =
|
|
|
|
{
|
|
|
|
#include "../bin/assets/benchmark.tic.dat"
|
|
|
|
};
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
FileSystem* fs = console->fs;
|
|
|
|
|
|
|
|
static const struct {const char* name; const u8* data; s32 size;} Demos[] =
|
|
|
|
{
|
2017-11-20 10:09:21 +01:00
|
|
|
{"fire.tic", DemoFire, sizeof DemoFire},
|
|
|
|
{"font.tic", DemoFont, sizeof DemoFont},
|
|
|
|
{"music.tic", DemoMusic, sizeof DemoMusic},
|
|
|
|
{"p3d.tic", DemoP3D, sizeof DemoP3D},
|
|
|
|
{"palette.tic", DemoPalette, sizeof DemoPalette},
|
|
|
|
{"quest.tic", GameQuest, sizeof GameQuest},
|
|
|
|
{"sfx.tic", DemoSFX, sizeof DemoSFX},
|
|
|
|
{"tetris.tic", GameTetris, sizeof GameTetris},
|
|
|
|
{"benchmark.tic", Benchmark, sizeof Benchmark},
|
2017-09-26 08:59:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
printBack(console, "\nadded carts:\n\n");
|
|
|
|
|
|
|
|
for(s32 i = 0; i < COUNT_OF(Demos); i++)
|
|
|
|
{
|
|
|
|
installDemoCart(fs, Demos[i].name, Demos[i].data, Demos[i].size);
|
|
|
|
printFront(console, Demos[i].name);
|
|
|
|
printFront(console, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleSurfCommand(Console* console, const char* param)
|
|
|
|
{
|
2017-09-28 16:20:27 +02:00
|
|
|
gotoSurf();
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
2017-11-04 00:11:45 +01:00
|
|
|
static void onConsoleCodeCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
gotoCode();
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
static void onConsoleKeymapCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
setStudioMode(TIC_KEYMAP_MODE);
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
2017-10-27 02:43:20 +02:00
|
|
|
static void onConsoleVersionCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
printBack(console, "\n");
|
2017-10-31 00:25:57 +01:00
|
|
|
consolePrint(console, TIC_VERSION_LABEL, CONSOLE_BACK_TEXT_COLOR);
|
2017-10-27 02:43:20 +02:00
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
static void onConsoleConfigCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(param == NULL)
|
|
|
|
{
|
|
|
|
onConsoleLoadCommand(console, CONFIG_TIC_PATH);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if(strcmp(param, "reset") == 0)
|
|
|
|
{
|
|
|
|
console->config->reset(console->config);
|
|
|
|
printBack(console, "\nconfiguration reset :)");
|
|
|
|
}
|
|
|
|
else if(strcmp(param, "default") == 0 || strcmp(param, "default lua") == 0)
|
|
|
|
{
|
|
|
|
onConsoleLoadDemoCommand(console, DefaultLuaTicPath);
|
|
|
|
}
|
|
|
|
else if(strcmp(param, "default moon") == 0 || strcmp(param, "default moonscript") == 0)
|
|
|
|
{
|
|
|
|
onConsoleLoadDemoCommand(console, DefaultMoonTicPath);
|
|
|
|
}
|
|
|
|
else if(strcmp(param, "default js") == 0)
|
|
|
|
{
|
|
|
|
onConsoleLoadDemoCommand(console, DefaultJSTicPath);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printError(console, "\nunknown parameter: ");
|
|
|
|
printError(console, param);
|
|
|
|
}
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onFileDownloaded(GetResult result, void* data)
|
|
|
|
{
|
|
|
|
Console* console = (Console*)data;
|
|
|
|
|
|
|
|
if(result == FS_FILE_NOT_DOWNLOADED)
|
|
|
|
printBack(console, "\nfile not downloaded :|");
|
|
|
|
else if (result == FS_FILE_DOWNLOADED)
|
|
|
|
printBack(console, "\nfile downloaded :)");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onImportCover(const char* name, const void* buffer, size_t size, void* data)
|
|
|
|
{
|
|
|
|
Console* console = (Console*)data;
|
|
|
|
|
|
|
|
if(name)
|
|
|
|
{
|
|
|
|
static const char GifExt[] = ".gif";
|
|
|
|
|
|
|
|
const char* pos = strstr(name, GifExt);
|
|
|
|
|
|
|
|
if(pos && strcmp(pos, GifExt) == 0)
|
|
|
|
{
|
|
|
|
gif_image* image = gif_read_data(buffer, (s32)size);
|
|
|
|
|
|
|
|
if (image)
|
|
|
|
{
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Width = TIC80_WIDTH,
|
|
|
|
Height = TIC80_HEIGHT,
|
|
|
|
Size = Width * Height,
|
|
|
|
};
|
|
|
|
|
|
|
|
if(image->width == Width && image->height == Height)
|
|
|
|
{
|
|
|
|
if(size <= sizeof console->tic->cart.cover.data)
|
|
|
|
{
|
|
|
|
console->tic->cart.cover.size = size;
|
|
|
|
SDL_memcpy(console->tic->cart.cover.data, buffer, size);
|
|
|
|
|
|
|
|
printLine(console);
|
|
|
|
printBack(console, name);
|
2017-10-16 05:03:05 +02:00
|
|
|
printBack(console, " successfully imported");
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
else printError(console, "\ncover image too big :(");
|
|
|
|
}
|
|
|
|
else printError(console, "\ncover image must be 240x136 :(");
|
|
|
|
|
|
|
|
gif_close(image);
|
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
else printError(console, "\nfile importing error :(");
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
else printBack(console, "\nonly .gif files can be imported :|");
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
else printBack(console, "\nfile not imported :|");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onImportSprites(const char* name, const void* buffer, size_t size, void* data)
|
|
|
|
{
|
|
|
|
Console* console = (Console*)data;
|
|
|
|
|
|
|
|
if(name)
|
|
|
|
{
|
|
|
|
static const char GifExt[] = ".gif";
|
|
|
|
|
|
|
|
const char* pos = strstr(name, GifExt);
|
|
|
|
|
|
|
|
if(pos && strcmp(pos, GifExt) == 0)
|
|
|
|
{
|
|
|
|
gif_image* image = gif_read_data(buffer, (s32)size);
|
|
|
|
|
|
|
|
if (image)
|
|
|
|
{
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Width = TIC_SPRITESHEET_SIZE,
|
|
|
|
Height = TIC_SPRITESHEET_SIZE*2,
|
|
|
|
};
|
|
|
|
|
|
|
|
s32 w = SDL_min(Width, image->width);
|
|
|
|
s32 h = SDL_min(Height, image->height);
|
|
|
|
|
|
|
|
for (s32 y = 0; y < h; y++)
|
|
|
|
for (s32 x = 0; x < w; x++)
|
|
|
|
{
|
|
|
|
u8 src = image->buffer[x + y * image->width];
|
|
|
|
const gif_color* c = &image->palette[src];
|
|
|
|
tic_rgb rgb = {c->r, c->g, c->b};
|
2017-12-13 17:54:00 +01:00
|
|
|
u8 color = tic_tool_find_closest_color(console->tic->cart.bank.palette.colors, &rgb);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-12-11 09:44:46 +01:00
|
|
|
setSpritePixel(console->tic->cart.bank.tiles.data, x, y, color);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
gif_close(image);
|
|
|
|
|
|
|
|
printLine(console);
|
|
|
|
printBack(console, name);
|
|
|
|
printBack(console, " successfully imported");
|
|
|
|
}
|
|
|
|
else printError(console, "\nfile importing error :(");
|
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
else printBack(console, "\nonly .gif files can be imported :|");
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
else printBack(console, "\nfile not imported :|");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
2017-11-28 07:16:52 +01:00
|
|
|
static void injectMap(Console* console, const void* buffer, s32 size)
|
|
|
|
{
|
|
|
|
enum {Size = sizeof(tic_map)};
|
|
|
|
|
2017-12-11 09:44:46 +01:00
|
|
|
SDL_memset(&console->tic->cart.bank.map, 0, Size);
|
|
|
|
SDL_memcpy(&console->tic->cart.bank.map, buffer, SDL_min(size, Size));
|
2017-11-28 07:16:52 +01:00
|
|
|
}
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
static void onImportMap(const char* name, const void* buffer, size_t size, void* data)
|
|
|
|
{
|
|
|
|
Console* console = (Console*)data;
|
|
|
|
|
2017-11-28 07:16:52 +01:00
|
|
|
if(name && buffer && size <= sizeof(tic_map))
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-11-28 07:16:52 +01:00
|
|
|
injectMap(console, buffer, size);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
printLine(console);
|
|
|
|
printBack(console, "map successfully imported");
|
|
|
|
}
|
|
|
|
else printBack(console, "\nfile not imported :|");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleImportCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(param == NULL)
|
|
|
|
{
|
|
|
|
printBack(console, "\nusage: import sprites|cover|map");
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
else if(param && strcmp(param, "sprites") == 0)
|
|
|
|
fsOpenFileData(onImportSprites, console);
|
|
|
|
else if(param && strcmp(param, "map") == 0)
|
|
|
|
fsOpenFileData(onImportMap, console);
|
|
|
|
else if(param && strcmp(param, "cover") == 0)
|
|
|
|
fsOpenFileData(onImportCover, console);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printError(console, "\nunknown parameter: ");
|
|
|
|
printError(console, param);
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onSpritesExported(GetResult result, void* data)
|
|
|
|
{
|
|
|
|
Console* console = (Console*)data;
|
|
|
|
|
|
|
|
if(result == FS_FILE_NOT_DOWNLOADED)
|
|
|
|
printBack(console, "\nsprites not exported :|");
|
|
|
|
else if (result == FS_FILE_DOWNLOADED)
|
|
|
|
printBack(console, "\nsprites successfully exported :)");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onCoverExported(GetResult result, void* data)
|
|
|
|
{
|
|
|
|
Console* console = (Console*)data;
|
|
|
|
|
|
|
|
if(result == FS_FILE_NOT_DOWNLOADED)
|
|
|
|
printBack(console, "\ncover image not exported :|");
|
|
|
|
else if (result == FS_FILE_DOWNLOADED)
|
|
|
|
printBack(console, "\ncover image successfully exported :)");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void exportCover(Console* console)
|
|
|
|
{
|
|
|
|
tic_cover_image* cover = &console->tic->cart.cover;
|
|
|
|
|
|
|
|
if(cover->size)
|
|
|
|
{
|
|
|
|
void* data = SDL_malloc(cover->size);
|
|
|
|
memcpy(data, cover->data, cover->size);
|
|
|
|
fsGetFileData(onCoverExported, "cover.gif", data, cover->size, DEFAULT_CHMOD, console);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printBack(console, "\ncover image is empty, run game and\npress [F7] to assign cover image");
|
2017-10-16 05:03:05 +02:00
|
|
|
commandDone(console);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void exportSprites(Console* console)
|
|
|
|
{
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Width = TIC_SPRITESHEET_SIZE,
|
|
|
|
Height = TIC_SPRITESHEET_SIZE*2,
|
|
|
|
};
|
|
|
|
|
2017-12-07 10:01:17 +01:00
|
|
|
enum{ Size = Width * Height * sizeof(gif_color)};
|
|
|
|
u8* buffer = (u8*)SDL_malloc(Size);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
if(buffer)
|
|
|
|
{
|
|
|
|
u8* data = (u8*)SDL_malloc(Width * Height);
|
|
|
|
|
|
|
|
if(data)
|
|
|
|
{
|
|
|
|
for (s32 y = 0; y < Height; y++)
|
|
|
|
for (s32 x = 0; x < Width; x++)
|
2017-12-11 09:44:46 +01:00
|
|
|
data[x + y * Width] = getSpritePixel(console->tic->cart.bank.tiles.data, x, y);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-12-07 10:01:17 +01:00
|
|
|
s32 size = 0;
|
2017-09-26 08:59:34 +02:00
|
|
|
if((size = writeGifData(console->tic, buffer, data, Width, Height)))
|
|
|
|
{
|
|
|
|
// buffer will be freed inside fsGetFileData
|
|
|
|
fsGetFileData(onSpritesExported, "sprites.gif", buffer, size, DEFAULT_CHMOD, console);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printError(console, "\nsprite export error :(");
|
|
|
|
commandDone(console);
|
|
|
|
SDL_free(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_free(data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onMapExported(GetResult result, void* data)
|
|
|
|
{
|
|
|
|
Console* console = (Console*)data;
|
|
|
|
|
|
|
|
if(result == FS_FILE_NOT_DOWNLOADED)
|
|
|
|
printBack(console, "\nmap not exported :|");
|
|
|
|
else if (result == FS_FILE_DOWNLOADED)
|
|
|
|
printBack(console, "\nmap successfully exported :)");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void exportMap(Console* console)
|
|
|
|
{
|
|
|
|
enum{Size = sizeof(tic_map)};
|
|
|
|
|
|
|
|
void* buffer = SDL_malloc(Size);
|
|
|
|
|
|
|
|
if(buffer)
|
|
|
|
{
|
2017-12-11 09:44:46 +01:00
|
|
|
SDL_memcpy(buffer, console->tic->cart.bank.map.data, Size);
|
2017-09-26 08:59:34 +02:00
|
|
|
fsGetFileData(onMapExported, "world.map", buffer, Size, DEFAULT_CHMOD, console);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-20 07:14:37 +01:00
|
|
|
#if defined(__EMSCRIPTEN__)
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
static void onConsoleExportCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(param == NULL || (param && strcmp(param, "native") == 0) || (param && strcmp(param, "html") == 0))
|
|
|
|
{
|
|
|
|
printBack(console, "\nweb/arm version doesn't support html or\nnative export");
|
|
|
|
printBack(console, "\nusage: export sprites|cover|map");
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
else if(param && strcmp(param, "sprites") == 0)
|
|
|
|
exportSprites(console);
|
|
|
|
else if(param && strcmp(param, "map") == 0)
|
|
|
|
exportMap(console);
|
|
|
|
else if(param && strcmp(param, "cover") == 0)
|
|
|
|
exportCover(console);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printError(console, "\nunknown parameter: ");
|
|
|
|
printError(console, param);
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#if !defined(__ANDROID__) && !defined(__MACOSX__) && !defined(__LINUX__)
|
|
|
|
|
|
|
|
static void *memmem(const void* haystack, size_t hlen, const void* needle, size_t nlen)
|
|
|
|
{
|
|
|
|
const u8* p = haystack;
|
|
|
|
size_t plen = hlen;
|
|
|
|
|
|
|
|
if(!nlen) return NULL;
|
|
|
|
|
|
|
|
s32 needle_first = *(u8*)needle;
|
|
|
|
|
|
|
|
while (plen >= nlen && (p = memchr(p, needle_first, plen - nlen + 1)))
|
|
|
|
{
|
|
|
|
if (!memcmp(p, needle, nlen))
|
|
|
|
return (void *)p;
|
|
|
|
|
|
|
|
p++;
|
|
|
|
plen = hlen - (p - (const u8*)haystack);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
Console* console;
|
|
|
|
const char* cartName;
|
|
|
|
} AppFileReadParam;
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
typedef struct
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
u8* data;
|
|
|
|
size_t size;
|
|
|
|
} MemoryBuffer;
|
|
|
|
|
|
|
|
static void writeMemoryData(MemoryBuffer* memory, const u8* src, size_t size)
|
|
|
|
{
|
|
|
|
memcpy(memory->data + memory->size, src, size);
|
|
|
|
memory->size += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void writeMemoryString(MemoryBuffer* memory, const char* str)
|
|
|
|
{
|
|
|
|
size_t size = strlen(str);
|
|
|
|
memcpy(memory->data + memory->size, str, size);
|
|
|
|
memory->size += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleExportHtmlCommand(Console* console, const char* name)
|
|
|
|
{
|
2017-11-08 12:07:23 +01:00
|
|
|
tic_mem* tic = console->tic;
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
char cartName[FILENAME_MAX];
|
|
|
|
strcpy(cartName, name);
|
|
|
|
|
|
|
|
{
|
|
|
|
static const char HtmlExt[] = ".html";
|
|
|
|
const char* pos = NULL;
|
|
|
|
|
|
|
|
if((pos = strstr(name, HtmlExt)) && strcmp(pos, HtmlExt) == 0);
|
|
|
|
else strcat(cartName, HtmlExt);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern const u8 EmbedIndexZip[];
|
|
|
|
extern const s32 EmbedIndexZipSize;
|
|
|
|
extern const u8 EmbedTicJsZip[];
|
|
|
|
extern const s32 EmbedTicJsZipSize;
|
|
|
|
|
|
|
|
static const char Placeholder[] = "<script async type=\"text/javascript\" src=\"tic.js\"></script>";
|
|
|
|
|
|
|
|
u8* EmbedIndex = NULL;
|
|
|
|
u32 EmbedIndexSize = unzip(&EmbedIndex, EmbedIndexZip, EmbedIndexZipSize);
|
|
|
|
|
|
|
|
u8* EmbedTicJs = NULL;
|
|
|
|
u32 EmbedTicJsSize = unzip(&EmbedTicJs, EmbedTicJsZip, EmbedTicJsZipSize);
|
|
|
|
|
|
|
|
u8* ptr = memmem(EmbedIndex, EmbedIndexSize, Placeholder, sizeof(Placeholder)-1);
|
|
|
|
|
|
|
|
if(ptr)
|
|
|
|
{
|
|
|
|
MemoryBuffer output = {(u8*)SDL_malloc(EmbedTicJsSize * 2), 0};
|
|
|
|
|
|
|
|
if(output.data)
|
|
|
|
{
|
|
|
|
writeMemoryData(&output, EmbedIndex, ptr - EmbedIndex);
|
|
|
|
writeMemoryString(&output, "<script type='text/javascript'>\n");
|
|
|
|
|
|
|
|
u8* buffer = (u8*)SDL_malloc(sizeof(tic_cartridge));
|
2017-10-16 05:03:05 +02:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
if(buffer)
|
|
|
|
{
|
|
|
|
writeMemoryString(&output, "var cartridge = [");
|
|
|
|
|
2017-11-21 15:31:01 +01:00
|
|
|
s32 size = tic->api.save(&tic->cart, buffer);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-11-08 12:07:23 +01:00
|
|
|
if(size)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-11-08 12:07:23 +01:00
|
|
|
// zip buffer
|
|
|
|
{
|
|
|
|
unsigned long outSize = sizeof(tic_cartridge);
|
|
|
|
u8* output = (u8*)SDL_malloc(outSize);
|
|
|
|
|
|
|
|
compress2(output, &outSize, buffer, size, Z_BEST_COMPRESSION);
|
|
|
|
SDL_free(buffer);
|
|
|
|
|
|
|
|
buffer = output;
|
|
|
|
size = outSize;
|
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
{
|
2017-11-08 12:07:23 +01:00
|
|
|
u8* ptr = buffer;
|
|
|
|
u8* end = ptr + size;
|
|
|
|
|
|
|
|
char value[] = "999,";
|
|
|
|
while(ptr != end)
|
|
|
|
{
|
|
|
|
sprintf(value, "%i,", *ptr++);
|
|
|
|
writeMemoryString(&output, value);
|
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
2017-11-08 12:07:23 +01:00
|
|
|
SDL_free(buffer);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-11-08 12:07:23 +01:00
|
|
|
writeMemoryString(&output, "];\n");
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-11-08 12:07:23 +01:00
|
|
|
writeMemoryData(&output, EmbedTicJs, EmbedTicJsSize);
|
|
|
|
writeMemoryString(&output, "</script>\n");
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-11-08 12:07:23 +01:00
|
|
|
ptr += sizeof(Placeholder)-1;
|
|
|
|
writeMemoryData(&output, ptr, EmbedIndexSize - (ptr - EmbedIndex));
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-11-08 12:07:23 +01:00
|
|
|
fsGetFileData(onFileDownloaded, cartName, output.data, output.size, DEFAULT_CHMOD, console);
|
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SDL_free(EmbedIndex);
|
|
|
|
SDL_free(EmbedTicJs);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CAN_EXPORT
|
|
|
|
|
|
|
|
static void* embedCart(Console* console, s32* size)
|
|
|
|
{
|
2017-11-08 13:31:56 +01:00
|
|
|
tic_mem* tic = console->tic;
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-11-21 15:31:01 +01:00
|
|
|
void* data = fsReadFile(console->appPath, size);
|
|
|
|
|
|
|
|
if(data)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-11-21 15:31:01 +01:00
|
|
|
void* start = memmem(data, *size, embed.prefix, sizeof(embed.prefix));
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-11-21 15:31:01 +01:00
|
|
|
if(start)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-11-21 15:31:01 +01:00
|
|
|
embed.yes = true;
|
|
|
|
SDL_memcpy(&embed.file, &tic->cart, sizeof(tic_cartridge));
|
|
|
|
SDL_memcpy(start, &embed, sizeof(embed));
|
|
|
|
embed.yes = false;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
2017-11-21 15:31:01 +01:00
|
|
|
|
2017-11-08 13:31:56 +01:00
|
|
|
return data;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
2017-11-21 15:31:01 +01:00
|
|
|
|
2017-11-08 13:31:56 +01:00
|
|
|
return NULL;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(__WINDOWS__)
|
|
|
|
|
|
|
|
static const char* getFileFolder(const char* path)
|
|
|
|
{
|
|
|
|
static char folder[FILENAME_MAX];
|
|
|
|
|
|
|
|
const char* pos = strrchr(path, '\\');
|
|
|
|
|
|
|
|
if(!pos)
|
|
|
|
pos = strrchr(path, '/');
|
|
|
|
|
|
|
|
if(pos)
|
|
|
|
{
|
|
|
|
s32 size = pos - path;
|
|
|
|
memcpy(folder, path, size);
|
|
|
|
folder[size] = 0;
|
|
|
|
|
|
|
|
return folder;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool exportToFolder(Console* console, const char* folder, const char* file)
|
|
|
|
{
|
|
|
|
const char* workFolder = getFileFolder(console->appPath);
|
|
|
|
|
|
|
|
if(workFolder)
|
|
|
|
{
|
|
|
|
char src[FILENAME_MAX];
|
|
|
|
strcpy(src, workFolder);
|
|
|
|
strcat(src, file);
|
|
|
|
|
|
|
|
char dst[FILENAME_MAX];
|
|
|
|
strcpy(dst, folder);
|
|
|
|
strcat(dst, file);
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
return fsCopyFile(src, dst);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleExportNativeCommand(Console* console, const char* cartName)
|
|
|
|
{
|
|
|
|
const char* folder = folder_dialog(console);
|
2017-10-16 05:03:05 +02:00
|
|
|
bool done = false;
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
if(folder)
|
|
|
|
{
|
|
|
|
s32 size = 0;
|
|
|
|
|
|
|
|
void* data = embedCart(console, &size);
|
|
|
|
|
|
|
|
if(data)
|
|
|
|
{
|
|
|
|
char path[FILENAME_MAX];
|
|
|
|
strcpy(path, folder);
|
|
|
|
strcat(path, "\\game.exe");
|
|
|
|
|
|
|
|
done = fsWriteFile(path, data, size);
|
|
|
|
|
|
|
|
SDL_free(data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printBack(console, "\ngame exporting error :(");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
if(done && exportToFolder(console, folder, "\\tic80.dll") &&
|
2017-09-26 08:59:34 +02:00
|
|
|
exportToFolder(console, folder, "\\SDL2.dll"))
|
|
|
|
printBack(console, "\ngame exported :)");
|
|
|
|
else printBack(console, "\ngame not exported :|");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static void onConsoleExportNativeCommand(Console* console, const char* cartName)
|
|
|
|
{
|
|
|
|
s32 size = 0;
|
|
|
|
void* data = embedCart(console, &size);
|
|
|
|
|
|
|
|
if(data)
|
|
|
|
{
|
|
|
|
fsGetFileData(onFileDownloaded, cartName, data, size, DEFAULT_CHMOD, console);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
onFileDownloaded(FS_FILE_NOT_DOWNLOADED, console);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static const char* getExportName(Console* console, bool html)
|
|
|
|
{
|
|
|
|
static char name[FILENAME_MAX];
|
|
|
|
|
|
|
|
if(strlen(console->romName))
|
|
|
|
{
|
|
|
|
memset(name, 0, sizeof name);
|
|
|
|
memcpy(name, console->romName, strstr(console->romName, ".tic") - console->romName);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(name, "game");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(html)
|
|
|
|
strcat(name, ".html");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if defined(__WINDOWS__)
|
|
|
|
strcat(name, ExeExt);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleExportCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(param)
|
|
|
|
{
|
|
|
|
if(strcmp(param, "html") == 0) onConsoleExportHtmlCommand(console, getExportName(console, true));
|
|
|
|
else
|
|
|
|
{
|
2017-10-16 05:03:05 +02:00
|
|
|
if(strcmp(param, "native") == 0)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
#ifdef CAN_EXPORT
|
|
|
|
onConsoleExportNativeCommand(console, getExportName(console, false));
|
|
|
|
#else
|
|
|
|
printBack(console, "\nnative export isn't supported on this platform\n");
|
|
|
|
commandDone(console);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else if(strcmp(param, "sprites") == 0)
|
|
|
|
{
|
|
|
|
exportSprites(console);
|
|
|
|
}
|
|
|
|
else if(strcmp(param, "map") == 0)
|
|
|
|
{
|
|
|
|
exportMap(console);
|
|
|
|
}
|
|
|
|
else if(strcmp(param, "cover") == 0)
|
|
|
|
{
|
|
|
|
exportCover(console);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printError(console, "\nunknown parameter: ");
|
|
|
|
printError(console, param);
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
onConsoleExportHtmlCommand(console, getExportName(console, true));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2017-11-19 16:41:39 +01:00
|
|
|
static CartSaveResult saveCartName(Console* console, const char* name)
|
2017-11-10 17:40:44 +01:00
|
|
|
{
|
2017-11-19 16:41:39 +01:00
|
|
|
tic_mem* tic = console->tic;
|
2017-11-10 17:40:44 +01:00
|
|
|
|
2017-11-19 16:41:39 +01:00
|
|
|
bool success = false;
|
2017-11-10 14:38:19 +01:00
|
|
|
|
2017-11-19 16:41:39 +01:00
|
|
|
if(name && strlen(name))
|
2017-11-10 14:38:19 +01:00
|
|
|
{
|
2017-11-19 16:41:39 +01:00
|
|
|
u8* buffer = (u8*)SDL_malloc(sizeof(tic_cartridge) * 3);
|
2017-11-10 14:38:19 +01:00
|
|
|
|
2017-11-19 16:41:39 +01:00
|
|
|
if(buffer)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
if(strcmp(name, CONFIG_TIC_PATH) == 0)
|
|
|
|
{
|
|
|
|
console->config->save(console->config);
|
|
|
|
studioRomSaved();
|
2017-10-16 05:03:05 +02:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
return CART_SAVE_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-11-19 16:41:39 +01:00
|
|
|
s32 size = 0;
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-11-19 16:41:39 +01:00
|
|
|
#if defined(TIC80_PRO)
|
2017-11-23 13:26:39 +01:00
|
|
|
if(hasProjectExt(name))
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
2017-11-23 13:26:39 +01:00
|
|
|
size = saveProject(console, buffer, projectComment(name));
|
2017-11-19 16:41:39 +01:00
|
|
|
}
|
|
|
|
else
|
2017-11-23 13:26:39 +01:00
|
|
|
#endif
|
2017-11-19 16:41:39 +01:00
|
|
|
{
|
|
|
|
name = getCartName(name);
|
|
|
|
size = tic->api.save(&tic->cart, buffer);
|
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
if(size && fsSaveFile(console->fs, name, buffer, size, true))
|
|
|
|
{
|
2017-11-27 18:46:32 +01:00
|
|
|
setCartName(console, name);
|
2017-09-26 08:59:34 +02:00
|
|
|
success = true;
|
|
|
|
studioRomSaved();
|
2017-10-16 05:03:05 +02:00
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
SDL_free(buffer);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strlen(console->romName))
|
|
|
|
{
|
|
|
|
return saveCartName(console, console->romName);
|
|
|
|
}
|
|
|
|
else return CART_SAVE_MISSING_NAME;
|
2017-10-16 05:03:05 +02:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
return success ? CART_SAVE_OK : CART_SAVE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
static CartSaveResult saveCart(Console* console)
|
|
|
|
{
|
|
|
|
return saveCartName(console, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleSaveCommandConfirmed(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
CartSaveResult rom = saveCartName(console, param);
|
|
|
|
|
|
|
|
if(rom == CART_SAVE_OK)
|
|
|
|
{
|
|
|
|
printBack(console, "\ncart ");
|
|
|
|
printFront(console, console->romName);
|
|
|
|
printBack(console, " saved!\n");
|
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
else if(rom == CART_SAVE_MISSING_NAME)
|
2017-09-26 08:59:34 +02:00
|
|
|
printBack(console, "\ncart name is missing\n");
|
2017-10-16 05:03:05 +02:00
|
|
|
else
|
2017-09-26 08:59:34 +02:00
|
|
|
printBack(console, "\ncart saving error");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleSaveCommand(Console* console, const char* param)
|
|
|
|
{
|
2017-11-10 17:40:44 +01:00
|
|
|
if(param && strlen(param) && fsExistsFile(console->fs, getCartName(param)))
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-10-16 05:03:05 +02:00
|
|
|
static const char* Rows[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
"THE CART",
|
|
|
|
"ALREADY EXISTS",
|
|
|
|
"",
|
|
|
|
"DO YOU WANT TO",
|
|
|
|
"OVERWRITE IT?",
|
|
|
|
};
|
|
|
|
|
|
|
|
confirmCommand(console, Rows, COUNT_OF(Rows), param, onConsoleSaveCommandConfirmed);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
onConsoleSaveCommandConfirmed(console, param);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleRunCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
commandDone(console);
|
|
|
|
|
|
|
|
console->tic->api.reset(console->tic);
|
|
|
|
|
|
|
|
setStudioMode(TIC_RUN_MODE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleResumeCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
commandDone(console);
|
|
|
|
|
|
|
|
console->tic->api.resume(console->tic);
|
|
|
|
console->tic->api.sync(console->tic, false);
|
|
|
|
|
|
|
|
setStudioMode(TIC_RUN_MODE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onAddFile(const char* name, AddResult result, void* data)
|
|
|
|
{
|
|
|
|
Console* console = (Console*)data;
|
|
|
|
|
|
|
|
printLine(console);
|
|
|
|
|
|
|
|
switch(result)
|
|
|
|
{
|
|
|
|
case FS_FILE_EXISTS:
|
|
|
|
printBack(console, "file ");
|
|
|
|
printFront(console, name);
|
|
|
|
printBack(console, " already exists :|");
|
|
|
|
break;
|
|
|
|
case FS_FILE_ADDED:
|
|
|
|
printBack(console, "file ");
|
|
|
|
printFront(console, name);
|
|
|
|
printBack(console, " is successfully added :)");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printBack(console, "file not added :(");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleAddCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
fsAddFile(console->fs, onAddFile, console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleGetCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(param)
|
|
|
|
{
|
|
|
|
fsGetFile(console->fs, onFileDownloaded, param, console);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else printBack(console, "\nfile name is missing");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleDelCommandConfirmed(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
if(param && strlen(param))
|
|
|
|
{
|
|
|
|
if(fsIsDir(console->fs, param))
|
|
|
|
{
|
|
|
|
printBack(console, fsDeleteDir(console->fs, param)
|
2017-10-16 05:03:05 +02:00
|
|
|
? "\ndir not deleted"
|
2017-09-26 08:59:34 +02:00
|
|
|
: "\ndir successfully deleted");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printBack(console, fsDeleteFile(console->fs, param)
|
2017-10-16 05:03:05 +02:00
|
|
|
? "\nfile not deleted"
|
2017-09-26 08:59:34 +02:00
|
|
|
: "\nfile successfully deleted");
|
|
|
|
}
|
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
else printBack(console, "\nname is missing");
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleDelCommand(Console* console, const char* param)
|
|
|
|
{
|
2017-10-16 05:03:05 +02:00
|
|
|
static const char* Rows[] =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
"", "",
|
|
|
|
"DO YOU REALLY WANT",
|
|
|
|
"TO DELETE FILE?",
|
|
|
|
};
|
|
|
|
|
|
|
|
confirmCommand(console, Rows, COUNT_OF(Rows), param, onConsoleDelCommandConfirmed);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printTable(Console* console, const char* text)
|
|
|
|
{
|
|
|
|
printf("%s", text);
|
|
|
|
|
|
|
|
const char* textPointer = text;
|
|
|
|
const char* endText = textPointer + strlen(text);
|
|
|
|
|
|
|
|
while(textPointer != endText)
|
|
|
|
{
|
|
|
|
char symbol = *textPointer++;
|
|
|
|
|
|
|
|
scrollConsole(console);
|
|
|
|
|
|
|
|
if(symbol == '\n')
|
|
|
|
{
|
|
|
|
console->cursor.x = 0;
|
|
|
|
console->cursor.y++;
|
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
else
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
s32 offset = console->cursor.x + console->cursor.y * CONSOLE_BUFFER_WIDTH;
|
|
|
|
*(console->buffer + offset) = symbol;
|
|
|
|
|
|
|
|
u8 color = 0;
|
|
|
|
|
|
|
|
switch(symbol)
|
|
|
|
{
|
|
|
|
case '+':
|
|
|
|
case '|':
|
|
|
|
case '-':
|
2017-10-20 09:37:30 +02:00
|
|
|
color = (tic_color_gray);
|
2017-09-26 08:59:34 +02:00
|
|
|
break;
|
|
|
|
default:
|
2017-10-20 09:37:30 +02:00
|
|
|
color = (tic_color_white);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
*(console->colorBuffer + offset) = color;
|
|
|
|
|
|
|
|
console->cursor.x++;
|
|
|
|
|
|
|
|
if(console->cursor.x >= CONSOLE_BUFFER_WIDTH)
|
|
|
|
{
|
|
|
|
console->cursor.x = 0;
|
|
|
|
console->cursor.y++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printRamInfo(Console* console, s32 addr, const char* name, s32 size)
|
|
|
|
{
|
|
|
|
char buf[STUDIO_TEXT_BUFFER_WIDTH];
|
|
|
|
sprintf(buf, "\n| %05X | %-17s | %-5i |", addr, name, size);
|
|
|
|
printTable(console, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleRamCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
printLine(console);
|
|
|
|
|
|
|
|
printTable(console, "\n+-----------------------------------+" \
|
|
|
|
"\n| 80K RAM LAYOUT |" \
|
|
|
|
"\n+-------+-------------------+-------+" \
|
|
|
|
"\n| ADDR | INFO | SIZE |" \
|
|
|
|
"\n+-------+-------------------+-------+");
|
|
|
|
|
2017-11-11 15:15:06 +01:00
|
|
|
static const struct{s32 addr; const char* info;} Layout[] =
|
|
|
|
{
|
|
|
|
{offsetof(tic_ram, vram.screen), "SCREEN"},
|
|
|
|
{offsetof(tic_ram, vram.palette), "PALETTE"},
|
|
|
|
{offsetof(tic_ram, vram.mapping), "PALETTE MAP"},
|
2017-12-10 11:02:13 +01:00
|
|
|
{offsetof(tic_ram, vram.vars.colors), "BORDER"},
|
2017-11-11 15:15:06 +01:00
|
|
|
{offsetof(tic_ram, vram.vars.offset), "SCREEN OFFSET"},
|
|
|
|
{offsetof(tic_ram, vram.vars.mask), "GAMEPAD MASK"},
|
|
|
|
{offsetof(tic_ram, vram.input.gamepad), "GAMEPAD"},
|
|
|
|
{offsetof(tic_ram, vram.input.reserved), "..."},
|
2017-12-10 09:32:49 +01:00
|
|
|
{offsetof(tic_ram, tiles), "TILES"},
|
|
|
|
{offsetof(tic_ram, sprites), "SPRITES"},
|
|
|
|
{offsetof(tic_ram, map), "MAP"},
|
2017-11-11 15:15:06 +01:00
|
|
|
{offsetof(tic_ram, persistent), "PERSISTENT MEMORY"},
|
|
|
|
{offsetof(tic_ram, registers), "SOUND REGISTERS"},
|
2017-12-10 10:12:09 +01:00
|
|
|
{offsetof(tic_ram, sfx.waveform), "WAVEFORMS"},
|
|
|
|
{offsetof(tic_ram, sfx.data), "SFX"},
|
|
|
|
{offsetof(tic_ram, music.patterns.data), "MUSIC PATTERNS"},
|
|
|
|
{offsetof(tic_ram, music.tracks.data), "MUSIC TRACKS"},
|
2017-11-11 15:15:06 +01:00
|
|
|
{offsetof(tic_ram, music_pos), "MUSIC POS"},
|
|
|
|
{TIC_RAM_SIZE, "..."},
|
2017-09-26 08:59:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
enum{Last = COUNT_OF(Layout)-1};
|
|
|
|
|
|
|
|
for(s32 i = 0; i < Last; i++)
|
|
|
|
printRamInfo(console, Layout[i].addr, Layout[i].info, Layout[i+1].addr-Layout[i].addr);
|
|
|
|
|
|
|
|
printRamInfo(console, Layout[Last].addr, Layout[Last].info, 0);
|
|
|
|
|
|
|
|
printTable(console, "\n+-------+-------------------+-------+");
|
|
|
|
|
|
|
|
printLine(console);
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static const struct
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
const char* command;
|
|
|
|
const char* alt;
|
|
|
|
const char* info;
|
|
|
|
void(*handler)(Console*, const char*);
|
|
|
|
|
|
|
|
} AvailableConsoleCommands[] =
|
|
|
|
{
|
|
|
|
{"help", NULL, "show this info", onConsoleHelpCommand},
|
|
|
|
{"ram", NULL, "show memory info", onConsoleRamCommand},
|
2017-12-07 15:13:05 +01:00
|
|
|
{"exit", "quit", "exit the application", onConsoleExitCommand},
|
2017-09-26 08:59:34 +02:00
|
|
|
{"new", NULL, "create new cart", onConsoleNewCommand},
|
|
|
|
{"load", NULL, "load cart", onConsoleLoadCommand},
|
|
|
|
{"save", NULL, "save cart", onConsoleSaveCommand},
|
|
|
|
{"run", NULL, "run loaded cart", onConsoleRunCommand},
|
|
|
|
{"resume", NULL, "resume run cart", onConsoleResumeCommand},
|
|
|
|
{"dir", "ls", "show list of files", onConsoleDirCommand},
|
|
|
|
{"cd", NULL, "change directory", onConsoleChangeDirectory},
|
|
|
|
{"mkdir", NULL, "make directory", onConsoleMakeDirectory},
|
|
|
|
#ifdef CAN_EXPORT
|
|
|
|
{"folder", NULL, "open working folder in OS", onConsoleFolderCommand},
|
|
|
|
#endif
|
|
|
|
{"add", NULL, "add file", onConsoleAddCommand},
|
|
|
|
{"get", NULL, "download file", onConsoleGetCommand},
|
|
|
|
{"export", NULL, "export html or native game", onConsoleExportCommand},
|
|
|
|
{"import", NULL, "import sprites from .gif", onConsoleImportCommand},
|
|
|
|
{"del", NULL, "delete file or dir", onConsoleDelCommand},
|
|
|
|
{"cls", NULL, "clear screen", onConsoleClsCommand},
|
|
|
|
{"demo", NULL, "install demo carts", onConsoleInstallDemosCommand},
|
|
|
|
{"config", NULL, "edit TIC config", onConsoleConfigCommand},
|
|
|
|
{"keymap", NULL, "configure keyboard mapping", onConsoleKeymapCommand},
|
2017-10-27 02:43:20 +02:00
|
|
|
{"version", NULL, "show the current version", onConsoleVersionCommand},
|
2017-11-04 00:11:45 +01:00
|
|
|
{"edit", NULL, "open cart editor", onConsoleCodeCommand},
|
2017-09-26 08:59:34 +02:00
|
|
|
{"surf", NULL, "open carts browser", onConsoleSurfCommand},
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool predictFilename(const char* name, const char* info, s32 id, void* data, bool dir)
|
|
|
|
{
|
|
|
|
char* buffer = (char*)data;
|
|
|
|
|
|
|
|
if(strstr(name, buffer) == name)
|
|
|
|
{
|
|
|
|
strcpy(buffer, name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void processConsoleTab(Console* console)
|
|
|
|
{
|
|
|
|
char* input = console->inputBuffer;
|
|
|
|
|
|
|
|
if(strlen(input))
|
|
|
|
{
|
|
|
|
char* param = SDL_strchr(input, ' ');
|
2017-10-16 05:03:05 +02:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
if(param && strlen(++param))
|
|
|
|
{
|
|
|
|
fsEnumFiles(console->fs, predictFilename, param);
|
|
|
|
console->inputPosition = strlen(input);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(s32 i = 0; i < COUNT_OF(AvailableConsoleCommands); i++)
|
|
|
|
{
|
|
|
|
const char* command = AvailableConsoleCommands[i].command;
|
|
|
|
|
|
|
|
if(strstr(command, input) == command)
|
|
|
|
{
|
|
|
|
strcpy(input, command);
|
|
|
|
console->inputPosition = strlen(input);
|
|
|
|
break;
|
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
}
|
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void toUpperStr(char* str)
|
|
|
|
{
|
|
|
|
while(*str)
|
|
|
|
{
|
|
|
|
*str = SDL_toupper(*str);
|
|
|
|
str++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onConsoleHelpCommand(Console* console, const char* param)
|
|
|
|
{
|
|
|
|
printBack(console, "\navailable commands:\n\n");
|
|
|
|
|
|
|
|
size_t maxName = 0;
|
|
|
|
for(s32 i = 0; i < COUNT_OF(AvailableConsoleCommands); i++)
|
|
|
|
{
|
|
|
|
size_t len = strlen(AvailableConsoleCommands[i].command);
|
2017-12-07 15:13:05 +01:00
|
|
|
|
|
|
|
{
|
|
|
|
const char* alt = AvailableConsoleCommands[i].alt;
|
|
|
|
if(alt)
|
|
|
|
len += strlen(alt) + 1;
|
|
|
|
}
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
if(len > maxName) maxName = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
char upName[64];
|
|
|
|
|
|
|
|
for(s32 i = 0; i < COUNT_OF(AvailableConsoleCommands); i++)
|
|
|
|
{
|
|
|
|
const char* command = AvailableConsoleCommands[i].command;
|
|
|
|
|
|
|
|
{
|
|
|
|
strcpy(upName, command);
|
|
|
|
toUpperStr(upName);
|
|
|
|
printFront(console, upName);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* alt = AvailableConsoleCommands[i].alt;
|
|
|
|
|
|
|
|
if(alt)
|
|
|
|
{
|
|
|
|
strcpy(upName, alt);
|
|
|
|
toUpperStr(upName);
|
|
|
|
printBack(console, "/");
|
|
|
|
printFront(console, upName);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t len = maxName - strlen(command) - (alt ? strlen(alt) : -1);
|
|
|
|
while(len--) printBack(console, " ");
|
|
|
|
|
|
|
|
printBack(console, AvailableConsoleCommands[i].info);
|
|
|
|
printLine(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
printBack(console, "\npress ");
|
|
|
|
|
|
|
|
#if defined(__ANDROID__)
|
|
|
|
printFront(console, "BACK");
|
|
|
|
#else
|
|
|
|
printFront(console, "ESC");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
printBack(console, " to enter UI mode\n");
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static s32 tic_strcasecmp(const char *str1, const char *str2)
|
|
|
|
{
|
|
|
|
char a = 0;
|
|
|
|
char b = 0;
|
|
|
|
while (*str1 && *str2) {
|
|
|
|
a = SDL_toupper((unsigned char) *str1);
|
|
|
|
b = SDL_toupper((unsigned char) *str2);
|
|
|
|
if (a != b)
|
|
|
|
break;
|
|
|
|
++str1;
|
|
|
|
++str2;
|
|
|
|
}
|
|
|
|
a = SDL_toupper(*str1);
|
|
|
|
b = SDL_toupper(*str2);
|
|
|
|
return (int) ((unsigned char) a - (unsigned char) b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void processCommand(Console* console, const char* command)
|
|
|
|
{
|
|
|
|
while(*command == ' ')
|
|
|
|
command++;
|
|
|
|
|
|
|
|
char* end = (char*)command + strlen(command) - 1;
|
|
|
|
|
|
|
|
while(*end == ' ' && end > command)
|
|
|
|
*end-- = '\0';
|
|
|
|
|
|
|
|
char* param = SDL_strchr(command, ' ');
|
|
|
|
|
|
|
|
if(param)
|
|
|
|
*param++ = '\0';
|
|
|
|
|
|
|
|
if(param && !strlen(param)) param = NULL;
|
|
|
|
|
|
|
|
for(s32 i = 0; i < COUNT_OF(AvailableConsoleCommands); i++)
|
2017-10-16 05:03:05 +02:00
|
|
|
if(tic_strcasecmp(command, AvailableConsoleCommands[i].command) == 0 ||
|
2017-09-26 08:59:34 +02:00
|
|
|
(AvailableConsoleCommands[i].alt && tic_strcasecmp(command, AvailableConsoleCommands[i].alt) == 0))
|
|
|
|
{
|
|
|
|
if(AvailableConsoleCommands[i].handler)
|
|
|
|
{
|
|
|
|
AvailableConsoleCommands[i].handler(console, param);
|
|
|
|
command = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(command)
|
|
|
|
{
|
|
|
|
printLine(console);
|
|
|
|
printError(console, "unknown command:");
|
|
|
|
printError(console, console->inputBuffer);
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fillInputBufferFromHistory(Console* console)
|
|
|
|
{
|
|
|
|
memset(console->inputBuffer, 0, sizeof(console->inputBuffer));
|
|
|
|
strcpy(console->inputBuffer, console->history->value);
|
|
|
|
processConsoleEnd(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onHistoryUp(Console* console)
|
|
|
|
{
|
|
|
|
if(console->history)
|
|
|
|
{
|
|
|
|
if(console->history->next)
|
|
|
|
console->history = console->history->next;
|
|
|
|
}
|
|
|
|
else console->history = console->historyHead;
|
|
|
|
|
|
|
|
if(console->history)
|
|
|
|
fillInputBufferFromHistory(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void onHistoryDown(Console* console)
|
|
|
|
{
|
|
|
|
if(console->history)
|
|
|
|
{
|
|
|
|
if(console->history->prev)
|
|
|
|
console->history = console->history->prev;
|
|
|
|
|
|
|
|
fillInputBufferFromHistory(console);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void appendHistory(Console* console, const char* value)
|
|
|
|
{
|
|
|
|
HistoryItem* item = (HistoryItem*)SDL_malloc(sizeof(HistoryItem));
|
|
|
|
item->value = SDL_strdup(value);
|
|
|
|
item->next = NULL;
|
|
|
|
item->prev = NULL;
|
|
|
|
|
|
|
|
if(console->historyHead == NULL)
|
|
|
|
{
|
|
|
|
console->historyHead = item;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
console->historyHead->prev = item;
|
|
|
|
item->next = console->historyHead;
|
|
|
|
console->historyHead = item;
|
|
|
|
console->history = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void processConsoleCommand(Console* console)
|
|
|
|
{
|
|
|
|
console->inputPosition = 0;
|
|
|
|
|
|
|
|
size_t commandSize = strlen(console->inputBuffer);
|
|
|
|
|
|
|
|
if(commandSize)
|
|
|
|
{
|
|
|
|
printFront(console, console->inputBuffer);
|
|
|
|
appendHistory(console, console->inputBuffer);
|
|
|
|
|
|
|
|
processCommand(console, console->inputBuffer);
|
|
|
|
|
|
|
|
memset(console->inputBuffer, 0, sizeof(console->inputBuffer));
|
|
|
|
}
|
|
|
|
else commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void error(Console* console, const char* info)
|
|
|
|
{
|
2017-10-20 09:37:30 +02:00
|
|
|
consolePrint(console, info ? info : "unknown error", (tic_color_red));
|
2017-09-26 08:59:34 +02:00
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void trace(Console* console, const char* text, u8 color)
|
|
|
|
{
|
|
|
|
consolePrint(console, text, color);
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setScroll(Console* console, s32 val)
|
|
|
|
{
|
|
|
|
if(console->scroll.pos != val)
|
|
|
|
{
|
|
|
|
console->scroll.pos = val;
|
|
|
|
|
|
|
|
if(console->scroll.pos < 0) console->scroll.pos = 0;
|
2017-10-16 05:03:05 +02:00
|
|
|
if(console->scroll.pos > console->cursor.y) console->scroll.pos = console->cursor.y;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void processGesture(Console* console)
|
|
|
|
{
|
|
|
|
SDL_Point point = {0, 0};
|
|
|
|
|
|
|
|
if(getGesturePos(&point))
|
|
|
|
{
|
|
|
|
if(console->scroll.active)
|
|
|
|
setScroll(console, (console->scroll.start - point.y) / STUDIO_TEXT_HEIGHT);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
console->scroll.start = point.y + console->scroll.pos * STUDIO_TEXT_HEIGHT;
|
|
|
|
console->scroll.active = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else console->scroll.active = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void checkNewVersion(Console* console)
|
|
|
|
{
|
|
|
|
Net* net = createNet();
|
|
|
|
|
|
|
|
if(net)
|
|
|
|
{
|
|
|
|
NetVersion version = netVersionRequest(net);
|
|
|
|
SDL_free(net);
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
if((version.major > TIC_VERSION_MAJOR) ||
|
2017-09-26 08:59:34 +02:00
|
|
|
(version.major == TIC_VERSION_MAJOR && version.minor > TIC_VERSION_MINOR) ||
|
|
|
|
(version.major == TIC_VERSION_MAJOR && version.minor == TIC_VERSION_MINOR && version.patch > TIC_VERSION_PATCH))
|
|
|
|
{
|
|
|
|
char msg[FILENAME_MAX] = {0};
|
|
|
|
sprintf(msg, "\n A new version %i.%i.%i is available.\n", version.major, version.minor, version.patch);
|
2017-10-20 09:37:30 +02:00
|
|
|
consolePrint(console, msg, (tic_color_light_green));
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tick(Console* console)
|
|
|
|
{
|
|
|
|
SDL_Event* event = NULL;
|
|
|
|
while ((event = pollEvent()))
|
|
|
|
{
|
|
|
|
switch(event->type)
|
|
|
|
{
|
|
|
|
case SDL_MOUSEWHEEL:
|
|
|
|
{
|
|
|
|
enum{Scroll = 3};
|
|
|
|
s32 delta = event->wheel.y > 0 ? -Scroll : Scroll;
|
|
|
|
setScroll(console, console->scroll.pos + delta);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SDL_KEYDOWN:
|
|
|
|
{
|
|
|
|
switch(event->key.keysym.sym)
|
|
|
|
{
|
|
|
|
case SDLK_UP:
|
|
|
|
onHistoryUp(console);
|
|
|
|
break;
|
|
|
|
case SDLK_DOWN:
|
|
|
|
onHistoryDown(console);
|
|
|
|
break;
|
|
|
|
case SDLK_RIGHT:
|
|
|
|
{
|
|
|
|
console->inputPosition++;
|
|
|
|
size_t len = strlen(console->inputBuffer);
|
|
|
|
if(console->inputPosition > len)
|
|
|
|
console->inputPosition = len;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SDLK_LEFT:
|
|
|
|
{
|
|
|
|
if(console->inputPosition > 0)
|
|
|
|
console->inputPosition--;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SDLK_RETURN: processConsoleCommand(console); break;
|
|
|
|
case SDLK_BACKSPACE: processConsoleBackspace(console); break;
|
|
|
|
case SDLK_DELETE: processConsoleDel(console); break;
|
|
|
|
case SDLK_HOME: processConsoleHome(console); break;
|
|
|
|
case SDLK_END: processConsoleEnd(console); break;
|
|
|
|
case SDLK_TAB: processConsoleTab(console); break;
|
|
|
|
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
scrollConsole(console);
|
2017-10-16 05:03:05 +02:00
|
|
|
console->cursor.delay = CONSOLE_CURSOR_DELAY;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SDL_TEXTINPUT:
|
|
|
|
{
|
|
|
|
const char* symbol = event->text.text;
|
|
|
|
|
|
|
|
if(strlen(symbol) == 1)
|
|
|
|
{
|
|
|
|
char sym = *symbol;
|
|
|
|
|
|
|
|
size_t size = strlen(console->inputBuffer);
|
|
|
|
|
|
|
|
if(size < sizeof(console->inputBuffer))
|
|
|
|
{
|
|
|
|
char* pos = console->inputBuffer + console->inputPosition;
|
|
|
|
memmove(pos + 1, pos, strlen(pos));
|
|
|
|
|
|
|
|
*(console->inputBuffer + console->inputPosition) = sym;
|
|
|
|
console->inputPosition++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
console->cursor.delay = CONSOLE_CURSOR_DELAY;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
processGesture(console);
|
|
|
|
|
|
|
|
if(console->tickCounter == 0)
|
|
|
|
{
|
|
|
|
if(!embed.yes)
|
|
|
|
{
|
|
|
|
loadDemo(console, tic_script_lua);
|
|
|
|
|
|
|
|
printBack(console, "\n hello! type ");
|
|
|
|
printFront(console, "help");
|
|
|
|
printBack(console, " for help\n");
|
|
|
|
|
|
|
|
if(getConfig()->checkNewVersion)
|
|
|
|
checkNewVersion(console);
|
|
|
|
|
|
|
|
commandDone(console);
|
|
|
|
}
|
|
|
|
else printBack(console, "\n loading cart...");
|
|
|
|
}
|
|
|
|
|
|
|
|
console->tic->api.clear(console->tic, TIC_COLOR_BG);
|
|
|
|
drawConsoleText(console);
|
|
|
|
|
|
|
|
if(embed.yes)
|
|
|
|
{
|
2017-12-07 12:25:39 +01:00
|
|
|
if(console->tickCounter >= (u32)(console->skipStart ? 1 : TIC_FRAMERATE))
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-12-07 12:25:39 +01:00
|
|
|
if(!console->skipStart)
|
2017-09-26 08:59:34 +02:00
|
|
|
console->showGameMenu = true;
|
|
|
|
|
|
|
|
memcpy(&console->tic->cart, &embed.file, sizeof(tic_cartridge));
|
|
|
|
setStudioMode(TIC_RUN_MODE);
|
|
|
|
embed.yes = false;
|
2017-12-07 12:25:39 +01:00
|
|
|
console->skipStart = false;
|
2017-09-26 08:59:34 +02:00
|
|
|
studioRomLoaded();
|
2017-09-28 13:31:28 +02:00
|
|
|
|
|
|
|
console->tic->api.reset(console->tic);
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
printLine(console);
|
|
|
|
commandDone(console);
|
|
|
|
console->active = true;
|
2017-11-20 10:00:59 +01:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2017-11-20 10:00:59 +01:00
|
|
|
{
|
2017-09-26 08:59:34 +02:00
|
|
|
if(console->cursor.delay)
|
|
|
|
console->cursor.delay--;
|
|
|
|
|
|
|
|
if(getStudioMode() != TIC_CONSOLE_MODE) return;
|
|
|
|
|
|
|
|
drawConsoleInputText(console);
|
|
|
|
}
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
console->tickCounter++;
|
2017-11-20 10:00:59 +01:00
|
|
|
|
|
|
|
if(console->startSurf)
|
|
|
|
{
|
|
|
|
console->startSurf = false;
|
|
|
|
gotoSurf();
|
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
2017-12-07 12:25:39 +01:00
|
|
|
static bool cmdLoadCart(Console* console, const char* name)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-12-07 12:25:39 +01:00
|
|
|
bool done = false;
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
s32 size = 0;
|
|
|
|
void* data = fsReadFile(name, &size);
|
|
|
|
|
|
|
|
if(data)
|
2017-10-16 05:03:05 +02:00
|
|
|
{
|
2017-11-19 14:58:54 +01:00
|
|
|
#if defined(TIC80_PRO)
|
2017-11-23 13:26:39 +01:00
|
|
|
if(hasProjectExt(name))
|
2017-11-19 14:58:54 +01:00
|
|
|
{
|
2017-11-23 13:26:39 +01:00
|
|
|
loadProject(console, name, data, size, &embed.file);
|
2017-11-27 18:46:32 +01:00
|
|
|
setCartName(console, fsFilename(name));
|
2017-11-24 10:09:25 +01:00
|
|
|
embed.yes = true;
|
2017-12-07 12:25:39 +01:00
|
|
|
console->skipStart = true;
|
|
|
|
done = true;
|
2017-11-19 14:58:54 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
|
2017-11-24 10:09:25 +01:00
|
|
|
if(hasExt(name, CART_EXT))
|
|
|
|
{
|
|
|
|
loadCart(console->tic, &embed.file, data, size, true);
|
2017-11-27 18:46:32 +01:00
|
|
|
setCartName(console, fsFilename(name));
|
2017-11-24 10:09:25 +01:00
|
|
|
embed.yes = true;
|
2017-12-07 12:25:39 +01:00
|
|
|
done = true;
|
2017-11-24 10:09:25 +01:00
|
|
|
}
|
2017-11-23 15:13:58 +01:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
SDL_free(data);
|
|
|
|
}
|
2017-12-07 12:25:39 +01:00
|
|
|
|
|
|
|
return done;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static bool loadFileIntoBuffer(Console* console, char* buffer, const char* fileName)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-10-16 05:03:05 +02:00
|
|
|
s32 size = 0;
|
|
|
|
void* contents = fsReadFile(fileName, &size);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
if(contents)
|
|
|
|
{
|
2017-10-16 20:22:25 +02:00
|
|
|
memset(buffer, 0, TIC_CODE_SIZE);
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
if(size > TIC_CODE_SIZE)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-10-16 05:03:05 +02:00
|
|
|
char messageBuffer[256];
|
|
|
|
sprintf(messageBuffer, "\n code is larger than %i symbols\n", TIC_CODE_SIZE);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
printError(console, messageBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buffer, contents, SDL_min(size, TIC_CODE_SIZE-1));
|
|
|
|
SDL_free(contents);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
static void tryReloadCode(Console* console, char* codeBuffer)
|
|
|
|
{
|
|
|
|
if(console->codeLiveReload.active)
|
|
|
|
{
|
|
|
|
const char* fileName = console->codeLiveReload.fileName;
|
|
|
|
loadFileIntoBuffer(console, codeBuffer, fileName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-07 12:25:39 +01:00
|
|
|
static bool cmdInjectCode(Console* console, const char* param, const char* name)
|
2017-10-16 05:03:05 +02:00
|
|
|
{
|
2017-12-07 12:25:39 +01:00
|
|
|
bool done = false;
|
|
|
|
|
2017-10-16 20:22:25 +02:00
|
|
|
bool watch = strcmp(param, "-code-watch") == 0;
|
2017-10-17 19:48:25 +02:00
|
|
|
if(watch || strcmp(param, "-code") == 0)
|
2017-10-16 05:03:05 +02:00
|
|
|
{
|
2017-12-13 17:54:00 +01:00
|
|
|
bool loaded = loadFileIntoBuffer(console, embed.file.bank.code.data, name);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
if(loaded)
|
|
|
|
{
|
2017-09-26 08:59:34 +02:00
|
|
|
embed.yes = true;
|
2017-12-07 12:25:39 +01:00
|
|
|
console->skipStart = true;
|
|
|
|
done = true;
|
2017-10-16 05:03:05 +02:00
|
|
|
|
2017-10-16 20:22:25 +02:00
|
|
|
if(watch)
|
|
|
|
{
|
|
|
|
console->codeLiveReload.active = true;
|
|
|
|
strcpy(console->codeLiveReload.fileName, name);
|
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
2017-12-07 12:25:39 +01:00
|
|
|
|
|
|
|
return done;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
2017-12-07 12:25:39 +01:00
|
|
|
static bool cmdInjectSprites(Console* console, const char* param, const char* name)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-12-07 12:25:39 +01:00
|
|
|
bool done = false;
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
if(strcmp(param, "-sprites") == 0)
|
|
|
|
{
|
|
|
|
s32 size = 0;
|
|
|
|
void* sprites = fsReadFile(name, &size);
|
|
|
|
|
|
|
|
if(sprites)
|
2017-10-16 05:03:05 +02:00
|
|
|
{
|
2017-09-26 08:59:34 +02:00
|
|
|
gif_image* image = gif_read_data(sprites, size);
|
|
|
|
|
|
|
|
if (image)
|
|
|
|
{
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Width = TIC_SPRITESHEET_SIZE,
|
|
|
|
Height = TIC_SPRITESHEET_SIZE*2,
|
|
|
|
};
|
|
|
|
|
|
|
|
s32 w = SDL_min(Width, image->width);
|
|
|
|
s32 h = SDL_min(Height, image->height);
|
|
|
|
|
|
|
|
for (s32 y = 0; y < h; y++)
|
|
|
|
for (s32 x = 0; x < w; x++)
|
|
|
|
{
|
|
|
|
u8 src = image->buffer[x + y * image->width];
|
|
|
|
const gif_color* c = &image->palette[src];
|
|
|
|
tic_rgb rgb = {c->r, c->g, c->b};
|
2017-12-13 17:54:00 +01:00
|
|
|
u8 color = tic_tool_find_closest_color(embed.file.bank.palette.colors, &rgb);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-12-11 09:44:46 +01:00
|
|
|
setSpritePixel(embed.file.bank.tiles.data, x, y, color);
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
gif_close(image);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_free(sprites);
|
|
|
|
|
|
|
|
embed.yes = true;
|
2017-12-07 12:25:39 +01:00
|
|
|
console->skipStart = true;
|
|
|
|
done = true;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2017-12-07 12:25:39 +01:00
|
|
|
|
|
|
|
return done;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
2017-12-07 12:25:39 +01:00
|
|
|
static bool cmdInjectMap(Console* console, const char* param, const char* name)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-12-07 12:25:39 +01:00
|
|
|
bool done = false;
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
if(strcmp(param, "-map") == 0)
|
|
|
|
{
|
|
|
|
s32 size = 0;
|
|
|
|
void* map = fsReadFile(name, &size);
|
|
|
|
|
|
|
|
if(map)
|
|
|
|
{
|
2017-11-28 07:16:52 +01:00
|
|
|
if(size <= sizeof(tic_map))
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-11-28 07:16:52 +01:00
|
|
|
injectMap(console, map, size);
|
2017-09-26 08:59:34 +02:00
|
|
|
|
|
|
|
embed.yes = true;
|
2017-12-07 12:25:39 +01:00
|
|
|
console->skipStart = true;
|
|
|
|
done = true;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SDL_free(map);
|
|
|
|
}
|
|
|
|
}
|
2017-12-07 12:25:39 +01:00
|
|
|
|
|
|
|
return done;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void initConsole(Console* console, tic_mem* tic, FileSystem* fs, Config* config, s32 argc, char **argv)
|
|
|
|
{
|
|
|
|
if(!console->buffer) console->buffer = SDL_malloc(CONSOLE_BUFFER_SIZE);
|
|
|
|
if(!console->colorBuffer) console->colorBuffer = SDL_malloc(CONSOLE_BUFFER_SIZE);
|
|
|
|
|
|
|
|
*console = (Console)
|
|
|
|
{
|
|
|
|
.tic = tic,
|
|
|
|
.config = config,
|
|
|
|
.load = onConsoleLoadCommandConfirmed,
|
2017-11-19 15:44:01 +01:00
|
|
|
|
|
|
|
#if defined(TIC80_PRO)
|
|
|
|
.loadProject = loadProject,
|
2017-11-21 17:47:36 +01:00
|
|
|
.updateProject = updateProject,
|
2017-11-19 15:44:01 +01:00
|
|
|
#else
|
|
|
|
.loadProject = NULL,
|
2017-11-21 17:47:36 +01:00
|
|
|
.updateProject = NULL,
|
2017-11-19 15:44:01 +01:00
|
|
|
#endif
|
2017-09-26 08:59:34 +02:00
|
|
|
.error = error,
|
|
|
|
.trace = trace,
|
|
|
|
.tick = tick,
|
|
|
|
.save = saveCart,
|
|
|
|
.cursor = {.x = 0, .y = 0, .delay = 0},
|
2017-10-16 05:03:05 +02:00
|
|
|
.scroll =
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
|
|
|
.pos = 0,
|
|
|
|
.start = 0,
|
|
|
|
.active = false,
|
|
|
|
},
|
2017-10-16 05:03:05 +02:00
|
|
|
.codeLiveReload =
|
|
|
|
{
|
|
|
|
.active = false,
|
|
|
|
.reload = tryReloadCode,
|
|
|
|
},
|
2017-09-26 08:59:34 +02:00
|
|
|
.inputPosition = 0,
|
|
|
|
.history = NULL,
|
|
|
|
.historyHead = NULL,
|
|
|
|
.tickCounter = 0,
|
|
|
|
.active = false,
|
|
|
|
.buffer = console->buffer,
|
|
|
|
.colorBuffer = console->colorBuffer,
|
|
|
|
.fs = fs,
|
|
|
|
.showGameMenu = false,
|
2017-11-20 10:00:59 +01:00
|
|
|
.startSurf = false,
|
2017-12-07 12:25:39 +01:00
|
|
|
.skipStart = false,
|
|
|
|
.goFullscreen = false,
|
2017-09-26 08:59:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
memset(console->buffer, 0, CONSOLE_BUFFER_SIZE);
|
|
|
|
memset(console->colorBuffer, TIC_COLOR_BG, CONSOLE_BUFFER_SIZE);
|
|
|
|
|
2017-10-16 05:03:05 +02:00
|
|
|
memset(console->codeLiveReload.fileName, 0, FILENAME_MAX);
|
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
if(argc)
|
|
|
|
{
|
|
|
|
strcpy(console->appPath, argv[0]);
|
|
|
|
|
|
|
|
#if defined(__WINDOWS__)
|
|
|
|
if(!strstr(console->appPath, ExeExt))
|
|
|
|
strcat(console->appPath, ExeExt);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
printFront(console, "\n " TIC_NAME_FULL "");
|
|
|
|
printBack(console, " " TIC_VERSION_LABEL "\n");
|
|
|
|
printBack(console, " " TIC_COPYRIGHT "\n");
|
|
|
|
|
|
|
|
if(argc > 1)
|
|
|
|
{
|
2017-12-13 17:54:00 +01:00
|
|
|
memcpy(embed.file.bank.palette.data, tic->config.palette.data, sizeof(tic_palette));
|
2017-10-16 05:03:05 +02:00
|
|
|
|
2017-12-07 12:25:39 +01:00
|
|
|
u32 argp = 1;
|
|
|
|
|
|
|
|
// trying to load cart
|
|
|
|
for (s32 i = 1; i < argc; i++)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-12-07 12:25:39 +01:00
|
|
|
if(cmdLoadCart(console, argv[i]))
|
|
|
|
{
|
|
|
|
argp |= 1 << i;
|
|
|
|
break;
|
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
2017-12-07 12:25:39 +01:00
|
|
|
|
|
|
|
// process '-key val' params
|
|
|
|
for (s32 i = 1; i < argc-1; i++)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-12-07 12:25:39 +01:00
|
|
|
s32 mask = 0b11 << i;
|
2017-09-26 08:59:34 +02:00
|
|
|
|
2017-12-07 12:25:39 +01:00
|
|
|
if(~argp & mask)
|
2017-09-26 08:59:34 +02:00
|
|
|
{
|
2017-12-07 12:25:39 +01:00
|
|
|
const char* first = argv[i];
|
|
|
|
const char* second = argv[i + 1];
|
|
|
|
|
|
|
|
if(cmdInjectCode(console, first, second)
|
|
|
|
|| cmdInjectSprites(console, first, second)
|
|
|
|
|| cmdInjectMap(console, first, second))
|
|
|
|
argp |= mask;
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
}
|
2017-11-20 09:29:52 +01:00
|
|
|
|
2017-12-07 12:25:39 +01:00
|
|
|
// proccess single params
|
2017-11-20 09:29:52 +01:00
|
|
|
for (s32 i = 1; i < argc; i++)
|
2017-11-20 10:00:59 +01:00
|
|
|
{
|
2017-12-07 12:25:39 +01:00
|
|
|
if(~argp & 1 << i)
|
|
|
|
{
|
|
|
|
const char* arg = argv[i];
|
|
|
|
|
|
|
|
if(strcmp(arg, "-nosound") == 0)
|
|
|
|
config->data.noSound = true;
|
|
|
|
|
|
|
|
else if(strcmp(arg, "-surf") == 0)
|
|
|
|
console->startSurf = true;
|
|
|
|
|
|
|
|
else if(strcmp(arg, "-fullscreen") == 0)
|
|
|
|
console->goFullscreen = true;
|
|
|
|
|
|
|
|
else if(strcmp(arg, "-skip") == 0)
|
|
|
|
console->skipStart = true;
|
|
|
|
|
|
|
|
else continue;
|
|
|
|
|
|
|
|
argp |= 0b1 << i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (s32 i = 1; i < argc; i++)
|
|
|
|
{
|
|
|
|
if(~argp & 1 << i)
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
sprintf(buf, "parameter or file not processed: %s\n", argv[i]);
|
|
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "Warning", buf, NULL);
|
|
|
|
}
|
2017-11-20 10:00:59 +01:00
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(__EMSCRIPTEN__)
|
|
|
|
|
|
|
|
if(!embed.yes)
|
|
|
|
{
|
|
|
|
void* cartPtr = (void*)EM_ASM_INT_V
|
|
|
|
(
|
|
|
|
if(typeof cartridge != 'undefined' && cartridge.length)
|
|
|
|
{
|
|
|
|
var ptr = Module._malloc(cartridge.length);
|
|
|
|
|
|
|
|
Module.writeArrayToMemory(cartridge, ptr);
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
else return 0;
|
|
|
|
);
|
|
|
|
|
|
|
|
if(cartPtr)
|
|
|
|
{
|
|
|
|
embed.yes = true;
|
|
|
|
|
|
|
|
s32 cartSize = EM_ASM_INT_V(return cartridge.length;);
|
|
|
|
|
|
|
|
u8* data = NULL;
|
|
|
|
s32 size = unzip(&data, cartPtr, cartSize);
|
|
|
|
loadCart(tic, &embed.file, data, size, true);
|
|
|
|
|
|
|
|
SDL_free(data);
|
|
|
|
|
|
|
|
EM_ASM_({Module._free($0);}, cartPtr);
|
2017-10-16 05:03:05 +02:00
|
|
|
}
|
2017-09-26 08:59:34 +02:00
|
|
|
}
|
2017-10-16 05:03:05 +02:00
|
|
|
|
2017-09-26 08:59:34 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
console->active = !embed.yes;
|
|
|
|
}
|