CHANGELOG added. Menu now naturally sorts names. Tool and Patch package types added to auto-installer.
This commit is contained in:
parent
881fb4de3f
commit
448c58e20e
6 changed files with 140 additions and 49 deletions
57
CHANGELOG.txt
Normal file
57
CHANGELOG.txt
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
SINGE 2.10
|
||||||
|
==========
|
||||||
|
|
||||||
|
Released ...?
|
||||||
|
|
||||||
|
|
||||||
|
New Features
|
||||||
|
------------
|
||||||
|
|
||||||
|
- spriteDraw() now has two more forms. In addition to being able to draw
|
||||||
|
regular sprites and streteched sprites it can now draw both using the
|
||||||
|
sprite's center as the anchor instead of the upper right. This is highly
|
||||||
|
useful when dealing with rotated sprites.
|
||||||
|
|
||||||
|
- Sprite scaling and rotation! Optional separate X & Y scaling.
|
||||||
|
|
||||||
|
- Optional sprite anti-aliasing.
|
||||||
|
|
||||||
|
- SINGE_DEAD_ZONE global variable now available based on the DEAD_ZONE
|
||||||
|
controller configuration option.
|
||||||
|
|
||||||
|
- SINGE_FRAMEWORK_VERSION variable added.
|
||||||
|
|
||||||
|
- All new Lua library handling. Previously Singe "injected" libraries
|
||||||
|
directly into the script context. Now there is a proper Lua module search
|
||||||
|
handler. Scripts can properly require() modules from the following:
|
||||||
|
- Lua Standard Library
|
||||||
|
- Lua Auxillary Library
|
||||||
|
- LuaFileSystem
|
||||||
|
- LuaSocket
|
||||||
|
- LuaSec
|
||||||
|
- LuaRS232
|
||||||
|
|
||||||
|
- New command line option: -p (or --program). This is similar to the
|
||||||
|
existing -t (or --trace) option. Where "trace" displays and logs script
|
||||||
|
execution, "program" displays and logs Singe internals. This should make
|
||||||
|
troubleshooting difficult setups and odd script crashes easier.
|
||||||
|
|
||||||
|
- Auto-installer for the new GAME, TOOL, and PATCH archive formats to make
|
||||||
|
managing games easier.
|
||||||
|
|
||||||
|
|
||||||
|
Fixes
|
||||||
|
-----
|
||||||
|
|
||||||
|
- USB controllers now work in games launched from the included menu.
|
||||||
|
|
||||||
|
- Framework.singe was missing keyboard mode constants. MODE_NORMAL and
|
||||||
|
MODE_FULL are now included.
|
||||||
|
|
||||||
|
- Taking screenshots could sometimes crash Singe.
|
||||||
|
|
||||||
|
- PNG files no longer generate warnings on the console.
|
||||||
|
|
||||||
|
- Building Singe depended on a lot of undocumented software cobbled together
|
||||||
|
from other projects. This has been vastly improved and should be usable by
|
||||||
|
actual humans now.
|
|
@ -40,7 +40,7 @@ COMMAND LINE
|
||||||
___ ___ _ _ ___ ___
|
___ ___ _ _ ___ ___
|
||||||
/ __|_ _| \| |/ __| __| Somewhat Interactive Nostalgic Game Engine v2.10
|
/ __|_ _| \| |/ __| __| Somewhat Interactive Nostalgic Game Engine v2.10
|
||||||
\__ \| || .` | (_ | _| Copyright (c) 2006-2024 Scott C. Duensing
|
\__ \| || .` | (_ | _| Copyright (c) 2006-2024 Scott C. Duensing
|
||||||
|___/___|_|\_|\___|___| https://kangaroopunch.com
|
|___/___|_|\_|\___|___| https://KangarooPunch.com https://SingeEngine.com
|
||||||
|
|
||||||
Usage: Singe-v2.10-Windows-x86_64.exe [OPTIONS] scriptName{.singe}
|
Usage: Singe-v2.10-Windows-x86_64.exe [OPTIONS] scriptName{.singe}
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ Usage: Singe-v2.10-Windows-x86_64.exe [OPTIONS] scriptName{.singe}
|
||||||
-l, --volume_vldp=PERCENT specify laserdisc volume in percent
|
-l, --volume_vldp=PERCENT specify laserdisc volume in percent
|
||||||
-m, --nomouse disable mouse
|
-m, --nomouse disable mouse
|
||||||
-n, --nocrosshair request game not display gun crosshairs
|
-n, --nocrosshair request game not display gun crosshairs
|
||||||
|
-p, --program trace Singe execution to screen and file
|
||||||
-s, --nosound, --mutesound mutes all sound
|
-s, --nosound, --mutesound mutes all sound
|
||||||
-t, --trace trace script execution to screen and file
|
-t, --trace trace script execution to screen and file
|
||||||
-u, --stretch use ugly stretched video
|
-u, --stretch use ugly stretched video
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
-- Singe 2.xx Features -------------------------------------------------------
|
-- Singe 2.xx Features -------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
SINGE_FRAMEWORK_VERSION = 2.10
|
||||||
|
|
||||||
|
|
||||||
function utilDeepCopy(orig)
|
function utilDeepCopy(orig)
|
||||||
local orig_type = type(orig)
|
local orig_type = type(orig)
|
||||||
local copy
|
local copy
|
||||||
|
|
|
@ -26,8 +26,19 @@ dofile("Singe/Framework.singe")
|
||||||
lfs = require("lfs")
|
lfs = require("lfs")
|
||||||
|
|
||||||
|
|
||||||
|
function cleanTitle(a)
|
||||||
|
local output = string.lower(a)
|
||||||
|
output = string.gsub(output, '%p', ' ')
|
||||||
|
output = string.gsub(output, '^ +', '')
|
||||||
|
output = string.gsub(output, '^the ', '')
|
||||||
|
output = string.gsub(output, '^a ', '')
|
||||||
|
output = string.gsub(output, '^an ', '')
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function compareTitles(a, b)
|
function compareTitles(a, b)
|
||||||
return a.TITLE < b.TITLE
|
return cleanTitle(a.TITLE) < cleanTitle(b.TITLE)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
53
src/main.c
53
src/main.c
|
@ -871,14 +871,28 @@ void unpackGames(void) {
|
||||||
char *extension;
|
char *extension;
|
||||||
char *filename;
|
char *filename;
|
||||||
char *toplevel = NULL;
|
char *toplevel = NULL;
|
||||||
|
int packageType = -1;
|
||||||
|
char *types[] = { "Game", "Tool", "Patch", 0 };
|
||||||
char *badFilenames[] = { "Framework.singe", 0 };
|
char *badFilenames[] = { "Framework.singe", 0 };
|
||||||
char *badExtensions[] = { "exe", "sh", "bat", "cmd", "index", 0 };
|
char *badExtensions[] = { "exe", "sh", "bat", "cmd", "index", 0 };
|
||||||
|
|
||||||
|
// Games cannot include forbidden extensions, Singe binaries, multiple folders, etc.
|
||||||
|
// Tools are like games but do not need a games.dat file.
|
||||||
|
// Patches can be pretty much anything except forbidden extensions.
|
||||||
|
|
||||||
if (dir == NULL) utilDie("Could not open the current directory.");
|
if (dir == NULL) utilDie("Could not open the current directory.");
|
||||||
|
|
||||||
while ((de = readdir(dir)) != NULL) {
|
while ((de = readdir(dir)) != NULL) {
|
||||||
if (de->d_type == DT_REG || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) {
|
if (de->d_type == DT_REG || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) {
|
||||||
if (utilStricmp(utilGetFileExtension(de->d_name), "game") == 0) {
|
packageType = -1;
|
||||||
|
x = 0;
|
||||||
|
while (types[x] != NULL) {
|
||||||
|
if (utilStricmp(utilGetFileExtension(de->d_name), types[x]) == 0) {
|
||||||
|
packageType = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (packageType >= 0) {
|
||||||
showHeader();
|
showHeader();
|
||||||
count++;
|
count++;
|
||||||
ok = true;
|
ok = true;
|
||||||
|
@ -891,7 +905,7 @@ void unpackGames(void) {
|
||||||
archive_read_support_format_all(a);
|
archive_read_support_format_all(a);
|
||||||
r = archive_read_open_filename(a, de->d_name, 10240);
|
r = archive_read_open_filename(a, de->d_name, 10240);
|
||||||
if (r != ARCHIVE_OK) {
|
if (r != ARCHIVE_OK) {
|
||||||
utilSay("!!! Cannot read game: %s", de->d_name);
|
utilSay("!!! Cannot read %s: %s", types[packageType], de->d_name);
|
||||||
ok = false;
|
ok = false;
|
||||||
} else {
|
} else {
|
||||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK && ok) {
|
while (archive_read_next_header(a, &entry) == ARCHIVE_OK && ok) {
|
||||||
|
@ -899,36 +913,35 @@ void unpackGames(void) {
|
||||||
filename = utilGetLastPathComponent(e);
|
filename = utilGetLastPathComponent(e);
|
||||||
extension = utilGetFileExtension(e);
|
extension = utilGetFileExtension(e);
|
||||||
|
|
||||||
// Do we have a top level folder name yet?
|
// If not a patch, do we have a top level folder name yet?
|
||||||
if (toplevel == NULL) {
|
if ((utilStricmp(types[packageType], "Patch") != 0) && (toplevel == NULL)) {
|
||||||
// No. Is this a folder?
|
// No. Is this a folder?
|
||||||
if (strstr(e, "/") == NULL) {
|
if (strstr(e, "/") == NULL) {
|
||||||
// No. BAD! No files in the root!
|
// No. BAD! No files in the root!
|
||||||
ok = false;
|
ok = false;
|
||||||
utilSay("!!! Game has files in root: %s", de->d_name);
|
utilSay("!!! %s has files in root: %s", types[packageType], de->d_name);
|
||||||
} else {
|
} else {
|
||||||
// Remember this folder.
|
// Remember this folder.
|
||||||
toplevel = strdup(e);
|
toplevel = strdup(e);
|
||||||
gamesDat = utilCreateString("%sgames.dat", toplevel);
|
gamesDat = utilCreateString("%sgames.dat", toplevel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Yes, we have a top level. Is this entry inside it?
|
// If this is not a patch, check for a top level. Is this entry inside it?
|
||||||
if (!utilStartsWith(e, toplevel)) {
|
if ((utilStricmp(types[packageType], "Patch") != 0) && (!utilStartsWith(e, toplevel))) {
|
||||||
// No. BAD! Everything has to be in the top level.
|
// No. BAD! Everything has to be in the top level.
|
||||||
ok = false;
|
ok = false;
|
||||||
if (strstr(e, "/") == NULL) {
|
if (strstr(e, "/") == NULL) {
|
||||||
utilSay("!!! Game has files in root: %s", de->d_name);
|
utilSay("!!! %s has files in root: %s", types[packageType], de->d_name);
|
||||||
} else {
|
} else {
|
||||||
utilSay("!!! Game has multiple top level directories: %s", de->d_name);
|
utilSay("!!! %s has multiple top level directories: %s", types[packageType], de->d_name);
|
||||||
}
|
}
|
||||||
utilSay("[%s] %s", toplevel, e);
|
|
||||||
} else {
|
} else {
|
||||||
// Is this a forbidden file?
|
// Is this a forbidden file?
|
||||||
x = 0;
|
x = 0;
|
||||||
while (badFilenames[x] != NULL && ok) {
|
while (badFilenames[x] != NULL && ok) {
|
||||||
if (utilStricmp(filename, badFilenames[x]) == 0) {
|
if (utilStricmp(filename, badFilenames[x]) == 0) {
|
||||||
ok = false;
|
ok = false;
|
||||||
utilSay("!!! Game has %s: %s", badFilenames[x], de->d_name);
|
utilSay("!!! %s has %s: %s", types[packageType], badFilenames[x], de->d_name);
|
||||||
}
|
}
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
|
@ -937,14 +950,14 @@ void unpackGames(void) {
|
||||||
while (badExtensions[x] != NULL && ok) {
|
while (badExtensions[x] != NULL && ok) {
|
||||||
if (utilStricmp(extension, badExtensions[x]) == 0) {
|
if (utilStricmp(extension, badExtensions[x]) == 0) {
|
||||||
ok = false;
|
ok = false;
|
||||||
utilSay("!!! Game has %s file: %s", badExtensions[x], de->d_name);
|
utilSay("!!! %s has %s file: %s", types[packageType], badExtensions[x], de->d_name);
|
||||||
}
|
}
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
// No extension, starts with 'singe' - could be unix binary.
|
// Not a patch, no extension, starts with 'singe' - could be unix binary.
|
||||||
if (ok && strlen(extension) == 0 && utilStartsWith(filename, "singe")) {
|
if ((utilStricmp(types[packageType], "Patch") != 0) && (ok && strlen(extension) == 0 && utilStartsWith(filename, "singe"))) {
|
||||||
ok = false;
|
ok = false;
|
||||||
utilSay("!!! Game has singe file: %s", de->d_name);
|
utilSay("!!! %s has singe file: %s", types[packageType], de->d_name);
|
||||||
}
|
}
|
||||||
// Is this games.dat?
|
// Is this games.dat?
|
||||||
if (ok && !hasGamesDat && utilStricmp(e, gamesDat) == 0) hasGamesDat = true;
|
if (ok && !hasGamesDat && utilStricmp(e, gamesDat) == 0) hasGamesDat = true;
|
||||||
|
@ -963,16 +976,16 @@ void unpackGames(void) {
|
||||||
gamesDat = NULL;
|
gamesDat = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Did we get a games.dat?
|
// If it's a game, did we get a games.dat?
|
||||||
if (ok && !hasGamesDat) {
|
if (((utilStricmp(types[packageType], "Game") == 0)) && (ok && !hasGamesDat)) {
|
||||||
ok = false;
|
ok = false;
|
||||||
utilSay("!!! Game has no games.dat: %s", de->d_name);
|
utilSay("!!! %s has no games.dat: %s", types[packageType], de->d_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpack it!
|
// Unpack it!
|
||||||
if (ok) {
|
if (ok) {
|
||||||
utilSay(">>> Unpacking Game: %s", de->d_name);
|
utilSay(">>> Unpacking %s: %s", types[packageType], de->d_name);
|
||||||
// https://github.com/libarchive/libarchive/wiki/Examples#user-content-A_Complete_Extractor
|
// https://github.com/libarchive/libarchive/wiki/Examples#user-content-A_Complete_Extractor
|
||||||
flags = ARCHIVE_EXTRACT_TIME;
|
flags = ARCHIVE_EXTRACT_TIME;
|
||||||
flags |= ARCHIVE_EXTRACT_PERM;
|
flags |= ARCHIVE_EXTRACT_PERM;
|
||||||
|
@ -1033,7 +1046,7 @@ void unpackGames(void) {
|
||||||
if (ok) unlink(de->d_name);
|
if (ok) unlink(de->d_name);
|
||||||
|
|
||||||
} // if ok
|
} // if ok
|
||||||
} // if extension is game
|
} // if extension is valid
|
||||||
} // if it's a file
|
} // if it's a file
|
||||||
} // while files
|
} // while files
|
||||||
|
|
||||||
|
|
56
src/singe.c
56
src/singe.c
|
@ -4623,31 +4623,27 @@ void startControllers(void) {
|
||||||
void startLuaContext(lua_State *L) {
|
void startLuaContext(lua_State *L) {
|
||||||
size_t length;
|
size_t length;
|
||||||
|
|
||||||
luaL_openlibs(L);
|
// What to do when bad things happen
|
||||||
lua_atpanic(L, luaError);
|
lua_atpanic(L, luaError);
|
||||||
|
|
||||||
// Get the package global table.
|
// Register the standard libraries
|
||||||
|
luaL_openlibs(L);
|
||||||
|
|
||||||
|
// Share configured controller DEAD_ZONE with the script
|
||||||
|
lua_pushinteger(L, _global.controllerDeadZone);
|
||||||
|
lua_setglobal(L, "SINGE_DEAD_ZONE");
|
||||||
|
|
||||||
|
// Get the package global table
|
||||||
lua_getglobal(L, "package");
|
lua_getglobal(L, "package");
|
||||||
// Get the list of searchers in the package table.
|
// Get the list of searchers in the package table
|
||||||
lua_getfield(L, -1, "searchers");
|
lua_getfield(L, -1, "searchers");
|
||||||
// Get the number of existing searchers in the table.
|
// Get the number of existing searchers in the table
|
||||||
length = lua_rawlen(L, -1);
|
length = lua_rawlen(L, -1);
|
||||||
// Add our own searcher to the list.
|
// Add our own searcher to the list
|
||||||
lua_pushcfunction(L, luaSearcher);
|
lua_pushcfunction(L, luaSearcher);
|
||||||
lua_rawseti(L, -2, length + 1);
|
lua_rawseti(L, -2, length + 1);
|
||||||
// Remove the seachers and the package tables from the stack.
|
// Remove the seachers and the package tables from the stack
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
|
|
||||||
/*
|
|
||||||
--[[
|
|
||||||
http = require("socket.http")
|
|
||||||
http.request{
|
|
||||||
url = "http://www.columbia.edu/~fdc/sample.html",
|
|
||||||
sink = ltn12.sink.file(io.stdout)
|
|
||||||
}
|
|
||||||
--]]
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4690,21 +4686,31 @@ void takeScreenshot(void) {
|
||||||
char filename[1024];
|
char filename[1024];
|
||||||
void *pixels = NULL;
|
void *pixels = NULL;
|
||||||
SDL_Surface *surface = NULL;
|
SDL_Surface *surface = NULL;
|
||||||
|
SDL_Surface *save = NULL;
|
||||||
SDL_Rect viewport;
|
SDL_Rect viewport;
|
||||||
|
|
||||||
while (x <= 999) {
|
while (x <= 9999) {
|
||||||
snprintf(filename, 1024, "%ssinge%03d.png", _global.conf->dataDir, x);
|
snprintf(filename, 1024, "%ssinge%03d.png", _global.conf->dataDir, x);
|
||||||
if (!utilFileExists(filename)) break;
|
if (!utilFileExists(filename)) break;
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
if (x > 999) utilDie("Seriously? You have 1000 screenshots in this folder? Remove some.");
|
if (x > 9999) utilDie("Seriously? You have 10,000 screenshots in this folder? Remove some.");
|
||||||
|
|
||||||
SDL_RenderGetViewport(_global.renderer, &viewport);
|
surface = SDL_GetWindowSurface(_global.window);
|
||||||
surface = SDL_CreateRGBSurface(0, viewport.w, viewport.h, 32, 0, 0, 0, 0);
|
pixels = (uint8_t *)malloc(surface->w * surface->h * surface->format->BytesPerPixel);
|
||||||
if (!surface) utilDie("%s", SDL_GetError());
|
SDL_RenderReadPixels(_global.renderer, &surface->clip_rect, surface->format->format, pixels, surface->w * surface->format->BytesPerPixel);
|
||||||
if (SDL_RenderReadPixels(_global.renderer, NULL, surface->format->format, surface->pixels, surface->pitch) != 0) utilDie("%s", SDL_GetError());
|
save = SDL_CreateRGBSurfaceFrom(pixels,
|
||||||
//***FIX*** This crashes with a SEGFAULT sometimes. Not sure why.
|
surface->w,
|
||||||
if (IMG_SavePNG(surface, filename) < 0) utilDie("%s", IMG_GetError());
|
surface->h,
|
||||||
|
surface->format->BitsPerPixel,
|
||||||
|
surface->w * surface->format->BytesPerPixel,
|
||||||
|
surface->format->Rmask,
|
||||||
|
surface->format->Gmask,
|
||||||
|
surface->format->Bmask,
|
||||||
|
surface->format->Amask
|
||||||
|
);
|
||||||
|
if (IMG_SavePNG(save, filename) < 0) utilDie("%s", IMG_GetError());
|
||||||
|
SDL_FreeSurface(save);
|
||||||
SDL_FreeSurface(surface);
|
SDL_FreeSurface(surface);
|
||||||
free(pixels);
|
free(pixels);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue