Merge remote-tracking branch 'remotes/origin/master' into feature/dbg-save-as-dialog
|
@ -11,11 +11,12 @@ out
|
|||
out.pgo
|
||||
out.pgen
|
||||
stella
|
||||
stella-pgo
|
||||
stella-pgo-generate
|
||||
stella-pgo
|
||||
stella-pgo-generate
|
||||
*.diff
|
||||
project.xcworkspace/
|
||||
xcuserdata/
|
||||
.DS_Store
|
||||
build/
|
||||
src/macosx/M6502.ins
|
||||
*.dSYM
|
||||
|
@ -33,4 +34,7 @@ src/**/*.vspx
|
|||
src/**/**.pdb
|
||||
Stella.xcscheme
|
||||
src/tools/fonts/*
|
||||
|
||||
*.sym
|
||||
a.out
|
||||
*.json
|
||||
*.sqlite3
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
.core-defs:
|
||||
variables:
|
||||
JNI_PATH: src/libretro
|
||||
MAKEFILE_PATH: src/libretro
|
||||
CORENAME: stella
|
||||
|
||||
include:
|
||||
|
@ -23,46 +24,37 @@ stages:
|
|||
#Desktop
|
||||
libretro-build-linux-x64:
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-linux-x64-make-default
|
||||
variables:
|
||||
MAKEFILE_PATH: src/libretro
|
||||
MAKEFILE: Makefile
|
||||
- .core-defs
|
||||
|
||||
libretro-build-windows-x64:
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-windows-x64-mingw-make-default
|
||||
variables:
|
||||
MAKEFILE_PATH: src/libretro
|
||||
MAKEFILE: Makefile
|
||||
- .core-defs
|
||||
|
||||
# Android
|
||||
android-armeabi-v7a:
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-android-jni-armeabi-v7a
|
||||
- .core-defs
|
||||
|
||||
android-arm64-v8a:
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-android-jni-arm64-v8a
|
||||
- .core-defs
|
||||
|
||||
android-x86_64:
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-android-jni-x86_64
|
||||
- .core-defs
|
||||
|
||||
android-x86:
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-android-jni-x86
|
||||
- .core-defs
|
||||
|
||||
# Static
|
||||
libretro-build-libnx-aarch64:
|
||||
extends:
|
||||
- .core-defs
|
||||
- .libretro-libnx-static-retroarch-master
|
||||
variables:
|
||||
MAKEFILE_PATH: src/libretro
|
||||
MAKEFILE: Makefile
|
||||
- .core-defs
|
||||
|
|
24
Changes.txt
|
@ -14,23 +14,35 @@
|
|||
|
||||
6.4 to 6.5 (December XX, 2020)
|
||||
|
||||
* Enhanced cut/copy/paste for text editing. (TODO: PromptWidget)
|
||||
* Added high scores saving.
|
||||
|
||||
* Added undo and redo to text editing. (TODO: PromptWidget)
|
||||
* Improved text editing functionality (except PromptWidget):
|
||||
- Enhanced selection and cut/copy/paste from keyboard.
|
||||
- Added undo and redo support.
|
||||
- Added mouse support (selection, cut/copy/paste).
|
||||
- All actions have keyboard shortcuts.
|
||||
|
||||
* Added wildcard support to launcher dialog filter.
|
||||
|
||||
* Added option to search subdirectories in launcher.
|
||||
* Various improvements to the ROM launcher:
|
||||
- Added wildcard support to the dialog filter
|
||||
- Added option to search subdirectories
|
||||
|
||||
* Added static tooltips to some UI items.
|
||||
|
||||
* Added dynamic tooltips to most debugger items.
|
||||
|
||||
* Added sound to Time Machine playback.
|
||||
|
||||
* Extended global hotkeys for input devices & ports settings.
|
||||
|
||||
* Increased sample size for CDFJ+.
|
||||
|
||||
* Fixed autofire bug for trackball controllers.
|
||||
|
||||
* Codebase now uses C++17 features.
|
||||
* Fixed Stelladaptor/2600'daptor devices sometimes not being assigned
|
||||
correct default mappings.
|
||||
|
||||
* Codebase now uses C++17 features, which means a minimum of gcc7
|
||||
or clang5 for Linux/Mac, and Visual Studio 2019 for Windows.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
|
|
@ -580,10 +580,6 @@ else
|
|||
darwin*)
|
||||
DEFINES="$DEFINES -DUNIX -DDARWIN"
|
||||
_host_os=darwin
|
||||
if test "$have_clang" = yes; then
|
||||
CXXFLAGS="$CXXFLAGS -Wno-documentation-unknown-command -Wno-documentation-pedantic -Wno-poison-system-directories"
|
||||
CXXFLAGS="$CXXFLAGS -Wno-unknown-warning-option"
|
||||
fi
|
||||
;;
|
||||
irix*)
|
||||
DEFINES="$DEFINES -DUNIX"
|
||||
|
|
|
@ -223,7 +223,7 @@ present in the debugger):</p>
|
|||
<p>For space reasons, the Prompt, TIA, I/O and Audio displays are split into
|
||||
4 tabs, only one of which is visible at a time. You can use the mouse or
|
||||
keyboard to select which tab you want to view. Control/Cmd + Tab cycles between
|
||||
tabs from left-to-right, Shift + Control/Cmd + Tab cycles right-to-left.
|
||||
tabs from left-to-right, Shift-Control/Cmd + Tab cycles right-to-left.
|
||||
Pressing Tab (or Shift + Tab) cycles between widgets in the current tab (except
|
||||
for in the Prompt Tab, where 'tab' is used for something else).</p>
|
||||
|
||||
|
@ -339,7 +339,7 @@ previous rewind operation. The rewind buffer is 100 levels deep by default, the
|
|||
size can be configured e.g. in the
|
||||
<b><a href="index.html#Debugger">Developer Settings</a> - Time Machine</b> dialog.<p>
|
||||
|
||||
<p>The other operations are Step, Trace, Scan+1, Frame+1 and Run.</p>
|
||||
<p>The other operations are Step, Trace, Scan +1, Frame +1 and Run.</p>
|
||||
|
||||
<p>You can also use the buttons from anywhere in the GUI via hotkeys.</p>
|
||||
<p>
|
||||
|
@ -349,48 +349,48 @@ size can be configured e.g. in the
|
|||
<th>Function</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Control-s</td>
|
||||
<td>Control + S</td>
|
||||
<td>Step</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Control-t</td>
|
||||
<td>Control + T</td>
|
||||
<td>Trace</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Control-L</td>
|
||||
<td>Scan+1</td>
|
||||
<td>Control + L</td>
|
||||
<td>Scan +1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Control-f</td>
|
||||
<td>Frame+1</td>
|
||||
<td>Control + F</td>
|
||||
<td>Frame +1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alt-Left arrow</td>
|
||||
<td>Alt + Left arrow</td>
|
||||
<td>Rewind 1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shift-Alt-Left arrow</td>
|
||||
<td>Shift-Alt + Left arrow</td>
|
||||
<td>Rewind 10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alt-Down arrow</td>
|
||||
<td>Alt + Down arrow</td>
|
||||
<td>Rewind all</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alt-Right arrow</td>
|
||||
<td>Alt + Right arrow</td>
|
||||
<td>Unwind 1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shift-Alt-Right arrow</td>
|
||||
<td>Shift-Alt + Right arrow</td>
|
||||
<td>Unwind 10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alt-Up arrow</td>
|
||||
<td>Alt + Up arrow</td>
|
||||
<td>Unwind all</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Backquote (`)</td>
|
||||
<td>Run</td>
|
||||
<td>Run, exits debugger</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
@ -433,18 +433,18 @@ Bash-style commands are also supported:</p>
|
|||
<tr><td>End</td><td>Move cursor to end of line</td></tr>
|
||||
<tr><td>Delete</td><td>Remove character to right of cursor</td></tr>
|
||||
<tr><td>Backspace</td><td>Remove character to left of cursor</td></tr>
|
||||
<tr><td>Control-a</td><td>Same function as 'Home'</td></tr>
|
||||
<tr><td>Control-e</td><td>Same function as 'End'</td></tr>
|
||||
<tr><td>Control-d</td><td>Same function as 'Delete'</td></tr>
|
||||
<tr><td>Control-k</td><td>Remove all characters from cursor to end of line</td></tr>
|
||||
<tr><td>Control-u</td><td>Remove all characters from cursor to beginning of line</td></tr>
|
||||
<tr><td>Control-w</td><td>Remove entire word to left of cursor</td></tr>
|
||||
<tr><td>Shift-PgUp</td><td>Scroll up through previous commands one screen/page</td></tr>
|
||||
<tr><td>Shift-PgDown</td><td>Scroll down through previous commands one screen/page</td></tr>
|
||||
<tr><td>Shift-Up</td><td>Scroll up through previous commands one line</td></tr>
|
||||
<tr><td>Shift-Down</td><td>Scroll down through previous commands one line</td></tr>
|
||||
<tr><td>Shift-Home</td><td>Scroll to beginning of commands</td></tr>
|
||||
<tr><td>Shift-End</td><td>Scroll to end of commands</td></tr>
|
||||
<tr><td>Control + A</td><td>Same function as 'Home'</td></tr>
|
||||
<tr><td>Control + E</td><td>Same function as 'End'</td></tr>
|
||||
<tr><td>Control + D</td><td>Same function as 'Delete'</td></tr>
|
||||
<tr><td>Control + K</td><td>Remove all characters from cursor to end of line</td></tr>
|
||||
<tr><td>Control + U</td><td>Remove all characters from cursor to beginning of line</td></tr>
|
||||
<tr><td>Control + W</td><td>Remove entire word to left of cursor</td></tr>
|
||||
<tr><td>Shift + PgUp</td><td>Scroll up through previous commands one screen/page</td></tr>
|
||||
<tr><td>Shift + PgDown</td><td>Scroll down through previous commands one screen/page</td></tr>
|
||||
<tr><td>Shift + Up</td><td>Scroll up through previous commands one line</td></tr>
|
||||
<tr><td>Shift + Down</td><td>Scroll down through previous commands one line</td></tr>
|
||||
<tr><td>Shift + Home</td><td>Scroll to beginning of commands</td></tr>
|
||||
<tr><td>Shift + End</td><td>Scroll to end of commands</td></tr>
|
||||
</table>
|
||||
<p>You can also scroll with the mouse. Copy and paste is not yet supported.</p>
|
||||
|
||||
|
@ -989,12 +989,12 @@ clearsavestateifs - Clear all savestate points
|
|||
runto - Run until string xx in disassembly
|
||||
runtopc - Run until PC is set to value xx
|
||||
s - Set Stack Pointer to value xx
|
||||
save - Save breaks, watches, traps and functions to file xx
|
||||
saveaccess - Save access counters to CSV file
|
||||
save - Save breaks, watches, traps and functions to file xx (use ? for file dialog)
|
||||
saveaccess - Save access counters to CSV file (use ? for file dialog)
|
||||
saveconfig - Save DiStella config file (with default name)
|
||||
savedis - Save DiStella disassembly (with default name)
|
||||
saverom - Save (possibly patched) ROM (with default name)
|
||||
saveses - Save console session (with default name)
|
||||
savedis - Save DiStella disassembly (use ? for file dialog)
|
||||
saverom - Save (possibly patched) ROM (use ? for file dialog)
|
||||
saveses - Save console session (use ? for file dialog)
|
||||
savesnap - Save current TIA image to PNG file
|
||||
saveallstates - Save all emulator states
|
||||
savestate - Save emulator state xx (valid args 0-9)
|
||||
|
|
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 18 KiB |
783
docs/index.html
|
@ -28,7 +28,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CheatManager::CheatManager(OSystem& osystem)
|
||||
: myOSystem(osystem)
|
||||
: myOSystem{osystem}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -253,8 +253,8 @@ void CheatManager::saveCheatDatabase()
|
|||
return;
|
||||
|
||||
stringstream out;
|
||||
for(const auto& iter: myCheatMap)
|
||||
out << "\"" << iter.first << "\" " << "\"" << iter.second << "\"" << endl;
|
||||
for(const auto& [md5, cheat]: myCheatMap)
|
||||
out << "\"" << md5 << "\" " << "\"" << cheat << "\"" << endl;
|
||||
|
||||
try { myOSystem.cheatFile().write(out); }
|
||||
catch(...) { return; }
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CheetahCheat::CheetahCheat(OSystem& os, const string& name, const string& code)
|
||||
: Cheat(os, name, code),
|
||||
address(0xf000 + unhex(code.substr(0, 3))),
|
||||
value(uInt8(unhex(code.substr(3, 2)))),
|
||||
count(uInt8(unhex(code.substr(5, 1)) + 1))
|
||||
address{uInt16(0xf000 + unhex(code.substr(0, 3)))},
|
||||
value{uInt8(unhex(code.substr(3, 2)))},
|
||||
count{uInt8(unhex(code.substr(5, 1)) + 1)}
|
||||
{
|
||||
// Back up original data; we need this if the cheat is ever disabled
|
||||
for(int i = 0; i < count; ++i)
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RamCheat::RamCheat(OSystem& os, const string& name, const string& code)
|
||||
: Cheat(os, name, code),
|
||||
address(uInt16(unhex(myCode.substr(0, 2)))),
|
||||
value(uInt8(unhex(myCode.substr(2, 2))))
|
||||
address{uInt16(unhex(myCode.substr(0, 2)))},
|
||||
value{uInt8(unhex(myCode.substr(2, 2)))}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -22,10 +22,10 @@ using std::lock_guard;
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AudioQueue::AudioQueue(uInt32 fragmentSize, uInt32 capacity, bool isStereo)
|
||||
: myFragmentSize(fragmentSize),
|
||||
myIsStereo(isStereo),
|
||||
myFragmentQueue(capacity),
|
||||
myAllFragments(capacity + 2)
|
||||
: myFragmentSize{fragmentSize},
|
||||
myIsStereo{isStereo},
|
||||
myFragmentQueue{capacity},
|
||||
myAllFragments{capacity + 2}
|
||||
{
|
||||
const uInt8 sampleSize = myIsStereo ? 2 : 1;
|
||||
|
||||
|
@ -48,7 +48,7 @@ uInt32 AudioQueue::capacity() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 AudioQueue::size()
|
||||
uInt32 AudioQueue::size() const
|
||||
{
|
||||
lock_guard<mutex> guard(myMutex);
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ class AudioQueue
|
|||
/**
|
||||
Size getter.
|
||||
*/
|
||||
uInt32 size();
|
||||
uInt32 size() const;
|
||||
|
||||
/**
|
||||
Stereo / mono getter.
|
||||
|
@ -120,7 +120,7 @@ class AudioQueue
|
|||
uInt32 myNextFragment{0};
|
||||
|
||||
// We need a mutex for thread safety.
|
||||
std::mutex myMutex;
|
||||
mutable std::mutex myMutex;
|
||||
|
||||
// The first (empty) enqueue call returns this fragment.
|
||||
Int16* myFirstFragmentForEnqueue{nullptr};
|
||||
|
|
|
@ -43,8 +43,7 @@ namespace {
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AudioSettings::AudioSettings(Settings& settings)
|
||||
: mySettings(settings),
|
||||
myIsPersistent(true)
|
||||
: mySettings{settings}
|
||||
{
|
||||
setPreset(normalizedPreset(mySettings.getInt(SETTING_PRESET)));
|
||||
}
|
||||
|
|
|
@ -129,15 +129,15 @@ class AudioSettings
|
|||
|
||||
Settings& mySettings;
|
||||
|
||||
Preset myPreset;
|
||||
Preset myPreset{Preset::custom};
|
||||
|
||||
uInt32 myPresetSampleRate;
|
||||
uInt32 myPresetFragmentSize;
|
||||
uInt32 myPresetBufferSize;
|
||||
uInt32 myPresetHeadroom;
|
||||
ResamplingQuality myPresetResamplingQuality;
|
||||
uInt32 myPresetSampleRate{0};
|
||||
uInt32 myPresetFragmentSize{0};
|
||||
uInt32 myPresetBufferSize{0};
|
||||
uInt32 myPresetHeadroom{0};
|
||||
ResamplingQuality myPresetResamplingQuality{ResamplingQuality::nearestNeightbour};
|
||||
|
||||
bool myIsPersistent;
|
||||
bool myIsPersistent{true};
|
||||
};
|
||||
|
||||
#endif // AUDIO_PARAMTERS_HXX
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
|
||||
: EventHandler(osystem)
|
||||
: EventHandler{osystem}
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FBBackendSDL2::FBBackendSDL2(OSystem& osystem)
|
||||
: myOSystem(osystem)
|
||||
: myOSystem{osystem}
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
|
@ -39,9 +39,8 @@ FBBackendSDL2::FBBackendSDL2(OSystem& osystem)
|
|||
if(SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
|
||||
{
|
||||
ostringstream buf;
|
||||
buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError() << endl;
|
||||
Logger::error(buf.str());
|
||||
throw runtime_error("FATAL ERROR");
|
||||
buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError();
|
||||
throw runtime_error(buf.str());
|
||||
}
|
||||
Logger::debug("FBBackendSDL2::FBBackendSDL2 SDL_Init()");
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
|
|||
uInt32 width, uInt32 height,
|
||||
ScalingInterpolation inter,
|
||||
const uInt32* staticData)
|
||||
: myBackend(backend),
|
||||
myInterpolationMode(inter)
|
||||
: myBackend{backend},
|
||||
myInterpolationMode{inter}
|
||||
{
|
||||
createSurface(width, height, staticData);
|
||||
}
|
||||
|
|
|
@ -94,8 +94,8 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
|||
FilesystemNodeZIP::FilesystemNodeZIP(
|
||||
const string& zipfile, const string& virtualpath,
|
||||
const AbstractFSNodePtr& realnode, bool isdir)
|
||||
: _isDirectory(isdir),
|
||||
_isFile(!isdir)
|
||||
: _isDirectory{isdir},
|
||||
_isFile{!isdir}
|
||||
{
|
||||
setFlags(zipfile, virtualpath, realnode);
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
const char* start = str.c_str();
|
||||
const char* cur = start + str.size() - 2;
|
||||
|
||||
while (cur >= start && !(*cur == '/' || *cur == '\\'))
|
||||
while (cur >= start && *cur != FilesystemNode::PATH_SEPARATOR)
|
||||
--cur;
|
||||
|
||||
return cur + 1;
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
|
||||
using namespace std::chrono;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FpsMeter::FpsMeter(uInt32 queueSize)
|
||||
: myQueue(queueSize)
|
||||
: myQueue{queueSize}
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FpsMeter::reset(uInt32 garbageFrameLimit)
|
||||
{
|
||||
myQueue.clear();
|
||||
|
@ -35,6 +37,7 @@ void FpsMeter::reset(uInt32 garbageFrameLimit)
|
|||
myGarbageFrameLimit = garbageFrameLimit;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FpsMeter::render(uInt32 frameCount)
|
||||
{
|
||||
if (myGarbageFrameCounter < myGarbageFrameLimit) {
|
||||
|
@ -67,6 +70,7 @@ void FpsMeter::render(uInt32 frameCount)
|
|||
if (myTimeInterval > 0) myFps = (myFrameCount - first.frames) / myTimeInterval;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
float FpsMeter::fps() const
|
||||
{
|
||||
return myFps;
|
||||
|
|
|
@ -0,0 +1,752 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
/*
|
||||
Formats (all optional):
|
||||
4, ; score digits
|
||||
0, ; trailing zeroes
|
||||
B, ; score format (BCD, HEX)
|
||||
|
||||
|
||||
0, ; invert score order
|
||||
|
||||
B, ; variation format (BCD, HEX)
|
||||
0, ; zero-based variation
|
||||
"", ; special label (5 chars)
|
||||
B, ; special format (BCD, HEX)
|
||||
0, ; zero-based special
|
||||
Addresses (in hex):
|
||||
n-times xx, ; score info, high to low
|
||||
xx, ; variation address (if more than 1 variation)
|
||||
xx ; special address (if defined)
|
||||
|
||||
TODO:
|
||||
- variation bits (Centipede)
|
||||
- score swaps (Asteroids)
|
||||
- special: one optional and named value extra per game (round, level...)
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "PropsSet.hxx"
|
||||
#include "System.hxx"
|
||||
#include "Cart.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "Launcher.hxx"
|
||||
#include "Base.hxx"
|
||||
#include "MD5.hxx"
|
||||
|
||||
#include "HighScoresManager.hxx"
|
||||
|
||||
using namespace BSPF;
|
||||
using namespace std;
|
||||
using namespace HSM;
|
||||
using Common::Base;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
HighScoresManager::HighScoresManager(OSystem& osystem)
|
||||
: myOSystem{osystem}
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int16 HighScoresManager::peek(uInt16 addr) const
|
||||
{
|
||||
if (myOSystem.hasConsole())
|
||||
{
|
||||
if(addr < 0x100u || myOSystem.console().cartridge().internalRamSize() == 0)
|
||||
return myOSystem.console().system().peek(addr);
|
||||
else
|
||||
return myOSystem.console().cartridge().internalRamGetValue(addr);
|
||||
}
|
||||
return NO_VALUE;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const json HighScoresManager::properties(const Properties& props) const
|
||||
{
|
||||
const string& property = props.get(PropType::Cart_Highscore);
|
||||
|
||||
if(property.empty())
|
||||
return json::array();
|
||||
|
||||
return json::parse(property);
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
json HighScoresManager::properties(json& jprops) const
|
||||
{
|
||||
Properties props;
|
||||
|
||||
if(myOSystem.hasConsole())
|
||||
{
|
||||
props = myOSystem.console().properties();
|
||||
}
|
||||
else
|
||||
{
|
||||
const string& md5 = myOSystem.launcher().selectedRomMD5();
|
||||
myOSystem.propSet().getMD5(md5, props);
|
||||
}
|
||||
|
||||
return jprops = properties(props);
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::enabled() const
|
||||
{
|
||||
json hsProp;
|
||||
|
||||
return properties(hsProp).contains(SCORE_ADDRESSES);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::numVariations(const json& jprops) const
|
||||
{
|
||||
return min(getPropInt(jprops, VARIATIONS_COUNT, DEFAULT_VARIATION), MAX_VARIATIONS);
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::get(const Properties& props, uInt32& numVariationsR,
|
||||
ScoresProps& info) const
|
||||
{
|
||||
json jprops = properties(props);
|
||||
|
||||
numVariationsR = numVariations(jprops);
|
||||
|
||||
info.numDigits = numDigits(jprops);
|
||||
info.trailingZeroes = trailingZeroes(jprops);
|
||||
info.scoreBCD = scoreBCD(jprops);
|
||||
info.scoreInvert = scoreInvert(jprops);
|
||||
info.varsBCD = varBCD(jprops);
|
||||
info.varsZeroBased = varZeroBased(jprops);
|
||||
info.special = specialLabel(jprops);
|
||||
info.specialBCD = specialBCD(jprops);
|
||||
info.specialZeroBased = specialZeroBased(jprops);
|
||||
info.notes = notes(jprops);
|
||||
|
||||
info.varsAddr = varAddress(jprops);
|
||||
info.specialAddr = specialAddress(jprops);
|
||||
|
||||
info.scoreAddr = getPropScoreAddr(jprops);
|
||||
|
||||
return enabled();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void HighScoresManager::set(Properties& props, uInt32 numVariations,
|
||||
const ScoresProps& info) const
|
||||
{
|
||||
json jprops = json::object();
|
||||
|
||||
// handle variations
|
||||
jprops[VARIATIONS_COUNT] = min(numVariations, MAX_VARIATIONS);
|
||||
if(numVariations != DEFAULT_VARIATION)
|
||||
jprops[VARIATIONS_ADDRESS] = "0x" + Base::toString(info.varsAddr, Base::Fmt::_16);
|
||||
if(info.varsBCD != DEFAULT_VARS_BCD)
|
||||
jprops[VARIATIONS_BCD] = info.varsBCD;
|
||||
if(info.varsZeroBased != DEFAULT_VARS_ZERO_BASED)
|
||||
jprops[VARIATIONS_ZERO_BASED] = info.varsZeroBased;
|
||||
|
||||
// handle score
|
||||
if(info.numDigits != DEFAULT_DIGITS)
|
||||
jprops[SCORE_DIGITS] = info.numDigits;
|
||||
if(info.trailingZeroes != DEFAULT_TRAILING)
|
||||
jprops[SCORE_TRAILING_ZEROES] = info.trailingZeroes;
|
||||
if(info.scoreBCD != DEFAULT_SCORE_BCD)
|
||||
jprops[SCORE_BCD] = info.scoreBCD;
|
||||
if(info.scoreInvert != DEFAULT_SCORE_REVERSED)
|
||||
jprops[SCORE_INVERTED] = info.scoreInvert;
|
||||
|
||||
uInt32 addrBytes = numAddrBytes(info.numDigits, info.trailingZeroes);
|
||||
json addresses = json::array();
|
||||
|
||||
for(uInt32 a = 0; a < addrBytes; ++a)
|
||||
addresses.push_back("0x" + Base::toString(info.scoreAddr[a], Base::Fmt::_16));
|
||||
jprops[SCORE_ADDRESSES] = addresses;
|
||||
|
||||
// handle special
|
||||
if(!info.special.empty())
|
||||
jprops[SPECIAL_LABEL] = info.special;
|
||||
if(!info.special.empty())
|
||||
jprops[SPECIAL_ADDRESS] = "0x" + Base::toString(info.specialAddr, Base::Fmt::_16);
|
||||
if(info.specialBCD != DEFAULT_SPECIAL_BCD)
|
||||
jprops[SPECIAL_BCD] = info.specialBCD;
|
||||
if(info.specialZeroBased != DEFAULT_SPECIAL_ZERO_BASED)
|
||||
jprops[SPECIAL_ZERO_BASED] = info.specialZeroBased;
|
||||
|
||||
// handle notes
|
||||
if(!info.notes.empty())
|
||||
jprops[NOTES] = info.notes;
|
||||
|
||||
props.set(PropType::Cart_Highscore, jprops.dump());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::numDigits(const json& jprops) const
|
||||
{
|
||||
return min(getPropInt(jprops, SCORE_DIGITS, DEFAULT_DIGITS), MAX_SCORE_DIGITS);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::trailingZeroes(const json& jprops) const
|
||||
{
|
||||
return min(getPropInt(jprops, SCORE_TRAILING_ZEROES, DEFAULT_TRAILING), MAX_TRAILING);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::scoreBCD(const json& jprops) const
|
||||
{
|
||||
return getPropBool(jprops, SCORE_BCD, DEFAULT_SCORE_BCD);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::scoreInvert(const json& jprops) const
|
||||
{
|
||||
return getPropBool(jprops, SCORE_INVERTED, DEFAULT_SCORE_REVERSED);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::varBCD(const json& jprops) const
|
||||
{
|
||||
return getPropBool(jprops, VARIATIONS_BCD, DEFAULT_VARS_BCD);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::varZeroBased(const json& jprops) const
|
||||
{
|
||||
return getPropBool(jprops, VARIATIONS_ZERO_BASED, DEFAULT_VARS_ZERO_BASED);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::specialLabel(const json& jprops) const
|
||||
{
|
||||
return getPropStr(jprops, SPECIAL_LABEL);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::specialBCD(const json& jprops) const
|
||||
{
|
||||
return getPropBool(jprops, SPECIAL_BCD, DEFAULT_SPECIAL_BCD);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::specialZeroBased(const json& jprops) const
|
||||
{
|
||||
return getPropBool(jprops, SPECIAL_ZERO_BASED, DEFAULT_SPECIAL_ZERO_BASED);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::notes(const json& jprops) const
|
||||
{
|
||||
return getPropStr(jprops, NOTES);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 HighScoresManager::varAddress(const json& jprops) const
|
||||
{
|
||||
return getPropAddr(jprops, VARIATIONS_ADDRESS, DEFAULT_ADDRESS);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 HighScoresManager::specialAddress(const json& jprops) const
|
||||
{
|
||||
return getPropAddr(jprops, SPECIAL_ADDRESS, DEFAULT_ADDRESS);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::numAddrBytes(Int32 digits, Int32 trailing) const
|
||||
{
|
||||
return (digits - trailing + 1) / 2;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::numAddrBytes(const json& jprops) const
|
||||
{
|
||||
return numAddrBytes(numDigits(jprops), trailingZeroes(jprops));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 HighScoresManager::numVariations() const
|
||||
{
|
||||
json jprops;
|
||||
|
||||
return numVariations(properties(jprops));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::specialLabel() const
|
||||
{
|
||||
json jprops;
|
||||
|
||||
return specialLabel(properties(jprops));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 HighScoresManager::variation(uInt16 addr, bool varBCD, bool zeroBased,
|
||||
uInt32 numVariations) const
|
||||
{
|
||||
if (!myOSystem.hasConsole())
|
||||
return DEFAULT_VARIATION;
|
||||
|
||||
Int32 var = peek(addr);
|
||||
|
||||
return convert(var, numVariations, varBCD, zeroBased);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 HighScoresManager::variation() const
|
||||
{
|
||||
json jprops;
|
||||
uInt16 addr = varAddress(properties(jprops));
|
||||
|
||||
if(addr == DEFAULT_ADDRESS) {
|
||||
if(numVariations() == 1)
|
||||
return DEFAULT_VARIATION;
|
||||
else
|
||||
return NO_VALUE;
|
||||
}
|
||||
|
||||
return variation(addr, varBCD(jprops), varZeroBased(jprops), numVariations(jprops));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 HighScoresManager::score(uInt32 numAddrBytes, uInt32 trailingZeroes,
|
||||
bool isBCD, const ScoreAddresses& scoreAddr) const
|
||||
{
|
||||
if (!myOSystem.hasConsole())
|
||||
return NO_VALUE;
|
||||
|
||||
Int32 totalScore = 0;
|
||||
|
||||
for (uInt32 b = 0; b < numAddrBytes; ++b)
|
||||
{
|
||||
uInt16 addr = scoreAddr[b];
|
||||
Int32 score;
|
||||
|
||||
totalScore *= isBCD ? 100 : 256;
|
||||
score = peek(addr);
|
||||
if (isBCD)
|
||||
{
|
||||
score = fromBCD(score);
|
||||
// verify if score is legit
|
||||
if (score == NO_VALUE)
|
||||
return NO_VALUE;
|
||||
}
|
||||
totalScore += score;
|
||||
}
|
||||
|
||||
if (totalScore != NO_VALUE)
|
||||
for (uInt32 i = 0; i < trailingZeroes; ++i)
|
||||
totalScore *= 10;
|
||||
|
||||
return totalScore;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 HighScoresManager::score() const
|
||||
{
|
||||
json jprops;
|
||||
uInt32 numBytes = numAddrBytes(properties(jprops));
|
||||
const ScoreAddresses scoreAddr = getPropScoreAddr(jprops);
|
||||
|
||||
if(uInt32(scoreAddr.size()) < numBytes)
|
||||
return NO_VALUE;
|
||||
return score(numBytes, trailingZeroes(jprops), scoreBCD(jprops), scoreAddr);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::formattedScore(Int32 score, Int32 width) const
|
||||
{
|
||||
if(score <= 0)
|
||||
return "";
|
||||
|
||||
ostringstream buf;
|
||||
json jprops;
|
||||
Int32 digits = numDigits(properties(jprops));
|
||||
|
||||
if(scoreBCD(jprops))
|
||||
{
|
||||
if(width > digits)
|
||||
digits = width;
|
||||
buf << std::setw(digits) << std::setfill(' ') << score;
|
||||
}
|
||||
else {
|
||||
if(width > digits)
|
||||
buf << std::setw(width - digits) << std::setfill(' ') << "";
|
||||
buf << std::hex << std::setw(digits) << std::setfill('0') << score;
|
||||
}
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
string HighScoresManager::md5Props() const
|
||||
{
|
||||
json jprops;
|
||||
properties(jprops);
|
||||
ostringstream buf;
|
||||
|
||||
buf << varAddress(jprops) << numVariations() << varBCD(jprops)
|
||||
<< varZeroBased(jprops);
|
||||
|
||||
uInt32 addrBytes = numAddrBytes(jprops);
|
||||
HSM::ScoreAddresses addr = getPropScoreAddr(jprops);
|
||||
for(uInt32 a = 0; a < addrBytes; ++a)
|
||||
buf << addr[a];
|
||||
buf << numDigits(jprops) << trailingZeroes(jprops) << scoreBCD(jprops)
|
||||
<< scoreInvert(jprops) << specialAddress(jprops) << specialBCD(jprops)
|
||||
<< specialZeroBased(jprops);
|
||||
|
||||
buf << specialAddress(jprops) << specialBCD(jprops) << specialZeroBased(jprops);
|
||||
|
||||
return MD5::hash(buf.str());
|
||||
}
|
||||
|
||||
bool HighScoresManager::scoreInvert() const
|
||||
{
|
||||
json jprops;
|
||||
|
||||
return scoreInvert(properties(jprops));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 HighScoresManager::special() const
|
||||
{
|
||||
if(!myOSystem.hasConsole())
|
||||
return NO_VALUE;
|
||||
|
||||
json jprops;
|
||||
uInt16 addr = specialAddress(properties(jprops));
|
||||
|
||||
if (addr == DEFAULT_ADDRESS)
|
||||
return NO_VALUE;
|
||||
|
||||
Int32 var = peek(addr);
|
||||
|
||||
if(specialBCD(jprops))
|
||||
var = fromBCD(var);
|
||||
|
||||
var += specialZeroBased(jprops) ? 1 : 0;
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::notes() const
|
||||
{
|
||||
json jprops;
|
||||
|
||||
return notes(properties(jprops));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 HighScoresManager::convert(Int32 val, uInt32 maxVal, bool isBCD, bool zeroBased) const
|
||||
{
|
||||
//maxVal += zeroBased ? 0 : 1;
|
||||
maxVal -= zeroBased ? 1 : 0;
|
||||
Int32 bits = isBCD
|
||||
? ceil(log(maxVal) / log(10) * 4)
|
||||
: ceil(log(maxVal) / log(2));
|
||||
|
||||
// limit to maxVal's bits
|
||||
val %= 1 << bits;
|
||||
|
||||
if (isBCD)
|
||||
val = fromBCD(val);
|
||||
|
||||
if(val == NO_VALUE)
|
||||
return 0;
|
||||
|
||||
val += zeroBased ? 1 : 0;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::getPropBool(const json& jprops, const string& key,
|
||||
bool defVal) const
|
||||
{
|
||||
return jprops.contains(key) ? jprops.at(key).get<bool>() : defVal;
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 HighScoresManager::getPropInt(const json& jprops, const string& key,
|
||||
uInt32 defVal) const
|
||||
{
|
||||
return jprops.contains(key) ? jprops.at(key).get<uInt32>() : defVal;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::getPropStr(const json& jprops, const string& key,
|
||||
const string& defVal) const
|
||||
{
|
||||
return jprops.contains(key) ? jprops.at(key).get<string>() : defVal;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 HighScoresManager::getPropAddr(const json& jprops, const string& key,
|
||||
uInt16 defVal) const
|
||||
{
|
||||
const string str = getPropStr(jprops, key);
|
||||
|
||||
return str.empty() ? defVal : fromHexStr(str);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const HSM::ScoreAddresses HighScoresManager::getPropScoreAddr(const json& jprops) const
|
||||
{
|
||||
ScoreAddresses scoreAddr{};
|
||||
|
||||
if(jprops.contains(SCORE_ADDRESSES))
|
||||
{
|
||||
const json addrProps = jprops.at(SCORE_ADDRESSES);
|
||||
|
||||
if(!addrProps.empty() && addrProps.is_array())
|
||||
{
|
||||
int a = 0;
|
||||
|
||||
for(const json& addresses : addrProps)
|
||||
{
|
||||
const string address = addresses.get<string>();
|
||||
|
||||
if(address.empty())
|
||||
scoreAddr[a++] = DEFAULT_ADDRESS;
|
||||
else
|
||||
scoreAddr[a++] = fromHexStr(address);
|
||||
}
|
||||
}
|
||||
}
|
||||
return scoreAddr;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 HighScoresManager::fromHexStr(const string& addr) const
|
||||
{
|
||||
string naked = addr;
|
||||
|
||||
if(int pos = naked.find("0x") != std::string::npos)
|
||||
naked = naked.substr(pos + 1);
|
||||
|
||||
return stringToIntBase16(naked);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Int32 HighScoresManager::fromBCD(uInt8 bcd) const
|
||||
{
|
||||
// verify if score is legit
|
||||
if ((bcd & 0xF0) >= 0xA0 || (bcd & 0xF) >= 0xA)
|
||||
return NO_VALUE;
|
||||
|
||||
return (bcd >> 4) * 10 + bcd % 16;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void HighScoresManager::saveHighScores(const string& cartName, ScoresData& data) const
|
||||
{
|
||||
ostringstream buf;
|
||||
|
||||
buf << myOSystem.stateDir() << cartName << ".hs" << data.variation;
|
||||
|
||||
// Make sure the file can be opened for writing
|
||||
FilesystemNode node(buf.str());
|
||||
|
||||
if(!node.isWritable())
|
||||
{
|
||||
buf.str("");
|
||||
buf << "Can't open/save to high scores file for variation " << data.variation;
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
}
|
||||
|
||||
// Do a complete high data save
|
||||
if(!save(node, data))
|
||||
{
|
||||
buf.str("");
|
||||
buf << "Error saving high scores for variation" << data.variation;
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void HighScoresManager::loadHighScores(const string& cartName, ScoresData& data)
|
||||
{
|
||||
for(uInt32 r = 0; r < NUM_RANKS; ++r)
|
||||
{
|
||||
data.scores[r].score = 0;
|
||||
data.scores[r].special = 0;
|
||||
data.scores[r].name = "";
|
||||
data.scores[r].date = "";
|
||||
}
|
||||
|
||||
ostringstream buf;
|
||||
|
||||
buf << myOSystem.stateDir() << cartName << ".hs" << data.variation;
|
||||
|
||||
FilesystemNode node(buf.str());
|
||||
stringstream in;
|
||||
|
||||
// Make sure the file can be opened
|
||||
try {
|
||||
node.read(in);
|
||||
}
|
||||
catch(...) { return; }
|
||||
|
||||
bool invalid = false;
|
||||
try {
|
||||
string highscores;
|
||||
|
||||
buf.str("");
|
||||
|
||||
if(getline(in, highscores) && highscores.length() != 0)
|
||||
{
|
||||
const json hsObject = json::parse(highscores);
|
||||
|
||||
if(hsObject.contains(DATA))
|
||||
{
|
||||
const json hsData = hsObject.at(DATA);
|
||||
|
||||
// First test if we have a valid header
|
||||
// If so, do a complete high data load
|
||||
if(!hsData.contains(VERSION) || hsData.at(VERSION) != HIGHSCORE_HEADER)
|
||||
buf << "Error: Incompatible high scores file for variation "
|
||||
<< data.variation << ".";
|
||||
else
|
||||
{
|
||||
if(!load(hsData, data)
|
||||
|| !hsData.contains(PROPCHECK) || hsData.at(PROPCHECK) != md5Props()
|
||||
|| !hsObject.contains(CHECKSUM) || hsObject.at(CHECKSUM) != MD5::hash(hsData.dump()))
|
||||
invalid = true;
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
invalid = true;
|
||||
}
|
||||
}
|
||||
catch(...) { invalid = true; }
|
||||
|
||||
if(invalid)
|
||||
buf << "Error: Invalid data in high scores file for variation " << data.variation << ".";
|
||||
myOSystem.frameBuffer().showTextMessage(buf.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::save(FilesystemNode& node, const ScoresData& data) const
|
||||
{
|
||||
try
|
||||
{
|
||||
json hsObject = json::object();
|
||||
json hsData = json::object();
|
||||
|
||||
// Add header so that if the high score format changes in the future,
|
||||
// we'll know right away, without having to parse the rest of the file
|
||||
hsData[VERSION] = HIGHSCORE_HEADER;
|
||||
hsData[MD5] = data.md5;
|
||||
hsData[VARIATION] = data.variation;
|
||||
|
||||
json jScores = json::array();
|
||||
|
||||
for(uInt32 r = 0; r < NUM_RANKS && data.scores[r].score; ++r)
|
||||
{
|
||||
json jScore = json::object();
|
||||
|
||||
jScore[SCORE] = data.scores[r].score;
|
||||
jScore[SPECIAL] = data.scores[r].special;
|
||||
jScore[NAME] = data.scores[r].name;
|
||||
jScore[DATE] = data.scores[r].date;
|
||||
|
||||
jScores.push_back(jScore);
|
||||
}
|
||||
hsData[SCORES] = jScores;
|
||||
hsData[PROPCHECK] = md5Props();
|
||||
|
||||
hsObject[DATA] = hsData;
|
||||
hsObject[CHECKSUM] = MD5::hash(hsData.dump());
|
||||
|
||||
stringstream ss(hsObject.dump());
|
||||
node.write(ss);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: HighScoresManager::save() exception\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool HighScoresManager::load(const json& hsData, ScoresData& data)
|
||||
{
|
||||
if(!hsData.contains(MD5) || hsData.at(MD5) != data.md5
|
||||
|| !hsData.contains(VARIATION) || hsData.at(VARIATION) != data.variation
|
||||
|| !hsData.contains(SCORES))
|
||||
return false;
|
||||
|
||||
const json& jScores = hsData.at(SCORES);
|
||||
|
||||
if(!jScores.empty() && jScores.is_array())
|
||||
{
|
||||
uInt32 r = 0;
|
||||
for(const json& jScore : jScores)
|
||||
{
|
||||
if(jScore.contains(SCORE))
|
||||
data.scores[r].score = jScore.at(SCORE).get<Int32>();
|
||||
if(jScore.contains(SPECIAL))
|
||||
data.scores[r].special = jScore.at(SPECIAL).get<Int32>();
|
||||
if(jScore.contains(NAME))
|
||||
data.scores[r].name = jScore.at(NAME).get<string>();
|
||||
if(jScore.contains(DATE))
|
||||
data.scores[r].date = jScore.at(DATE).get<string>();
|
||||
|
||||
if(++r == NUM_RANKS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string HighScoresManager::VARIATIONS_COUNT = "variations_count";
|
||||
const string HighScoresManager::VARIATIONS_ADDRESS = "variations_address";
|
||||
const string HighScoresManager::VARIATIONS_BCD = "variations_bcd";
|
||||
const string HighScoresManager::VARIATIONS_ZERO_BASED = "variations_zero_based";
|
||||
const string HighScoresManager::SCORE_DIGITS = "score_digits";
|
||||
const string HighScoresManager::SCORE_TRAILING_ZEROES = "score_trailing_zeroes";
|
||||
const string HighScoresManager::SCORE_BCD = "score_bcd";
|
||||
const string HighScoresManager::SCORE_INVERTED = "score_inverted";
|
||||
const string HighScoresManager::SCORE_ADDRESSES = "score_addresses";
|
||||
const string HighScoresManager::SPECIAL_LABEL = "special_label";
|
||||
const string HighScoresManager::SPECIAL_ADDRESS = "special_address";
|
||||
const string HighScoresManager::SPECIAL_BCD = "special_bcd";
|
||||
const string HighScoresManager::SPECIAL_ZERO_BASED = "special_zero_based";
|
||||
const string HighScoresManager::NOTES = "notes";
|
||||
|
||||
const string HighScoresManager::DATA = "data";
|
||||
const string HighScoresManager::VERSION = "version";
|
||||
const string HighScoresManager::MD5 = "md5";
|
||||
const string HighScoresManager::VARIATION = "variation";
|
||||
const string HighScoresManager::SCORES = "scores";
|
||||
const string HighScoresManager::SCORE = "score";
|
||||
const string HighScoresManager::SPECIAL = "special";
|
||||
const string HighScoresManager::NAME = "name";
|
||||
const string HighScoresManager::DATE = "date";
|
||||
const string HighScoresManager::PROPCHECK = "propcheck";
|
||||
const string HighScoresManager::CHECKSUM = "checksum";
|
|
@ -0,0 +1,265 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef HIGHSCORES_MANAGER_HXX
|
||||
#define HIGHSCORES_MANAGER_HXX
|
||||
|
||||
#define HIGHSCORE_HEADER "06010000highscores"
|
||||
|
||||
class OSystem;
|
||||
|
||||
#include "Props.hxx"
|
||||
#include "json_lib.hxx"
|
||||
#include "FSNode.hxx"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
/**
|
||||
This class provides an interface to all things related to high scores.
|
||||
|
||||
@author Thomas Jentzsch
|
||||
*/
|
||||
|
||||
namespace HSM {
|
||||
static constexpr uInt32 MAX_SCORE_DIGITS = 8;
|
||||
static constexpr uInt32 MAX_ADDR_CHARS = MAX_SCORE_DIGITS / 2;
|
||||
static constexpr uInt32 MAX_SCORE_ADDR = 4;
|
||||
static constexpr uInt32 MAX_SPECIAL_NAME = 5;
|
||||
static constexpr uInt32 MAX_SPECIAL_DIGITS = 3;
|
||||
|
||||
static constexpr uInt32 DEFAULT_VARIATION = 1;
|
||||
static constexpr uInt32 DEFAULT_ADDRESS = 0;
|
||||
|
||||
static constexpr Int32 NO_VALUE = -1;
|
||||
|
||||
using ScoreAddresses = array<Int16, MAX_SCORE_ADDR>;
|
||||
|
||||
static const uInt32 NUM_RANKS = 10;
|
||||
|
||||
struct ScoresProps {
|
||||
// Formats
|
||||
uInt32 numDigits;
|
||||
uInt32 trailingZeroes;
|
||||
bool scoreBCD;
|
||||
bool scoreInvert;
|
||||
bool varsBCD;
|
||||
bool varsZeroBased;
|
||||
string special;
|
||||
bool specialBCD;
|
||||
bool specialZeroBased;
|
||||
string notes;
|
||||
// Addresses
|
||||
ScoreAddresses scoreAddr;
|
||||
uInt16 varsAddr;
|
||||
uInt16 specialAddr;
|
||||
};
|
||||
|
||||
struct ScoreEntry {
|
||||
Int32 score;
|
||||
Int32 special;
|
||||
string name;
|
||||
string date;
|
||||
};
|
||||
|
||||
struct ScoresData {
|
||||
Int32 variation;
|
||||
string md5;
|
||||
ScoreEntry scores[NUM_RANKS];
|
||||
};
|
||||
} // namespace HSM
|
||||
|
||||
/**
|
||||
This class provides an interface to define, load and save scores. It is meant
|
||||
for games which do not support saving highscores.
|
||||
|
||||
@author Thomas Jentzsch
|
||||
*/
|
||||
|
||||
class HighScoresManager
|
||||
{
|
||||
public:
|
||||
explicit HighScoresManager(OSystem& osystem);
|
||||
virtual ~HighScoresManager() = default;
|
||||
|
||||
|
||||
// check if high score data has been defined
|
||||
bool enabled() const;
|
||||
|
||||
/**
|
||||
Get the highscore data of game's properties
|
||||
|
||||
@return True if highscore data exists, else false
|
||||
*/
|
||||
bool get(const Properties& props, uInt32& numVariations,
|
||||
HSM::ScoresProps& info) const;
|
||||
/**
|
||||
Set the highscore data of game's properties
|
||||
*/
|
||||
void set(Properties& props, uInt32 numVariations,
|
||||
const HSM::ScoresProps& info) const;
|
||||
|
||||
/**
|
||||
Calculate the score from given parameters
|
||||
|
||||
@return The current score or -1 if no valid data exists
|
||||
*/
|
||||
Int32 score(uInt32 numAddrBytes, uInt32 trailingZeroes, bool isBCD,
|
||||
const HSM::ScoreAddresses& scoreAddr) const;
|
||||
|
||||
// Convert the given value, using only the maximum bits required by maxVal
|
||||
// and adjusted for BCD and zero based data
|
||||
Int32 convert(Int32 val, uInt32 maxVal, bool isBCD, bool zeroBased) const;
|
||||
|
||||
/**
|
||||
Calculate the number of bytes for one player's score from given parameters
|
||||
|
||||
@return The number of score address bytes
|
||||
*/
|
||||
uInt32 numAddrBytes(Int32 digits, Int32 trailing) const;
|
||||
|
||||
// Retrieve current values (using game's properties)
|
||||
Int32 numVariations() const;
|
||||
const string specialLabel() const;
|
||||
Int32 variation() const;
|
||||
Int32 score() const;
|
||||
const string formattedScore(Int32 score, Int32 width = -1) const;
|
||||
bool scoreInvert() const;
|
||||
Int32 special() const;
|
||||
const string notes() const;
|
||||
|
||||
// Get md5 property definition checksum
|
||||
string md5Props() const;
|
||||
|
||||
// Peek into memory
|
||||
Int16 peek(uInt16 addr) const;
|
||||
|
||||
void saveHighScores(const string& cartName, HSM::ScoresData& scores) const;
|
||||
void loadHighScores(const string& cartName, HSM::ScoresData& scores);
|
||||
|
||||
private:
|
||||
static const string VARIATIONS_COUNT;
|
||||
static const string VARIATIONS_ADDRESS;
|
||||
static const string VARIATIONS_BCD;
|
||||
static const string VARIATIONS_ZERO_BASED;
|
||||
static const string SCORE_DIGITS;
|
||||
static const string SCORE_TRAILING_ZEROES;
|
||||
static const string SCORE_BCD;
|
||||
static const string SCORE_INVERTED;
|
||||
static const string SCORE_ADDRESSES;
|
||||
static const string SPECIAL_LABEL;
|
||||
static const string SPECIAL_ADDRESS;
|
||||
static const string SPECIAL_BCD;
|
||||
static const string SPECIAL_ZERO_BASED;
|
||||
static const string NOTES;
|
||||
|
||||
static constexpr uInt32 MAX_VARIATIONS = 256;
|
||||
|
||||
static constexpr uInt32 MAX_TRAILING = 3;
|
||||
static constexpr uInt32 DEFAULT_DIGITS = 4;
|
||||
static constexpr uInt32 DEFAULT_TRAILING = 0;
|
||||
static constexpr bool DEFAULT_SCORE_BCD = true;
|
||||
static constexpr bool DEFAULT_SCORE_REVERSED = false;
|
||||
static constexpr bool DEFAULT_VARS_BCD = true;
|
||||
static constexpr bool DEFAULT_VARS_ZERO_BASED = false;
|
||||
static constexpr bool DEFAULT_SPECIAL_BCD = true;
|
||||
static constexpr bool DEFAULT_SPECIAL_ZERO_BASED = false;
|
||||
|
||||
static const string DATA;
|
||||
static const string VERSION;
|
||||
static const string MD5;
|
||||
static const string VARIATION;
|
||||
static const string SCORES;
|
||||
static const string SCORE;
|
||||
static const string SPECIAL;
|
||||
static const string NAME;
|
||||
static const string DATE;
|
||||
static const string PROPCHECK;
|
||||
static const string CHECKSUM;
|
||||
|
||||
private:
|
||||
// Retrieve current values from (using given parameters)
|
||||
Int32 variation(uInt16 addr, bool varBCD, bool zeroBased, uInt32 numVariations) const;
|
||||
|
||||
// Get individual highscore info from properties
|
||||
uInt32 numVariations(const json& jprops) const;
|
||||
uInt16 varAddress(const json& jprops) const;
|
||||
uInt16 specialAddress(const json& jprops) const;
|
||||
uInt32 numDigits(const json& jprops) const;
|
||||
uInt32 trailingZeroes(const json& jprops) const;
|
||||
bool scoreBCD(const json& jprops) const;
|
||||
bool scoreInvert(const json& jprops) const;
|
||||
bool varBCD(const json& jprops) const;
|
||||
bool varZeroBased(const json& jprops) const;
|
||||
const string specialLabel(const json& jprops) const;
|
||||
bool specialBCD(const json& jprops) const;
|
||||
bool specialZeroBased(const json& jprops) const;
|
||||
const string notes(const json& jprops) const;
|
||||
|
||||
// Calculate the number of bytes for one player's score from property parameters
|
||||
uInt32 numAddrBytes(const json& jprops) const;
|
||||
|
||||
// Get properties
|
||||
const json properties(const Properties& props) const;
|
||||
json properties(json& jprops) const;
|
||||
|
||||
// Get value from highscore properties for given key
|
||||
bool getPropBool(const json& jprops, const string& key,
|
||||
bool defVal = false) const;
|
||||
uInt32 getPropInt(const json& jprops, const string& key,
|
||||
uInt32 defVal = 0) const;
|
||||
const string getPropStr(const json& jprops, const string& key,
|
||||
const string& defVal = "") const;
|
||||
uInt16 getPropAddr(const json& jprops, const string& key,
|
||||
uInt16 defVal = 0) const;
|
||||
const HSM::ScoreAddresses getPropScoreAddr(const json& jprops) const;
|
||||
|
||||
uInt16 fromHexStr(const string& addr) const;
|
||||
Int32 fromBCD(uInt8 bcd) const;
|
||||
|
||||
/**
|
||||
Saves the current high scores for this game and variation to the given file system node.
|
||||
|
||||
@param node The file system node to save to.
|
||||
@param scores The saved high score data
|
||||
|
||||
@return The result of the save. True on success, false on failure.
|
||||
*/
|
||||
bool save(FilesystemNode& node, const HSM::ScoresData& scores) const;
|
||||
|
||||
/**
|
||||
Loads the current high scores for this game and variation from the given JSON object.
|
||||
|
||||
@param hsData The JSON to parse
|
||||
@param scores The loaded high score data
|
||||
|
||||
@return The result of the load. True on success, false on failure.
|
||||
*/
|
||||
bool load(const json& hsData, HSM::ScoresData& scores);
|
||||
|
||||
private:
|
||||
// Reference to the osystem object
|
||||
OSystem& myOSystem;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
HighScoresManager() = delete;
|
||||
HighScoresManager(const HighScoresManager&) = delete;
|
||||
HighScoresManager(HighScoresManager&&) = delete;
|
||||
HighScoresManager& operator=(const HighScoresManager&) = delete;
|
||||
HighScoresManager& operator=(HighScoresManager&&) = delete;
|
||||
};
|
||||
#endif
|
|
@ -66,7 +66,7 @@ void JoyMap::erase(const EventMode mode, const int button,
|
|||
Event::Type JoyMap::get(const JoyMapping& mapping) const
|
||||
{
|
||||
auto find = myMap.find(mapping);
|
||||
if (find != myMap.end())
|
||||
if(find != myMap.end())
|
||||
return find->second;
|
||||
|
||||
// try without button as modifier
|
||||
|
@ -75,7 +75,7 @@ Event::Type JoyMap::get(const JoyMapping& mapping) const
|
|||
m.button = JOY_CTRL_NONE;
|
||||
|
||||
find = myMap.find(m);
|
||||
if (find != myMap.end())
|
||||
if(find != myMap.end())
|
||||
return find->second;
|
||||
|
||||
return Event::Type::NoType;
|
||||
|
@ -96,7 +96,7 @@ Event::Type JoyMap::get(const EventMode mode, const int button,
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool JoyMap::check(const JoyMapping & mapping) const
|
||||
bool JoyMap::check(const JoyMapping& mapping) const
|
||||
{
|
||||
auto find = myMap.find(mapping);
|
||||
|
||||
|
@ -117,14 +117,14 @@ string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const
|
|||
ostringstream buf;
|
||||
|
||||
// button description
|
||||
if (mapping.button != JOY_CTRL_NONE)
|
||||
if(mapping.button != JOY_CTRL_NONE)
|
||||
buf << "/B" << mapping.button;
|
||||
|
||||
// axis description
|
||||
if (mapping.axis != JoyAxis::NONE)
|
||||
if(mapping.axis != JoyAxis::NONE)
|
||||
{
|
||||
buf << "/A";
|
||||
switch (mapping.axis)
|
||||
switch(mapping.axis)
|
||||
{
|
||||
case JoyAxis::X: buf << "X"; break;
|
||||
case JoyAxis::Y: buf << "Y"; break;
|
||||
|
@ -132,19 +132,19 @@ string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const
|
|||
default: buf << int(mapping.axis); break;
|
||||
}
|
||||
|
||||
if (Event::isAnalog(event))
|
||||
if(Event::isAnalog(event))
|
||||
buf << "+|-";
|
||||
else if (mapping.adir == JoyDir::NEG)
|
||||
else if(mapping.adir == JoyDir::NEG)
|
||||
buf << "-";
|
||||
else
|
||||
buf << "+";
|
||||
}
|
||||
|
||||
// hat description
|
||||
if (mapping.hat != JOY_CTRL_NONE)
|
||||
if(mapping.hat != JOY_CTRL_NONE)
|
||||
{
|
||||
buf << "/H" << mapping.hat;
|
||||
switch (mapping.hdir)
|
||||
switch(mapping.hdir)
|
||||
{
|
||||
case JoyHatDir::UP: buf << "Y+"; break;
|
||||
case JoyHatDir::DOWN: buf << "Y-"; break;
|
||||
|
@ -162,13 +162,13 @@ string JoyMap::getEventMappingDesc(int stick, const Event::Type event, const Eve
|
|||
{
|
||||
ostringstream buf;
|
||||
|
||||
for (auto item : myMap)
|
||||
for (const auto& [_mapping, _event]: myMap)
|
||||
{
|
||||
if (item.second == event && item.first.mode == mode)
|
||||
if (_event == event && _mapping.mode == mode)
|
||||
{
|
||||
if (buf.str() != "")
|
||||
if(buf.str() != "")
|
||||
buf << ", ";
|
||||
buf << "J" << stick << getDesc(event, item.first);
|
||||
buf << "J" << stick << getDesc(event, _mapping);
|
||||
}
|
||||
}
|
||||
return buf.str();
|
||||
|
@ -179,9 +179,9 @@ JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const E
|
|||
{
|
||||
JoyMappingArray map;
|
||||
|
||||
for (auto item : myMap)
|
||||
if (item.second == event && item.first.mode == mode)
|
||||
map.push_back(item.first);
|
||||
for (const auto& [_mapping, _event]: myMap)
|
||||
if (_event == event && _mapping.mode == mode)
|
||||
map.push_back(_mapping);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
@ -189,25 +189,51 @@ JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const E
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
json JoyMap::saveMapping(const EventMode mode) const
|
||||
{
|
||||
using MapType = std::pair<JoyMapping, Event::Type>;
|
||||
std::vector<MapType> sortedMap(myMap.begin(), myMap.end());
|
||||
|
||||
std::sort(sortedMap.begin(), sortedMap.end(),
|
||||
[](const MapType& a, const MapType& b)
|
||||
{
|
||||
// Event::Type first
|
||||
if(a.first.button != b.first.button)
|
||||
return a.first.button < b.first.button;
|
||||
|
||||
if(a.first.axis != b.first.axis)
|
||||
return a.first.axis < b.first.axis;
|
||||
|
||||
if(a.first.adir != b.first.adir)
|
||||
return a.first.adir < b.first.adir;
|
||||
|
||||
if(a.first.hat != b.first.hat)
|
||||
return a.first.hat < b.first.hat;
|
||||
|
||||
if(a.first.hdir != b.first.hdir)
|
||||
return a.first.hdir < b.first.hdir;
|
||||
|
||||
return a.second < b.second;
|
||||
}
|
||||
);
|
||||
|
||||
json eventMappings = json::array();
|
||||
|
||||
for (auto& item: myMap) {
|
||||
if (item.first.mode != mode) continue;
|
||||
for (const auto& [_mapping, _event]: sortedMap) {
|
||||
if (_mapping.mode != mode) continue;
|
||||
|
||||
json eventMapping = json::object();
|
||||
|
||||
eventMapping["event"] = item.second;
|
||||
eventMapping["event"] = _event;
|
||||
|
||||
if (item.first.button != JOY_CTRL_NONE) eventMapping["button"] = item.first.button;
|
||||
if (_mapping.button != JOY_CTRL_NONE) eventMapping["button"] = _mapping.button;
|
||||
|
||||
if (item.first.axis != JoyAxis::NONE) {
|
||||
eventMapping["axis"] = item.first.axis;
|
||||
eventMapping["axisDirection"] = item.first.adir;
|
||||
if (_mapping.axis != JoyAxis::NONE) {
|
||||
eventMapping["axis"] = _mapping.axis;
|
||||
eventMapping["axisDirection"] = _mapping.adir;
|
||||
}
|
||||
|
||||
if (item.first.hat != -1) {
|
||||
eventMapping["hat"] = item.first.hat;
|
||||
eventMapping["hatDirection"] = item.first.hdir;
|
||||
if (_mapping.hat != -1) {
|
||||
eventMapping["hat"] = _mapping.hat;
|
||||
eventMapping["hatDirection"] = _mapping.hdir;
|
||||
}
|
||||
|
||||
eventMappings.push_back(eventMapping);
|
||||
|
@ -221,7 +247,7 @@ int JoyMap::loadMapping(const json& eventMappings, const EventMode mode)
|
|||
{
|
||||
int i = 0;
|
||||
|
||||
for (const json& eventMapping: eventMappings) {
|
||||
for(const json& eventMapping : eventMappings) {
|
||||
int button = eventMapping.contains("button") ? eventMapping.at("button").get<int>() : JOY_CTRL_NONE;
|
||||
JoyAxis axis = eventMapping.contains("axis") ? eventMapping.at("axis").get<JoyAxis>() : JoyAxis::NONE;
|
||||
JoyDir axisDirection = eventMapping.contains("axis") ? eventMapping.at("axisDirection").get<JoyDir>() : JoyDir::NONE;
|
||||
|
@ -240,7 +266,7 @@ int JoyMap::loadMapping(const json& eventMappings, const EventMode mode)
|
|||
);
|
||||
|
||||
i++;
|
||||
} catch (json::exception) {
|
||||
} catch (const json::exception&) {
|
||||
Logger::error("ignoring invalid joystick event");
|
||||
}
|
||||
}
|
||||
|
@ -262,7 +288,7 @@ json JoyMap::convertLegacyMapping(string list)
|
|||
istringstream buf(list);
|
||||
int event, button, axis, adir, hat, hdir;
|
||||
|
||||
while (buf >> event && buf >> button
|
||||
while(buf >> event && buf >> button
|
||||
&& buf >> axis && buf >> adir
|
||||
&& buf >> hat && buf >> hdir)
|
||||
{
|
||||
|
@ -270,14 +296,14 @@ json JoyMap::convertLegacyMapping(string list)
|
|||
|
||||
eventMapping["event"] = Event::Type(event);
|
||||
|
||||
if (button != JOY_CTRL_NONE) eventMapping["button"] = button;
|
||||
if(button != JOY_CTRL_NONE) eventMapping["button"] = button;
|
||||
|
||||
if (JoyAxis(axis) != JoyAxis::NONE) {
|
||||
if(JoyAxis(axis) != JoyAxis::NONE) {
|
||||
eventMapping["axis"] = JoyAxis(axis);
|
||||
eventMapping["axisDirection"] = JoyDir(adir);
|
||||
}
|
||||
|
||||
if (hat != -1) {
|
||||
if(hat != -1) {
|
||||
eventMapping["hat"] = hat;
|
||||
eventMapping["hatDirection"] = JoyHatDir(hdir);
|
||||
}
|
||||
|
@ -291,8 +317,8 @@ json JoyMap::convertLegacyMapping(string list)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JoyMap::eraseMode(const EventMode mode)
|
||||
{
|
||||
for (auto item = myMap.begin(); item != myMap.end();)
|
||||
if (item->first.mode == mode) {
|
||||
for(auto item = myMap.begin(); item != myMap.end();)
|
||||
if(item->first.mode == mode) {
|
||||
auto _item = item++;
|
||||
erase(_item->first);
|
||||
}
|
||||
|
@ -302,8 +328,8 @@ void JoyMap::eraseMode(const EventMode mode)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JoyMap::eraseEvent(const Event::Type event, const EventMode mode)
|
||||
{
|
||||
for (auto item = myMap.begin(); item != myMap.end();)
|
||||
if (item->second == event && item->first.mode == mode) {
|
||||
for(auto item = myMap.begin(); item != myMap.end();)
|
||||
if(item->second == event && item->first.mode == mode) {
|
||||
auto _item = item++;
|
||||
erase(_item->first);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "Event.hxx"
|
||||
#include "EventHandlerConstants.hxx"
|
||||
#include "json.hxx"
|
||||
#include "json_lib.hxx"
|
||||
|
||||
/**
|
||||
This class handles controller mappings in Stella.
|
||||
|
@ -44,19 +44,19 @@ class JoyMap
|
|||
explicit JoyMapping(EventMode c_mode, int c_button,
|
||||
JoyAxis c_axis, JoyDir c_adir,
|
||||
int c_hat, JoyHatDir c_hdir)
|
||||
: mode(c_mode), button(c_button),
|
||||
axis(c_axis), adir(c_adir),
|
||||
hat(c_hat), hdir(c_hdir) { }
|
||||
: mode{c_mode}, button{c_button},
|
||||
axis{c_axis}, adir{c_adir},
|
||||
hat{c_hat}, hdir{c_hdir} { }
|
||||
explicit JoyMapping(EventMode c_mode, int c_button,
|
||||
JoyAxis c_axis, JoyDir c_adir)
|
||||
: mode(c_mode), button(c_button),
|
||||
axis(c_axis), adir(c_adir),
|
||||
hat(JOY_CTRL_NONE), hdir(JoyHatDir::CENTER) { }
|
||||
: mode{c_mode}, button{c_button},
|
||||
axis{c_axis}, adir{c_adir},
|
||||
hat{JOY_CTRL_NONE}, hdir{JoyHatDir::CENTER} { }
|
||||
explicit JoyMapping(EventMode c_mode, int c_button,
|
||||
int c_hat, JoyHatDir c_hdir)
|
||||
: mode(c_mode), button(c_button),
|
||||
axis(JoyAxis::NONE), adir(JoyDir::NONE),
|
||||
hat(c_hat), hdir(c_hdir) { }
|
||||
: mode{c_mode}, button{c_button},
|
||||
axis{JoyAxis::NONE}, adir{JoyDir::NONE},
|
||||
hat{c_hat}, hdir{c_hdir} { }
|
||||
|
||||
JoyMapping(const JoyMapping&) = default;
|
||||
JoyMapping& operator=(const JoyMapping&) = default;
|
||||
|
|
|
@ -22,6 +22,52 @@
|
|||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace {
|
||||
json serializeModkeyMask(int mask)
|
||||
{
|
||||
if(mask == StellaMod::KBDM_NONE) return json(nullptr);
|
||||
|
||||
json serializedMask = json::array();
|
||||
|
||||
for(StellaMod mod: {
|
||||
StellaMod::KBDM_CTRL,
|
||||
StellaMod::KBDM_SHIFT,
|
||||
StellaMod::KBDM_ALT,
|
||||
StellaMod::KBDM_GUI,
|
||||
StellaMod::KBDM_LSHIFT,
|
||||
StellaMod::KBDM_RSHIFT,
|
||||
StellaMod::KBDM_LCTRL,
|
||||
StellaMod::KBDM_RCTRL,
|
||||
StellaMod::KBDM_LALT,
|
||||
StellaMod::KBDM_RALT,
|
||||
StellaMod::KBDM_LGUI,
|
||||
StellaMod::KBDM_RGUI,
|
||||
StellaMod::KBDM_NUM,
|
||||
StellaMod::KBDM_CAPS,
|
||||
StellaMod::KBDM_MODE,
|
||||
StellaMod::KBDM_RESERVED
|
||||
}) {
|
||||
if((mask & mod) != mod) continue;
|
||||
|
||||
serializedMask.push_back(json(mod));
|
||||
mask &= ~mod;
|
||||
}
|
||||
|
||||
return serializedMask.size() == 1 ? serializedMask.at(0) : serializedMask;
|
||||
}
|
||||
|
||||
int deserializeModkeyMask(json serializedMask)
|
||||
{
|
||||
if(serializedMask.is_null()) return StellaMod::KBDM_NONE;
|
||||
if(!serializedMask.is_array()) return serializedMask.get<StellaMod>();
|
||||
|
||||
int mask = 0;
|
||||
for(const json& mod: serializedMask) mask |= mod.get<StellaMod>();
|
||||
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void KeyMap::add(const Event::Type event, const Mapping& mapping)
|
||||
{
|
||||
|
@ -51,10 +97,10 @@ Event::Type KeyMap::get(const Mapping& mapping) const
|
|||
{
|
||||
Mapping m = convertMod(mapping);
|
||||
|
||||
if (myModEnabled)
|
||||
if(myModEnabled)
|
||||
{
|
||||
auto find = myMap.find(m);
|
||||
if (find != myMap.end())
|
||||
if(find != myMap.end())
|
||||
return find->second;
|
||||
}
|
||||
|
||||
|
@ -62,7 +108,7 @@ Event::Type KeyMap::get(const Mapping& mapping) const
|
|||
m.mod = StellaMod(0);
|
||||
|
||||
auto find = myMap.find(m);
|
||||
if (find != myMap.end())
|
||||
if(find != myMap.end())
|
||||
return find->second;
|
||||
|
||||
return Event::Type::NoType;
|
||||
|
@ -112,26 +158,26 @@ string KeyMap::getDesc(const Mapping& mapping) const
|
|||
int RMOD3 = KBDM_RALT;
|
||||
#endif
|
||||
|
||||
if ((mapping.mod & KBDM_CTRL) == KBDM_CTRL) buf << "Ctrl";
|
||||
else if (mapping.mod & KBDM_LCTRL) buf << "Left Ctrl";
|
||||
else if (mapping.mod & KBDM_RCTRL) buf << "Right Ctrl";
|
||||
if((mapping.mod & KBDM_CTRL) == KBDM_CTRL) buf << "Ctrl";
|
||||
else if(mapping.mod & KBDM_LCTRL) buf << "Left Ctrl";
|
||||
else if(mapping.mod & KBDM_RCTRL) buf << "Right Ctrl";
|
||||
|
||||
if ((mapping.mod & (MOD2)) && buf.tellp()) buf << "+";
|
||||
if ((mapping.mod & MOD2) == MOD2) buf << mod2;
|
||||
else if (mapping.mod & LMOD2) buf << "Left " << mod2;
|
||||
else if (mapping.mod & RMOD2) buf << "Right " << mod2;
|
||||
if((mapping.mod & (MOD2)) && buf.tellp()) buf << "+";
|
||||
if((mapping.mod & MOD2) == MOD2) buf << mod2;
|
||||
else if(mapping.mod & LMOD2) buf << "Left " << mod2;
|
||||
else if(mapping.mod & RMOD2) buf << "Right " << mod2;
|
||||
|
||||
if ((mapping.mod & (MOD3)) && buf.tellp()) buf << "+";
|
||||
if ((mapping.mod & MOD3) == MOD3) buf << mod3;
|
||||
else if (mapping.mod & LMOD3) buf << "Left " << mod3;
|
||||
else if (mapping.mod & RMOD3) buf << "Right " << mod3;
|
||||
if((mapping.mod & (MOD3)) && buf.tellp()) buf << "+";
|
||||
if((mapping.mod & MOD3) == MOD3) buf << mod3;
|
||||
else if(mapping.mod & LMOD3) buf << "Left " << mod3;
|
||||
else if(mapping.mod & RMOD3) buf << "Right " << mod3;
|
||||
|
||||
if ((mapping.mod & (KBDM_SHIFT)) && buf.tellp()) buf << "+";
|
||||
if ((mapping.mod & KBDM_SHIFT) == KBDM_SHIFT) buf << "Shift";
|
||||
else if (mapping.mod & KBDM_LSHIFT) buf << "Left Shift";
|
||||
else if (mapping.mod & KBDM_RSHIFT) buf << "Right Shift";
|
||||
if((mapping.mod & (KBDM_SHIFT)) && buf.tellp()) buf << "+";
|
||||
if((mapping.mod & KBDM_SHIFT) == KBDM_SHIFT) buf << "Shift";
|
||||
else if(mapping.mod & KBDM_LSHIFT) buf << "Left Shift";
|
||||
else if(mapping.mod & KBDM_RSHIFT) buf << "Right Shift";
|
||||
|
||||
if (buf.tellp()) buf << "+";
|
||||
if(buf.tellp()) buf << "+";
|
||||
buf << StellaKeyName::forKey(mapping.key);
|
||||
|
||||
return buf.str();
|
||||
|
@ -148,13 +194,13 @@ string KeyMap::getEventMappingDesc(const Event::Type event, const EventMode mode
|
|||
{
|
||||
ostringstream buf;
|
||||
|
||||
for (auto item : myMap)
|
||||
for (const auto& [_mapping, _event]: myMap)
|
||||
{
|
||||
if (item.second == event && item.first.mode == mode)
|
||||
if (_event == event && _mapping.mode == mode)
|
||||
{
|
||||
if (buf.str() != "")
|
||||
if(buf.str() != "")
|
||||
buf << ", ";
|
||||
buf << getDesc(item.first);
|
||||
buf << getDesc(_mapping);
|
||||
}
|
||||
}
|
||||
return buf.str();
|
||||
|
@ -165,9 +211,9 @@ KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const Even
|
|||
{
|
||||
MappingArray map;
|
||||
|
||||
for (auto item : myMap)
|
||||
if (item.second == event && item.first.mode == mode)
|
||||
map.push_back(item.first);
|
||||
for (const auto& [_mapping, _event]: myMap)
|
||||
if (_event == event && _mapping.mode == mode)
|
||||
map.push_back(_mapping);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
@ -175,18 +221,35 @@ KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const Even
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
json KeyMap::saveMapping(const EventMode mode) const
|
||||
{
|
||||
using MapType = std::pair<Mapping, Event::Type>;
|
||||
std::vector<MapType> sortedMap(myMap.begin(), myMap.end());
|
||||
|
||||
std::sort(sortedMap.begin(), sortedMap.end(),
|
||||
[](const MapType& a, const MapType& b)
|
||||
{
|
||||
// Event::Type first
|
||||
if(a.first.key != b.first.key)
|
||||
return a.first.key < b.first.key;
|
||||
|
||||
if(a.first.mod != b.first.mod)
|
||||
return a.first.mod < b.first.mod;
|
||||
|
||||
return a.second < b.second;
|
||||
}
|
||||
);
|
||||
|
||||
json mappings = json::array();
|
||||
|
||||
for (auto item : myMap) {
|
||||
if (item.first.mode != mode) continue;
|
||||
for (const auto& [_mapping, _event]: sortedMap) {
|
||||
if (_mapping.mode != mode) continue;
|
||||
|
||||
json mapping = json::object();
|
||||
|
||||
mapping["event"] = item.second;
|
||||
mapping["key"] = item.first.key;
|
||||
mapping["event"] = _event;
|
||||
mapping["key"] = _mapping.key;
|
||||
|
||||
if (item.first.mod != StellaMod::KBDM_NONE)
|
||||
mapping["mod"] = item.first.mod;
|
||||
if (_mapping.mod != StellaMod::KBDM_NONE)
|
||||
mapping["mod"] = serializeModkeyMask(_mapping.mod);
|
||||
|
||||
mappings.push_back(mapping);
|
||||
}
|
||||
|
@ -198,17 +261,18 @@ json KeyMap::saveMapping(const EventMode mode) const
|
|||
int KeyMap::loadMapping(const json& mappings, const EventMode mode) {
|
||||
int i = 0;
|
||||
|
||||
for (const json& mapping: mappings) {
|
||||
for(const json& mapping : mappings)
|
||||
{
|
||||
try {
|
||||
add(
|
||||
mapping.at("event").get<Event::Type>(),
|
||||
mode,
|
||||
mapping.at("key").get<StellaKey>(),
|
||||
mapping.contains("mod") ? mapping.at("mod").get<StellaMod>() : StellaMod::KBDM_NONE
|
||||
mapping.contains("mod") ? deserializeModkeyMask(mapping.at("mod")) : StellaMod::KBDM_NONE
|
||||
);
|
||||
|
||||
i++;
|
||||
} catch (json::exception) {
|
||||
} catch (const json::exception&) {
|
||||
Logger::error("ignoring bad keyboard mapping");
|
||||
}
|
||||
}
|
||||
|
@ -229,13 +293,15 @@ json KeyMap::convertLegacyMapping(string list)
|
|||
istringstream buf(list);
|
||||
int event, key, mod;
|
||||
|
||||
while (buf >> event && buf >> key && buf >> mod) {
|
||||
while(buf >> event && buf >> key && buf >> mod)
|
||||
{
|
||||
json mapping = json::object();
|
||||
|
||||
mapping["event"] = Event::Type(event);
|
||||
mapping["key"] = StellaKey(key);
|
||||
|
||||
if (StellaMod(mod) != StellaMod::KBDM_NONE) mapping["mod"] = StellaMod(mod);
|
||||
if(StellaMod(mod) != StellaMod::KBDM_NONE)
|
||||
mapping["mod"] = serializeModkeyMask(StellaMod(mod));
|
||||
|
||||
convertedMapping.push_back(mapping);
|
||||
}
|
||||
|
@ -246,8 +312,8 @@ json KeyMap::convertLegacyMapping(string list)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void KeyMap::eraseMode(const EventMode mode)
|
||||
{
|
||||
for (auto item = myMap.begin(); item != myMap.end();)
|
||||
if (item->first.mode == mode) {
|
||||
for(auto item = myMap.begin(); item != myMap.end();)
|
||||
if(item->first.mode == mode) {
|
||||
auto _item = item++;
|
||||
erase(_item->first);
|
||||
}
|
||||
|
@ -257,8 +323,8 @@ void KeyMap::eraseMode(const EventMode mode)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void KeyMap::eraseEvent(const Event::Type event, const EventMode mode)
|
||||
{
|
||||
for (auto item = myMap.begin(); item != myMap.end();)
|
||||
if (item->second == event && item->first.mode == mode) {
|
||||
for(auto item = myMap.begin(); item != myMap.end();)
|
||||
if(item->second == event && item->first.mode == mode) {
|
||||
auto _item = item++;
|
||||
erase(_item->first);
|
||||
}
|
||||
|
@ -270,7 +336,7 @@ KeyMap::Mapping KeyMap::convertMod(const Mapping& mapping) const
|
|||
{
|
||||
Mapping m = mapping;
|
||||
|
||||
if (m.key >= KBDK_LCTRL && m.key <= KBDK_RGUI)
|
||||
if(m.key >= KBDK_LCTRL && m.key <= KBDK_RGUI)
|
||||
// handle solo modifier keys differently
|
||||
m.mod = KBDM_NONE;
|
||||
else
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "Event.hxx"
|
||||
#include "EventHandlerConstants.hxx"
|
||||
#include "StellaKeys.hxx"
|
||||
#include "json.hxx"
|
||||
#include "json_lib.hxx"
|
||||
|
||||
/**
|
||||
This class handles keyboard mappings in Stella.
|
||||
|
@ -39,9 +39,9 @@ class KeyMap
|
|||
StellaMod mod{StellaMod(0)};
|
||||
|
||||
explicit Mapping(EventMode c_mode, StellaKey c_key, StellaMod c_mod)
|
||||
: mode(c_mode), key(c_key), mod(c_mod) { }
|
||||
: mode{c_mode}, key{c_key}, mod{c_mod} { }
|
||||
explicit Mapping(EventMode c_mode, int c_key, int c_mod)
|
||||
: mode(c_mode), key(StellaKey(c_key)), mod(StellaMod(c_mod)) { }
|
||||
: mode{c_mode}, key{StellaKey(c_key)}, mod{StellaMod(c_mod)} { }
|
||||
Mapping(const Mapping&) = default;
|
||||
Mapping& operator=(const Mapping&) = default;
|
||||
Mapping(Mapping&&) = default;
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
MouseControl::MouseControl(Console& console, const string& mode)
|
||||
: myProps(console.properties()),
|
||||
myLeftController(console.leftController()),
|
||||
myRightController(console.rightController())
|
||||
: myProps{console.properties()},
|
||||
myLeftController{console.leftController()},
|
||||
myRightController{console.rightController()}
|
||||
{
|
||||
istringstream m_axis(mode);
|
||||
string m_mode;
|
||||
|
@ -137,14 +137,18 @@ MouseControl::MouseControl(Console& console, const string& mode)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string& MouseControl::next()
|
||||
const string& MouseControl::change(int direction)
|
||||
{
|
||||
myCurrentModeNum = BSPF::clampw(myCurrentModeNum + direction, 0, int(myModeList.size() - 1));
|
||||
const MouseMode& mode = myModeList[myCurrentModeNum];
|
||||
myCurrentModeNum = (myCurrentModeNum + 1) % myModeList.size();
|
||||
|
||||
bool leftControl =
|
||||
myLeftController.setMouseControl(mode.xtype, mode.xid, mode.ytype, mode.yid);
|
||||
bool rightControl =
|
||||
myRightController.setMouseControl(mode.xtype, mode.xid, mode.ytype, mode.yid);
|
||||
|
||||
myHasMouseControl = leftControl || rightControl;
|
||||
|
||||
return mode.message;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,12 @@ class MouseControl
|
|||
|
||||
@return A message explaining the current mouse mode
|
||||
*/
|
||||
const string& next();
|
||||
const string& change(int direction = +1);
|
||||
|
||||
/**
|
||||
Get whether any current controller supports mouse control
|
||||
*/
|
||||
bool hasMouseControl() const { return myHasMouseControl; }
|
||||
|
||||
private:
|
||||
void addLeftControllerModes(bool noswap);
|
||||
|
@ -101,6 +106,7 @@ class MouseControl
|
|||
|
||||
int myCurrentModeNum{0};
|
||||
vector<MouseMode> myModeList;
|
||||
bool myHasMouseControl{false};
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#include "OSystem.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "Joystick.hxx"
|
||||
#include "Paddles.hxx"
|
||||
#include "PointingDevice.hxx"
|
||||
#include "Driving.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "PJoystickHandler.hxx"
|
||||
|
@ -33,8 +36,8 @@ using json = nlohmann::json;
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalJoystickHandler::PhysicalJoystickHandler(
|
||||
OSystem& system, EventHandler& handler)
|
||||
: myOSystem(system),
|
||||
myHandler(handler)
|
||||
: myOSystem{system},
|
||||
myHandler{handler}
|
||||
{
|
||||
if(myOSystem.settings().getInt("event_ver") != Event::VERSION) {
|
||||
Logger::info("event version mismatch; dropping previous joystick mappings");
|
||||
|
@ -47,7 +50,7 @@ PhysicalJoystickHandler::PhysicalJoystickHandler(
|
|||
|
||||
try {
|
||||
mappings = json::parse(serializedMapping);
|
||||
} catch (json::exception) {
|
||||
} catch (const json::exception&) {
|
||||
Logger::info("converting legacy joystick mappings");
|
||||
|
||||
mappings = convertLegacyMapping(serializedMapping);
|
||||
|
@ -122,8 +125,8 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
|
|||
// For non-unique names that already have a database entry,
|
||||
// we append ' #x', where 'x' increases consecutively
|
||||
int count = 0;
|
||||
for(const auto& i: myDatabase)
|
||||
if(BSPF::startsWithIgnoreCase(i.first, stick->name) && i.second.joy)
|
||||
for(const auto& [_name, _info]: myDatabase)
|
||||
if(BSPF::startsWithIgnoreCase(_name, stick->name) && _info.joy)
|
||||
++count;
|
||||
|
||||
if(count > 0)
|
||||
|
@ -132,12 +135,13 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
|
|||
name << stick->name << " #" << count+1;
|
||||
stick->name = name.str();
|
||||
}
|
||||
stick->type = PhysicalJoystick::JT_REGULAR;
|
||||
stick->type = PhysicalJoystick::Type::REGULAR;
|
||||
}
|
||||
// The stick *must* be inserted here, since it may be used below
|
||||
mySticks[stick->ID] = stick;
|
||||
|
||||
// Map the stelladaptors we've found according to the specified ports
|
||||
// The 'type' is also set there
|
||||
if(specialAdaptor)
|
||||
mapStelladaptors(myOSystem.settings().getString("saport"));
|
||||
|
||||
|
@ -217,45 +221,45 @@ void PhysicalJoystickHandler::mapStelladaptors(const string& saport)
|
|||
// We know there will be only two such devices (at most), since the logic
|
||||
// in setupJoysticks take care of that
|
||||
int saCount = 0;
|
||||
int saOrder[NUM_PORTS] = { 1, 2 };
|
||||
int saOrder[] = { 1, 2 };
|
||||
if(BSPF::equalsIgnoreCase(saport, "rl"))
|
||||
{
|
||||
saOrder[0] = 2; saOrder[1] = 1;
|
||||
}
|
||||
|
||||
for(auto& stick: mySticks)
|
||||
for(auto& [_id, _joyptr]: mySticks)
|
||||
{
|
||||
// remove previously added emulated ports
|
||||
size_t pos = stick.second->name.find(" (emulates ");
|
||||
size_t pos = _joyptr->name.find(" (emulates ");
|
||||
|
||||
if(pos != std::string::npos)
|
||||
stick.second->name.erase(pos);
|
||||
_joyptr->name.erase(pos);
|
||||
|
||||
if(BSPF::startsWithIgnoreCase(stick.second->name, "Stelladaptor"))
|
||||
if(BSPF::startsWithIgnoreCase(_joyptr->name, "Stelladaptor"))
|
||||
{
|
||||
if(saOrder[saCount] == 1)
|
||||
{
|
||||
stick.second->name += " (emulates left joystick port)";
|
||||
stick.second->type = PhysicalJoystick::JT_STELLADAPTOR_LEFT;
|
||||
_joyptr->name += " (emulates left joystick port)";
|
||||
_joyptr->type = PhysicalJoystick::Type::LEFT_STELLADAPTOR;
|
||||
}
|
||||
else if(saOrder[saCount] == 2)
|
||||
{
|
||||
stick.second->name += " (emulates right joystick port)";
|
||||
stick.second->type = PhysicalJoystick::JT_STELLADAPTOR_RIGHT;
|
||||
_joyptr->name += " (emulates right joystick port)";
|
||||
_joyptr->type = PhysicalJoystick::Type::RIGHT_STELLADAPTOR;
|
||||
}
|
||||
saCount++;
|
||||
}
|
||||
else if(BSPF::startsWithIgnoreCase(stick.second->name, "2600-daptor"))
|
||||
else if(BSPF::startsWithIgnoreCase(_joyptr->name, "2600-daptor"))
|
||||
{
|
||||
if(saOrder[saCount] == 1)
|
||||
{
|
||||
stick.second->name += " (emulates left joystick port)";
|
||||
stick.second->type = PhysicalJoystick::JT_2600DAPTOR_LEFT;
|
||||
_joyptr->name += " (emulates left joystick port)";
|
||||
_joyptr->type = PhysicalJoystick::Type::LEFT_2600DAPTOR;
|
||||
}
|
||||
else if(saOrder[saCount] == 2)
|
||||
{
|
||||
stick.second->name += " (emulates right joystick port)";
|
||||
stick.second->type = PhysicalJoystick::JT_2600DAPTOR_RIGHT;
|
||||
_joyptr->name += " (emulates right joystick port)";
|
||||
_joyptr->type = PhysicalJoystick::Type::RIGHT_2600DAPTOR;
|
||||
}
|
||||
saCount++;
|
||||
}
|
||||
|
@ -263,6 +267,24 @@ void PhysicalJoystickHandler::mapStelladaptors(const string& saport)
|
|||
myOSystem.settings().setValue("saport", saport);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool PhysicalJoystickHandler::hasStelladaptors() const
|
||||
{
|
||||
for(auto& [_id, _joyptr] : mySticks)
|
||||
{
|
||||
// remove previously added emulated ports
|
||||
size_t pos = _joyptr->name.find(" (emulates ");
|
||||
|
||||
if(pos != std::string::npos)
|
||||
_joyptr->name.erase(pos);
|
||||
|
||||
if(BSPF::startsWithIgnoreCase(_joyptr->name, "Stelladaptor")
|
||||
|| BSPF::startsWithIgnoreCase(_joyptr->name, "2600-daptor"))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Depending on parameters, this method does the following:
|
||||
// 1. update all events with default (event == Event::NoType, updateDefault == true)
|
||||
|
@ -313,7 +335,15 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
|
|||
switch (mode)
|
||||
{
|
||||
case EventMode::kEmulationMode:
|
||||
if((stick % 2) == 0) // even sticks
|
||||
{
|
||||
// A regular joystick defaults to left or right based on the
|
||||
// stick number being even or odd; 'daptor joysticks request a
|
||||
// specific port
|
||||
const bool useLeftMappings =
|
||||
j->type == PhysicalJoystick::Type::REGULAR ? ((stick % 2) == 0) :
|
||||
(j->type == PhysicalJoystick::Type::LEFT_STELLADAPTOR ||
|
||||
j->type == PhysicalJoystick::Type::LEFT_2600DAPTOR);
|
||||
if(useLeftMappings)
|
||||
{
|
||||
// put all controller events into their own mode's mappings
|
||||
for (const auto& item : DefaultLeftJoystickMapping)
|
||||
|
@ -323,7 +353,7 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
|
|||
for (const auto& item : DefaultLeftKeypadMapping)
|
||||
setDefaultAction(stick, item, event, EventMode::kKeypadMode, updateDefaults);
|
||||
}
|
||||
else // odd sticks
|
||||
else
|
||||
{
|
||||
// put all controller events into their own mode's mappings
|
||||
for (const auto& item : DefaultRightJoystickMapping)
|
||||
|
@ -338,6 +368,7 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
|
|||
// update running emulation mapping too
|
||||
enableEmulationMappings();
|
||||
break;
|
||||
}
|
||||
|
||||
case EventMode::kMenuMode:
|
||||
for (const auto& item : DefaultMenuMapping)
|
||||
|
@ -354,8 +385,8 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
|
|||
void PhysicalJoystickHandler::setDefaultMapping(Event::Type event, EventMode mode)
|
||||
{
|
||||
eraseMapping(event, mode);
|
||||
for (auto& i : mySticks)
|
||||
setStickDefaultMapping(i.first, event, mode);
|
||||
for (const auto& [_id, _joyptr]: mySticks)
|
||||
setStickDefaultMapping(_id, event, mode);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -529,24 +560,24 @@ void PhysicalJoystickHandler::eraseMapping(Event::Type event, EventMode mode)
|
|||
// Otherwise, only reset the given event
|
||||
if(event == Event::NoType)
|
||||
{
|
||||
for (auto& stick : mySticks)
|
||||
for (auto& [_id, _joyptr]: mySticks)
|
||||
{
|
||||
stick.second->eraseMap(mode); // erase all events
|
||||
_joyptr->eraseMap(mode); // erase all events
|
||||
if(mode == EventMode::kEmulationMode)
|
||||
{
|
||||
stick.second->eraseMap(EventMode::kCommonMode);
|
||||
stick.second->eraseMap(EventMode::kJoystickMode);
|
||||
stick.second->eraseMap(EventMode::kPaddlesMode);
|
||||
stick.second->eraseMap(EventMode::kKeypadMode);
|
||||
_joyptr->eraseMap(EventMode::kCommonMode);
|
||||
_joyptr->eraseMap(EventMode::kJoystickMode);
|
||||
_joyptr->eraseMap(EventMode::kPaddlesMode);
|
||||
_joyptr->eraseMap(EventMode::kKeypadMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& stick : mySticks)
|
||||
for (auto& [_id, _joyptr]: mySticks)
|
||||
{
|
||||
stick.second->eraseEvent(event, mode); // only reset the specific event
|
||||
stick.second->eraseEvent(event, getEventMode(event, mode));
|
||||
_joyptr->eraseEvent(event, mode); // only reset the specific event
|
||||
_joyptr->eraseEvent(event, getEventMode(event, mode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -558,9 +589,9 @@ void PhysicalJoystickHandler::saveMapping()
|
|||
// any changes that have been made during the program run
|
||||
json mapping = json::array();
|
||||
|
||||
for(const auto& i: myDatabase)
|
||||
for(const auto& [_name, _info]: myDatabase)
|
||||
{
|
||||
json map = i.second.joy ? i.second.joy->getMap() : i.second.mapping;
|
||||
json map = _info.joy ? _info.joy->getMap() : _info.mapping;
|
||||
|
||||
if (!map.is_null()) mapping.emplace_back(map);
|
||||
}
|
||||
|
@ -574,19 +605,16 @@ string PhysicalJoystickHandler::getMappingDesc(Event::Type event, EventMode mode
|
|||
ostringstream buf;
|
||||
EventMode evMode = getEventMode(event, mode);
|
||||
|
||||
for(const auto& s: mySticks)
|
||||
for(const auto& [_id, _joyptr]: mySticks)
|
||||
{
|
||||
uInt32 stick = s.first;
|
||||
const PhysicalJoystickPtr j = s.second;
|
||||
|
||||
if(j)
|
||||
if(_joyptr)
|
||||
{
|
||||
//Joystick mapping / labeling
|
||||
if(j->joyMap.getEventMapping(event, evMode).size())
|
||||
if(_joyptr->joyMap.getEventMapping(event, evMode).size())
|
||||
{
|
||||
if(buf.str() != "")
|
||||
buf << ", ";
|
||||
buf << j->joyMap.getEventMappingDesc(stick, event, evMode);
|
||||
buf << _joyptr->joyMap.getEventMappingDesc(_id, event, evMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -819,8 +847,8 @@ void PhysicalJoystickHandler::handleHatEvent(int stick, int hat, int value)
|
|||
VariantList PhysicalJoystickHandler::database() const
|
||||
{
|
||||
VariantList db;
|
||||
for(const auto& i: myDatabase)
|
||||
VarList::push_back(db, i.first, i.second.joy ? i.second.joy->ID : -1);
|
||||
for(const auto& [_name, _info]: myDatabase)
|
||||
VarList::push_back(db, _name, _info.joy ? _info.joy->ID : -1);
|
||||
|
||||
return db;
|
||||
}
|
||||
|
@ -830,19 +858,160 @@ ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh)
|
|||
{
|
||||
os << "---------------------------------------------------------" << endl
|
||||
<< "joy database:" << endl;
|
||||
for(const auto& i: jh.myDatabase)
|
||||
os << i.first << endl << i.second << endl << endl;
|
||||
for(const auto& [_name, _info]: jh.myDatabase)
|
||||
os << _name << endl << _info << endl << endl;
|
||||
|
||||
os << "---------------------" << endl
|
||||
<< "joy active:" << endl;
|
||||
for(const auto& i: jh.mySticks)
|
||||
os << i.first << ": " << *i.second << endl;
|
||||
for(const auto& [_id, _joyptr]: jh.mySticks)
|
||||
os << _id << ": " << *_joyptr << endl;
|
||||
os << "---------------------------------------------------------"
|
||||
<< endl << endl << endl;
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeDeadzone(int direction)
|
||||
{
|
||||
int deadzone = BSPF::clamp(myOSystem.settings().getInt("joydeadzone") + direction,
|
||||
Joystick::DEAD_ZONE_MIN, Joystick::DEAD_ZONE_MAX);
|
||||
myOSystem.settings().setValue("joydeadzone", deadzone);
|
||||
|
||||
Joystick::setDeadZone(deadzone);
|
||||
|
||||
int value = Joystick::deadZoneValue(deadzone);
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Joystick deadzone", std::to_string(value),
|
||||
value, 3200, 32200);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeAnalogPaddleSensitivity(int direction)
|
||||
{
|
||||
int sense = BSPF::clamp(myOSystem.settings().getInt("psense") + direction,
|
||||
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
|
||||
myOSystem.settings().setValue("psense", sense);
|
||||
|
||||
Paddles::setAnalogSensitivity(sense);
|
||||
|
||||
ostringstream ss;
|
||||
ss << std::round(Paddles::analogSensitivityValue(sense) * 100.F) << "%";
|
||||
myOSystem.frameBuffer().showGaugeMessage("Analog paddle sensitivity", ss.str(), sense,
|
||||
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changePaddleDejitterAveraging(int direction)
|
||||
{
|
||||
int dejitter = BSPF::clamp(myOSystem.settings().getInt("dejitter.base") + direction,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
myOSystem.settings().setValue("dejitter.base", dejitter);
|
||||
|
||||
Paddles::setDejitterBase(dejitter);
|
||||
|
||||
ostringstream ss;
|
||||
if(dejitter)
|
||||
ss << dejitter;
|
||||
else
|
||||
ss << "Off";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Analog paddle dejitter averaging",
|
||||
ss.str(), dejitter,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changePaddleDejitterReaction(int direction)
|
||||
{
|
||||
int dejitter = BSPF::clamp(myOSystem.settings().getInt("dejitter.diff") + direction,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
myOSystem.settings().setValue("dejitter.diff", dejitter);
|
||||
|
||||
Paddles::setDejitterDiff(dejitter);
|
||||
|
||||
ostringstream ss;
|
||||
if(dejitter)
|
||||
ss << dejitter;
|
||||
else
|
||||
ss << "Off";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Analog paddle dejitter reaction",
|
||||
ss.str(), dejitter,
|
||||
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeDigitalPaddleSensitivity(int direction)
|
||||
{
|
||||
int sense = BSPF::clamp(myOSystem.settings().getInt("dsense") + direction,
|
||||
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
|
||||
myOSystem.settings().setValue("dsense", sense);
|
||||
|
||||
Paddles::setDigitalSensitivity(sense);
|
||||
|
||||
ostringstream ss;
|
||||
if(sense)
|
||||
ss << sense * 10 << "%";
|
||||
else
|
||||
ss << "Off";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Digital sensitivity",
|
||||
ss.str(), sense,
|
||||
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeMousePaddleSensitivity(int direction)
|
||||
{
|
||||
int sense = BSPF::clamp(myOSystem.settings().getInt("msense") + direction,
|
||||
Paddles::MIN_MOUSE_SENSE, Paddles::MAX_MOUSE_SENSE);
|
||||
myOSystem.settings().setValue("msense", sense);
|
||||
|
||||
Paddles::setMouseSensitivity(sense);
|
||||
|
||||
ostringstream ss;
|
||||
ss << sense * 10 << "%";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Mouse paddle sensitivity",
|
||||
ss.str(), sense,
|
||||
Paddles::MIN_MOUSE_SENSE, Paddles::MAX_MOUSE_SENSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeMouseTrackballSensitivity(int direction)
|
||||
{
|
||||
int sense = BSPF::clamp(myOSystem.settings().getInt("tsense") + direction,
|
||||
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
|
||||
myOSystem.settings().setValue("tsense", sense);
|
||||
|
||||
PointingDevice::setSensitivity(sense);
|
||||
|
||||
ostringstream ss;
|
||||
ss << sense * 10 << "%";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Mouse trackball sensitivity",
|
||||
ss.str(), sense,
|
||||
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalJoystickHandler::changeDrivingSensitivity(int direction)
|
||||
{
|
||||
int sense = BSPF::clamp(myOSystem.settings().getInt("dcsense") + direction,
|
||||
Driving::MIN_SENSE, Driving::MAX_SENSE);
|
||||
myOSystem.settings().setValue("dcsense", sense);
|
||||
|
||||
Driving::setSensitivity(sense);
|
||||
|
||||
ostringstream ss;
|
||||
ss << sense * 10 << "%";
|
||||
|
||||
myOSystem.frameBuffer().showGaugeMessage("Driving controller sensitivity",
|
||||
ss.str(), sense,
|
||||
Driving::MIN_SENSE, Driving::MAX_SENSE);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftJoystickMapping = {
|
||||
// Left joystick (assume buttons zero..two)
|
||||
|
@ -956,7 +1125,8 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRight
|
|||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultCommonMapping = {
|
||||
PhysicalJoystickHandler::EventMappingArray
|
||||
PhysicalJoystickHandler::DefaultCommonMapping = {
|
||||
// valid for all joysticks
|
||||
//#if defined(RETRON77)
|
||||
{Event::CmdMenuMode, 3}, // Note: buttons 0..2 are used by controllers!
|
||||
|
@ -969,7 +1139,8 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultCommo
|
|||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultMenuMapping = {
|
||||
PhysicalJoystickHandler::EventMappingArray
|
||||
PhysicalJoystickHandler::DefaultMenuMapping = {
|
||||
// valid for all joysticks
|
||||
{Event::UISelect, 0},
|
||||
{Event::UIOK, 1},
|
||||
|
|
|
@ -28,7 +28,7 @@ class Event;
|
|||
#include "EventHandlerConstants.hxx"
|
||||
#include "PhysicalJoystick.hxx"
|
||||
#include "Variant.hxx"
|
||||
#include "json.hxx"
|
||||
#include "json_lib.hxx"
|
||||
|
||||
using PhysicalJoystickPtr = shared_ptr<PhysicalJoystick>;
|
||||
|
||||
|
@ -49,8 +49,8 @@ class PhysicalJoystickHandler
|
|||
private:
|
||||
struct StickInfo
|
||||
{
|
||||
StickInfo(const nlohmann::json& map = nullptr, PhysicalJoystickPtr stick = nullptr)
|
||||
: mapping(map), joy(std::move(stick)) {}
|
||||
explicit StickInfo(nlohmann::json map, PhysicalJoystickPtr stick = nullptr)
|
||||
: mapping(map), joy{std::move(stick)} {}
|
||||
|
||||
nlohmann::json mapping;
|
||||
PhysicalJoystickPtr joy;
|
||||
|
@ -71,6 +71,7 @@ class PhysicalJoystickHandler
|
|||
bool remove(int id);
|
||||
bool remove(const string& name);
|
||||
void mapStelladaptors(const string& saport);
|
||||
bool hasStelladaptors() const;
|
||||
void setDefaultMapping(Event::Type type, EventMode mode);
|
||||
|
||||
/** define mappings for current controllers */
|
||||
|
@ -109,6 +110,15 @@ class PhysicalJoystickHandler
|
|||
/** Returns a list of pairs consisting of joystick name and associated ID. */
|
||||
VariantList database() const;
|
||||
|
||||
void changeDeadzone(int direction = +1);
|
||||
void changeAnalogPaddleSensitivity(int direction = +1);
|
||||
void changePaddleDejitterAveraging(int direction = +1);
|
||||
void changePaddleDejitterReaction(int direction = +1);
|
||||
void changeDigitalPaddleSensitivity(int direction = +1);
|
||||
void changeMousePaddleSensitivity(int direction = +1);
|
||||
void changeMouseTrackballSensitivity(int direction = +1);
|
||||
void changeDrivingSensitivity(int direction = +1);
|
||||
|
||||
private:
|
||||
using StickDatabase = std::map<string,StickInfo>;
|
||||
using StickList = std::map<int, PhysicalJoystickPtr>;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "Console.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "PKeyboardHandler.hxx"
|
||||
#include "json.hxx"
|
||||
#include "json_lib.hxx"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
|
@ -40,8 +40,8 @@ static constexpr int MOD3 = KBDM_ALT;
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler& handler)
|
||||
: myOSystem(system),
|
||||
myHandler(handler)
|
||||
: myOSystem{system},
|
||||
myHandler{handler}
|
||||
{
|
||||
Int32 version = myOSystem.settings().getInt("event_ver");
|
||||
bool updateDefaults = false;
|
||||
|
@ -74,7 +74,7 @@ void PhysicalKeyboardHandler::loadSerializedMappings(const string& serializedMap
|
|||
|
||||
try {
|
||||
mapping = json::parse(serializedMapping);
|
||||
} catch (json::exception) {
|
||||
} catch (const json::exception&) {
|
||||
Logger::info("converting legacy keyboard mappings");
|
||||
|
||||
mapping = KeyMap::convertLegacyMapping(serializedMapping);
|
||||
|
@ -82,7 +82,7 @@ void PhysicalKeyboardHandler::loadSerializedMappings(const string& serializedMap
|
|||
|
||||
try {
|
||||
myKeyMap.loadMapping(mapping, mode);
|
||||
} catch (json::exception) {
|
||||
} catch (const json::exception&) {
|
||||
Logger::error("ignoring bad keyboard mappings");
|
||||
}
|
||||
}
|
||||
|
@ -480,160 +480,215 @@ void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod,
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PhysicalKeyboardHandler::toggleModKeys(bool toggle)
|
||||
{
|
||||
bool modCombo = myOSystem.settings().getBool("modcombo");
|
||||
|
||||
if(toggle)
|
||||
{
|
||||
modCombo = !modCombo;
|
||||
myKeyMap.enableMod() = modCombo;
|
||||
myOSystem.settings().setValue("modcombo", modCombo);
|
||||
}
|
||||
|
||||
ostringstream ss;
|
||||
ss << "Modifier key combos ";
|
||||
ss << (modCombo ? "enabled" : "disabled");
|
||||
myOSystem.frameBuffer().showTextMessage(ss.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PhysicalKeyboardHandler::EventMappingArray
|
||||
PhysicalKeyboardHandler::DefaultCommonMapping = {
|
||||
{Event::ConsoleSelect, KBDK_F1},
|
||||
{Event::ConsoleReset, KBDK_F2},
|
||||
{Event::ConsoleColor, KBDK_F3},
|
||||
{Event::Console7800Pause, KBDK_F3, MOD3},
|
||||
{Event::ConsoleLeftDiffA, KBDK_F5},
|
||||
{Event::ConsoleRightDiffA, KBDK_F7},
|
||||
{Event::SaveState, KBDK_F9},
|
||||
{Event::SaveAllStates, KBDK_F9, MOD3},
|
||||
{Event::PreviousState, KBDK_F10, KBDM_SHIFT},
|
||||
{Event::NextState, KBDK_F10},
|
||||
{Event::ToggleAutoSlot, KBDK_F10, MOD3},
|
||||
{Event::LoadState, KBDK_F11},
|
||||
{Event::LoadAllStates, KBDK_F11, MOD3},
|
||||
{Event::TakeSnapshot, KBDK_F12},
|
||||
#ifdef BSPF_MACOS
|
||||
{Event::TogglePauseMode, KBDK_P, KBDM_SHIFT | MOD3},
|
||||
#else
|
||||
{Event::TogglePauseMode, KBDK_PAUSE},
|
||||
#endif
|
||||
{Event::OptionsMenuMode, KBDK_TAB},
|
||||
{Event::CmdMenuMode, KBDK_BACKSLASH},
|
||||
{Event::TimeMachineMode, KBDK_T, KBDM_SHIFT},
|
||||
{Event::DebuggerMode, KBDK_GRAVE},
|
||||
{Event::ExitMode, KBDK_ESCAPE},
|
||||
#ifdef BSPF_MACOS
|
||||
{Event::Quit, KBDK_Q, MOD3},
|
||||
#else
|
||||
{Event::Quit, KBDK_Q, KBDM_CTRL},
|
||||
#endif
|
||||
{Event::ReloadConsole, KBDK_R, KBDM_CTRL},
|
||||
{Event::PreviousMultiCartRom, KBDK_R, KBDM_SHIFT | KBDM_CTRL},
|
||||
{ Event::ConsoleSelect, KBDK_F1 },
|
||||
{ Event::ConsoleReset, KBDK_F2 },
|
||||
{ Event::ConsoleColor, KBDK_F3 },
|
||||
{ Event::Console7800Pause, KBDK_F3, MOD3 },
|
||||
{ Event::ConsoleLeftDiffA, KBDK_F5 },
|
||||
{ Event::ConsoleRightDiffA, KBDK_F7 },
|
||||
{ Event::SaveState, KBDK_F9 },
|
||||
{ Event::SaveAllStates, KBDK_F9, MOD3 },
|
||||
{ Event::PreviousState, KBDK_F10, KBDM_SHIFT },
|
||||
{ Event::NextState, KBDK_F10 },
|
||||
{ Event::ToggleAutoSlot, KBDK_F10, MOD3 },
|
||||
{ Event::LoadState, KBDK_F11 },
|
||||
{ Event::LoadAllStates, KBDK_F11, MOD3 },
|
||||
{ Event::TakeSnapshot, KBDK_F12 },
|
||||
#ifdef BSPF_MACOS
|
||||
{ Event::TogglePauseMode, KBDK_P, KBDM_SHIFT | MOD3 },
|
||||
#else
|
||||
{ Event::TogglePauseMode, KBDK_PAUSE },
|
||||
#endif
|
||||
{ Event::OptionsMenuMode, KBDK_TAB },
|
||||
{ Event::CmdMenuMode, KBDK_BACKSLASH },
|
||||
{ Event::TimeMachineMode, KBDK_T, KBDM_SHIFT },
|
||||
{ Event::DebuggerMode, KBDK_GRAVE },
|
||||
{ Event::ExitMode, KBDK_ESCAPE },
|
||||
#ifdef BSPF_MACOS
|
||||
{ Event::Quit, KBDK_Q, MOD3 },
|
||||
#else
|
||||
{ Event::Quit, KBDK_Q, KBDM_CTRL },
|
||||
#endif
|
||||
{ Event::ReloadConsole, KBDK_R, KBDM_CTRL },
|
||||
{ Event::PreviousMultiCartRom, KBDK_R, KBDM_SHIFT | KBDM_CTRL },
|
||||
|
||||
{Event::VidmodeDecrease, KBDK_MINUS, MOD3},
|
||||
{Event::VidmodeIncrease, KBDK_EQUALS, MOD3},
|
||||
{Event::VCenterDecrease, KBDK_PAGEUP, MOD3},
|
||||
{Event::VCenterIncrease, KBDK_PAGEDOWN, MOD3},
|
||||
{Event::VSizeAdjustDecrease, KBDK_PAGEDOWN, KBDM_SHIFT | MOD3},
|
||||
{Event::VSizeAdjustIncrease, KBDK_PAGEUP, KBDM_SHIFT | MOD3},
|
||||
{Event::ToggleCorrectAspectRatio, KBDK_C, KBDM_CTRL},
|
||||
{Event::VolumeDecrease, KBDK_LEFTBRACKET, MOD3},
|
||||
{Event::VolumeIncrease, KBDK_RIGHTBRACKET, MOD3},
|
||||
{Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL},
|
||||
{ Event::VidmodeDecrease, KBDK_MINUS, MOD3 },
|
||||
{ Event::VidmodeIncrease, KBDK_EQUALS, MOD3 },
|
||||
{ Event::VCenterDecrease, KBDK_PAGEUP, MOD3 },
|
||||
{ Event::VCenterIncrease, KBDK_PAGEDOWN, MOD3 },
|
||||
{ Event::VSizeAdjustDecrease, KBDK_PAGEDOWN, KBDM_SHIFT | MOD3 },
|
||||
{ Event::VSizeAdjustIncrease, KBDK_PAGEUP, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ToggleCorrectAspectRatio, KBDK_C, KBDM_CTRL },
|
||||
{ Event::VolumeDecrease, KBDK_LEFTBRACKET, MOD3 },
|
||||
{ Event::VolumeIncrease, KBDK_RIGHTBRACKET, MOD3 },
|
||||
{ Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL },
|
||||
|
||||
{Event::ToggleFullScreen, KBDK_RETURN, MOD3},
|
||||
{Event::ToggleAdaptRefresh, KBDK_R, MOD3},
|
||||
{Event::OverscanDecrease, KBDK_PAGEDOWN, KBDM_SHIFT},
|
||||
{Event::OverscanIncrease, KBDK_PAGEUP, KBDM_SHIFT},
|
||||
{ Event::ToggleFullScreen, KBDK_RETURN, MOD3 },
|
||||
{ Event::ToggleAdaptRefresh, KBDK_R, MOD3 },
|
||||
{ Event::OverscanDecrease, KBDK_PAGEDOWN, KBDM_SHIFT },
|
||||
{ Event::OverscanIncrease, KBDK_PAGEUP, KBDM_SHIFT },
|
||||
//{Event::VidmodeStd, KBDK_1, MOD3},
|
||||
//{Event::VidmodeRGB, KBDK_2, MOD3},
|
||||
//{Event::VidmodeSVideo, KBDK_3, MOD3},
|
||||
//{Event::VidModeComposite, KBDK_4, MOD3},
|
||||
//{Event::VidModeBad, KBDK_5, MOD3},
|
||||
//{Event::VidModeCustom, KBDK_6, MOD3},
|
||||
{Event::PreviousVideoMode, KBDK_1, KBDM_SHIFT | MOD3},
|
||||
{Event::NextVideoMode, KBDK_1, MOD3},
|
||||
{Event::PreviousAttribute, KBDK_2, KBDM_SHIFT | MOD3},
|
||||
{Event::NextAttribute, KBDK_2, MOD3},
|
||||
{Event::DecreaseAttribute, KBDK_3, KBDM_SHIFT | MOD3},
|
||||
{Event::IncreaseAttribute, KBDK_3, MOD3},
|
||||
{Event::PhosphorDecrease, KBDK_4, KBDM_SHIFT | MOD3},
|
||||
{Event::PhosphorIncrease, KBDK_4, MOD3},
|
||||
{Event::TogglePhosphor, KBDK_P, MOD3},
|
||||
{Event::ScanlinesDecrease, KBDK_5, KBDM_SHIFT | MOD3},
|
||||
{Event::ScanlinesIncrease, KBDK_5, MOD3},
|
||||
{Event::PreviousPaletteAttribute, KBDK_9, KBDM_SHIFT | MOD3},
|
||||
{Event::NextPaletteAttribute, KBDK_9, MOD3},
|
||||
{Event::PaletteAttributeDecrease, KBDK_0, KBDM_SHIFT | MOD3},
|
||||
{Event::PaletteAttributeIncrease, KBDK_0, MOD3},
|
||||
{Event::ToggleColorLoss, KBDK_L, KBDM_CTRL},
|
||||
{Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL},
|
||||
{Event::PaletteIncrease, KBDK_P, KBDM_CTRL},
|
||||
|
||||
#ifndef BSPF_MACOS
|
||||
{Event::PreviousSetting, KBDK_END},
|
||||
{Event::NextSetting, KBDK_HOME},
|
||||
{Event::PreviousSettingGroup, KBDK_END, KBDM_CTRL},
|
||||
{Event::NextSettingGroup, KBDK_HOME, KBDM_CTRL},
|
||||
#else
|
||||
{ Event::PreviousVideoMode, KBDK_1, KBDM_SHIFT | MOD3 },
|
||||
{ Event::NextVideoMode, KBDK_1, MOD3 },
|
||||
{ Event::PreviousAttribute, KBDK_2, KBDM_SHIFT | MOD3 },
|
||||
{ Event::NextAttribute, KBDK_2, MOD3 },
|
||||
{ Event::DecreaseAttribute, KBDK_3, KBDM_SHIFT | MOD3 },
|
||||
{ Event::IncreaseAttribute, KBDK_3, MOD3 },
|
||||
{ Event::PhosphorDecrease, KBDK_4, KBDM_SHIFT | MOD3 },
|
||||
{ Event::PhosphorIncrease, KBDK_4, MOD3 },
|
||||
{ Event::TogglePhosphor, KBDK_P, MOD3 },
|
||||
{ Event::ScanlinesDecrease, KBDK_5, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ScanlinesIncrease, KBDK_5, MOD3 },
|
||||
{ Event::PreviousPaletteAttribute, KBDK_9, KBDM_SHIFT | MOD3 },
|
||||
{ Event::NextPaletteAttribute, KBDK_9, MOD3 },
|
||||
{ Event::PaletteAttributeDecrease, KBDK_0, KBDM_SHIFT | MOD3 },
|
||||
{ Event::PaletteAttributeIncrease, KBDK_0, MOD3 },
|
||||
{ Event::ToggleColorLoss, KBDK_L, KBDM_CTRL },
|
||||
{ Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL },
|
||||
{ Event::PaletteIncrease, KBDK_P, KBDM_CTRL },
|
||||
{ Event::FormatDecrease, KBDK_F, KBDM_SHIFT | KBDM_CTRL },
|
||||
{ Event::FormatIncrease, KBDK_F, KBDM_CTRL },
|
||||
#ifndef BSPF_MACOS
|
||||
{ Event::PreviousSetting, KBDK_END },
|
||||
{ Event::NextSetting, KBDK_HOME },
|
||||
{ Event::PreviousSettingGroup, KBDK_END, KBDM_CTRL },
|
||||
{ Event::NextSettingGroup, KBDK_HOME, KBDM_CTRL },
|
||||
#else
|
||||
// HOME & END keys are swapped on Mac keyboards
|
||||
{Event::PreviousSetting, KBDK_HOME},
|
||||
{Event::NextSetting, KBDK_END},
|
||||
{Event::PreviousSettingGroup, KBDK_HOME, KBDM_CTRL},
|
||||
{Event::NextSettingGroup, KBDK_END, KBDM_CTRL},
|
||||
#endif
|
||||
{Event::PreviousSetting, KBDK_KP_1},
|
||||
{Event::NextSetting, KBDK_KP_7},
|
||||
{Event::PreviousSettingGroup, KBDK_KP_1, KBDM_CTRL},
|
||||
{Event::NextSettingGroup, KBDK_KP_7, KBDM_CTRL},
|
||||
{Event::SettingDecrease, KBDK_PAGEDOWN},
|
||||
{Event::SettingDecrease, KBDK_KP_3, KBDM_CTRL},
|
||||
{Event::SettingIncrease, KBDK_PAGEUP},
|
||||
{Event::SettingIncrease, KBDK_KP_9, KBDM_CTRL},
|
||||
{ Event::PreviousSetting, KBDK_HOME },
|
||||
{ Event::NextSetting, KBDK_END },
|
||||
{ Event::PreviousSettingGroup, KBDK_HOME, KBDM_CTRL },
|
||||
{ Event::NextSettingGroup, KBDK_END, KBDM_CTRL },
|
||||
#endif
|
||||
{ Event::PreviousSetting, KBDK_KP_1 },
|
||||
{ Event::NextSetting, KBDK_KP_7 },
|
||||
{ Event::PreviousSettingGroup, KBDK_KP_1, KBDM_CTRL },
|
||||
{ Event::NextSettingGroup, KBDK_KP_7, KBDM_CTRL },
|
||||
{ Event::SettingDecrease, KBDK_PAGEDOWN },
|
||||
{ Event::SettingDecrease, KBDK_KP_3, KBDM_CTRL },
|
||||
{ Event::SettingIncrease, KBDK_PAGEUP },
|
||||
{ Event::SettingIncrease, KBDK_KP_9, KBDM_CTRL },
|
||||
|
||||
{Event::ToggleInter, KBDK_I, KBDM_CTRL},
|
||||
{Event::DecreaseSpeed, KBDK_S, KBDM_SHIFT | KBDM_CTRL},
|
||||
{Event::IncreaseSpeed, KBDK_S, KBDM_CTRL },
|
||||
{Event::ToggleTurbo, KBDK_T, KBDM_CTRL},
|
||||
{Event::ToggleJitter, KBDK_J, MOD3},
|
||||
{Event::ToggleFrameStats, KBDK_L, MOD3},
|
||||
{Event::ToggleTimeMachine, KBDK_T, MOD3},
|
||||
{ Event::ToggleInter, KBDK_I, KBDM_CTRL },
|
||||
{ Event::DecreaseSpeed, KBDK_S, KBDM_SHIFT | KBDM_CTRL },
|
||||
{ Event::IncreaseSpeed, KBDK_S, KBDM_CTRL },
|
||||
{ Event::ToggleTurbo, KBDK_T, KBDM_CTRL },
|
||||
{ Event::ToggleJitter, KBDK_J, MOD3 },
|
||||
{ Event::ToggleFrameStats, KBDK_L, MOD3 },
|
||||
{ Event::ToggleTimeMachine, KBDK_T, MOD3 },
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
{Event::ToggleContSnapshots, KBDK_S, MOD3 | KBDM_CTRL},
|
||||
{Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3 | KBDM_CTRL},
|
||||
#endif
|
||||
#ifdef PNG_SUPPORT
|
||||
{ Event::ToggleContSnapshots, KBDK_S, MOD3 | KBDM_CTRL },
|
||||
{ Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3 | KBDM_CTRL },
|
||||
#endif
|
||||
|
||||
{Event::DecreaseAutoFire, KBDK_A, KBDM_SHIFT | KBDM_CTRL},
|
||||
{Event::IncreaseAutoFire, KBDK_A, KBDM_CTRL },
|
||||
{Event::HandleMouseControl, KBDK_0, KBDM_CTRL},
|
||||
{Event::ToggleGrabMouse, KBDK_G, KBDM_CTRL},
|
||||
{Event::ToggleSAPortOrder, KBDK_1, KBDM_CTRL},
|
||||
{Event::FormatDecrease, KBDK_F, KBDM_SHIFT | KBDM_CTRL},
|
||||
{Event::FormatIncrease, KBDK_F, KBDM_CTRL},
|
||||
{ Event::DecreaseDeadzone, KBDK_F1, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncreaseDeadzone, KBDK_F1, KBDM_CTRL },
|
||||
{ Event::DecAnalogSense, KBDK_F2, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncAnalogSense, KBDK_F2, KBDM_CTRL },
|
||||
{ Event::DecDejtterAveraging, KBDK_F3, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncDejtterAveraging, KBDK_F3, KBDM_CTRL },
|
||||
{ Event::DecDejtterReaction, KBDK_F4, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncDejtterReaction, KBDK_F4, KBDM_CTRL },
|
||||
{ Event::DecDigitalSense, KBDK_F5, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncDigitalSense, KBDK_F5, KBDM_CTRL },
|
||||
{ Event::DecreaseAutoFire, KBDK_A, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncreaseAutoFire, KBDK_A, KBDM_CTRL },
|
||||
{ Event::ToggleFourDirections, KBDK_F6, KBDM_CTRL },
|
||||
{ Event::ToggleKeyCombos, KBDK_F7, KBDM_CTRL },
|
||||
{ Event::ToggleSAPortOrder, KBDK_1, KBDM_CTRL },
|
||||
|
||||
{Event::ToggleP0Collision, KBDK_Z, KBDM_SHIFT | MOD3},
|
||||
{Event::ToggleP0Bit, KBDK_Z, MOD3},
|
||||
{Event::ToggleP1Collision, KBDK_X, KBDM_SHIFT | MOD3},
|
||||
{Event::ToggleP1Bit, KBDK_X, MOD3},
|
||||
{Event::ToggleM0Collision, KBDK_C, KBDM_SHIFT | MOD3},
|
||||
{Event::ToggleM0Bit, KBDK_C, MOD3},
|
||||
{Event::ToggleM1Collision, KBDK_V, KBDM_SHIFT | MOD3},
|
||||
{Event::ToggleM1Bit, KBDK_V, MOD3},
|
||||
{Event::ToggleBLCollision, KBDK_B, KBDM_SHIFT | MOD3},
|
||||
{Event::ToggleBLBit, KBDK_B, MOD3},
|
||||
{Event::TogglePFCollision, KBDK_N, KBDM_SHIFT | MOD3},
|
||||
{Event::TogglePFBit, KBDK_N, MOD3},
|
||||
{Event::ToggleCollisions, KBDK_COMMA, KBDM_SHIFT | MOD3},
|
||||
{Event::ToggleBits, KBDK_COMMA, MOD3},
|
||||
{Event::ToggleFixedColors, KBDK_PERIOD, MOD3},
|
||||
{ Event::PrevMouseAsController, KBDK_F8, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::NextMouseAsController, KBDK_F8, KBDM_CTRL },
|
||||
{ Event::DecMousePaddleSense, KBDK_F9, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncMousePaddleSense, KBDK_F9, KBDM_CTRL },
|
||||
{ Event::DecMouseTrackballSense, KBDK_F10, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncMouseTrackballSense, KBDK_F10, KBDM_CTRL },
|
||||
{ Event::DecreaseDrivingSense, KBDK_F11, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncreaseDrivingSense, KBDK_F11, KBDM_CTRL },
|
||||
{ Event::PreviousCursorVisbility, KBDK_F12, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::NextCursorVisbility, KBDK_F12, KBDM_CTRL },
|
||||
{ Event::ToggleGrabMouse, KBDK_G, KBDM_CTRL },
|
||||
|
||||
{Event::RewindPause, KBDK_LEFT, KBDM_SHIFT},
|
||||
{Event::Rewind1Menu, KBDK_LEFT, MOD3},
|
||||
{Event::Rewind10Menu, KBDK_LEFT, KBDM_SHIFT | MOD3},
|
||||
{Event::RewindAllMenu, KBDK_DOWN, MOD3},
|
||||
{Event::UnwindPause, KBDK_LEFT, KBDM_SHIFT},
|
||||
{Event::Unwind1Menu, KBDK_RIGHT, MOD3},
|
||||
{Event::Unwind10Menu, KBDK_RIGHT, KBDM_SHIFT | MOD3},
|
||||
{Event::UnwindAllMenu, KBDK_UP, MOD3},
|
||||
{Event::TogglePlayBackMode, KBDK_SPACE, KBDM_SHIFT},
|
||||
{ Event::PreviousLeftPort, KBDK_2, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::NextLeftPort, KBDK_2, KBDM_CTRL },
|
||||
{ Event::PreviousRightPort, KBDK_3, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::NextRightPort, KBDK_3, KBDM_CTRL },
|
||||
{ Event::ToggleSwapPorts, KBDK_4, KBDM_CTRL },
|
||||
{ Event::ToggleSwapPaddles, KBDK_5, KBDM_CTRL },
|
||||
{ Event::DecreasePaddleCenterX, KBDK_6, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncreasePaddleCenterX, KBDK_6, KBDM_CTRL },
|
||||
{ Event::DecreasePaddleCenterY, KBDK_7, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncreasePaddleCenterY, KBDK_7, KBDM_CTRL },
|
||||
{ Event::PreviousMouseControl, KBDK_0, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::NextMouseControl, KBDK_0, KBDM_CTRL },
|
||||
{ Event::DecreaseMouseAxesRange, KBDK_8, KBDM_CTRL | KBDM_SHIFT },
|
||||
{ Event::IncreaseMouseAxesRange, KBDK_8, KBDM_CTRL },
|
||||
|
||||
#if defined(RETRON77)
|
||||
{Event::ConsoleColorToggle, KBDK_F4}, // back ("COLOR","B/W")
|
||||
{Event::ConsoleLeftDiffToggle, KBDK_F6}, // front ("SKILL P1")
|
||||
{Event::ConsoleRightDiffToggle, KBDK_F8}, // front ("SKILL P2")
|
||||
{Event::CmdMenuMode, KBDK_F13}, // back ("4:3","16:9")
|
||||
{Event::ExitMode, KBDK_BACKSPACE}, // back ("FRY")
|
||||
#else // defining duplicate keys must be avoided!
|
||||
{Event::ConsoleBlackWhite, KBDK_F4},
|
||||
{Event::ConsoleLeftDiffB, KBDK_F6},
|
||||
{Event::ConsoleRightDiffB, KBDK_F8},
|
||||
{Event::Fry, KBDK_BACKSPACE},
|
||||
{ Event::ToggleP0Collision, KBDK_Z, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ToggleP0Bit, KBDK_Z, MOD3 },
|
||||
{ Event::ToggleP1Collision, KBDK_X, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ToggleP1Bit, KBDK_X, MOD3 },
|
||||
{ Event::ToggleM0Collision, KBDK_C, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ToggleM0Bit, KBDK_C, MOD3 },
|
||||
{ Event::ToggleM1Collision, KBDK_V, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ToggleM1Bit, KBDK_V, MOD3 },
|
||||
{ Event::ToggleBLCollision, KBDK_B, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ToggleBLBit, KBDK_B, MOD3 },
|
||||
{ Event::TogglePFCollision, KBDK_N, KBDM_SHIFT | MOD3 },
|
||||
{ Event::TogglePFBit, KBDK_N, MOD3 },
|
||||
{ Event::ToggleCollisions, KBDK_COMMA, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ToggleBits, KBDK_COMMA, MOD3 },
|
||||
{ Event::ToggleFixedColors, KBDK_PERIOD, MOD3 },
|
||||
|
||||
{ Event::RewindPause, KBDK_LEFT, KBDM_SHIFT },
|
||||
{ Event::Rewind1Menu, KBDK_LEFT, MOD3 },
|
||||
{ Event::Rewind10Menu, KBDK_LEFT, KBDM_SHIFT | MOD3 },
|
||||
{ Event::RewindAllMenu, KBDK_DOWN, MOD3 },
|
||||
{ Event::UnwindPause, KBDK_LEFT, KBDM_SHIFT },
|
||||
{ Event::Unwind1Menu, KBDK_RIGHT, MOD3 },
|
||||
{ Event::Unwind10Menu, KBDK_RIGHT, KBDM_SHIFT | MOD3 },
|
||||
{ Event::UnwindAllMenu, KBDK_UP, MOD3 },
|
||||
{ Event::HighScoresMenuMode, KBDK_INSERT },
|
||||
{ Event::TogglePlayBackMode, KBDK_SPACE, KBDM_SHIFT },
|
||||
|
||||
#if defined(RETRON77)
|
||||
{ Event::ConsoleColorToggle, KBDK_F4 }, // back ("COLOR","B/W")
|
||||
{ Event::ConsoleLeftDiffToggle, KBDK_F6 }, // front ("SKILL P1")
|
||||
{ Event::ConsoleRightDiffToggle, KBDK_F8 }, // front ("SKILL P2")
|
||||
{ Event::CmdMenuMode, KBDK_F13 }, // back ("4:3","16:9")
|
||||
{ Event::ExitMode, KBDK_BACKSPACE }, // back ("FRY")
|
||||
#else // defining duplicate keys must be avoided!
|
||||
{ Event::ConsoleBlackWhite, KBDK_F4 },
|
||||
{ Event::ConsoleLeftDiffB, KBDK_F6 },
|
||||
{ Event::ConsoleRightDiffB, KBDK_F8 },
|
||||
{ Event::Fry, KBDK_BACKSPACE },
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@ class PhysicalKeyboardHandler
|
|||
/** See comments on KeyMap.myModEnabled for more information. */
|
||||
bool& useModKeys() { return myKeyMap.enableMod(); }
|
||||
|
||||
void toggleModKeys(bool toggle = true);
|
||||
|
||||
private:
|
||||
|
||||
// Structure used for action menu items
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PNGLibrary::PNGLibrary(OSystem& osystem)
|
||||
: myOSystem(osystem)
|
||||
: myOSystem{osystem}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,9 @@
|
|||
|
||||
#include "PaletteHandler.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PaletteHandler::PaletteHandler(OSystem& system)
|
||||
: myOSystem(system)
|
||||
: myOSystem{system}
|
||||
{
|
||||
// Load user-defined palette for this ROM
|
||||
loadUserPalette();
|
||||
|
@ -441,7 +442,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing)
|
|||
if(timing == ConsoleTiming::ntsc)
|
||||
{
|
||||
vector2d IQ[NUM_CHROMA];
|
||||
// YIQ is YUV shifted by 33°
|
||||
// YIQ is YUV shifted by 33 degrees
|
||||
constexpr float offset = 33 * BSPF::PI_f / 180;
|
||||
const float shift = myPhaseNTSC * BSPF::PI_f / 180;
|
||||
|
||||
|
@ -541,7 +542,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing)
|
|||
void PaletteHandler::adjustHueSaturation(int& R, int& G, int& B, float H, float S)
|
||||
{
|
||||
// Adapted from http://beesbuzz.biz/code/16-hsv-color-transforms
|
||||
// (C) J. “Fluffy” Shagam
|
||||
// (C) J. Fluffy Shagam
|
||||
// License: CC BY-SA 4.0
|
||||
const float su = S * cosf(-H * BSPF::PI_f);
|
||||
const float sw = S * sinf(-H * BSPF::PI_f);
|
||||
|
|
|
@ -65,7 +65,7 @@ class PaletteHandler
|
|||
};
|
||||
|
||||
public:
|
||||
PaletteHandler(OSystem& system);
|
||||
explicit PaletteHandler(OSystem& system);
|
||||
|
||||
/**
|
||||
Cycle through available palettes.
|
||||
|
@ -139,7 +139,7 @@ class PaletteHandler
|
|||
float y{0.F};
|
||||
|
||||
explicit vector2d(float _x = 0.F, float _y = 0.F)
|
||||
: x(_x), y(_y) { }
|
||||
: x{_x}, y{_y} { }
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,7 +38,7 @@ class PhosphorHandler
|
|||
|
||||
@return Averaged value of the two RGB colors
|
||||
*/
|
||||
static inline uInt32 getPixel(const uInt32 c, const uInt32 p)
|
||||
static constexpr uInt32 getPixel(const uInt32 c, const uInt32 p)
|
||||
{
|
||||
// Mix current calculated frame with previous displayed frame
|
||||
const uInt8 rc = static_cast<uInt8>(c >> 16),
|
||||
|
|
|
@ -87,7 +87,7 @@ bool PhysicalJoystick::setMap(const json& map)
|
|||
|
||||
try {
|
||||
joyMap.loadMapping(entry.value(), eventModeFromJsonName(entry.key()));
|
||||
} catch (json::exception) {
|
||||
} catch (const json::exception&) {
|
||||
Logger::error("ignoring invalid json mapping for " + entry.key());
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "Event.hxx"
|
||||
#include "EventHandlerConstants.hxx"
|
||||
#include "JoyMap.hxx"
|
||||
#include "json.hxx"
|
||||
#include "json_lib.hxx"
|
||||
|
||||
/**
|
||||
An abstraction of a physical (real) joystick in Stella.
|
||||
|
@ -59,17 +59,13 @@ class PhysicalJoystick
|
|||
int axes, int buttons, int hats, int balls);
|
||||
|
||||
private:
|
||||
// TODO: these are not required anymore, delete or keep for future usage?
|
||||
enum JoyType {
|
||||
JT_NONE = 0,
|
||||
JT_REGULAR = 1,
|
||||
JT_STELLADAPTOR_LEFT = 2,
|
||||
JT_STELLADAPTOR_RIGHT = 3,
|
||||
JT_2600DAPTOR_LEFT = 4,
|
||||
JT_2600DAPTOR_RIGHT = 5
|
||||
enum class Type {
|
||||
REGULAR,
|
||||
LEFT_STELLADAPTOR, RIGHT_STELLADAPTOR,
|
||||
LEFT_2600DAPTOR, RIGHT_2600DAPTOR
|
||||
};
|
||||
|
||||
JoyType type{JT_NONE};
|
||||
Type type{Type::REGULAR};
|
||||
int ID{-1};
|
||||
string name{"None"};
|
||||
int numAxes{0}, numButtons{0}, numHats{0};
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace Common {
|
|||
*/
|
||||
struct Point
|
||||
{
|
||||
// FIXME : make this uInt32
|
||||
Int32 x{0}; //!< The horizontal part of the point
|
||||
Int32 y{0}; //!< The vertical part of the point
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
|
||||
: myOSystem(system),
|
||||
myStateManager(statemgr)
|
||||
: myOSystem{system},
|
||||
myStateManager{statemgr}
|
||||
{
|
||||
setup();
|
||||
}
|
||||
|
@ -41,18 +41,15 @@ void RewindManager::setup()
|
|||
|
||||
const string& prefix = myOSystem.settings().getBool("dev.settings") ? "dev." : "plr.";
|
||||
|
||||
// Work around a bug in XCode 11.2 with -O0 and -O1
|
||||
const uInt32 maxBufSize = MAX_BUF_SIZE;
|
||||
|
||||
// TODO - Add proper bounds checking (define constexpr variables for this)
|
||||
// Use those bounds in DeveloperDialog too
|
||||
mySize = std::min<uInt32>(
|
||||
myOSystem.settings().getInt(prefix + "tm.size"), maxBufSize);
|
||||
myOSystem.settings().getInt(prefix + "tm.size"), MAX_BUF_SIZE);
|
||||
if(mySize != myStateList.capacity())
|
||||
resize(mySize);
|
||||
|
||||
myUncompressed = std::min<uInt32>(
|
||||
myOSystem.settings().getInt(prefix + "tm.uncompressed"), maxBufSize);
|
||||
myOSystem.settings().getInt(prefix + "tm.uncompressed"), MAX_BUF_SIZE);
|
||||
|
||||
myInterval = INTERVAL_CYCLES[0];
|
||||
for(int i = 0; i < NUM_INTERVALS; ++i)
|
||||
|
|
|
@ -158,6 +158,7 @@ class RewindManager
|
|||
uInt64 getFirstCycles() const;
|
||||
uInt64 getCurrentCycles() const;
|
||||
uInt64 getLastCycles() const;
|
||||
uInt64 getInterval() const { return myInterval; }
|
||||
|
||||
/**
|
||||
Get a collection of cycle timestamps, offset from the first one in
|
||||
|
|
|
@ -40,8 +40,8 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
|
||||
: Sound(osystem),
|
||||
myAudioSettings(audioSettings)
|
||||
: Sound{osystem},
|
||||
myAudioSettings{audioSettings}
|
||||
{
|
||||
ASSERT_MAIN_THREAD;
|
||||
|
||||
|
@ -273,7 +273,7 @@ void SoundSDL2::adjustVolume(int direction)
|
|||
|
||||
if(percent > 0 && !enabled)
|
||||
{
|
||||
setEnabled(!enabled);
|
||||
setEnabled(true);
|
||||
myOSystem.console().initializeAudio();
|
||||
}
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace {
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
StaggeredLogger::StaggeredLogger(const string& message, Logger::Level level)
|
||||
: myMessage(message),
|
||||
myLevel(level)
|
||||
: myMessage{message},
|
||||
myLevel{level}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
StateManager::StateManager(OSystem& osystem)
|
||||
: myOSystem(osystem)
|
||||
: myOSystem{osystem}
|
||||
{
|
||||
myRewindManager = make_unique<RewindManager>(myOSystem, *this);
|
||||
reset();
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TimerManager::TimerManager()
|
||||
: nextId(no_timer + 1),
|
||||
: nextId{no_timer + 1},
|
||||
queue()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -44,8 +44,8 @@ class Variant
|
|||
public:
|
||||
Variant() { } // NOLINT
|
||||
|
||||
Variant(const string& s) : data(s) { }
|
||||
Variant(const char* s) : data(s) { }
|
||||
Variant(const string& s) : data{s} { }
|
||||
Variant(const char* s) : data{s} { }
|
||||
|
||||
Variant(Int32 i) { buf().str(""); buf() << i; data = buf().str(); }
|
||||
Variant(uInt32 i) { buf().str(""); buf() << i; data = buf().str(); }
|
||||
|
|
|
@ -105,14 +105,12 @@ VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, Stretch smode,
|
|||
VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
|
||||
Stretch smode, Int32 fsindex, const string& desc,
|
||||
float zoomLevel, float overscan)
|
||||
: stretch(smode),
|
||||
: screenS(sw, sh),
|
||||
stretch(smode),
|
||||
description(desc),
|
||||
zoom(zoomLevel),
|
||||
fsIndex(fsindex)
|
||||
{
|
||||
// First set default size and positioning
|
||||
screenS = Common::Size(sw, sh);
|
||||
|
||||
// Now resize based on windowed/fullscreen mode and stretch factor
|
||||
if(fsIndex != -1) // fullscreen mode
|
||||
{
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ConvolutionBuffer::ConvolutionBuffer(uInt32 size)
|
||||
: mySize(size)
|
||||
: myData{make_unique<float[]>(size)},
|
||||
mySize{size}
|
||||
{
|
||||
myData = make_unique<float[]>(mySize);
|
||||
std::fill_n(myData.get(), mySize, 0.F);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
HighPass::HighPass(float cutOffFrequency, float frequency)
|
||||
: myAlpha(1.F / (1.F + 2.F*BSPF::PI_f*cutOffFrequency/frequency))
|
||||
: myAlpha{1.F / (1.F + 2.F*BSPF::PI_f*cutOffFrequency/frequency)}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -69,12 +69,12 @@ LanczosResampler::LanczosResampler(
|
|||
// formatFrom.sampleRate / formatTo.sampleRate = M / N
|
||||
//
|
||||
// -> we find N from fully reducing the fraction.
|
||||
myPrecomputedKernelCount(reducedDenominator(formatFrom.sampleRate, formatTo.sampleRate)),
|
||||
myKernelSize(2 * kernelParameter),
|
||||
myKernelParameter(kernelParameter),
|
||||
myHighPassL(HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate)),
|
||||
myHighPassR(HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate)),
|
||||
myHighPass(HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate))
|
||||
myPrecomputedKernelCount{reducedDenominator(formatFrom.sampleRate, formatTo.sampleRate)},
|
||||
myKernelSize{2 * kernelParameter},
|
||||
myKernelParameter{kernelParameter},
|
||||
myHighPassL{HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate)},
|
||||
myHighPassR{HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate)},
|
||||
myHighPass{HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate)}
|
||||
{
|
||||
myPrecomputedKernels = make_unique<float[]>(myPrecomputedKernelCount * myKernelSize);
|
||||
|
||||
|
|
|
@ -51,12 +51,11 @@ class Resampler {
|
|||
public:
|
||||
|
||||
Resampler(Format formatFrom, Format formatTo,
|
||||
const NextFragmentCallback& nextFragmentCallback) :
|
||||
myFormatFrom(formatFrom),
|
||||
myFormatTo(formatTo),
|
||||
myNextFragmentCallback(nextFragmentCallback),
|
||||
myUnderrunLogger("audio buffer underrun", Logger::Level::INFO)
|
||||
{}
|
||||
const NextFragmentCallback& nextFragmentCallback)
|
||||
: myFormatFrom{formatFrom},
|
||||
myFormatTo{formatTo},
|
||||
myNextFragmentCallback{nextFragmentCallback},
|
||||
myUnderrunLogger{"audio buffer underrun", Logger::Level::INFO} { }
|
||||
|
||||
virtual void fillFragment(float* fragment, uInt32 length) = 0;
|
||||
|
||||
|
|
|
@ -39,13 +39,11 @@ class SimpleResampler : public Resampler
|
|||
bool myIsUnderrun{true};
|
||||
|
||||
private:
|
||||
|
||||
SimpleResampler() = delete;
|
||||
SimpleResampler(const SimpleResampler&) = delete;
|
||||
SimpleResampler(SimpleResampler&&) = delete;
|
||||
SimpleResampler& operator=(const SimpleResampler&) = delete;
|
||||
SimpleResampler& operator=(const SimpleResampler&&) = delete;
|
||||
|
||||
};
|
||||
|
||||
#endif // SIMPLE_RESAMPLER_HXX
|
||||
|
|
|
@ -47,6 +47,7 @@ using uInt64 = uint64_t;
|
|||
#include <iomanip>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
@ -60,6 +61,7 @@ using std::cout;
|
|||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
using std::string_view;
|
||||
using std::istream;
|
||||
using std::ostream;
|
||||
using std::fstream;
|
||||
|
@ -193,51 +195,54 @@ namespace BSPF
|
|||
catch(...) { return defaultValue; }
|
||||
}
|
||||
|
||||
// Compare two strings, ignoring case
|
||||
inline int compareIgnoreCase(const string& s1, const string& s2)
|
||||
// Convert string with base 16 to integer, using default value on any error
|
||||
inline int stringToIntBase16(const string& s, const int defaultValue = 0)
|
||||
{
|
||||
#if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
|
||||
return _stricmp(s1.c_str(), s2.c_str());
|
||||
#else
|
||||
return strcasecmp(s1.c_str(), s2.c_str());
|
||||
#endif
|
||||
}
|
||||
inline int compareIgnoreCase(const char* s1, const char* s2)
|
||||
{
|
||||
#if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
|
||||
return _stricmp(s1, s2);
|
||||
#else
|
||||
return strcasecmp(s1, s2);
|
||||
#endif
|
||||
try { return std::stoi(s, nullptr, 16); }
|
||||
catch(...) { return defaultValue; }
|
||||
}
|
||||
|
||||
// Test whether the first string starts with the second one (case insensitive)
|
||||
inline bool startsWithIgnoreCase(const string& s1, const string& s2)
|
||||
// Compare two strings (case insensitive)
|
||||
// Return negative, zero, positive result for <,==,> respectively
|
||||
static constexpr int compareIgnoreCase(string_view s1, string_view s2)
|
||||
{
|
||||
#if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
|
||||
return _strnicmp(s1.c_str(), s2.c_str(), s2.length()) == 0;
|
||||
#else
|
||||
return strncasecmp(s1.c_str(), s2.c_str(), s2.length()) == 0;
|
||||
#endif
|
||||
}
|
||||
inline bool startsWithIgnoreCase(const char* s1, const char* s2)
|
||||
{
|
||||
#if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
|
||||
return _strnicmp(s1, s2, strlen(s2)) == 0;
|
||||
#else
|
||||
return strncasecmp(s1, s2, strlen(s2)) == 0;
|
||||
#endif
|
||||
// Only compare up to the length of the shorter string
|
||||
const auto maxsize = std::min(s1.size(), s2.size());
|
||||
for(size_t i = 0; i < maxsize; ++i)
|
||||
if(toupper(s1[i]) != toupper(s2[i]))
|
||||
return toupper(s1[i]) - toupper(s2[i]);
|
||||
|
||||
// Otherwise the length of the string takes priority
|
||||
return static_cast<int>(s1.size() - s2.size());
|
||||
}
|
||||
|
||||
// Test whether two strings are equal (case insensitive)
|
||||
inline bool equalsIgnoreCase(const string& s1, const string& s2)
|
||||
inline constexpr bool equalsIgnoreCase(string_view s1, string_view s2)
|
||||
{
|
||||
return compareIgnoreCase(s1, s2) == 0;
|
||||
return s1.size() == s2.size() ? (compareIgnoreCase(s1, s2) == 0) : false;
|
||||
}
|
||||
|
||||
// Test whether the first string starts with the second one (case insensitive)
|
||||
inline constexpr bool startsWithIgnoreCase(string_view s1, string_view s2)
|
||||
{
|
||||
if(s1.size() >= s2.size())
|
||||
return compareIgnoreCase(s1.substr(0, s2.size()), s2) == 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test whether the first string ends with the second one (case insensitive)
|
||||
inline constexpr bool endsWithIgnoreCase(string_view s1, string_view s2)
|
||||
{
|
||||
if(s1.size() >= s2.size())
|
||||
return compareIgnoreCase(s1.substr(s1.size() - s2.size()), s2) == 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find location (if any) of the second string within the first,
|
||||
// starting from 'startpos' in the first string
|
||||
inline size_t findIgnoreCase(const string& s1, const string& s2, size_t startpos = 0)
|
||||
static size_t findIgnoreCase(string_view s1, string_view s2, size_t startpos = 0)
|
||||
{
|
||||
auto pos = std::search(s1.cbegin()+startpos, s1.cend(),
|
||||
s2.cbegin(), s2.cend(), [](char ch1, char ch2) {
|
||||
|
@ -246,19 +251,8 @@ namespace BSPF
|
|||
return pos == s1.cend() ? string::npos : pos - (s1.cbegin()+startpos);
|
||||
}
|
||||
|
||||
// Test whether the first string ends with the second one (case insensitive)
|
||||
inline bool endsWithIgnoreCase(const string& s1, const string& s2)
|
||||
{
|
||||
if(s1.length() >= s2.length())
|
||||
{
|
||||
const char* end = s1.c_str() + s1.length() - s2.length();
|
||||
return compareIgnoreCase(end, s2.c_str()) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test whether the first string contains the second one (case insensitive)
|
||||
inline bool containsIgnoreCase(const string& s1, const string& s2)
|
||||
inline bool containsIgnoreCase(string_view s1, string_view s2)
|
||||
{
|
||||
return findIgnoreCase(s1, s2) != string::npos;
|
||||
}
|
||||
|
@ -266,14 +260,14 @@ namespace BSPF
|
|||
// Test whether the first string matches the second one (case insensitive)
|
||||
// - the first character must match
|
||||
// - the following characters must appear in the order of the first string
|
||||
inline bool matches(const string& s1, const string& s2)
|
||||
inline bool matches(string_view s1, string_view s2)
|
||||
{
|
||||
if(BSPF::startsWithIgnoreCase(s1, s2.substr(0, 1)))
|
||||
if(startsWithIgnoreCase(s1, s2.substr(0, 1)))
|
||||
{
|
||||
size_t pos = 1;
|
||||
for(uInt32 j = 1; j < s2.size(); ++j)
|
||||
{
|
||||
size_t found = BSPF::findIgnoreCase(s1, s2.substr(j, 1), pos);
|
||||
size_t found = findIgnoreCase(s1, s2.substr(j, 1), pos);
|
||||
if(found == string::npos)
|
||||
return false;
|
||||
pos += found + 1;
|
||||
|
@ -283,6 +277,27 @@ namespace BSPF
|
|||
return false;
|
||||
}
|
||||
|
||||
// Modify 'str', replacing all occurrences of 'from' with 'to'
|
||||
inline void replaceAll(string& str, const string& from, const string& to)
|
||||
{
|
||||
if(from.empty()) return;
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = str.find(from, start_pos)) != string::npos)
|
||||
{
|
||||
str.replace(start_pos, from.length(), to);
|
||||
start_pos += to.length(); // In case 'to' contains 'from',
|
||||
// like replacing 'x' with 'yx'
|
||||
}
|
||||
}
|
||||
|
||||
// Trim leading and trailing whitespace from a string
|
||||
inline string trim(const string& str)
|
||||
{
|
||||
string::size_type first = str.find_first_not_of(' ');
|
||||
return (first == string::npos) ? EmptyString :
|
||||
str.substr(first, str.find_last_not_of(' ')-first+1);
|
||||
}
|
||||
|
||||
// C++11 way to get local time
|
||||
// Equivalent to the C-style localtime() function, but is thread-safe
|
||||
inline std::tm localTime()
|
||||
|
|
|
@ -1,9 +1,26 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef JSON_DEFINITIONS_HXX
|
||||
#define JSON_DEFINITIONS_HXX
|
||||
|
||||
#include "EventHandlerConstants.hxx"
|
||||
#include "Event.hxx"
|
||||
#include "json.hxx"
|
||||
#include "json_lib.hxx"
|
||||
#include "StellaKeys.hxx"
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(JoyAxis, {
|
||||
|
@ -27,7 +44,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(JoyHatDir, {
|
|||
{JoyHatDir::LEFT, "left"},
|
||||
{JoyHatDir::RIGHT, "right"},
|
||||
{JoyHatDir::UP, "up"}
|
||||
});
|
||||
})
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(EventMode, {
|
||||
{EventMode::kEditMode, "kEditMode"},
|
||||
|
@ -39,7 +56,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(EventMode, {
|
|||
{EventMode::kCompuMateMode, "kCompuMateMode"},
|
||||
{EventMode::kCommonMode, "kCommonMode"},
|
||||
{EventMode::kNumModes, "kNumModes"},
|
||||
});
|
||||
})
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
|
||||
{Event::NoType, "NoType"},
|
||||
|
@ -69,6 +86,16 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
|
|||
{Event::JoystickOneFire, "JoystickOneFire"},
|
||||
{Event::JoystickOneFire5, "JoystickOneFire5"},
|
||||
{Event::JoystickOneFire9, "JoystickOneFire9"},
|
||||
{Event::JoystickTwoUp, "JoystickTwoUp"},
|
||||
{Event::JoystickTwoDown, "JoystickTwoDown"},
|
||||
{Event::JoystickTwoLeft, "JoystickTwoLeft"},
|
||||
{Event::JoystickTwoRight, "JoystickTwoRight"},
|
||||
{Event::JoystickTwoFire, "JoystickTwoFire"},
|
||||
{Event::JoystickThreeUp, "JoystickThreeUp"},
|
||||
{Event::JoystickThreeDown, "JoystickThreeDown"},
|
||||
{Event::JoystickThreeLeft, "JoystickThreeLeft"},
|
||||
{Event::JoystickThreeRight, "JoystickThreeRight"},
|
||||
{Event::JoystickThreeFire, "JoystickThreeFire"},
|
||||
{Event::PaddleZeroDecrease, "PaddleZeroDecrease"},
|
||||
{Event::PaddleZeroIncrease, "PaddleZeroIncrease"},
|
||||
{Event::PaddleZeroAnalog, "PaddleZeroAnalog"},
|
||||
|
@ -160,6 +187,50 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
|
|||
{Event::CompuMateEquals, "CompuMateEquals"},
|
||||
{Event::CompuMatePlus, "CompuMatePlus"},
|
||||
{Event::CompuMateSlash, "CompuMateSlash"},
|
||||
|
||||
{Event::DecreaseDeadzone, "DecreaseDeadzone"},
|
||||
{Event::IncreaseDeadzone, "IncreaseDeadzone"},
|
||||
{Event::DecAnalogSense, "DecAnalogSense"},
|
||||
{Event::IncAnalogSense, "IncAnalogSense"},
|
||||
{Event::DecDejtterAveraging, "DecDejtterAveraging"},
|
||||
{Event::IncDejtterAveraging, "IncDejtterAveraging"},
|
||||
{Event::DecDejtterReaction, "DecDejtterReaction"},
|
||||
{Event::IncDejtterReaction, "IncDejtterReaction"},
|
||||
{Event::DecDigitalSense, "DecDigitalSense"},
|
||||
{Event::IncDigitalSense, "IncDigitalSense"},
|
||||
{Event::DecreaseAutoFire, "DecreaseAutoFire"},
|
||||
{Event::IncreaseAutoFire, "IncreaseAutoFire"},
|
||||
{Event::ToggleFourDirections, "ToggleFourDirections"},
|
||||
{Event::ToggleKeyCombos, "ToggleKeyCombos"},
|
||||
{Event::ToggleSAPortOrder, "ToggleSAPortOrder"},
|
||||
|
||||
{Event::PrevMouseAsController, "PrevMouseAsController"},
|
||||
{Event::NextMouseAsController, "NextMouseAsController"},
|
||||
{Event::DecMousePaddleSense, "DecMousePaddleSense"},
|
||||
{Event::IncMousePaddleSense, "IncMousePaddleSense"},
|
||||
{Event::DecMouseTrackballSense, "DecMouseTrackballSense"},
|
||||
{Event::IncMouseTrackballSense, "IncMouseTrackballSense"},
|
||||
{Event::DecreaseDrivingSense, "DecreaseDrivingSense"},
|
||||
{Event::IncreaseDrivingSense, "IncreaseDrivingSense"},
|
||||
{Event::PreviousCursorVisbility, "PreviousCursorVisbility"},
|
||||
{Event::NextCursorVisbility, "NextCursorVisbility"},
|
||||
{Event::ToggleGrabMouse, "ToggleGrabMouse"},
|
||||
|
||||
{Event::PreviousLeftPort, "PreviousLeftPort"},
|
||||
{Event::NextLeftPort, "NextLeftPort"},
|
||||
{Event::PreviousRightPort, "PreviousRightPort"},
|
||||
{Event::NextRightPort, "NextRightPort"},
|
||||
{Event::ToggleSwapPorts, "ToggleSwapPorts"},
|
||||
{Event::ToggleSwapPaddles,"ToggleSwapPaddles"},
|
||||
{Event::DecreasePaddleCenterX, "DecreasePaddleCenterX"},
|
||||
{Event::IncreasePaddleCenterX, "IncreasePaddleCenterX"},
|
||||
{Event::DecreasePaddleCenterY, "DecreasePaddleCenterY"},
|
||||
{Event::IncreasePaddleCenterY, "IncreasePaddleCenterY"},
|
||||
{Event::PreviousMouseControl, "PreviousMouseControl"},
|
||||
{Event::NextMouseControl, "NextMouseControl"},
|
||||
{Event::DecreaseMouseAxesRange, "DecreaseMouseAxesRange"},
|
||||
{Event::IncreaseMouseAxesRange, "IncreaseMouseAxesRange"},
|
||||
|
||||
{Event::Combo1, "Combo1"},
|
||||
{Event::Combo2, "Combo2"},
|
||||
{Event::Combo3, "Combo3"},
|
||||
|
@ -192,8 +263,6 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
|
|||
{Event::UIPrevDir, "UIPrevDir"},
|
||||
{Event::UITabPrev, "UITabPrev"},
|
||||
{Event::UITabNext, "UITabNext"},
|
||||
{Event::HandleMouseControl, "HandleMouseControl"},
|
||||
{Event::ToggleGrabMouse, "ToggleGrabMouse"},
|
||||
{Event::MouseAxisXMove, "MouseAxisXMove"},
|
||||
{Event::MouseAxisYMove, "MouseAxisYMove"},
|
||||
{Event::MouseAxisXValue, "MouseAxisXValue"},
|
||||
|
@ -207,6 +276,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
|
|||
{Event::StartPauseMode, "StartPauseMode"},
|
||||
{Event::OptionsMenuMode, "OptionsMenuMode"},
|
||||
{Event::CmdMenuMode, "CmdMenuMode"},
|
||||
{Event::HighScoresMenuMode, "HighScoresMenuMode"},
|
||||
{Event::DebuggerMode, "DebuggerMode"},
|
||||
{Event::ExitMode, "ExitMode"},
|
||||
{Event::TakeSnapshot, "TakeSnapshot"},
|
||||
|
@ -286,7 +356,6 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
|
|||
{Event::ToggleBits, "ToggleBits"},
|
||||
{Event::ToggleFixedColors, "ToggleFixedColors"},
|
||||
{Event::ToggleFrameStats, "ToggleFrameStats"},
|
||||
{Event::ToggleSAPortOrder, "ToggleSAPortOrder"},
|
||||
{Event::ExitGame, "ExitGame"},
|
||||
{Event::SettingDecrease, "SettingDecrease"},
|
||||
{Event::SettingIncrease, "SettingIncrease"},
|
||||
|
@ -301,16 +370,6 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
|
|||
{Event::IncreaseAutoFire, "IncreaseAutoFire"},
|
||||
{Event::DecreaseSpeed, "DecreaseSpeed"},
|
||||
{Event::IncreaseSpeed, "IncreaseSpeed"},
|
||||
{Event::JoystickTwoUp, "JoystickTwoUp"},
|
||||
{Event::JoystickTwoDown, "JoystickTwoDown"},
|
||||
{Event::JoystickTwoLeft, "JoystickTwoLeft"},
|
||||
{Event::JoystickTwoRight, "JoystickTwoRight"},
|
||||
{Event::JoystickTwoFire, "JoystickTwoFire"},
|
||||
{Event::JoystickThreeUp, "JoystickThreeUp"},
|
||||
{Event::JoystickThreeDown, "JoystickThreeDown"},
|
||||
{Event::JoystickThreeLeft, "JoystickThreeLeft"},
|
||||
{Event::JoystickThreeRight, "JoystickThreeRight"},
|
||||
{Event::JoystickThreeFire, "JoystickThreeFire"},
|
||||
{Event::ToggleCorrectAspectRatio, "ToggleCorrectAspectRatio"},
|
||||
{Event::MoveLeftChar, "MoveLeftChar"},
|
||||
{Event::MoveRightChar, "MoveRightChar"},
|
||||
|
|
|
@ -123,11 +123,11 @@ void parseCommandLine(int ac, char* av[],
|
|||
|
||||
#if 0
|
||||
cout << "Global opts:" << endl;
|
||||
for(const auto& x: globalOpts)
|
||||
cout << " -> " << x.first << ": " << x.second << endl;
|
||||
for(const auto& [key, value]: globalOpts)
|
||||
cout << " -> " << key << ": " << value << endl;
|
||||
cout << "Local opts:" << endl;
|
||||
for(const auto& x: localOpts)
|
||||
cout << " -> " << x.first << ": " << x.second << endl;
|
||||
for(const auto& [key, value]: localOpts)
|
||||
cout << " -> " << key << ": " << value << endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ MODULE_OBJS := \
|
|||
src/common/FBSurfaceSDL2.o \
|
||||
src/common/FpsMeter.o \
|
||||
src/common/FSNodeZIP.o \
|
||||
src/common/HighScoresManager.o \
|
||||
src/common/JoyMap.o \
|
||||
src/common/KeyMap.o \
|
||||
src/common/Logger.o \
|
||||
|
|
|
@ -18,18 +18,9 @@
|
|||
#include "KeyValueRepositoryConfigfile.hxx"
|
||||
#include "Logger.hxx"
|
||||
|
||||
namespace {
|
||||
string trim(const string& str)
|
||||
{
|
||||
string::size_type first = str.find_first_not_of(' ');
|
||||
return (first == string::npos) ? EmptyString :
|
||||
str.substr(first, str.find_last_not_of(' ')-first+1);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
KeyValueRepositoryConfigfile::KeyValueRepositoryConfigfile(const FilesystemNode& file)
|
||||
: myFile(file)
|
||||
: myFile{file}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -67,8 +58,8 @@ std::map<string, Variant> KeyValueRepositoryConfigfile::load()
|
|||
continue;
|
||||
|
||||
// Split the line into key/value pairs and trim any whitespace
|
||||
key = trim(line.substr(0, equalPos));
|
||||
value = trim(line.substr(equalPos + 1, line.length() - key.length() - 1));
|
||||
key = BSPF::trim(line.substr(0, equalPos));
|
||||
value = BSPF::trim(line.substr(equalPos + 1, line.length() - key.length() - 1));
|
||||
|
||||
// Skip absent key
|
||||
if(key.length() == 0)
|
||||
|
@ -100,8 +91,8 @@ void KeyValueRepositoryConfigfile::save(const std::map<string, Variant>& values)
|
|||
<< ";" << endl;
|
||||
|
||||
// Write out each of the key and value pairs
|
||||
for(const auto& pair: values)
|
||||
out << pair.first << " = " << pair.second << endl;
|
||||
for(const auto& [key, value]: values)
|
||||
out << key << " = " << value << endl;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -22,10 +22,9 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
KeyValueRepositorySqlite::KeyValueRepositorySqlite(
|
||||
SqliteDatabase& db,
|
||||
const string& tableName
|
||||
) : myTableName(tableName),
|
||||
myDb(db)
|
||||
SqliteDatabase& db, const string& tableName)
|
||||
: myTableName{tableName},
|
||||
myDb{db}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -20,12 +20,11 @@
|
|||
#include "SqliteError.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SettingsDb::SettingsDb(
|
||||
const string& databaseDirectory,
|
||||
const string& databaseName
|
||||
) : myDatabaseDirectory(databaseDirectory),
|
||||
myDatabaseName(databaseName)
|
||||
{}
|
||||
SettingsDb::SettingsDb(const string& databaseDirectory, const string& databaseName)
|
||||
: myDatabaseDirectory{databaseDirectory},
|
||||
myDatabaseName{databaseName}
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SettingsDb::initialize()
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SqliteDatabase::SqliteDatabase(const string& databaseDirectory,
|
||||
const string& databaseName)
|
||||
: myDatabaseFile(databaseDirectory + SEPARATOR + databaseName + ".sqlite3")
|
||||
: myDatabaseFile{databaseDirectory + SEPARATOR + databaseName + ".sqlite3"}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SqliteStatement::SqliteStatement(sqlite3* handle, string sql)
|
||||
: myHandle(handle)
|
||||
: myHandle{handle}
|
||||
{
|
||||
if (sqlite3_prepare_v2(handle, sql.c_str(), -1, &myStmt, nullptr) != SQLITE_OK)
|
||||
throw SqliteError(handle);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SqliteTransaction::SqliteTransaction(SqliteDatabase& db)
|
||||
: myDb(db)
|
||||
: myDb{db}
|
||||
{
|
||||
myDb.exec("BEGIN TRANSACTION");
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
BilinearBlitter::BilinearBlitter(FBBackendSDL2& fb, bool interpolate)
|
||||
: myFB(fb),
|
||||
myInterpolate(interpolate)
|
||||
: myFB{fb},
|
||||
myInterpolate{interpolate}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
#include "BilinearBlitter.hxx"
|
||||
#include "QisBlitter.hxx"
|
||||
|
||||
unique_ptr<Blitter> BlitterFactory::createBlitter(FBBackendSDL2& fb, ScalingAlgorithm scaling)
|
||||
unique_ptr<Blitter>
|
||||
BlitterFactory::createBlitter(FBBackendSDL2& fb, ScalingAlgorithm scaling)
|
||||
{
|
||||
if (!fb.isInitialized()) {
|
||||
throw runtime_error("BlitterFactory requires an initialized framebuffer!");
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
QisBlitter::QisBlitter(FBBackendSDL2& fb)
|
||||
: myFB(fb)
|
||||
: myFB{fb}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,374 @@
|
|||
"Cart.MD5" "05215b73ec33b502449ee726ac6b201f"
|
||||
"Cart.Name" "draconian_20171013_RC6"
|
||||
"Display.Phosphor" "YES"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "8,0,B,0,B,1,SECT.,D,1,VARIATIONS_ARE_DIFFICULTY_LEVEL"
|
||||
"Cart.Addresses" "177B,177A,1779,1778,811,1780"
|
||||
""
|
||||
|
||||
"Cart.MD5" "081e2c114c9c20b61acf25fc95c71bf4"
|
||||
"Cart.Manufacturer" "Parker Brothers, Ed English, David Lamkins"
|
||||
"Cart.ModelNo" "PB5300"
|
||||
"Cart.Name" "Frogger (1982) (Parker Bros)"
|
||||
"Display.Phosphor" "YES"
|
||||
"Cart.Variations" "6"
|
||||
"Cart.Addresses" "CC,CE,DD,E6"
|
||||
""
|
||||
|
||||
"Cart.MD5" "136f75c4dd02c29283752b7e5799f978"
|
||||
"Cart.Manufacturer" "Atari, Dan Hitchens - Sears"
|
||||
"Cart.ModelNo" "CX2650 - 49-75168"
|
||||
"Cart.Name" "Berzerk (1982) (Atari)"
|
||||
"Cart.Rarity" "Common"
|
||||
"Cart.Variations" "12"
|
||||
"Cart.Formats" "6"
|
||||
"Cart.Addresses" "DD,DE,DF,80"
|
||||
""
|
||||
|
||||
"Cart.MD5" "137373599e9b7bf2cf162a102eb5927f"
|
||||
"Cart.Manufacturer" "AtariAge, Joe Grand"
|
||||
"Cart.Name" "Ultra SCSIcide (SCSIcide 2.0)"
|
||||
"Controller.Left" "PADDLES"
|
||||
"Cart.Formats" "6,0,H"
|
||||
"Cart.Addresses" "DC,DD,DE"
|
||||
""
|
||||
|
||||
"Cart.MD5" "211774f4c5739042618be8ff67351177"
|
||||
"Cart.Manufacturer" "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker"
|
||||
"Cart.ModelNo" "CX2684"
|
||||
"Cart.Name" "Galaxian (1983) (Atari)"
|
||||
"Display.Phosphor" "YES"
|
||||
"Cart.Variations" "9"
|
||||
"Cart.Formats" "6,0,B,0,B,0,WAVE"
|
||||
"Cart.Addresses" "AC,AD,AE,B3,AF"
|
||||
""
|
||||
|
||||
"Cart.MD5" "240bfbac5163af4df5ae713985386f92"
|
||||
"Cart.Manufacturer" "Activision, Steve Cartwright"
|
||||
"Cart.ModelNo" "AX-022"
|
||||
"Cart.Name" "Seaquest (1983) (Activision)"
|
||||
"Cart.Formats" "6,0,B,0,B,0,_,B,0,HIGH_SCORE_IS_FROM_CURRENT_PLAYER"
|
||||
"Cart.Addresses" "B8,B9,BA"
|
||||
""
|
||||
|
||||
"Cart.MD5" "278f14887d601b5e5b620f1870bc09f6"
|
||||
"Cart.Manufacturer" "Thomas Jentzsch"
|
||||
"Cart.Name" "SWOOPS! (v0.96) (TJ)"
|
||||
"Cart.Note" "Uses the Joystick (L) and Paddle (R) Controllers"
|
||||
"Cart.Rarity" "Homebrew"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "6,0,B,0,B,1"
|
||||
"Cart.Addresses" "FD,FE,FF,FC"
|
||||
""
|
||||
|
||||
"Cart.MD5" "2903896d88a341511586d69fcfc20f7d"
|
||||
"Cart.Manufacturer" "Activision, David Crane"
|
||||
"Cart.ModelNo" "AX-014, AX-014-04"
|
||||
"Cart.Name" "Grand Prix (1982) (Activision)"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "5,0,B,1,B,1,_,B,0,TIME/SCORE_SHOWS_EXTRA_DIGIT"
|
||||
"Cart.Addresses" "EB,EC,ED,80"
|
||||
""
|
||||
|
||||
"Cart.MD5" "2a0ba55e56e7a596146fa729acf0e109"
|
||||
"Cart.Manufacturer" "Activision, Bob Whitehead"
|
||||
"Cart.ModelNo" "AG-019"
|
||||
"Cart.Name" "Sky Jinks (1982) (Activision)"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "6,0,B,1,B,1"
|
||||
"Cart.Addresses" "9E,A6,A2,99"
|
||||
""
|
||||
|
||||
"Cart.MD5" "2bb9f4686f7e08c5fcc69ec1a1c66fe7"
|
||||
"Cart.Manufacturer" "Atari - GCC, John Allred, Mike Feinstein"
|
||||
"Cart.ModelNo" "CX2688"
|
||||
"Cart.Name" "Jungle Hunt (1983) (Atari)"
|
||||
"Cart.Variations" "2"
|
||||
"Cart.Formats" "6,0,B,0,B,1"
|
||||
"Cart.Addresses" "85,84,83,8B"
|
||||
""
|
||||
|
||||
"Cart.MD5" "318a9d6dda791268df92d72679914ac3"
|
||||
"Cart.Manufacturer" "Activision, Steve Cartwright"
|
||||
"Cart.ModelNo" "AX-017, AX-017-04"
|
||||
"Cart.Name" "MegaMania (1982) (Activision)"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "6,0,B,0,B,1"
|
||||
"Cart.Addresses" "DB,DC,DD,80"
|
||||
""
|
||||
|
||||
"Cart.MD5" "36b20c427975760cb9cf4a47e41369e4"
|
||||
"Cart.Manufacturer" "Coleco - Woodside Design Associates - Imaginative Systems Software, Garry Kitchen"
|
||||
"Cart.ModelNo" "2451"
|
||||
"Cart.Name" "Donkey Kong (1982) (Coleco)"
|
||||
"Cart.Formats" "6,2"
|
||||
"Cart.Addresses" "87,88"
|
||||
""
|
||||
|
||||
"Cart.MD5" "3a2e2d0c6892aa14544083dfb7762782"
|
||||
"Cart.Manufacturer" "Atari, Rob Fulop - Sears"
|
||||
"Cart.ModelNo" "CX2638 - 49-75166"
|
||||
"Cart.Name" "Missile Command (1981) (Atari)"
|
||||
"Display.Phosphor" "YES"
|
||||
"Cart.Variations" "34"
|
||||
"Cart.Formats" "6"
|
||||
"Cart.Addresses" "F3,F1,EF,E9"
|
||||
""
|
||||
|
||||
"Cart.MD5" "3e90cf23106f2e08b2781e41299de556"
|
||||
"Cart.Manufacturer" "Activision, David Crane"
|
||||
"Cart.ModelNo" "AX-018, AX-018-04"
|
||||
"Cart.Name" "Pitfall! (1982) (Activision)"
|
||||
"Cart.Note" "Pitfall Harry's Jungle Adventure (Jungle Runner)"
|
||||
"Cart.Formats" "6"
|
||||
"Cart.Addresses" "D5,D6,D7"
|
||||
""
|
||||
|
||||
"Cart.MD5" "4ca73eb959299471788f0b685c3ba0b5"
|
||||
"Cart.Manufacturer" "Activision, Steve Cartwright"
|
||||
"Cart.ModelNo" "AX-031"
|
||||
"Cart.Name" "Frostbite (1983) (Activision)"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "6,0,B,0,B,1,LEVEL,B,1"
|
||||
"Cart.Addresses" "C8,C9,CA,80,CB"
|
||||
""
|
||||
|
||||
"Cart.MD5" "515046e3061b7b18aa3a551c3ae12673"
|
||||
"Cart.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito"
|
||||
"Cart.ModelNo" "CX2692"
|
||||
"Cart.Name" "Moon Patrol (1983) (Atari)"
|
||||
"Cart.Variations" "6"
|
||||
"Cart.Formats" "6,0,B,0,B,1"
|
||||
"Cart.Addresses" "EA,EB,EC,F9"
|
||||
""
|
||||
|
||||
"Cart.MD5" "541cac55ebcf7891d9d51c415922303f"
|
||||
"Cart.Name" "SF2_20131217_RC8_NTSC"
|
||||
"Display.Phosphor" "YES"
|
||||
"Cart.Formats" "8,0,B,0,B,0,LEVEL,D,1"
|
||||
"Cart.Addresses" "1CF7,1CF6,1CF5,1CF4,0,18AC"
|
||||
""
|
||||
|
||||
"Cart.MD5" "6dda84fb8e442ecf34241ac0d1d91d69"
|
||||
"Cart.Manufacturer" "Atari - GCC, Douglas B. Macrae"
|
||||
"Cart.ModelNo" "CX2677"
|
||||
"Cart.Name" "Dig Dug (1983) (Atari)"
|
||||
"Cart.Variations" "2"
|
||||
"Cart.Formats" "4,0,B,0,B,1,_,B,0,VARIATION_1_IS_EASY;_2_IS_NORMAL"
|
||||
"Cart.Addresses" "F0FE,F0FD,80"
|
||||
""
|
||||
|
||||
"Cart.MD5" "72ffbef6504b75e69ee1045af9075f66"
|
||||
"Cart.Manufacturer" "Atari, Richard Maurer - Sears"
|
||||
"Cart.ModelNo" "CX2632 - 49-75153"
|
||||
"Cart.Name" "Space Invaders (1980) (Atari)"
|
||||
"Cart.Variations" "112"
|
||||
"Cart.Formats" "4,0,B,0,D,1,_,B,0,ONLY_PLAYER_1_SUPPORTED"
|
||||
"Cart.Addresses" "E6,E8,DC"
|
||||
""
|
||||
|
||||
"Cart.MD5" "77057d9d14b99e465ea9e29783af0ae3"
|
||||
"Cart.Manufacturer" "Activision, David Crane"
|
||||
"Cart.ModelNo" "AG-001"
|
||||
"Cart.Name" "Dragster (1980) (Activision)"
|
||||
"Cart.Note" "AKA Drag Strip"
|
||||
"Cart.Formats" "4,0,B,1,B,1"
|
||||
"Cart.Addresses" "B3,B5,80,0"
|
||||
""
|
||||
|
||||
"Cart.MD5" "7e52a95074a66640fcfde124fffd491a"
|
||||
"Cart.Manufacturer" "Atari - GCC, Mike Feinstein, John Mracek"
|
||||
"Cart.ModelNo" "CX2673"
|
||||
"Cart.Name" "Phoenix (1983) (Atari)"
|
||||
"Cart.Formats" "6"
|
||||
"Cart.Addresses" "C9,C8,C7"
|
||||
""
|
||||
|
||||
"Cart.MD5" "87e79cd41ce136fd4f72cc6e2c161bee"
|
||||
"Cart.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker"
|
||||
"Cart.ModelNo" "CX2675"
|
||||
"Cart.Name" "Ms. Pac-Man (1983) (Atari)"
|
||||
"Display.Phosphor" "YES"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "6,0,B,0,B,1,_,D,1,VARS_VALID_AT_GAME_OVER;_CHERRIES_=_VAR_#4"
|
||||
"Cart.Addresses" "FA,F9,F8,F7,0"
|
||||
""
|
||||
|
||||
"Cart.MD5" "91c2098e88a6b13f977af8c003e0bca5"
|
||||
"Cart.Manufacturer" "Atari - GCC"
|
||||
"Cart.ModelNo" "CX2676"
|
||||
"Cart.Name" "Centipede (1983) (Atari)"
|
||||
"Cart.Formats" "6,0,B,0,B,0,_,B,0,VARIATIONS_CANNOT_BE_DEFINED"
|
||||
"Cart.Addresses" "F4,F5,F6"
|
||||
""
|
||||
|
||||
"Cart.MD5" "91f0a708eeb93c133e9672ad2c8e0429"
|
||||
"Cart.Name" "Oystron (V2.9) (Piero Cavina) (PD)"
|
||||
"Cart.Rarity" "New Release"
|
||||
"Cart.Variations" "3"
|
||||
"Cart.Formats" "5,1,B,0,B,1"
|
||||
"Cart.Addresses" "D4,D3,E5"
|
||||
""
|
||||
|
||||
"Cart.MD5" "94b92a882f6dbaa6993a46e2dcc58402"
|
||||
"Cart.Manufacturer" "Activision, Larry Miller"
|
||||
"Cart.ModelNo" "AX-026, AX-026-04"
|
||||
"Cart.Name" "Enduro (1983) (Activision)"
|
||||
"Cart.Formats" "6,0,B,0,B,0,DAY"
|
||||
"Cart.Addresses" "AA,A9,A8,0,AD"
|
||||
""
|
||||
|
||||
"Cart.MD5" "9ad36e699ef6f45d9eb6c4cf90475c9f"
|
||||
"Cart.Manufacturer" "Imagic, Dennis Koble"
|
||||
"Cart.ModelNo" "720103-1A, 720103-1B, IA3203, IX-010-04"
|
||||
"Cart.Name" "Atlantis (1982) (Imagic)"
|
||||
"Cart.Note" "AKA Lost City of Atlantis"
|
||||
"Cart.Rarity" "Uncommon"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "6,2,B,0,B,1"
|
||||
"Cart.Addresses" "A3,A2,8D"
|
||||
""
|
||||
|
||||
"Cart.MD5" "ab5bf1ef5e463ad1cbb11b6a33797228"
|
||||
"Cart.Manufacturer" "Imagic, Rob Fulop"
|
||||
"Cart.ModelNo" "720104-1A, 720104-1B, IA3204"
|
||||
"Cart.Name" "Cosmic Ark (1982) (Imagic)"
|
||||
"Cart.Variations" "6"
|
||||
"Cart.Formats" "6"
|
||||
"Cart.Addresses" "AE,B0,B2,BC"
|
||||
""
|
||||
|
||||
"Cart.MD5" "ac7c2260378975614192ca2bc3d20e0b"
|
||||
"Cart.Manufacturer" "Activision, David Crane"
|
||||
"Cart.ModelNo" "AG-930-04, AZ-030"
|
||||
"Cart.Name" "Decathlon (1983) (Activision)"
|
||||
"Cart.Rarity" "Rare"
|
||||
"Cart.Variations" "10"
|
||||
"Cart.Formats" "4,0,B,0,D,1,_,B,0,DECATHLON_&_100M_DASH_SHARE_VARIATION_1"
|
||||
"Cart.Addresses" "95,96,80,0"
|
||||
""
|
||||
|
||||
"Cart.MD5" "be929419902e21bd7830a7a7d746195d"
|
||||
"Cart.Manufacturer" "Activision, Garry Kitchen"
|
||||
"Cart.ModelNo" "AX-025, AX-025-04"
|
||||
"Cart.Name" "Keystone Kapers (1983) (Activision)"
|
||||
"Cart.Formats" "6"
|
||||
"Cart.Addresses" "9A,9B,9C"
|
||||
""
|
||||
|
||||
"Cart.MD5" "c1cb228470a87beb5f36e90ac745da26"
|
||||
"Cart.Manufacturer" "Activision, Bob Whitehead"
|
||||
"Cart.ModelNo" "AX-015, AX-015-04"
|
||||
"Cart.Name" "Chopper Command (1982) (Activision)"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "6,0,B,0,B,1"
|
||||
"Cart.Addresses" "EC,EE,F0,E0"
|
||||
""
|
||||
|
||||
"Cart.MD5" "c5930d0e8cdae3e037349bfa08e871be"
|
||||
"Cart.Manufacturer" "Atari, Howard Scott Warshaw - Sears"
|
||||
"Cart.ModelNo" "CX2655 - 49-75167"
|
||||
"Cart.Name" "Yars' Revenge (1982) (Atari)"
|
||||
"Display.Phosphor" "YES"
|
||||
"Cart.Variations" "8"
|
||||
"Cart.Formats" "6,0,B,0,B,1,_,B,0,VARIATIONS_ARE_LARGER_BY_1"
|
||||
"Cart.Addresses" "E0,E1,E2,80"
|
||||
""
|
||||
|
||||
"Cart.MD5" "c6556e082aac04260596b4045bc122de"
|
||||
"Cart.Manufacturer" "Atari - GCC, Dave Payne"
|
||||
"Cart.ModelNo" "CX2669"
|
||||
"Cart.Name" "Vanguard (1983) (Atari)"
|
||||
"Cart.Formats" "6,0,B,0,B,0,_,B,0,SCORE_IS_FOR_CURRENT_PLAYER"
|
||||
"Cart.Addresses" "99,98,97"
|
||||
""
|
||||
|
||||
"Cart.MD5" "ccbd36746ed4525821a8083b0d6d2c2c"
|
||||
"Cart.Manufacturer" "Atari, Brad Stewart - Sears"
|
||||
"Cart.ModelNo" "CX2649, 49-75163"
|
||||
"Cart.Name" "Asteroids (1981) (Atari) [no copyright]"
|
||||
"Cart.Rarity" "Common"
|
||||
"Display.Phosphor" "YES"
|
||||
"Cart.Variations" "66"
|
||||
"Cart.Formats" "5,1,H,1,D,0,_,B,0,VARIATIONS_>_32_DIFFER_BY_1"
|
||||
"Cart.Addresses" "BD,BE,80"
|
||||
""
|
||||
|
||||
"Cart.MD5" "d69559f9c9dc6ef528d841bf9d91b275"
|
||||
"Cart.Manufacturer" "Activision, Alan Miller"
|
||||
"Cart.ModelNo" "AX-016"
|
||||
"Cart.Name" "StarMaster (1982) (Activision)"
|
||||
"Cart.Note" "Use Color/BW switch to change between galactic chart and front views"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "4,0,B,0,B,1,_,B,0,SCORE_ONLY_CALCULATED_WHEN_GAME_IS_OVER"
|
||||
"Cart.Addresses" "C1,C2,80"
|
||||
""
|
||||
|
||||
"Cart.MD5" "dd7884b4f93cab423ac471aa1935e3df"
|
||||
"Cart.Manufacturer" "Atari, Brad Stewart - Sears"
|
||||
"Cart.ModelNo" "CX2649, 49-75163"
|
||||
"Cart.Name" "Asteroids (1981) (Atari)"
|
||||
"Cart.Variations" "66"
|
||||
"Cart.Formats" "5,1,H,1,D,0,_,B,0,VARIATIONS_>_32_DIFFER_BY_1"
|
||||
"Cart.Addresses" "BD,BE,80"
|
||||
""
|
||||
|
||||
"Cart.MD5" "dde55d9868911407fe8b3fefef396f00"
|
||||
"Cart.Name" "Seawolf (2004) (Xype, Manuel Rotschkar)"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "6,0,B,0,B,0,_,B,0,USER_DEFINED_VARIATION_BASED_ON_SWITCHES"
|
||||
"Cart.Addresses" "90,91,92,0,0"
|
||||
""
|
||||
|
||||
"Cart.MD5" "f0e0addc07971561ab80d9abe1b8d333"
|
||||
"Cart.Manufacturer" "Imagic, Rob Fulop"
|
||||
"Cart.ModelNo" "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04"
|
||||
"Cart.Name" "Demon Attack (1982) (Imagic)"
|
||||
"Cart.Note" "AKA Death from Above"
|
||||
"Cart.Variations" "10"
|
||||
"Cart.Formats" "6,0,B,0,B,0,WAVE,B,1"
|
||||
"Cart.Addresses" "81,83,85,EA,80"
|
||||
""
|
||||
|
||||
"Cart.MD5" "f1489e27a4539a0c6c8529262f9f7e18"
|
||||
"Cart.Manufacturer" "Champ Games"
|
||||
"Cart.ModelNo" "CG-01-P"
|
||||
"Cart.Name" "Lady Bug (PAL60)"
|
||||
"Cart.Rarity" "Homebrew"
|
||||
"Console.RightDiff" "A"
|
||||
"Display.Format" "PAL60"
|
||||
"Display.Phosphor" "YES"
|
||||
"Cart.Variations" "3"
|
||||
"Cart.Formats" "6,0,B,0,B,1,PART,D,1"
|
||||
"Cart.Addresses" "8E,8D,8C,8A,89"
|
||||
""
|
||||
|
||||
"Cart.MD5" "f34f08e5eb96e500e851a80be3277a56"
|
||||
"Cart.Manufacturer" "Atari, Brad Stewart - Sears"
|
||||
"Cart.ModelNo" "CX2622 - 6-99813, 49-75107"
|
||||
"Cart.Name" "Breakout (1978) (Atari)"
|
||||
"Cart.Note" "Uses the Paddle Controllers"
|
||||
"Controller.MouseAxis" "01 60"
|
||||
"Cart.Formats" "3,0,B,0,B,0,_,B,0,VARIATIONS_CANNOT_BE_DEFINED"
|
||||
"Cart.Addresses" "CE,CD"
|
||||
""
|
||||
|
||||
"Cart.MD5" "f8240e62d8c0a64a61e19388414e3104"
|
||||
"Cart.Manufacturer" "Activision, Steve Cartwright"
|
||||
"Cart.ModelNo" "AX-013"
|
||||
"Cart.Name" "Barnstorming (1982) (Activision)"
|
||||
"Cart.Rarity" "Uncommon"
|
||||
"Cart.Variations" "4"
|
||||
"Cart.Formats" "6,0,B,1,B,1"
|
||||
"Cart.Addresses" "B5,B6,B7,80"
|
||||
""
|
||||
|
||||
"Cart.MD5" "fca4a5be1251927027f2c24774a02160"
|
||||
"Cart.Manufacturer" "Activision, John Van Ryzin"
|
||||
"Cart.ModelNo" "AZ-036-04"
|
||||
"Cart.Name" "H.E.R.O. (1984) (Activision)"
|
||||
"Cart.Variations" "5"
|
||||
"Cart.Formats" "6,0,B,0,B,1,LEVEL,D,1"
|
||||
"Cart.Addresses" "B7,B8,B9,80,F5"
|
||||
""
|
||||
|
|
@ -232,7 +232,7 @@ class AtariNTSC
|
|||
}
|
||||
|
||||
// Common ntsc macros
|
||||
static inline constexpr void ATARI_NTSC_CLAMP( uInt32& io, uInt32 shift ) {
|
||||
static constexpr void ATARI_NTSC_CLAMP( uInt32& io, uInt32 shift ) {
|
||||
uInt32 sub = io >> (9-(shift)) & atari_ntsc_clamp_mask;
|
||||
uInt32 clamp = atari_ntsc_clamp_add - sub;
|
||||
io |= clamp;
|
||||
|
@ -240,31 +240,31 @@ class AtariNTSC
|
|||
io &= clamp;
|
||||
}
|
||||
|
||||
static inline constexpr void RGB_TO_YIQ(float r, float g, float b,
|
||||
static constexpr void RGB_TO_YIQ(float r, float g, float b,
|
||||
float& y, float& i, float& q) {
|
||||
y = r * 0.299F + g * 0.587F + b * 0.114F;
|
||||
i = r * 0.595716F - g * 0.274453F - b * 0.321263F;
|
||||
q = r * 0.211456F - g * 0.522591F + b * 0.311135F;
|
||||
}
|
||||
static inline constexpr void YIQ_TO_RGB(float y, float i, float q,
|
||||
static constexpr void YIQ_TO_RGB(float y, float i, float q,
|
||||
const float* to_rgb, int& ir, int& ig, int& ib) {
|
||||
ir = static_cast<int>(y + to_rgb[0] * i + to_rgb[1] * q);
|
||||
ig = static_cast<int>(y + to_rgb[2] * i + to_rgb[3] * q);
|
||||
ib = static_cast<int>(y + to_rgb[4] * i + to_rgb[5] * q);
|
||||
}
|
||||
|
||||
static inline constexpr uInt32 PACK_RGB( int r, int g, int b ) {
|
||||
static constexpr uInt32 PACK_RGB( int r, int g, int b ) {
|
||||
return r << 21 | g << 11 | b << 1;
|
||||
}
|
||||
|
||||
// Converted from C-style macros; I don't even pretend to understand the logic here :)
|
||||
static inline constexpr int PIXEL_OFFSET1( int ntsc, int scaled ) {
|
||||
static constexpr int PIXEL_OFFSET1( int ntsc, int scaled ) {
|
||||
return (kernel_size / 2 + ((ntsc) - (scaled) / rescale_out * rescale_in) +
|
||||
((((scaled) + rescale_out * 10) % rescale_out) != 0) +
|
||||
(rescale_out - (((scaled) + rescale_out * 10) % rescale_out)) % rescale_out +
|
||||
(kernel_size * 2 * (((scaled) + rescale_out * 10) % rescale_out)));
|
||||
}
|
||||
static inline constexpr int PIXEL_OFFSET2( int ntsc ) {
|
||||
static constexpr int PIXEL_OFFSET2( int ntsc ) {
|
||||
return 1.0F - (((ntsc) + 100) & 2);
|
||||
}
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ void NTSCFilter::getAdjustables(Adjustable& adjustable, Preset preset) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void NTSCFilter::setCustomAdjustables(Adjustable& adjustable)
|
||||
void NTSCFilter::setCustomAdjustables(const Adjustable& adjustable)
|
||||
{
|
||||
#ifdef BLARGG_PALETTE
|
||||
//myCustomSetup.hue = scaleFrom100(adjustable.hue);
|
||||
|
|
|
@ -90,7 +90,7 @@ class NTSCFilter
|
|||
// Set custom adjustables to given values
|
||||
// Values will be scaled to 0 - 100 range, independent of how
|
||||
// they're actually stored internally
|
||||
void setCustomAdjustables(Adjustable& adjustable);
|
||||
void setCustomAdjustables(const Adjustable& adjustable);
|
||||
|
||||
// The following methods cycle through each custom adjustable
|
||||
// They are used in conjunction with the increase/decrease
|
||||
|
|
|
@ -30,12 +30,12 @@
|
|||
class BreakpointMap
|
||||
{
|
||||
private:
|
||||
static const uInt16 ADDRESS_MASK = 0x1fff; // either 0x1fff or 0xffff (not needed then)
|
||||
static constexpr uInt16 ADDRESS_MASK = 0x1fff; // either 0x1fff or 0xffff (not needed then)
|
||||
|
||||
public:
|
||||
// breakpoint flags
|
||||
static const uInt32 ONE_SHOT = 1 << 0; // used for 'trace' command
|
||||
static const uInt8 ANY_BANK = 255; // breakpoint valid in any bank
|
||||
static constexpr uInt32 ONE_SHOT = 1 << 0; // used for 'trace' command
|
||||
static constexpr uInt8 ANY_BANK = 255; // breakpoint valid in any bank
|
||||
|
||||
struct Breakpoint
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ using std::right;
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||
: DebuggerSystem(dbg, console),
|
||||
myOSystem(osystem)
|
||||
myOSystem{osystem}
|
||||
{
|
||||
// Add case sensitive compare for user labels
|
||||
// TODO - should user labels be case insensitive too?
|
||||
|
@ -1041,7 +1041,7 @@ string CartDebug::saveConfigFile()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartDebug::saveDisassembly()
|
||||
string CartDebug::saveDisassembly(string path)
|
||||
{
|
||||
string NTSC_COLOR[16] = {
|
||||
"BLACK", "YELLOW", "BROWN", "ORANGE",
|
||||
|
@ -1350,9 +1350,16 @@ string CartDebug::saveDisassembly()
|
|||
// And finally, output the disassembly
|
||||
out << buf.str();
|
||||
|
||||
const string& propsname =
|
||||
myConsole.properties().get(PropType::Cart_Name) + ".asm";
|
||||
FilesystemNode node(myOSystem.defaultSaveDir().getPath() + propsname);
|
||||
|
||||
if(path.empty())
|
||||
path = myOSystem.defaultSaveDir().getPath()
|
||||
+ myConsole.properties().get(PropType::Cart_Name) + ".asm";
|
||||
else
|
||||
// Append default extension when missing
|
||||
if(path.find_last_of('.') == string::npos)
|
||||
path += ".asm";
|
||||
|
||||
FilesystemNode node(path);
|
||||
stringstream retVal;
|
||||
try
|
||||
{
|
||||
|
@ -1370,11 +1377,18 @@ string CartDebug::saveDisassembly()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartDebug::saveRom()
|
||||
string CartDebug::saveRom(string path)
|
||||
{
|
||||
const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".a26";
|
||||
if(path.empty())
|
||||
path = myOSystem.defaultSaveDir().getPath()
|
||||
+ myConsole.properties().get(PropType::Cart_Name) + ".a26";
|
||||
else
|
||||
// Append default extension when missing
|
||||
if(path.find_last_of('.') == string::npos)
|
||||
path += ".a26";
|
||||
|
||||
FilesystemNode node(path);
|
||||
|
||||
FilesystemNode node(myOSystem.defaultSaveDir().getPath() + rom);
|
||||
if(myConsole.cartridge().saveROM(node))
|
||||
return "saved ROM as " + node.getShortPath();
|
||||
else
|
||||
|
@ -1382,7 +1396,7 @@ string CartDebug::saveRom()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartDebug::saveAccessFile()
|
||||
string CartDebug::saveAccessFile(string path)
|
||||
{
|
||||
stringstream out;
|
||||
out << myConsole.tia().getAccessCounters();
|
||||
|
@ -1391,8 +1405,15 @@ string CartDebug::saveAccessFile()
|
|||
|
||||
try
|
||||
{
|
||||
const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".csv";
|
||||
FilesystemNode node(myOSystem.defaultSaveDir().getPath() + rom);
|
||||
if(path.empty())
|
||||
path = myOSystem.defaultSaveDir().getPath()
|
||||
+ myConsole.properties().get(PropType::Cart_Name) + ".csv";
|
||||
else
|
||||
// Append default extension when missing
|
||||
if(path.find_last_of('.') == string::npos)
|
||||
path += ".csv";
|
||||
|
||||
FilesystemNode node(path);
|
||||
|
||||
node.write(out);
|
||||
return "saved access counters as " + node.getShortPath();
|
||||
|
@ -1516,7 +1537,7 @@ CartDebug::AddrType CartDebug::addressType(uInt16 addr) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const
|
||||
void CartDebug::getBankDirectives(ostream& buf, const BankInfo& info) const
|
||||
{
|
||||
// Start with the offset for this bank
|
||||
buf << "ORG " << Base::HEX4 << info.offset << endl;
|
||||
|
|
|
@ -236,13 +236,13 @@ class CartDebug : public DebuggerSystem
|
|||
/**
|
||||
Save disassembly and ROM file
|
||||
*/
|
||||
string saveDisassembly();
|
||||
string saveRom();
|
||||
string saveDisassembly(string path);
|
||||
string saveRom(string path);
|
||||
|
||||
/**
|
||||
Save access counters file
|
||||
*/
|
||||
string saveAccessFile();
|
||||
string saveAccessFile(string path);
|
||||
|
||||
/**
|
||||
Show Distella directives (both set by the user and determined by Distella)
|
||||
|
@ -324,7 +324,7 @@ class CartDebug : public DebuggerSystem
|
|||
|
||||
// Analyze of bank of ROM, generating a list of Distella directives
|
||||
// based on its disassembly
|
||||
void getBankDirectives(ostream& buf, BankInfo& info) const;
|
||||
void getBankDirectives(ostream& buf, const BankInfo& info) const;
|
||||
|
||||
// Get access enum type from 'flags', taking precendence into account
|
||||
Device::AccessType accessTypeAbsolute(Device::AccessFlags flags) const;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CpuDebug::CpuDebug(Debugger& dbg, Console& console)
|
||||
: DebuggerSystem(dbg, console),
|
||||
my6502(mySystem.m6502())
|
||||
my6502{mySystem.m6502()}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -62,8 +62,8 @@ Debugger* Debugger::myStaticDebugger = nullptr;
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Debugger::Debugger(OSystem& osystem, Console& console)
|
||||
: DialogContainer(osystem),
|
||||
myConsole(console),
|
||||
mySystem(console.system())
|
||||
myConsole{console},
|
||||
mySystem{console.system()}
|
||||
{
|
||||
// Init parser
|
||||
myParser = make_unique<DebuggerParser>(*this, osystem.settings());
|
||||
|
@ -716,10 +716,8 @@ bool Debugger::addFunction(const string& name, const string& definition,
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::isBuiltinFunction(const string& name)
|
||||
{
|
||||
for(const auto& func: ourBuiltinFunctions)
|
||||
if(name == func.name)
|
||||
return true;
|
||||
return false;
|
||||
return std::any_of(ourBuiltinFunctions.cbegin(), ourBuiltinFunctions.cend(),
|
||||
[&](const auto& func) { return name == func.name; });
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -76,9 +76,6 @@ class Debugger : public DialogContainer
|
|||
Debugger(OSystem& osystem, Console& console);
|
||||
~Debugger() override;
|
||||
|
||||
private:
|
||||
static const Int8 ANY_BANK = -1;
|
||||
|
||||
public:
|
||||
/**
|
||||
Initialize the debugger dialog container.
|
||||
|
@ -284,8 +281,6 @@ class Debugger : public DialogContainer
|
|||
*/
|
||||
Dialog* baseDialog() override { return myDialog; }
|
||||
|
||||
static const Int32 NOT_FOUND = -1;
|
||||
|
||||
private:
|
||||
/**
|
||||
Save state of each debugger subsystem and, by default, mark all
|
||||
|
@ -367,6 +362,8 @@ class Debugger : public DialogContainer
|
|||
static std::array<BuiltinFunction, 18> ourBuiltinFunctions;
|
||||
static std::array<PseudoRegister, 16> ourPseudoRegisters;
|
||||
|
||||
static constexpr Int8 ANY_BANK = -1;
|
||||
|
||||
private:
|
||||
// rewind/unwind n states
|
||||
uInt16 windStates(uInt16 numStates, bool unwind, string& message);
|
||||
|
|
|
@ -91,7 +91,7 @@ class ByteDerefOffsetExpression : public Expression
|
|||
class ConstExpression : public Expression
|
||||
{
|
||||
public:
|
||||
ConstExpression(const int value) : Expression(), myValue(value) { }
|
||||
ConstExpression(const int value) : Expression(), myValue{value} { }
|
||||
Int32 evaluate() const override
|
||||
{ return myValue; }
|
||||
|
||||
|
@ -103,7 +103,7 @@ class ConstExpression : public Expression
|
|||
class CpuMethodExpression : public Expression
|
||||
{
|
||||
public:
|
||||
CpuMethodExpression(CpuMethod method) : Expression(), myMethod(std::mem_fn(method)) { }
|
||||
CpuMethodExpression(CpuMethod method) : Expression(), myMethod{std::mem_fn(method)} { }
|
||||
Int32 evaluate() const override
|
||||
{ return myMethod(Debugger::debugger().cpuDebug()); }
|
||||
|
||||
|
@ -134,7 +134,7 @@ class EqualsExpression : public Expression
|
|||
class EquateExpression : public Expression
|
||||
{
|
||||
public:
|
||||
EquateExpression(const string& label) : Expression(), myLabel(label) { }
|
||||
EquateExpression(const string& label) : Expression(), myLabel{label} { }
|
||||
Int32 evaluate() const override
|
||||
{ return Debugger::debugger().cartDebug().getAddress(myLabel); }
|
||||
|
||||
|
@ -146,7 +146,7 @@ class EquateExpression : public Expression
|
|||
class FunctionExpression : public Expression
|
||||
{
|
||||
public:
|
||||
FunctionExpression(const string& label) : Expression(), myLabel(label) { }
|
||||
FunctionExpression(const string& label) : Expression(), myLabel{label} { }
|
||||
Int32 evaluate() const override
|
||||
{ return Debugger::debugger().getFunction(myLabel).evaluate(); }
|
||||
|
||||
|
@ -285,7 +285,7 @@ class PlusExpression : public Expression
|
|||
class CartMethodExpression : public Expression
|
||||
{
|
||||
public:
|
||||
CartMethodExpression(CartMethod method) : Expression(), myMethod(std::mem_fn(method)) { }
|
||||
CartMethodExpression(CartMethod method) : Expression(), myMethod{std::mem_fn(method)} { }
|
||||
Int32 evaluate() const override
|
||||
{ return myMethod(Debugger::debugger().cartDebug()); }
|
||||
|
||||
|
@ -315,7 +315,7 @@ class ShiftRightExpression : public Expression
|
|||
class RiotMethodExpression : public Expression
|
||||
{
|
||||
public:
|
||||
RiotMethodExpression(RiotMethod method) : Expression(), myMethod(std::mem_fn(method)) { }
|
||||
RiotMethodExpression(RiotMethod method) : Expression(), myMethod{std::mem_fn(method)} { }
|
||||
Int32 evaluate() const override
|
||||
{ return myMethod(Debugger::debugger().riotDebug()); }
|
||||
|
||||
|
@ -327,7 +327,7 @@ class RiotMethodExpression : public Expression
|
|||
class TiaMethodExpression : public Expression
|
||||
{
|
||||
public:
|
||||
TiaMethodExpression(TiaMethod method) : Expression(), myMethod(std::mem_fn(method)) { }
|
||||
TiaMethodExpression(TiaMethod method) : Expression(), myMethod{std::mem_fn(method)} { }
|
||||
Int32 evaluate() const override
|
||||
{ return myMethod(Debugger::debugger().tiaDebug()); }
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ using std::right;
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
DebuggerParser::DebuggerParser(Debugger& d, Settings& s)
|
||||
: debugger(d),
|
||||
settings(s)
|
||||
: debugger{d},
|
||||
settings{s}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -565,6 +565,12 @@ string DebuggerParser::eval()
|
|||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string& DebuggerParser::cartName() const
|
||||
{
|
||||
return debugger.myOSystem.console().properties().get(PropType::Cart_Name);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerParser::listTraps(bool listCond)
|
||||
{
|
||||
|
@ -630,15 +636,11 @@ string DebuggerParser::trapStatus(const Trap& trap)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string DebuggerParser::saveScriptFile(string file)
|
||||
{
|
||||
// Append 'script' extension when necessary
|
||||
if(file.find_last_of('.') == string::npos)
|
||||
file += ".script";
|
||||
|
||||
stringstream out;
|
||||
Debugger::FunctionDefMap funcs = debugger.getFunctionDefMap();
|
||||
for(const auto& f: funcs)
|
||||
if (!debugger.isBuiltinFunction(f.first))
|
||||
out << "function " << f.first << " {" << f.second << "}" << endl;
|
||||
for(const auto& [name, cmd]: funcs)
|
||||
if (!debugger.isBuiltinFunction(name))
|
||||
out << "function " << name << " {" << cmd << "}" << endl;
|
||||
|
||||
for(const auto& w: myWatches)
|
||||
out << "watch " << w << endl;
|
||||
|
@ -675,7 +677,16 @@ string DebuggerParser::saveScriptFile(string file)
|
|||
out << endl;
|
||||
}
|
||||
|
||||
FilesystemNode node(debugger.myOSystem.defaultSaveDir().getPath() + file);
|
||||
// Append 'script' extension when necessary
|
||||
if(file.find_last_of('.') == string::npos)
|
||||
file += ".script";
|
||||
|
||||
// Use default path if no path is provided
|
||||
if(file.find_first_of(FilesystemNode::PATH_SEPARATOR) == string::npos)
|
||||
file = debugger.myOSystem.defaultSaveDir().getPath() + file;
|
||||
|
||||
FilesystemNode node(file);
|
||||
|
||||
try
|
||||
{
|
||||
node.write(out);
|
||||
|
@ -1527,10 +1538,8 @@ void DebuggerParser::executeListfunctions()
|
|||
const Debugger::FunctionDefMap& functions = debugger.getFunctionDefMap();
|
||||
|
||||
if(functions.size() > 0)
|
||||
{
|
||||
for(const auto& iter: functions)
|
||||
commandResult << iter.first << " -> " << iter.second << endl;
|
||||
}
|
||||
for(const auto& [name, cmd]: functions)
|
||||
commandResult << name << " -> " << cmd << endl;
|
||||
else
|
||||
commandResult << "no user-defined functions";
|
||||
}
|
||||
|
@ -1837,7 +1846,11 @@ void DebuggerParser::executeS()
|
|||
void DebuggerParser::executeSave()
|
||||
{
|
||||
if(argCount && argStrings[0] == "?")
|
||||
debugger.myDialog->showBrowser(DebuggerDialog::svScript);
|
||||
{
|
||||
debugger.myDialog->showBrowser(DebuggerDialog::svScript, cartName() + ".script");
|
||||
// avoid printing a new prompt
|
||||
commandResult << "_EXIT_DEBUGGER";
|
||||
}
|
||||
else
|
||||
commandResult << saveScriptFile(argStrings[0]);
|
||||
}
|
||||
|
@ -1847,9 +1860,13 @@ void DebuggerParser::executeSave()
|
|||
void DebuggerParser::executeSaveAccess()
|
||||
{
|
||||
if(argCount && argStrings[0] == "?")
|
||||
debugger.myDialog->showBrowser(DebuggerDialog::svAccess);
|
||||
{
|
||||
debugger.myDialog->showBrowser(DebuggerDialog::svAccess, cartName() + ".csv");
|
||||
// avoid printing a new prompt
|
||||
commandResult << "_EXIT_DEBUGGER";
|
||||
}
|
||||
else
|
||||
commandResult << debugger.cartDebug().saveAccessFile();
|
||||
commandResult << debugger.cartDebug().saveAccessFile(argCount ? argStrings[0] : EmptyString);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1863,14 +1880,28 @@ void DebuggerParser::executeSaveconfig()
|
|||
// "savedis"
|
||||
void DebuggerParser::executeSavedisassembly()
|
||||
{
|
||||
commandResult << debugger.cartDebug().saveDisassembly();
|
||||
if(argCount && argStrings[0] == "?")
|
||||
{
|
||||
debugger.myDialog->showBrowser(DebuggerDialog::svDis, cartName() + ".asm");
|
||||
// avoid printing a new prompt
|
||||
commandResult << "_EXIT_DEBUGGER";
|
||||
}
|
||||
else
|
||||
commandResult << debugger.cartDebug().saveDisassembly(argCount ? argStrings[0] : EmptyString);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "saverom"
|
||||
void DebuggerParser::executeSaverom()
|
||||
{
|
||||
commandResult << debugger.cartDebug().saveRom();
|
||||
if(argCount && argStrings[0] == "?")
|
||||
{
|
||||
debugger.myDialog->showBrowser(DebuggerDialog::svRom, cartName() + ".a26");
|
||||
// avoid printing a new prompt
|
||||
commandResult << "_EXIT_DEBUGGER";
|
||||
}
|
||||
else
|
||||
commandResult << debugger.cartDebug().saveRom(argCount ? argStrings[0] : EmptyString);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -1881,11 +1912,21 @@ void DebuggerParser::executeSaveses()
|
|||
auto timeinfo = BSPF::localTime();
|
||||
filename << debugger.myOSystem.defaultSaveDir()
|
||||
<< std::put_time(&timeinfo, "session_%F_%H-%M-%S.txt");
|
||||
|
||||
if(argCount && argStrings[0] == "?")
|
||||
{
|
||||
debugger.myDialog->showBrowser(DebuggerDialog::svSession, filename.str());
|
||||
commandResult << "_EXIT_DEBUGGER";
|
||||
}
|
||||
else
|
||||
{
|
||||
FilesystemNode file(filename.str());
|
||||
|
||||
if(debugger.prompt().saveBuffer(file))
|
||||
commandResult << "saved " + file.getShortPath() + " OK";
|
||||
else
|
||||
commandResult << "unable to save session";
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -3051,7 +3092,7 @@ std::array<DebuggerParser::Command, 100> DebuggerParser::commands = { {
|
|||
{
|
||||
"save",
|
||||
"Save breaks, watches, traps and functions to file xx",
|
||||
"Example: save commands.script",
|
||||
"Example: save commands.script, save ?",
|
||||
true,
|
||||
false,
|
||||
{ Parameters::ARG_FILE, Parameters::ARG_END_ARGS },
|
||||
|
@ -3061,10 +3102,11 @@ std::array<DebuggerParser::Command, 100> DebuggerParser::commands = { {
|
|||
{
|
||||
"saveaccess",
|
||||
"Save the access counters to CSV file",
|
||||
"Example: saveaccess (no parameters)",
|
||||
"Example: saveaccess, saveaccess ?\n"
|
||||
"NOTE: saves to default save location without ? parameter",
|
||||
false,
|
||||
false,
|
||||
{ Parameters::ARG_END_ARGS },
|
||||
{ Parameters::ARG_FILE, Parameters::ARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeSaveAccess)
|
||||
},
|
||||
|
||||
|
@ -3080,34 +3122,34 @@ std::array<DebuggerParser::Command, 100> DebuggerParser::commands = { {
|
|||
|
||||
{
|
||||
"savedis",
|
||||
"Save Distella disassembly (with default name)",
|
||||
"Example: savedis\n"
|
||||
"NOTE: saves to default save location",
|
||||
"Save Distella disassembly",
|
||||
"Example: savedis, savedis ?\n"
|
||||
"NOTE: saves to default save location without ? parameter",
|
||||
false,
|
||||
false,
|
||||
{ Parameters::ARG_END_ARGS },
|
||||
{ Parameters::ARG_FILE, Parameters::ARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeSavedisassembly)
|
||||
},
|
||||
|
||||
{
|
||||
"saverom",
|
||||
"Save (possibly patched) ROM (with default name)",
|
||||
"Example: saverom\n"
|
||||
"NOTE: saves to default save location",
|
||||
"Save (possibly patched) ROM",
|
||||
"Example: saverom, saverom ?\n"
|
||||
"NOTE: saves to default save location without ? parameter",
|
||||
false,
|
||||
false,
|
||||
{ Parameters::ARG_END_ARGS },
|
||||
{ Parameters::ARG_FILE, Parameters::ARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeSaverom)
|
||||
},
|
||||
|
||||
{
|
||||
"saveses",
|
||||
"Save console session (with default name)",
|
||||
"Example: saveses\n"
|
||||
"NOTE: saves to default save location",
|
||||
"Save console session",
|
||||
"Example: saveses, saveses ?\n"
|
||||
"NOTE: saves to default save location without ? parameter",
|
||||
false,
|
||||
false,
|
||||
{ Parameters::ARG_END_ARGS },
|
||||
{ Parameters::ARG_FILE, Parameters::ARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeSaveses)
|
||||
},
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ class DebuggerParser
|
|||
bool validateArgs(int cmd);
|
||||
string eval();
|
||||
string saveScriptFile(string file);
|
||||
const string& cartName() const;
|
||||
|
||||
private:
|
||||
// Constants for argument processing
|
||||
|
|
|
@ -27,12 +27,12 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
|
|||
CartDebug::AddrTypeArray& labels,
|
||||
CartDebug::AddrTypeArray& directives,
|
||||
CartDebug::ReservedEquates& reserved)
|
||||
: myDbg(dbg),
|
||||
myList(list),
|
||||
mySettings(s),
|
||||
myReserved(reserved),
|
||||
myLabels(labels),
|
||||
myDirectives(directives)
|
||||
: myDbg{dbg},
|
||||
myList{list},
|
||||
mySettings{s},
|
||||
myReserved{reserved},
|
||||
myLabels{labels},
|
||||
myDirectives{directives}
|
||||
{
|
||||
bool resolve_code = mySettings.resolveCode;
|
||||
CartDebug::AddressList& debuggerAddresses = info.addressList;
|
||||
|
|
|
@ -32,7 +32,7 @@ class Expression
|
|||
{
|
||||
public:
|
||||
Expression(Expression* lhs = nullptr, Expression* rhs = nullptr)
|
||||
: myLHS(lhs), myRHS(rhs) { }
|
||||
: myLHS{lhs}, myRHS{rhs} { }
|
||||
virtual ~Expression() = default;
|
||||
|
||||
virtual Int32 evaluate() const { return 0; }
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
TIADebug::TIADebug(Debugger& dbg, Console& console)
|
||||
: DebuggerSystem(dbg, console),
|
||||
myTIA(console.tia())
|
||||
myTIA{console.tia()}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ Cartridge3EPlusWidget::Cartridge3EPlusWidget(
|
|||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, Cartridge3EPlus& cart)
|
||||
: CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart),
|
||||
myCart3EP(cart)
|
||||
myCart3EP{cart}
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ Cartridge4A50Widget::Cartridge4A50Widget(
|
|||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, Cartridge4A50& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
myCart{cart}
|
||||
{
|
||||
string info =
|
||||
"4A50 cartridge - 128K ROM and 32K RAM, split in various bank configurations\n"
|
||||
|
|
|
@ -27,7 +27,7 @@ CartridgeARWidget::CartridgeARWidget(
|
|||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeAR& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
myCart{cart}
|
||||
{
|
||||
size_t size = myCart.mySize;
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ CartridgeBUSWidget::CartridgeBUSWidget(
|
|||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeBUS& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
myCart{cart}
|
||||
{
|
||||
uInt16 size = 8 * 4096;
|
||||
|
||||
|
@ -75,7 +75,6 @@ CartridgeBUSWidget::CartridgeBUSWidget(
|
|||
ypos += myLineHeight + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Datastream Pointers", TextAlign::Left);
|
||||
xpos += lwidth;
|
||||
|
||||
myDatastreamPointers = new DataGridWidget(boss, _nfont, DS_X, ypos+myLineHeight-2, 4, 4, 6, 32, Common::Base::Fmt::_16_3_2);
|
||||
myDatastreamPointers->setTarget(this);
|
||||
|
|
|
@ -24,7 +24,7 @@ CartridgeCDFWidget::CartridgeCDFWidget(
|
|||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeCDF& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
myCart{cart}
|
||||
{
|
||||
const int VBORDER = 8;
|
||||
const int HBORDER = 2;
|
||||
|
|
|
@ -31,7 +31,7 @@ CartridgeCMWidget::CartridgeCMWidget(
|
|||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeCM& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
myCart{cart}
|
||||
{
|
||||
uInt16 size = 4 * 4096;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ CartridgeCTYWidget::CartridgeCTYWidget(
|
|||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeCTY& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
myCart{cart}
|
||||
{
|
||||
uInt16 size = 8 * 4096;
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ CartridgeDPCPlusWidget::CartridgeDPCPlusWidget(
|
|||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeDPCPlus& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
myCart{cart}
|
||||
{
|
||||
size_t size = cart.mySize;
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ CartridgeDPCWidget::CartridgeDPCWidget(
|
|||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeDPC& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
myCart{cart}
|
||||
{
|
||||
const int V_GAP = 4;
|
||||
size_t size = cart.mySize;
|
||||
|
@ -68,11 +68,10 @@ CartridgeDPCWidget::CartridgeDPCWidget(
|
|||
ypos += myLineHeight + V_GAP * 3;
|
||||
|
||||
// Data fetchers
|
||||
int lwidth = _font.getStringWidth("Data fetchers ");
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, "Data fetchers ");
|
||||
|
||||
// Top registers
|
||||
lwidth = _font.getStringWidth("Counter registers ");
|
||||
int lwidth = _font.getStringWidth("Counter registers ");
|
||||
xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, "Top registers ");
|
||||
xpos += lwidth;
|
||||
|
|
|
@ -29,11 +29,11 @@ CartDebugWidget::CartDebugWidget(GuiObject* boss, const GUI::Font& lfont,
|
|||
int x, int y, int w, int h)
|
||||
: Widget(boss, lfont, x, y, w, h),
|
||||
CommandSender(boss),
|
||||
_nfont(nfont),
|
||||
myFontWidth(lfont.getMaxCharWidth()),
|
||||
myFontHeight(lfont.getFontHeight()),
|
||||
myLineHeight(lfont.getLineHeight()),
|
||||
myButtonHeight(myLineHeight + 4)
|
||||
_nfont{nfont},
|
||||
myFontWidth{lfont.getMaxCharWidth()},
|
||||
myFontHeight{lfont.getFontHeight()},
|
||||
myLineHeight{lfont.getLineHeight()},
|
||||
myButtonHeight{myLineHeight + 4}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ CartridgeEnhancedWidget::CartridgeEnhancedWidget(GuiObject* boss, const GUI::Fon
|
|||
int x, int y, int w, int h,
|
||||
CartridgeEnhanced& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
myCart{cart}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ CartridgeFA2Widget::CartridgeFA2Widget(
|
|||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeFA2& cart)
|
||||
: CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart),
|
||||
myCartFA2(cart)
|
||||
myCartFA2{cart}
|
||||
{
|
||||
int xpos = 2,
|
||||
ypos = initialize();
|
||||
|
|