Commit 282c4e8a authored by Andre Leiradella's avatar Andre Leiradella
Browse files

added auto-configuration to the core; games from the bob's stuff collection...

added auto-configuration to the core; games from the bob's stuff collection were added to the game database
parent 5e5dd844
......@@ -31,11 +31,11 @@ The only core option available on the frontend is:
* Tape Fast Load (enabled|disabled): Instantly loads files if enabled, or disabled it to see the moving horizontal lines while the game loads
* 8K-16K Contents (ROM shadow|RAM|dK'tronics 4K Graphics ROM + 4K RAM): Selects the contents of memory addresses between 8192 and 16383, a shadow copy of the ROM, 8K of RAM, or [dK'tronics 4K ROM plus 4K of RAM](http://www.fruitcake.plus.com/Sinclair/ZX81/Chroma/ChromaInterface_Software_CharacterSetROM.htm)
* High Resolution (none|WRX): Enables WRX high resolution
* Emulate Chroma 81 (disabled|enabled): Enable the [Chroma 81](http://www.fruitcake.plus.com/Sinclair/ZX81/Chroma/ChromaInterface.htm) interface
* High Resolution (auto|none|WRX): Enables WRX high resolution
* Emulate Chroma 81 (auto|disabled|enabled): Enable the [Chroma 81](http://www.fruitcake.plus.com/Sinclair/ZX81/Chroma/ChromaInterface.htm) interface
* Video Presets (clean|tv|noisy): Change how the video is emulated (if Chroma 81 is enabled, the video is set to "clean" regardless of this option)
* Sound emulation (none|Zon X-81): Enables sound emulation
* Joypad Up, Down, Left, Right and Fire mappings (default|new line|shift|space|.|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z): Maps a joypad button to a keyboard key, defaults are the cursor keys and 0 to fire
* Sound emulation (auto|none|Zon X-81): Enables sound emulation
* Joypad button mappings (up, down, left, right, a, b, x, y, l, r, l2, r2): (auto|default|new line|shift|space|.|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z): Maps a joypad button to a keyboard key, defaults are the cursor keys for the directional pad and '0' to all the other buttons
* Transparent Keyboard Overlay (enabled|disabled): If the keyboard overlay is transparent or opaque
* Time to Release Key in ms (500|1000|100|300): How many milliseconds to wait before releasing the key pressed using the keyboard overlay
......@@ -49,7 +49,7 @@ The `p` and the `tzx` formats are supported.
## Save States
Save states are supported, but are likely to change when more machines are emulated.
Save states are supported, but the format is likely to change when more machines are emulated.
## Setup
......@@ -57,6 +57,14 @@ Save states are supported, but are likely to change when more machines are emula
1. Copy the resulting `81_libretro.dll` or `81_libretro.so` into the `cores` folder of your libretro frontend
1. Profit!
## Game Database
Since configuring the core for each game can be a tedious task, **81-libretro** now features auto-configuration. Games support auto-configuration are listed in the `src/gamedb/gamedb.json` file, along with some information and the configuration required to play them.
Currently, there's no way to change the auto-configuration settings short of recompiling the core after making the changes. If you feel the provided auto-configuration could be better or has bugs, please open an issue and I'll take a look.
The core comes with auto-configuration for all homebrew games from [Bob's Stuff](http://www.bobs-stuff.co.uk/zx81.html). If you want to add an auto-configuration for a missing game, please submit a push request with changes only to the `gamedb.json` file.
## Thanks
Erik Olofsen for help with:
......@@ -66,6 +74,8 @@ Erik Olofsen for help with:
* `tzx` support
* Zon X-81 sound emulation
See also the `colorized` subfolder.
## Versions
Versions that are being used to build and test **81-libretro**:
......
......@@ -39,6 +39,7 @@ SOURCES_C += $(CORE_DIR)/src/keybovl.c
SOURCES_C += $(CORE_DIR)/src/eo.c
SOURCES_C += $(CORE_DIR)/src/kbds/zx81kbd.c
SOURCES_C += $(CORE_DIR)/src/version.c
SOURCES_C += $(CORE_DIR)/src/gamedb/sha1.c
SOURCES_CXX += $(CORE_DIR)/src/compat.cpp
ROMS += $(CORE_DIR)/bin/ROM/zx81.rom
......
......@@ -4,7 +4,7 @@ else
TARGET = 81_libretro$(SOEXT)
endif
DEFINES +=
DEFINES += SHA1_REMOVE_MAIN=1
CFLAGS += -Wall
CXXFLAGS += -Wall
LDFLAGS +=
......
#include <coreopt.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
int coreopt( retro_environment_t env_cb, const struct retro_variable* vars, const char* opt_name, const char** opt_value )
#include <libretro.h>
#include <gamedb/db.inl>
static int getindex( const char* options, const char* value )
{
const char* option = options;
size_t opt_len = strlen( value );
for ( ;; )
{
option = strstr( option, value );
if ( !option )
{
break;
}
if ( ( option == options || option[ -1 ] == '|' ) && ( option[ opt_len ] == 0 || option[ opt_len ] == '|' ) )
{
int pipes = 0;
while ( option > options )
{
pipes += *--option == '|';
}
return pipes;
}
option += opt_len;
}
return -1;
}
static int coreopt_env( retro_environment_t env_cb, const char* options, const char* opt_name, const char** opt_value )
{
struct retro_variable user_opt;
user_opt.key = opt_name;
user_opt.value = NULL;
if ( env_cb( RETRO_ENVIRONMENT_GET_VARIABLE, &user_opt ) && user_opt.value )
{
*opt_value = user_opt.value;
return getindex( options, user_opt.value );
}
return -1;
}
static int compare_hashes( const void* e1, const void* e2 )
{
const overrides_t* o1 = (const overrides_t*)e1;
const overrides_t* o2 = (const overrides_t*)e2;
const uint32_t* s1 = o1->sha1;
const uint32_t* s2 = o2->sha1;
const uint32_t* end1 = s1 + sizeof( o1->sha1 ) / sizeof( o1->sha1[ 1 ] ) - 1;
while ( s1 < end1 )
{
if ( *s1 < *s2 )
{
return -1;
}
else if ( *s1 > *s2 )
{
return 1;
}
s1++, s2++;
}
if ( *s1 < *s2 )
{
return -1;
}
else if ( *s1 > *s2 )
{
return 1;
}
else
{
return 0;
}
}
static int compare_vars( const void* e1, const void* e2 )
{
const struct retro_variable* v1 = (struct retro_variable*)e1;
const struct retro_variable* v2 = (struct retro_variable*)e2;
return strcmp( v1->key, v2->key );
}
static int coreopt_auto( uint32_t* sha1, const char* options, const char* opt_name, const char** opt_value )
{
overrides_t key;
memcpy( &key.sha1, sha1, sizeof( key.sha1 ) );
overrides_t* overrides = bsearch( &key, s_overrides, sizeof( s_overrides ) / sizeof( s_overrides[ 0 ] ), sizeof( s_overrides[ 0 ] ), compare_hashes );
if ( overrides )
{
struct retro_variable key;
key.key = opt_name;
struct retro_variable* var = bsearch( &key, overrides->vars, sizeof( overrides->vars ) / sizeof( overrides->vars[ 0 ] ), sizeof( overrides->vars[ 0 ] ), compare_vars );
if ( var )
{
*opt_value = var->value;
return getindex( options, var->value );
}
}
return -1;
}
int coreopt( retro_environment_t env_cb, const struct retro_variable* vars, uint32_t* sha1, const char* opt_name, const char** opt_value )
{
const struct retro_variable* var = vars;
......@@ -15,55 +138,35 @@ int coreopt( retro_environment_t env_cb, const struct retro_variable* vars, cons
++var;
}
int index = -1;
const char* value;
if ( var->key )
{
const char* first_opt = strchr( var->value, ';' );
const char* options = strchr( var->value, ';' );
if ( first_opt )
if ( options )
{
while ( *++first_opt == ' ' ) /* do nothing */;
struct retro_variable user_opt;
user_opt.key = var->key;
user_opt.value = NULL;
if ( env_cb( RETRO_ENVIRONMENT_GET_VARIABLE, &user_opt ) && user_opt.value )
while ( *++options == ' ' ) /* do nothing */;
index = coreopt_env( env_cb, options, opt_name, &value );
if ( !strcmp( value, "auto" ) && sha1 )
{
const char* option = first_opt;
size_t opt_len = strlen( user_opt.value );
for ( ;; )
int index2 = coreopt_auto( sha1, options, opt_name, &value );
if ( index2 != -1 )
{
option = strstr( option, user_opt.value );
if ( !option )
{
break;
}
if ( ( option == first_opt || option[ -1 ] == '|' ) && ( option[ opt_len ] == 0 || option[ opt_len ] == '|' ) )
{
int pipes = 0;
while ( option > first_opt )
{
pipes += *--option == '|';
}
if ( opt_value )
{
*opt_value = user_opt.value;
}
return pipes;
}
option += opt_len;
index = index2;
}
}
}
}
return -1;
if ( opt_value )
{
*opt_value = value;
}
return index;
}
......@@ -2,6 +2,7 @@
#define COREOPT_H
#include <libretro.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
......@@ -11,7 +12,7 @@ extern "C" {
* retro_variable. Returns -1 if the option wasn't found in the list or if
* opt_name is not a valid option.
*/
int coreopt( retro_environment_t env_cb, const struct retro_variable* vars, const char* opt_name, const char** opt_value );
int coreopt( retro_environment_t env_cb, const struct retro_variable* vars, uint32_t* sha1, const char* opt_name, const char** opt_value );
#ifdef __cplusplus
}
......
#include <stdint.h>
#include <libretro.h>
typedef struct
{
uint32_t sha1[ 5 ];
struct retro_variable vars[ 15 ];
}
overrides_t;
static overrides_t s_overrides[] =
{
{
/* Virus, 2010, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x0f7a62faU, 0x0d575d59U, 0x5857aafdU, 0xefc78b33U, 0xa207be91U },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "0" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "6" },
{ "81_joypad_l", "c" },
{ "81_joypad_l2", "q" },
{ "81_joypad_left", "5" },
{ "81_joypad_r", "r" },
{ "81_joypad_r2", "p" },
{ "81_joypad_right", "8" },
{ "81_joypad_up", "7" },
{ "81_joypad_x", "default" },
{ "81_joypad_y", "s" },
{ "81_sound", "none" },
},
},
{
/* Impact!, 2012, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x11c5fe8dU, 0x44763d94U, 0xa3eedf59U, 0x7b6daf04U, 0x38364e22U },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "0" },
{ "81_joypad_b", "h" },
{ "81_joypad_down", "6" },
{ "81_joypad_l", "default" },
{ "81_joypad_l2", "default" },
{ "81_joypad_left", "5" },
{ "81_joypad_r", "default" },
{ "81_joypad_r2", "default" },
{ "81_joypad_right", "8" },
{ "81_joypad_up", "7" },
{ "81_joypad_x", "default" },
{ "81_joypad_y", "s" },
{ "81_sound", "none" },
},
},
{
/* U-Bend, 2015, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x17c49e4aU, 0xc9179ed0U, 0xd08c18c6U, 0x71f3db53U, 0x43bad3ccU },
{
{ "81_chroma_81", "enabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "l" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "m" },
{ "81_joypad_l", "c" },
{ "81_joypad_l2", "default" },
{ "81_joypad_left", "z" },
{ "81_joypad_r", "default" },
{ "81_joypad_r2", "default" },
{ "81_joypad_right", "x" },
{ "81_joypad_up", "k" },
{ "81_joypad_x", "default" },
{ "81_joypad_y", "p" },
{ "81_sound", "none" },
},
},
{
/* Ant Attack, 2013, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x1b4fc9ebU, 0x5cd3373aU, 0x9986fcd3U, 0x95d0117cU, 0x6b3c4718U },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "c" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "default" },
{ "81_joypad_l", "f" },
{ "81_joypad_l2", "g" },
{ "81_joypad_left", "z" },
{ "81_joypad_r", "s" },
{ "81_joypad_r2", "d" },
{ "81_joypad_right", "x" },
{ "81_joypad_up", "v" },
{ "81_joypad_x", "g" },
{ "81_joypad_y", "b" },
{ "81_sound", "none" },
},
},
{
/* Pandemic, 2014, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x28afa426U, 0xe660186aU, 0x1c1c56d7U, 0x4251b604U, 0xe25bb2a1U },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "l" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "m" },
{ "81_joypad_l", "c" },
{ "81_joypad_l2", "m" },
{ "81_joypad_left", "z" },
{ "81_joypad_r", "default" },
{ "81_joypad_r2", "p" },
{ "81_joypad_right", "x" },
{ "81_joypad_up", "k" },
{ "81_joypad_x", "r" },
{ "81_joypad_y", "s" },
{ "81_sound", "none" },
},
},
{
/* Boulder Logic, 2011, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x3c74569eU, 0xf70327ecU, 0xf17db982U, 0xef92b455U, 0x7c17b538U },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "0" },
{ "81_joypad_b", "p" },
{ "81_joypad_down", "6" },
{ "81_joypad_l", "l" },
{ "81_joypad_l2", "q" },
{ "81_joypad_left", "5" },
{ "81_joypad_r", "r" },
{ "81_joypad_r2", "p" },
{ "81_joypad_right", "8" },
{ "81_joypad_up", "7" },
{ "81_joypad_x", "c" },
{ "81_joypad_y", "s" },
{ "81_sound", "none" },
},
},
{
/* Miner Man, 2011, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x54db0c53U, 0x05f89a62U, 0x9a19e5e1U, 0x07f34e65U, 0xd2bfbd93U },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "default" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "6" },
{ "81_joypad_l", "l" },
{ "81_joypad_l2", "q" },
{ "81_joypad_left", "5" },
{ "81_joypad_r", "r" },
{ "81_joypad_r2", "p" },
{ "81_joypad_right", "8" },
{ "81_joypad_up", "7" },
{ "81_joypad_x", "c" },
{ "81_joypad_y", "s" },
{ "81_sound", "none" },
},
},
{
/* Noir Shapes, 2012, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x5642ddd9U, 0x4d1c6649U, 0xbc2e01caU, 0x112b7d76U, 0xf376c826U },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "0" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "6" },
{ "81_joypad_l", "l" },
{ "81_joypad_l2", "q" },
{ "81_joypad_left", "5" },
{ "81_joypad_r", "r" },
{ "81_joypad_r2", "default" },
{ "81_joypad_right", "8" },
{ "81_joypad_up", "7" },
{ "81_joypad_x", "c" },
{ "81_joypad_y", "s" },
{ "81_sound", "none" },
},
},
{
/* ZXagon, 2014, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x59dae098U, 0x079f00c3U, 0xe72ec464U, 0x7ccbd2edU, 0x99b979f1U },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "default" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "default" },
{ "81_joypad_l", "default" },
{ "81_joypad_l2", "default" },
{ "81_joypad_left", "z" },
{ "81_joypad_r", "default" },
{ "81_joypad_r2", "default" },
{ "81_joypad_right", "x" },
{ "81_joypad_up", "default" },
{ "81_joypad_x", "default" },
{ "81_joypad_y", "s" },
{ "81_sound", "none" },
},
},
{
/* Rebound, 2014, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x6abc2d4dU, 0xe5bb40aaU, 0xc8f3703eU, 0x5c33a9ceU, 0x3a31be75U },
{
{ "81_chroma_81", "enabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "l" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "default" },
{ "81_joypad_l", "default" },
{ "81_joypad_l2", "default" },
{ "81_joypad_left", "z" },
{ "81_joypad_r", "default" },
{ "81_joypad_r2", "p" },
{ "81_joypad_right", "x" },
{ "81_joypad_up", "default" },
{ "81_joypad_x", "default" },
{ "81_joypad_y", "s" },
{ "81_sound", "none" },
},
},
{
/* One Little Ghost, 2012, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x7bd65421U, 0x239915daU, 0xd4137206U, 0xc0c7572fU, 0x31c6ac5aU },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "default" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "5" },
{ "81_joypad_l", "default" },
{ "81_joypad_l2", "default" },
{ "81_joypad_left", "7" },
{ "81_joypad_r", "default" },
{ "81_joypad_r2", "default" },
{ "81_joypad_right", "6" },
{ "81_joypad_up", "8" },
{ "81_joypad_x", "default" },
{ "81_joypad_y", "p" },
{ "81_sound", "none" },
},
},
{
/* Domin8tr1s, 2010, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x8e8ee9c4U, 0xfc589f38U, 0x6596ef3bU, 0x3e8fab9bU, 0x9ee799efU },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "0" },
{ "81_joypad_b", "6" },
{ "81_joypad_down", "default" },
{ "81_joypad_l", "s" },
{ "81_joypad_l2", "w" },
{ "81_joypad_left", "5" },
{ "81_joypad_r", "i" },
{ "81_joypad_r2", "h" },
{ "81_joypad_right", "8" },
{ "81_joypad_up", "default" },
{ "81_joypad_x", "default" },
{ "81_joypad_y", "n" },
{ "81_sound", "none" },
},
},
{
/* CroZXy Road, 2015, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0x98ef4e7aU, 0x24f87c9dU, 0x253da0dcU, 0x68698850U, 0xdcd2752fU },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "default" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "6" },
{ "81_joypad_l", "default" },
{ "81_joypad_l2", "m" },
{ "81_joypad_left", "5" },
{ "81_joypad_r", "default" },
{ "81_joypad_r2", "default" },
{ "81_joypad_right", "8" },
{ "81_joypad_up", "7" },
{ "81_joypad_x", "default" },
{ "81_joypad_y", "p" },
{ "81_sound", "none" },
},
},
{
/* Quack!, 2014, Bob Smith, http://www.bobs-stuff.co.uk/zx81.html*/
{ 0xd7e40348U, 0xcc9181d2U, 0x033c63e1U, 0x7e8fe075U, 0x89e90c64U },
{
{ "81_chroma_81", "disabled" },
{ "81_highres", "none" },
{ "81_joypad_a", "0" },
{ "81_joypad_b", "default" },
{ "81_joypad_down", "6" },
{ "81_joypad_l", "default" },
{ "81_joypad_l2", "default" },
{ "81_joypad_left", "5" },
{ "81_joypad_r", "default" },
{ "81_joypad_r2", "default" },
{ "81_joypad_right", "8" },
{ "81_joypad_up", "7" },
{ "81_joypad_x", "default" },
{ "81_joypad_y", "default" },
{ "81_sound", "none" },
},
},
};
local json = require 'dkjson'
local function map( game, button )
if game.settings.mapping[ button ] then
return game.settings.mapping[ button ].key
else
return 'default'
end
end
local function label( game, button )
if game.settings.mapping[ button ] then
return game.settings.mapping[ button ].label
else
return ''
end
end
local db = io.open( 'gamedb.json' ):read( '*a' )
local obj, pos, err = json.decode( db, 1, nil )
if err then
error( err )
end
io.write( '#include <stdint.h>\n' )
io.write( '#include <libretro.h>\n\n' )
io.write( 'typedef struct\n' )
io.write( '{\n' )
io.write( ' uint32_t sha1[ 5 ];\n' )
io.write( ' struct retro_variable vars[ 15 ];\n' )
io.write( '}\n' )
io.write( 'overrides_t;\n\n' )
io.write( 'static overrides_t s_overrides[] =\n' )
io.write( '{\n' )
table.sort( obj.games, function (e1, e2) return e1.sha1 < e2.sha1 end )
for i = 1, #obj.games do
local game = obj.games[ i ]
io.write( ' {\n' )
io.write( ' /* ', game.name, ', ', game.year, ', ', game.author, ', ', game.url, '*/\n' )
io.write( ' { ' )