add HighScoreManager class

add high score tab in GameInfoDialog
This commit is contained in:
thrust26 2020-02-09 12:41:59 +01:00
parent 6930e91fa5
commit 8bbcdc4e69
13 changed files with 650 additions and 181 deletions

View File

@ -0,0 +1,197 @@
//============================================================================
//
// 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.
//============================================================================
#include "OSystem.hxx"
//#include "Props.hxx"
#include "PropsSet.hxx"
#include "Console.hxx"
#include "Launcher.hxx"
#include "System.hxx"
#include "HighScoreManager.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
HighScoreManager::HighScoreManager(OSystem& osystem)
: myOSystem(osystem)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Properties& HighScoreManager::properties(Properties& props) const
{
if (myOSystem.hasConsole())
{
props = myOSystem.console().properties();
}
else
{
const string& md5 = myOSystem.launcher().selectedRomMD5();
myOSystem.propSet().getMD5(md5, props);
}
return props;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoreManager::numVariations()
{
Properties props;
string numVariations = properties(props).get(PropType::Cart_Variations);
return (numVariations == EmptyString) ? 1 : std::min(stoi(numVariations), 256);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoreManager::numPlayers()
{
Properties props;
string numPlayers = properties(props).get(PropType::Cart_Players);
return (numPlayers == EmptyString) ? 1 : std::min(stoi(numPlayers), 4);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoreManager::parseAddresses(Int32& variation, Int32& player, Int32 scores[])
{
variation = 1; player = 0; scores[0] = 0;
if (!myOSystem.hasConsole())
return false;
System& system = myOSystem.console().system();
// Formats (all optional):
// 2, ; score addresses per player
// 1, ; score multiplier
// B, ; score format (BCD, HEX)
// B, ; variation format (BCD, HEX)
// 0, ; add to variation
// Addresses (in hex):
// n*p-times xx, ; score addresses for each player, high to low
// xx, ; variation address (if more than 1 variation)
// xx, ; player address (if more than 1 player)
// TODO:
// - variation bits (Centipede)
// - player bits (Asteroids, Space Invaders)
// - score swaps (Asteroids)
Properties props;
string formats = properties(props).get(PropType::Cart_Formats);
string addresses = properties(props).get(PropType::Cart_Addresses);
char scoreFormat;
char varFormat;
Int16 addr;
Int32 varAdd, numScoreAddr, scoreMult;
// Since istringstream swallows whitespace, we have to make the
// delimiters be spaces
std::replace(formats.begin(), formats.end(), ',', ' ');
std::replace(formats.begin(), formats.end(), '|', ' ');
std::replace(addresses.begin(), addresses.end(), ',', ' ');
std::replace(addresses.begin(), addresses.end(), '|', ' ');
istringstream addrBuf(addresses);
istringstream formatBuf(formats);
// 1. retrieve formats
if (!(formatBuf >> numScoreAddr))
numScoreAddr = 2;
if (!(formatBuf >> scoreMult))
scoreMult = 1;
if (!(formatBuf >> scoreFormat))
scoreFormat = 'B';
if (!(formatBuf >> varFormat))
varFormat = 'B';
if (!(formatBuf >> varAdd))
varAdd = 0;
// 2. retrieve current scores for all players
for (int i = 0; i < numPlayers(); ++i)
{
Int32 totalScore = 0;
for (int j = 0; j < numScoreAddr; ++j)
{
Int32 score;
if (!(addrBuf >> std::hex >> addr))
return false;
totalScore *= (scoreFormat == 'B') ? 100 : 256;
score = system.peek(addr);
if (scoreFormat == 'B')
score = (score >> 4) * 10 + score % 16;
totalScore += score;
}
scores[i] = totalScore * scoreMult;
}
// 3. retrieve current variation (0..255)
if (numVariations() == 1)
return true;
if (!(addrBuf >> std::hex >> addr))
return false;
variation = system.peek(addr);
if (varFormat == 'B')
variation = (variation >> 4) * 10 + variation % 16;
variation += varAdd;
variation = std::min(variation, numVariations());
// 4. retrieve current player (0..3)
if (numPlayers() == 1)
return true;
if (!(addrBuf >> std::hex >> addr))
return false;
player = system.peek(addr);
player = std::min(player, numPlayers() - 1);
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoreManager::variation()
{
Int32 variation, player, scores[4];
if (parseAddresses(variation, player, scores))
return variation;
return -1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoreManager::player()
{
Int32 variation, player, scores[4];
if (parseAddresses(variation, player, scores))
return player;
return -1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoreManager::score()
{
Int32 variation, player, scores[4];
if (parseAddresses(variation, player, scores))
return scores[std::min(player, Int32(3))];
return -1;
}

View File

@ -0,0 +1,56 @@
//============================================================================
//
// 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 HIGHSCORE_MANAGER_HXX
#define HIGHSCORE_MANAGER_HXX
class OSystem;
class HighScoreManager
{
public:
HighScoreManager(OSystem& osystem);
virtual ~HighScoreManager() = default;
/*
Methods for returning high score related variables
Return -1 if undefined
*/
Int32 numVariations();
Int32 numPlayers();
Int32 variation();
Int32 player();
Int32 score();
private:
Properties& properties(Properties& props) const;
bool parseAddresses(Int32& variation, Int32& player, Int32 scores[]);
private:
// Reference to the osystem object
OSystem& myOSystem;
private:
// Following constructors and assignment operators not supported
HighScoreManager() = delete;
HighScoreManager(const HighScoreManager&) = delete;
HighScoreManager(HighScoreManager&&) = delete;
HighScoreManager& operator=(const HighScoreManager&) = delete;
HighScoreManager& operator=(HighScoreManager&&) = delete;
};
#endif

View File

@ -6,6 +6,7 @@ MODULE_OBJS := \
src/common/FBSurfaceSDL2.o \
src/common/FrameBufferSDL2.o \
src/common/FSNodeZIP.o \
src/common/HighScoreManager.o \
src/common/JoyMap.o \
src/common/KeyMap.o \
src/common/Logger.o \

View File

@ -1145,152 +1145,6 @@ void Console::stateChanged(EventHandlerState state)
// only the CompuMate used to care about state changes
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Console::numVariations()
{
string numVariations = myProperties.get(PropType::Cart_Variations);
return (numVariations == EmptyString) ? 1 : std::min(stoi(numVariations), 256);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Console::numPlayers()
{
string numPlayers = myProperties.get(PropType::Cart_Players);
return (numPlayers == EmptyString) ? 1 : std::min(stoi(numPlayers), 4);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Console::parseAdresses(Int32& variation, Int32& player, Int32 scores[])
{
// Formats (all optional):
// 2, ; score addresses per player
// 1, ; score multiplier
// B, ; score format (BCD, HEX)
// B, ; variation format (BCD, HEX)
// 0, ; add to variation
// Addresses (in hex):
// n*p-times xx, ; score addresses for each player, high to low
// xx, ; variation address (if more than 1 variation)
// xx, ; player address (if more than 1 player)
// TODO:
// - variation bits (Centipede)
// - player bits (Asteroids)
// - score swaps (Asteroids)
string formats = myProperties.get(PropType::Cart_Formats);
string addresses = myProperties.get(PropType::Cart_Addresses);
char scoreFormat;
char varFormat;
Int16 addr;
Int32 varAdd, numScoreAddr, scoreMult;
// Since istringstream swallows whitespace, we have to make the
// delimiters be spaces
std::replace(formats.begin(), formats.end(), ',', ' ');
std::replace(formats.begin(), formats.end(), '|', ' ');
std::replace(addresses.begin(), addresses.end(), ',', ' ');
std::replace(addresses.begin(), addresses.end(), '|', ' ');
istringstream addrBuf(addresses);
istringstream formatBuf(formats);
// 1. retrieve formats
if (!(formatBuf >> numScoreAddr))
numScoreAddr = 2;
if (!(formatBuf >> scoreMult))
scoreMult = 1;
if (!(formatBuf >> scoreFormat))
scoreFormat = 'B';
if (!(formatBuf >> varFormat))
varFormat = 'B';
if (!(formatBuf >> varAdd))
varAdd = 0;
// 2. retrieve current scores for all players
for (int i = 0; i < numPlayers(); ++i)
{
Int32 totalScore = 0;
for (int j = 0; j < numScoreAddr; ++j)
{
Int32 score;
if (!(addrBuf >> std::hex >> addr))
return false;
totalScore *= (scoreFormat == 'B') ? 100 : 256;
score = mySystem->peek(addr);
if (scoreFormat == 'B')
score = (score >> 4) * 10 + score % 16;
totalScore += score;
}
scores[i] = totalScore * scoreMult;
}
variation = 1; player = 0;
// 3. retrieve current variation (0..255)
if (numVariations() == 1)
return true;
if (!(addrBuf >> std::hex >> addr))
return false;
variation = mySystem->peek(addr);
if (varFormat == 'B')
variation = (variation >> 4) * 10 + variation % 16;
variation += varAdd;
variation = std::min(variation, numVariations());
// 4. retrieve current player (0..3)
if (numPlayers() == 1)
return true;
if (!(addrBuf >> std::hex >> addr))
return false;
player = mySystem->peek(addr);
player = std::min(player, numPlayers() - 1);
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Console::variation()
{
Int32 variation, player, scores[4];
if (parseAdresses(variation, player, scores))
return variation;
return -1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Console::player()
{
Int32 variation, player, scores[4];
if (parseAdresses(variation, player, scores))
return player;
return -1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Console::score()
{
Int32 variation, player, scores[4];
if (parseAdresses(variation, player, scores))
return scores[std::min(player, Int32(3))];
return -1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PaletteArray Console::ourNTSCPalette = {
0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0,

View File

@ -326,16 +326,6 @@ class Console : public Serializable, public ConsoleIO
*/
void setTIAProperties();
/*
Methods for returning high score related variables
Return -1 if undefined
*/
Int32 numVariations();
Int32 numPlayers();
Int32 variation();
Int32 player();
Int32 score();
private:
/**
* Define console timing based on current display format
@ -452,8 +442,6 @@ class Console : public Serializable, public ConsoleIO
// The audio settings
AudioSettings& myAudioSettings;
bool parseAdresses(Int32& variation, Int32& player, Int32 scores[]);
// Table of RGB values for NTSC, PAL and SECAM
static PaletteArray ourNTSCPalette;
static PaletteArray ourPALPalette;

View File

@ -25,7 +25,7 @@
regenerated and the application recompiled.
*/
static constexpr uInt32 DEF_PROPS_SIZE = 2994;
static constexpr uInt32 DEF_PROPS_SIZE = 2979;
static constexpr BSPF::array2D<const char*, DEF_PROPS_SIZE, 25> DefProps = {{
{ "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
@ -3007,21 +3007,6 @@ static constexpr BSPF::array2D<const char*, DEF_PROPS_SIZE, 25> DefProps = {{
{ "dca90ea1084a2fdbe300d7178ca1a138", "Imagic, Dennis Koble", "IA3000P", "Trick Shot (1982) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "" },
{ "dca941dab5c6f859b71883b13ade9744", "", "", "Hangman Pac-Man Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dcba0e33aa4aed67630a4b292386f405", "Retroactive", "", "Qb (V2.08) (Half Speed Version) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "" },
{ "dcc2956c7a39fdbf1e861fc5c595da0d", "M Network - INTV - APh Technological Consulting, David Rolfe", "MT5664", "Frogs and Flies (1982) (M Network)", "AKA Frogs 'n' Flies", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dcec46a98f45b193f07239611eb878c2", "", "", "Bars and Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd08e18cfee87a0e7fc19a684b36e124", "Atari - GCC, Kevin Osborn", "CX2689, CX2689P", "Kangaroo (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd0cbe5351551a538414fb9e37fc56e8", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd0de0f61af2a2a4878e377b880a3933", "SOLID Corp. (D. Scott Williamson)", "CX2655-013", "Star Castle 2600 (SolidCorp) [013]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "", "", "", "", "" },
{ "dd10b5ee37fdbf909423f2998a1f3179", "", "", "Space Instigators (V1.9) (21-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd13a16d14100819f79b1ce3a5bf499c", "Thomas Jentzsch", "", "Missile Control - Atari Mouse Hack v1.15 (PAL) (TJ)", "Uses Atari Mouse Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd1422ffd538e2e33b339ebeef4f259d", "Atari, Michael Sierchio", "", "Football Demo (1982) (Atari)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd17711a30ad60109c8beace0d4a76e8", "", "", "Karate (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd1842ba0f3f9d94dccb21eaa0f069b7", "Bit Corporation", "R320", "Defender (32 in 1) (BitCorp) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd45e370aceff765f1e72c619efd4399", "Bit Corporation", "PG201", "Sea Monster (1982) (BitCorp)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd4f4e0fbd81762533e39e6f5b55bb3a", "Thomas Jentzsch", "", "Turbo WIP (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd7598b8bcb81590428900f71b720efb", "Xonox - K-Tel Software - Computer Magic", "99005, 6220, 6250", "Robin Hood (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
{ "dd7884b4f93cab423ac471aa1935e3df", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "", "2", "66", "2,10,b,h,1", "bd,be,c0,c1,80,c7" },
{ "dd8a2124d4eda200df715c698a6ea887", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (3 of 3) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },
}};
#endif

View File

@ -35,6 +35,7 @@
#include "StateManager.hxx"
#include "RewindManager.hxx"
#include "TimerManager.hxx"
#include "HighScoreManager.hxx"
#include "Switches.hxx"
#include "M6532.hxx"
#include "MouseControl.hxx"
@ -721,7 +722,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
if (pressed)
{
ostringstream msg;
msg << "Score: " << myOSystem.console().score();
msg << "Score: " << myOSystem.highScore().score();
myOSystem.frameBuffer().showMessage(msg.str());
}
return;
@ -730,7 +731,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
if (pressed)
{
ostringstream msg;
msg << "Variation: " << myOSystem.console().variation();
msg << "Variation: " << myOSystem.highScore().variation();
myOSystem.frameBuffer().showMessage(msg.str());
}
return;

View File

@ -58,6 +58,7 @@
#include "Random.hxx"
#include "StateManager.hxx"
#include "TimerManager.hxx"
#include "HighScoreManager.hxx"
#include "Version.hxx"
#include "TIA.hxx"
#include "DispatchResult.hxx"
@ -153,6 +154,7 @@ bool OSystem::create()
myStateManager = make_unique<StateManager>(*this);
myTimerManager = make_unique<TimerManager>();
myHighScoreManager = make_unique<HighScoreManager>(*this);
myAudioSettings = make_unique<AudioSettings>(*mySettings);
// Create the sound object; the sound subsystem isn't actually

View File

@ -27,6 +27,7 @@ class Random;
class Sound;
class StateManager;
class TimerManager;
class HighScoreManager;
class EmulationWorker;
class AudioSettings;
#ifdef CHEATCODE_SUPPORT
@ -148,6 +149,13 @@ class OSystem
*/
AudioSettings& audioSettings() { return *myAudioSettings; }
/**
Get the high score manager of the system.
@return The highscore manager object
*/
HighScoreManager& highScore() const { return *myHighScoreManager; }
/**
Get the state manager of the system.
@ -517,6 +525,9 @@ class OSystem
// Pointer to the TimerManager object
unique_ptr<TimerManager> myTimerManager;
// Pointer to the HighScoreManager object
unique_ptr<HighScoreManager> myHighScoreManager;
// Indicates whether ROM launcher was ever opened during this run
bool myLauncherUsed{false};

View File

@ -66,7 +66,7 @@ GameInfoDialog::GameInfoDialog(
StaticTextWidget* t;
// Set real dimensions
setSize(53 * fontWidth + 8,
setSize(HBORDER * 2 + 53 * fontWidth,
8 * (lineHeight + VGAP) + 1 * (infoLineHeight + VGAP) + VBORDER * 2 + _th +
buttonHeight + fontHeight + ifont.getLineHeight() + 20,
max_w, max_h);
@ -78,7 +78,7 @@ GameInfoDialog::GameInfoDialog(
//////////////////////////////////////////////////////////////////////////////
// 1) Emulation properties
tabID = myTab->addTab("Emulation");
tabID = myTab->addTab("Emulation", TabWidget::AUTO_WIDTH);
ypos = VBORDER;
@ -159,7 +159,7 @@ GameInfoDialog::GameInfoDialog(
//////////////////////////////////////////////////////////////////////////////
// 2) Console properties
wid.clear();
tabID = myTab->addTab("Console");
tabID = myTab->addTab(" Console ", TabWidget::AUTO_WIDTH);
xpos = HBORDER; ypos = VBORDER;
lwidth = font.getStringWidth(GUI::RIGHT_DIFFICULTY + " ");
@ -202,7 +202,7 @@ GameInfoDialog::GameInfoDialog(
//////////////////////////////////////////////////////////////////////////////
// 3) Controller properties
wid.clear();
tabID = myTab->addTab("Controllers");
tabID = myTab->addTab("Controllers", TabWidget::AUTO_WIDTH);
ctrls.clear();
VarList::push_back(ctrls, "Auto-detect", "AUTO");
@ -304,7 +304,7 @@ GameInfoDialog::GameInfoDialog(
//////////////////////////////////////////////////////////////////////////////
// 4) Cartridge properties
wid.clear();
tabID = myTab->addTab("Cartridge");
tabID = myTab->addTab("Cartridge", TabWidget::AUTO_WIDTH);
xpos = HBORDER; ypos = VBORDER;
lwidth = font.getStringWidth("Manufacturer ");
@ -348,6 +348,198 @@ GameInfoDialog::GameInfoDialog(
// Add items for tab 3
addToFocusList(wid, myTab, tabID);
//////////////////////////////////////////////////////////////////////////////
// 4) High Scores properties
wid.clear();
tabID = myTab->addTab("High Scores", TabWidget::AUTO_WIDTH);
xpos = HBORDER; ypos = VBORDER;
lwidth = font.getStringWidth("Variations ");
myHighScores = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Enable High Scores", kHiScoresChanged);
xpos += 20; ypos += lineHeight + VGAP;
items.clear();
VarList::push_back(items, "1", "1");
VarList::push_back(items, "2", "2");
VarList::push_back(items, "3", "3");
VarList::push_back(items, "4", "4");
pwidth = font.getStringWidth("4");
myPlayersLabel = new StaticTextWidget(myTab, font, xpos, ypos + 1, lwidth, fontHeight, "Players");
myPlayers = new PopUpWidget(myTab, font, xpos + lwidth, ypos, pwidth, lineHeight, items, "", 0, kPlayersChanged);
wid.push_back(myPlayers);
int awidth = font.getStringWidth("FFFF") + 4;
EditableWidget::TextFilter fAddr = [](char c) {
return (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9');
};
int rwidth = font.getStringWidth("FF") + 4;
myPlayersAddressLabel = new StaticTextWidget(myTab, font, myPlayers->getRight() + 16, ypos + 1, "Address ");
myPlayersAddress = new EditTextWidget(myTab, font, myPlayersAddressLabel->getRight(), ypos - 1, awidth, lineHeight);
myPlayersAddress->setTextFilter(fAddr);
wid.push_back(myPlayersAddress);
myPlayersAddressVal = new EditTextWidget(myTab, font, myPlayersAddress->getRight() + 2, ypos - 1, rwidth, lineHeight, "56");
myPlayersAddressVal->setEditable(false);
ypos += lineHeight + VGAP;
fwidth = font.getStringWidth("255") + 5;
myVariationsLabel = new StaticTextWidget(myTab, font, xpos, ypos + 1, lwidth, fontHeight, "Variations");
myVariations = new EditTextWidget(myTab, font, xpos + lwidth, ypos - 1, fwidth, lineHeight);
wid.push_back(myVariations);
myVarAddressLabel = new StaticTextWidget(myTab, font, myPlayersAddressLabel->getLeft(), ypos + 1, "Address ");
myVarAddress = new EditTextWidget(myTab, font, myVarAddressLabel->getRight(), ypos - 1, awidth, lineHeight);
myVarAddress->setTextFilter(fAddr);
wid.push_back(myVarAddress);
myVarAddressVal = new EditTextWidget(myTab, font, myVarAddress->getRight() + 2, ypos - 1, rwidth, lineHeight, "56");
myVarAddressVal->setEditable(false);
myVarFormat = new CheckboxWidget(myTab, font, myVarAddressVal->getRight() + 16, ypos + 1, "BCD", kVarFormatChanged);
wid.push_back(myVarFormat);
myVarZeroBased = new CheckboxWidget(myTab, font, myVarFormat->getRight() + 16, ypos + 1, "0-based", kVar0BasedChanged);
wid.push_back(myVarZeroBased);
ypos += lineHeight + VGAP;
items.clear();
VarList::push_back(items, "1", "1");
VarList::push_back(items, "2", "2");
VarList::push_back(items, "3", "3");
VarList::push_back(items, "4", "4");
VarList::push_back(items, "5", "5");
VarList::push_back(items, "6", "6");
myScoresLabel = new StaticTextWidget(myTab, font, xpos, ypos + 1, lwidth, fontHeight, "Scores");
xpos += 20; ypos += lineHeight + VGAP;
myScoreDigitsLabel = new StaticTextWidget(myTab, font, xpos, ypos + 1, "Digits ");
myScoreDigits = new PopUpWidget(myTab, font, myScoreDigitsLabel->getRight(), ypos, pwidth, lineHeight,
items, "", 0, kScoreDigitsChanged);
wid.push_back(myScoreDigits);
items.clear();
VarList::push_back(items, "1", "1");
VarList::push_back(items, "10", "10");
VarList::push_back(items, "100", "100");
pwidth = font.getStringWidth("100");
myScoreMultLabel = new StaticTextWidget(myTab, font, myScoreDigits->getRight() + 20, ypos + 1, "Multiplier ");
myScoreMult = new PopUpWidget(myTab, font, myScoreMultLabel->getRight(), ypos, pwidth, lineHeight,
items, "", 0, kScoreMultChanged);
wid.push_back(myScoreMult);
myScoreFormat = new CheckboxWidget(myTab, font, myVarFormat->getLeft(), ypos + 1, "BCD", kScoreFormatChanged);
wid.push_back(myScoreFormat);
ypos += lineHeight + VGAP;
myP1AddressLabel = new StaticTextWidget(myTab, font, xpos, ypos + 1, "P1 Addresses ");
myP1Address0 = new EditTextWidget(myTab, font, myP1AddressLabel->getRight(), ypos - 1, awidth, lineHeight);
myP1Address0->setTextFilter(fAddr);
wid.push_back(myP1Address0);
myP1Address0Val = new EditTextWidget(myTab, font, myP1Address0->getRight() + 2, ypos - 1, rwidth, lineHeight, "12");
myP1Address0Val->setEditable(false);
myP1Address1 = new EditTextWidget(myTab, font, myP1Address0Val->getRight() + 16, ypos - 1, awidth, lineHeight);
myP1Address1->setTextFilter(fAddr);
wid.push_back(myP1Address1);
myP1Address1Val = new EditTextWidget(myTab, font, myP1Address1->getRight() + 2, ypos - 1, rwidth, lineHeight, "34");
myP1Address1Val->setEditable(false);
myP1Address2 = new EditTextWidget(myTab, font, myP1Address1Val->getRight() + 16, ypos - 1, awidth, lineHeight);
myP1Address2->setTextFilter(fAddr);
wid.push_back(myP1Address2);
myP1Address2Val = new EditTextWidget(myTab, font, myP1Address2->getRight() + 2, ypos - 1, rwidth, lineHeight, "56");
myP1Address2Val->setEditable(false);
ypos += lineHeight + VGAP;
myP2AddressLabel = new StaticTextWidget(myTab, font, xpos, ypos + 1, "P2 Addresses ");
myP2Address0 = new EditTextWidget(myTab, font, myP2AddressLabel->getRight(), ypos - 1, awidth, lineHeight);
myP2Address0->setTextFilter(fAddr);
wid.push_back(myP2Address0);
myP2Address0Val = new EditTextWidget(myTab, font, myP2Address0->getRight() + 2, ypos - 1, rwidth, lineHeight, "12");
myP2Address0Val->setEditable(false);
myP2Address1 = new EditTextWidget(myTab, font, myP2Address0Val->getRight() + 16, ypos - 1, awidth, lineHeight);
myP2Address1->setTextFilter(fAddr);
wid.push_back(myP2Address1);
myP2Address1Val = new EditTextWidget(myTab, font, myP2Address1->getRight() + 2, ypos - 1, rwidth, lineHeight, "34");
myP2Address1Val->setEditable(false);
myP2Address2 = new EditTextWidget(myTab, font, myP2Address1Val->getRight() + 16, ypos - 1, awidth, lineHeight);
myP2Address2->setTextFilter(fAddr);
wid.push_back(myP2Address2);
myP2Address2Val = new EditTextWidget(myTab, font, myP2Address2->getRight() + 2, ypos - 1, rwidth, lineHeight, "56");
myP2Address2Val->setEditable(false);
ypos += lineHeight + VGAP;
myP3AddressLabel = new StaticTextWidget(myTab, font, xpos, ypos + 1, "P3 Addresses ");
myP3Address0 = new EditTextWidget(myTab, font, myP3AddressLabel->getRight(), ypos - 1, awidth, lineHeight);
myP3Address0->setTextFilter(fAddr);
wid.push_back(myP3Address0);
myP3Address0Val = new EditTextWidget(myTab, font, myP3Address0->getRight() + 2, ypos - 1, rwidth, lineHeight, "");
myP3Address0Val->setEditable(false);
myP3Address1 = new EditTextWidget(myTab, font, myP3Address0Val->getRight() + 16, ypos - 1, awidth, lineHeight);
myP3Address1->setTextFilter(fAddr);
wid.push_back(myP3Address1);
myP3Address1Val = new EditTextWidget(myTab, font, myP3Address1->getRight() + 2, ypos - 1, rwidth, lineHeight, "");
myP3Address1Val->setEditable(false);
myP3Address2 = new EditTextWidget(myTab, font, myP3Address1Val->getRight() + 16, ypos - 1, awidth, lineHeight);
myP3Address2->setTextFilter(fAddr);
wid.push_back(myP3Address2);
myP3Address2Val = new EditTextWidget(myTab, font, myP3Address2->getRight() + 2, ypos - 1, rwidth, lineHeight, "");
myP3Address2Val->setEditable(false);
ypos += lineHeight + VGAP;
myP4AddressLabel = new StaticTextWidget(myTab, font, xpos, ypos + 1, "P4 Addresses ");
myP4Address0 = new EditTextWidget(myTab, font, myP4AddressLabel->getRight(), ypos - 1, awidth, lineHeight);
myP4Address0->setTextFilter(fAddr);
wid.push_back(myP4Address0);
myP4Address0Val = new EditTextWidget(myTab, font, myP4Address0->getRight() + 2, ypos - 1, rwidth, lineHeight, "");
myP4Address0Val->setEditable(false);
myP4Address1 = new EditTextWidget(myTab, font, myP4Address0Val->getRight() + 16, ypos - 1, awidth, lineHeight);
myP4Address1->setTextFilter(fAddr);
wid.push_back(myP4Address1);
myP4Address1Val = new EditTextWidget(myTab, font, myP4Address1->getRight() + 2, ypos - 1, rwidth, lineHeight, "");
myP4Address1Val->setEditable(false);
myP4Address2 = new EditTextWidget(myTab, font, myP4Address1Val->getRight() + 16, ypos - 1, awidth, lineHeight);
myP4Address2->setTextFilter(fAddr);
wid.push_back(myP4Address2);
myP4Address2Val = new EditTextWidget(myTab, font, myP4Address2->getRight() + 2, ypos - 1, rwidth, lineHeight, "");
myP4Address2Val->setEditable(false);
/*ypos += lineHeight + VGAP;
fwidth = _w - lwidth - HBORDER * 2 - 22;
new StaticTextWidget(myTab, font, xpos, ypos + 1, lwidth, fontHeight, "Formats");
myFormats = new EditTextWidget(myTab, font, xpos + lwidth, ypos - 1,
fwidth, lineHeight);
wid.push_back(myVariations);
ypos += lineHeight + VGAP;
new StaticTextWidget(myTab, font, xpos, ypos + 1, lwidth, fontHeight, "Addresses");
myAddresses = new EditTextWidget(myTab, font, xpos + lwidth, ypos - 1,
fwidth, lineHeight);
wid.push_back(myVariations);*/
// Add items for tab 3
addToFocusList(wid, myTab, tabID);
//////////////////////////////////////////////////////////////////////////////
// Activate the first tab
myTab->setActiveTab(0);
@ -374,6 +566,7 @@ void GameInfoDialog::loadConfig()
loadConsoleProperties(myGameProperties);
loadControllerProperties(myGameProperties);
loadCartridgeProperties(myGameProperties);
loadHighScoresProperties(myGameProperties);
myTab->loadConfig();
}
@ -540,6 +733,20 @@ void GameInfoDialog::loadCartridgeProperties(const Properties& props)
myNote->setText(props.get(PropType::Cart_Note));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GameInfoDialog::loadHighScoresProperties(const Properties& props)
{
//bool enable = instance().hasConsole() && instance().console().par
myHighScores->setState(true);
myPlayers->setSelected(props.get(PropType::Cart_Players));
myVariations->setText(props.get(PropType::Cart_Variations));
handleHighScoresWidgets();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GameInfoDialog::saveConfig()
{
@ -635,6 +842,10 @@ void GameInfoDialog::setDefaults()
loadCartridgeProperties(defaultProperties);
break;
case 4: // High Scores properties
loadHighScoresProperties(defaultProperties);
break;
default: // make the compiler happy
break;
}
@ -745,6 +956,93 @@ void GameInfoDialog::eraseEEPROM()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GameInfoDialog::handleHighScoresWidgets()
{
bool enable = myHighScores->getState();
int players = myPlayers->getSelected() + 1;
bool enablePlayers = enable && players > 1;
bool enableVars = enable && myVariations->getText() > "1";
int numAddr = (myScoreDigits->getSelected() - myScoreMult->getSelected() + 2) / 2;
bool enable1 = enable && numAddr >= 2;
bool enable2 = enable && numAddr >= 3;
myPlayersLabel->setEnabled(enable);
myPlayers->setEnabled(enable);
myPlayersAddressLabel->setEnabled(enablePlayers);
myPlayersAddress->setEnabled(enablePlayers);
myPlayersAddress->setEditable(enablePlayers);
myPlayersAddressVal->setEnabled(enablePlayers);
myVariationsLabel->setEnabled(enable);
myVariations->setEnabled(enable);
myVariations->setEditable(enable);
myVarAddressLabel->setEnabled(enableVars);
myVarAddress->setEnabled(enableVars);
myVarAddress->setEditable(enableVars);
myVarAddressVal->setEnabled(enableVars);
myVarFormat->setEnabled(enableVars);
myVarZeroBased->setEnabled(enableVars);
myScoresLabel->setEnabled(enable);
myScoreDigitsLabel->setEnabled(enable);
myScoreDigits->setEnabled(enable);
myScoreFormat->setEnabled(enable);
myScoreMultLabel->setEnabled(enable);
myScoreMult->setEnabled(enable);
myP1AddressLabel->setEnabled(enable);
myP1Address0->setEnabled(enable);
myP1Address0->setEditable(enable);
myP1Address0Val->setEnabled(enable);
myP1Address1->setEnabled(enable1);
myP1Address1->setEditable(enable1);
myP1Address1Val->setEnabled(enable1);
myP1Address2->setEnabled(enable2);
myP1Address2->setEditable(enable2);
myP1Address2Val->setEnabled(enable2);
enable &= players >= 2;
enable1 &= enable; enable2 &= enable;
myP2AddressLabel->setEnabled(enable);
myP2Address0->setEnabled(enable);
myP2Address0->setEditable(enable);
myP2Address0Val->setEnabled(enable);
myP2Address1->setEnabled(enable1);
myP2Address1->setEditable(enable1);
myP2Address1Val->setEnabled(enable1);
myP2Address2->setEnabled(enable2);
myP2Address2->setEditable(enable2);
myP2Address2Val->setEnabled(enable2);
enable &= players >= 3;
enable1 &= enable; enable2 &= enable;
myP3AddressLabel->setEnabled(enable);
myP3Address0->setEnabled(enable);
myP3Address0->setEditable(enable);
myP3Address0Val->setEnabled(enable);
myP3Address1->setEnabled(enable1);
myP3Address1->setEditable(enable1);
myP3Address1Val->setEnabled(enable1);
myP3Address2->setEnabled(enable2);
myP3Address2->setEditable(enable2);
myP3Address2Val->setEnabled(enable2);
enable &= players >= 4;
enable1 &= enable; enable2 &= enable;
myP4AddressLabel->setEnabled(enable);
myP4Address0->setEnabled(enable);
myP4Address0->setEditable(enable);
myP4Address0Val->setEnabled(enable);
myP4Address1->setEnabled(enable1);
myP4Address1->setEditable(enable1);
myP4Address1->setEditable(enable1);
myP4Address1Val->setEnabled(enable1);
myP4Address2->setEnabled(enable2);
myP4Address2->setEditable(enable2);
myP4Address2Val->setEnabled(enable2);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GameInfoDialog::handleCommand(CommandSender* sender, int cmd,
int data, int id)
@ -812,6 +1110,13 @@ void GameInfoDialog::handleCommand(CommandSender* sender, int cmd,
break;
}
case kHiScoresChanged:
case kPlayersChanged:
case kScoreDigitsChanged:
case kScoreMultChanged:
handleHighScoresWidgets();
break;
default:
Dialog::handleCommand(sender, cmd, data, 0);
break;

View File

@ -53,9 +53,12 @@ class GameInfoDialog : public Dialog, public CommandSender
void loadControllerProperties(const Properties& props);
// load the properties for the 'Cartridge' tab
void loadCartridgeProperties(const Properties& props);
// load the properties for the 'High Scores' tab
void loadHighScoresProperties(const Properties& props);
void updateControllerStates();
void eraseEEPROM();
void handleHighScoresWidgets();
private:
TabWidget* myTab{nullptr};
@ -102,6 +105,57 @@ class GameInfoDialog : public Dialog, public CommandSender
EditTextWidget* myRarity{nullptr};
EditTextWidget* myNote{nullptr};
// High Scores properties
CheckboxWidget* myHighScores{nullptr};
StaticTextWidget* myPlayersLabel{ nullptr };
PopUpWidget* myPlayers{nullptr};
StaticTextWidget* myPlayersAddressLabel{ nullptr };
EditTextWidget* myPlayersAddress{ nullptr };
EditTextWidget* myPlayersAddressVal{ nullptr };
StaticTextWidget* myVariationsLabel{ nullptr };
EditTextWidget* myVariations{nullptr};
StaticTextWidget* myVarAddressLabel{ nullptr };
EditTextWidget* myVarAddress{ nullptr };
EditTextWidget* myVarAddressVal{ nullptr };
CheckboxWidget* myVarFormat{ nullptr };
CheckboxWidget* myVarZeroBased{ nullptr };
StaticTextWidget* myScoresLabel{ nullptr };
StaticTextWidget* myScoreDigitsLabel{ nullptr };
PopUpWidget* myScoreDigits{nullptr};
StaticTextWidget* myScoreMultLabel{ nullptr };
PopUpWidget* myScoreMult{nullptr};
CheckboxWidget* myScoreFormat{nullptr};
StaticTextWidget* myP1AddressLabel{nullptr};
EditTextWidget* myP1Address0{nullptr};
EditTextWidget* myP1Address0Val{ nullptr };
EditTextWidget* myP1Address1{nullptr};
EditTextWidget* myP1Address1Val{ nullptr };
EditTextWidget* myP1Address2{nullptr};
EditTextWidget* myP1Address2Val{ nullptr };
StaticTextWidget* myP2AddressLabel{nullptr};
EditTextWidget* myP2Address0{nullptr};
EditTextWidget* myP2Address0Val{ nullptr };
EditTextWidget* myP2Address1{nullptr};
EditTextWidget* myP2Address1Val{ nullptr };
EditTextWidget* myP2Address2{nullptr};
EditTextWidget* myP2Address2Val{ nullptr };
StaticTextWidget* myP3AddressLabel{nullptr};
EditTextWidget* myP3Address0{nullptr};
EditTextWidget* myP3Address0Val{ nullptr };
EditTextWidget* myP3Address1{nullptr};
EditTextWidget* myP3Address1Val{ nullptr };
EditTextWidget* myP3Address2{nullptr};
EditTextWidget* myP3Address2Val{ nullptr };
StaticTextWidget* myP4AddressLabel{nullptr};
EditTextWidget* myP4Address0{nullptr};
EditTextWidget* myP4Address0Val{ nullptr };
EditTextWidget* myP4Address1{nullptr};
EditTextWidget* myP4Address1Val{ nullptr };
EditTextWidget* myP4Address2{nullptr};
EditTextWidget* myP4Address2Val{ nullptr };
enum {
kVCenterChanged = 'Vcch',
kPhosphorChanged = 'PPch',
@ -110,6 +164,13 @@ class GameInfoDialog : public Dialog, public CommandSender
kRightCChanged = 'RCch',
kMCtrlChanged = 'MCch',
kEEButtonPressed = 'EEgb',
kHiScoresChanged = 'HSch',
kPlayersChanged = 'Plch',
kVar0BasedChanged = 'VZch',
kVarFormatChanged = 'VFch',
kScoreDigitsChanged = 'SDch',
kScoreMultChanged = 'SMch',
kScoreFormatChanged = 'SFch'
};
// Game properties for currently loaded ROM

View File

@ -382,6 +382,7 @@
<ClCompile Include="..\common\FpsMeter.cxx" />
<ClCompile Include="..\common\FrameBufferSDL2.cxx" />
<ClCompile Include="..\common\FSNodeZIP.cxx" />
<ClCompile Include="..\common\HighScoreManager.cxx" />
<ClCompile Include="..\common\JoyMap.cxx" />
<ClCompile Include="..\common\KeyMap.cxx" />
<ClCompile Include="..\common\Logger.cxx" />
@ -1088,6 +1089,7 @@
<ClInclude Include="..\common\FrameBufferSDL2.hxx" />
<ClInclude Include="..\common\FSNodeFactory.hxx" />
<ClInclude Include="..\common\FSNodeZIP.hxx" />
<ClInclude Include="..\common\HighScoreManager.hxx" />
<ClInclude Include="..\common\JoyMap.hxx" />
<ClInclude Include="..\common\KeyMap.hxx" />
<ClInclude Include="..\common\LinkedObjectPool.hxx" />

View File

@ -1005,6 +1005,9 @@
<ClCompile Include="..\gui\MessageDialog.cxx">
<Filter>Source Files\gui</Filter>
</ClCompile>
<ClCompile Include="..\common\HighScoreManager.cxx">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\bspf.hxx">
@ -2054,6 +2057,9 @@
<ClInclude Include="..\gui\MessageDialog.hxx">
<Filter>Header Files\gui</Filter>
</ClInclude>
<ClInclude Include="..\common\HighScoreManager.hxx">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="stella.ico">