CHANGELOG added. Menu now naturally sorts names. Tool and Patch package types added to auto-installer.

This commit is contained in:
Scott Duensing 2023-11-19 21:49:09 -06:00
parent 881fb4de3f
commit 448c58e20e
6 changed files with 140 additions and 49 deletions

57
CHANGELOG.txt Normal file
View 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.

View file

@ -40,7 +40,7 @@ COMMAND LINE
___ ___ _ _ ___ ___
/ __|_ _| \| |/ __| __| Somewhat Interactive Nostalgic Game Engine v2.10
\__ \| || .` | (_ | _| 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}
@ -54,6 +54,7 @@ Usage: Singe-v2.10-Windows-x86_64.exe [OPTIONS] scriptName{.singe}
-l, --volume_vldp=PERCENT specify laserdisc volume in percent
-m, --nomouse disable mouse
-n, --nocrosshair request game not display gun crosshairs
-p, --program trace Singe execution to screen and file
-s, --nosound, --mutesound mutes all sound
-t, --trace trace script execution to screen and file
-u, --stretch use ugly stretched video

View file

@ -24,6 +24,9 @@
-- Singe 2.xx Features -------------------------------------------------------
SINGE_FRAMEWORK_VERSION = 2.10
function utilDeepCopy(orig)
local orig_type = type(orig)
local copy

View file

@ -26,8 +26,19 @@ dofile("Singe/Framework.singe")
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)
return a.TITLE < b.TITLE
return cleanTitle(a.TITLE) < cleanTitle(b.TITLE)
end

View file

@ -871,14 +871,28 @@ void unpackGames(void) {
char *extension;
char *filename;
char *toplevel = NULL;
int packageType = -1;
char *types[] = { "Game", "Tool", "Patch", 0 };
char *badFilenames[] = { "Framework.singe", 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.");
while ((de = readdir(dir)) != NULL) {
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();
count++;
ok = true;
@ -891,7 +905,7 @@ void unpackGames(void) {
archive_read_support_format_all(a);
r = archive_read_open_filename(a, de->d_name, 10240);
if (r != ARCHIVE_OK) {
utilSay("!!! Cannot read game: %s", de->d_name);
utilSay("!!! Cannot read %s: %s", types[packageType], de->d_name);
ok = false;
} else {
while (archive_read_next_header(a, &entry) == ARCHIVE_OK && ok) {
@ -899,36 +913,35 @@ void unpackGames(void) {
filename = utilGetLastPathComponent(e);
extension = utilGetFileExtension(e);
// Do we have a top level folder name yet?
if (toplevel == NULL) {
// If not a patch, do we have a top level folder name yet?
if ((utilStricmp(types[packageType], "Patch") != 0) && (toplevel == NULL)) {
// No. Is this a folder?
if (strstr(e, "/") == NULL) {
// No. BAD! No files in the root!
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 {
// Remember this folder.
toplevel = strdup(e);
gamesDat = utilCreateString("%sgames.dat", toplevel);
}
} else {
// Yes, we have a top level. Is this entry inside it?
if (!utilStartsWith(e, toplevel)) {
// If this is not a patch, check for a top level. Is this entry inside it?
if ((utilStricmp(types[packageType], "Patch") != 0) && (!utilStartsWith(e, toplevel))) {
// No. BAD! Everything has to be in the top level.
ok = false;
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 {
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 {
// Is this a forbidden file?
x = 0;
while (badFilenames[x] != NULL && ok) {
if (utilStricmp(filename, badFilenames[x]) == 0) {
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++;
}
@ -937,14 +950,14 @@ void unpackGames(void) {
while (badExtensions[x] != NULL && ok) {
if (utilStricmp(extension, badExtensions[x]) == 0) {
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++;
}
// No extension, starts with 'singe' - could be unix binary.
if (ok && strlen(extension) == 0 && utilStartsWith(filename, "singe")) {
// Not a patch, no extension, starts with 'singe' - could be unix binary.
if ((utilStricmp(types[packageType], "Patch") != 0) && (ok && strlen(extension) == 0 && utilStartsWith(filename, "singe"))) {
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?
if (ok && !hasGamesDat && utilStricmp(e, gamesDat) == 0) hasGamesDat = true;
@ -963,16 +976,16 @@ void unpackGames(void) {
gamesDat = NULL;
}
// Did we get a games.dat?
if (ok && !hasGamesDat) {
// If it's a game, did we get a games.dat?
if (((utilStricmp(types[packageType], "Game") == 0)) && (ok && !hasGamesDat)) {
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!
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
flags = ARCHIVE_EXTRACT_TIME;
flags |= ARCHIVE_EXTRACT_PERM;
@ -1033,7 +1046,7 @@ void unpackGames(void) {
if (ok) unlink(de->d_name);
} // if ok
} // if extension is game
} // if extension is valid
} // if it's a file
} // while files

View file

@ -4623,31 +4623,27 @@ void startControllers(void) {
void startLuaContext(lua_State *L) {
size_t length;
luaL_openlibs(L);
// What to do when bad things happen
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");
// Get the list of searchers in the package table.
// Get the list of searchers in the package table
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);
// Add our own searcher to the list.
// Add our own searcher to the list
lua_pushcfunction(L, luaSearcher);
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);
/*
--[[
http = require("socket.http")
http.request{
url = "http://www.columbia.edu/~fdc/sample.html",
sink = ltn12.sink.file(io.stdout)
}
--]]
*/
}
@ -4690,23 +4686,33 @@ void takeScreenshot(void) {
char filename[1024];
void *pixels = NULL;
SDL_Surface *surface = NULL;
SDL_Surface *save = NULL;
SDL_Rect viewport;
while (x <= 999) {
while (x <= 9999) {
snprintf(filename, 1024, "%ssinge%03d.png", _global.conf->dataDir, x);
if (!utilFileExists(filename)) break;
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_CreateRGBSurface(0, viewport.w, viewport.h, 32, 0, 0, 0, 0);
if (!surface) utilDie("%s", SDL_GetError());
if (SDL_RenderReadPixels(_global.renderer, NULL, surface->format->format, surface->pixels, surface->pitch) != 0) utilDie("%s", SDL_GetError());
//***FIX*** This crashes with a SEGFAULT sometimes. Not sure why.
if (IMG_SavePNG(surface, filename) < 0) utilDie("%s", IMG_GetError());
SDL_FreeSurface(surface);
free(pixels);
surface = SDL_GetWindowSurface(_global.window);
pixels = (uint8_t *)malloc(surface->w * surface->h * surface->format->BytesPerPixel);
SDL_RenderReadPixels(_global.renderer, &surface->clip_rect, surface->format->format, pixels, surface->w * surface->format->BytesPerPixel);
save = SDL_CreateRGBSurfaceFrom(pixels,
surface->w,
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);
free(pixels);
}