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
|
||||
\__ \| || .` | (_ | _| 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
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
-- Singe 2.xx Features -------------------------------------------------------
|
||||
|
||||
|
||||
SINGE_FRAMEWORK_VERSION = 2.10
|
||||
|
||||
|
||||
function utilDeepCopy(orig)
|
||||
local orig_type = type(orig)
|
||||
local copy
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
53
src/main.c
53
src/main.c
|
@ -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
|
||||
|
||||
|
|
60
src/singe.c
60
src/singe.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue