mirror of https://github.com/stella-emu/stella.git
619 lines
18 KiB
C++
619 lines
18 KiB
C++
//============================================================================
|
|
//
|
|
// 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 "Console.hxx"
|
|
#include "Launcher.hxx"
|
|
#include "EventHandler.hxx"
|
|
#include "Font.hxx"
|
|
#include "PropsSet.hxx"
|
|
#include "FBSurface.hxx"
|
|
#include "EditTextWidget.hxx"
|
|
#include "PopUpWidget.hxx"
|
|
#include "MessageBox.hxx"
|
|
#include "HighScoresManager.hxx"
|
|
|
|
#include "HighScoresDialog.hxx"
|
|
|
|
static constexpr int BUTTON_GFX_W = 10, BUTTON_GFX_H = 10;
|
|
|
|
static constexpr std::array<uInt32, BUTTON_GFX_H> PREV_GFX = {
|
|
0b0000110000,
|
|
0b0000110000,
|
|
0b0001111000,
|
|
0b0001111000,
|
|
0b0011001100,
|
|
0b0011001100,
|
|
0b0110000110,
|
|
0b0110000110,
|
|
0b1100000011,
|
|
0b1100000011,
|
|
};
|
|
|
|
static constexpr std::array<uInt32, BUTTON_GFX_H> NEXT_GFX = {
|
|
0b1100000011,
|
|
0b1100000011,
|
|
0b0110000110,
|
|
0b0110000110,
|
|
0b0011001100,
|
|
0b0011001100,
|
|
0b0001111000,
|
|
0b0001111000,
|
|
0b0000110000,
|
|
0b0000110000,
|
|
};
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
HighScoresDialog::HighScoresDialog(OSystem& osystem, DialogContainer& parent,
|
|
int max_w, int max_h,
|
|
Menu::AppMode mode)
|
|
: Dialog(osystem, parent, osystem.frameBuffer().font(), "High Scores"),
|
|
myDirty(false),
|
|
myHighScoreSaved(false),
|
|
_max_w(max_w),
|
|
_max_h(max_h),
|
|
myVariation(HSM::DEFAULT_VARIATION),
|
|
myInitials(""),
|
|
myMode(mode)
|
|
{
|
|
const GUI::Font& ifont = instance().frameBuffer().infoFont();
|
|
const int lineHeight = _font.getLineHeight(),
|
|
infoLineHeight = ifont.getLineHeight();
|
|
const int VBORDER = 10;
|
|
const int HBORDER = 10;
|
|
const int VGAP = 4;
|
|
|
|
int xpos, ypos;
|
|
WidgetArray wid;
|
|
VariantList items;
|
|
|
|
ypos = VBORDER + _th; xpos = HBORDER;
|
|
ypos += lineHeight + VGAP * 2; // space for game name
|
|
|
|
StaticTextWidget* s = new StaticTextWidget(this, _font, xpos, ypos + 1, "Variation ");
|
|
myVariationPopup = new PopUpWidget(this, _font, s->getRight(), ypos,
|
|
_font.getStringWidth("256") - 4, lineHeight, items, "", 0,
|
|
kVariationChanged);
|
|
wid.push_back(myVariationPopup);
|
|
myPrevVarButton = new ButtonWidget(this, _font, myVariationPopup->getRight() + 157, ypos - 1,
|
|
48, myVariationPopup->getHeight(),
|
|
PREV_GFX.data(), BUTTON_GFX_W, BUTTON_GFX_H, kPrevVariation);
|
|
wid.push_back(myPrevVarButton);
|
|
myNextVarButton = new ButtonWidget(this, _font, myPrevVarButton->getRight() + 8, ypos - 1,
|
|
48, myVariationPopup->getHeight(),
|
|
NEXT_GFX.data(), BUTTON_GFX_W, BUTTON_GFX_H, kNextVariation);
|
|
wid.push_back(myNextVarButton);
|
|
|
|
ypos += lineHeight + VGAP * 4;
|
|
|
|
int xposRank = HBORDER;
|
|
int xposScore = xposRank + _font.getStringWidth("Rank");
|
|
int xposSpecial = xposScore + _font.getStringWidth(" Score") + 16;
|
|
int xposName = xposSpecial + _font.getStringWidth("Round") + 16;
|
|
int xposDate = xposName + _font.getStringWidth("Name") + 16;
|
|
int xposDelete = xposDate + _font.getStringWidth("YY-MM-DD HH:MM") + 16;
|
|
int nWidth = _font.getStringWidth("ABC") + 4;
|
|
|
|
new StaticTextWidget(this, _font, xposRank, ypos + 1, "Rank");
|
|
new StaticTextWidget(this, _font, xposScore, ypos + 1, " Score");
|
|
mySpecialLabelWidget = new StaticTextWidget(this, _font, xposSpecial, ypos + 1, "Round");
|
|
new StaticTextWidget(this, _font, xposName - 2, ypos + 1, "Name");
|
|
new StaticTextWidget(this, _font, xposDate+16, ypos + 1, "Date Time");
|
|
|
|
ypos += lineHeight + VGAP;
|
|
|
|
for (uInt32 r = 0; r < NUM_RANKS; ++r)
|
|
{
|
|
myRankWidgets[r] = new StaticTextWidget(this, _font, xposRank + 8, ypos + 1,
|
|
(r < 9 ? " " : "") + std::to_string(r + 1));
|
|
myScoreWidgets[r] = new StaticTextWidget(this, _font, xposScore, ypos + 1, "12345678");
|
|
mySpecialWidgets[r] = new StaticTextWidget(this, _font, xposSpecial + 8, ypos + 1, "123");
|
|
myNameWidgets[r] = new StaticTextWidget(this, _font, xposName + 2, ypos + 1, " ");
|
|
myEditNameWidgets[r] = new EditTextWidget(this, _font, xposName, ypos - 1, nWidth, lineHeight);
|
|
myEditNameWidgets[r]->setFlags(EditTextWidget::FLAG_INVISIBLE);
|
|
myEditNameWidgets[r]->setEnabled(false);
|
|
wid.push_back(myEditNameWidgets[r]);
|
|
myDateWidgets[r] = new StaticTextWidget(this, _font, xposDate, ypos + 1, "YY-MM-DD HH:MM");
|
|
myDeleteButtons[r] = new ButtonWidget(this, _font, xposDelete, ypos + 1, 18, 18, "X",
|
|
kDeleteSingle);
|
|
myDeleteButtons[r]->setID(r);
|
|
wid.push_back(myDeleteButtons[r]);
|
|
|
|
ypos += lineHeight + VGAP;
|
|
}
|
|
ypos += VGAP;
|
|
|
|
_w = myDeleteButtons[0]->getRight() + HBORDER;
|
|
myNotesWidget = new StaticTextWidget(this, ifont, xpos, ypos + 1, _w - HBORDER * 2,
|
|
infoLineHeight, "Note: ");
|
|
|
|
ypos += infoLineHeight + VGAP;
|
|
|
|
myMD5Widget = new StaticTextWidget(this, ifont, xpos, ypos + 1,
|
|
"MD5: 12345678901234567890123456789012");
|
|
|
|
_h = myMD5Widget->getBottom() + VBORDER + buttonHeight(_font) + VBORDER;
|
|
|
|
myGameNameWidget = new StaticTextWidget(this, _font, HBORDER, VBORDER + _th + 1,
|
|
_w - HBORDER * 2, lineHeight);
|
|
|
|
addDefaultsOKCancelBGroup(wid, _font, "Save", "Cancel", " Reset ");
|
|
addToFocusList(wid);
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
HighScoresDialog::~HighScoresDialog()
|
|
{
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void HighScoresDialog::loadConfig()
|
|
{
|
|
// Enable blending (only once is necessary)
|
|
if (myMode == Menu::AppMode::emulator && !surface().attributes().blending)
|
|
{
|
|
surface().attributes().blending = true;
|
|
surface().attributes().blendalpha = 90;
|
|
surface().applyAttributes();
|
|
}
|
|
|
|
VariantList items;
|
|
|
|
// fill drown down with all variation numbers of current game
|
|
items.clear();
|
|
for (Int32 i = 1; i <= instance().highScores().numVariations(); ++i)
|
|
{
|
|
ostringstream buf;
|
|
buf << std::setw(3) << std::setfill(' ') << i;
|
|
VarList::push_back(items, buf.str(), i);
|
|
}
|
|
myVariationPopup->addItems(items);
|
|
|
|
Int32 variation;
|
|
if(instance().highScores().numVariations() == 1)
|
|
variation = HSM::DEFAULT_VARIATION;
|
|
else
|
|
variation = instance().highScores().variation();
|
|
if(variation != HSM::NO_VALUE)
|
|
{
|
|
myVariationPopup->setSelected(variation);
|
|
myUserDefVar = false;
|
|
}
|
|
else
|
|
{
|
|
// use last selected variation
|
|
myVariationPopup->setSelected(myVariation);
|
|
myUserDefVar = true;
|
|
}
|
|
|
|
myVariationPopup->setEnabled(instance().highScores().numVariations() > 1);
|
|
|
|
if(myInitials.empty())
|
|
// load initials from last session
|
|
myInitials = instance().settings().getString("initials");
|
|
|
|
string label = " " + instance().highScores().specialLabel();
|
|
if (label.length() > 5)
|
|
label = label.substr(label.length() - 5);
|
|
mySpecialLabelWidget->setLabel(label);
|
|
|
|
if(!instance().highScores().notes().empty())
|
|
myNotesWidget->setLabel("Note: " + instance().highScores().notes());
|
|
else
|
|
myNotesWidget->setLabel("");
|
|
|
|
if (instance().hasConsole())
|
|
myMD5 = instance().console().properties().get(PropType::Cart_MD5);
|
|
else
|
|
myMD5 = instance().launcher().selectedRomMD5();
|
|
|
|
myMD5Widget->setLabel("MD5: " + myMD5);
|
|
|
|
// requires the current MD5
|
|
myGameNameWidget->setLabel(cartName());
|
|
|
|
myEditRank = myHighScoreRank = -1;
|
|
myNow = now();
|
|
myDirty = myHighScoreSaved = false;
|
|
handleVariation(true);
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void HighScoresDialog::saveConfig()
|
|
{
|
|
// save initials and remember for the next time
|
|
if (myHighScoreRank != -1)
|
|
{
|
|
myInitials = myEditNameWidgets[myHighScoreRank]->getText();
|
|
myNames[myHighScoreRank] = myInitials;
|
|
// remember initials for next session
|
|
instance().settings().setValue("initials", myInitials);
|
|
}
|
|
// save selected variation
|
|
saveHighScores(myVariation);
|
|
if(myVariation == instance().highScores().variation() || myUserDefVar)
|
|
myHighScoreSaved = true;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void HighScoresDialog::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case kOKCmd:
|
|
saveConfig();
|
|
[[fallthrough]];
|
|
case kCloseCmd:
|
|
if(myMode != Menu::AppMode::emulator)
|
|
close();
|
|
else
|
|
instance().eventHandler().leaveMenuMode();
|
|
break;
|
|
|
|
case kVariationChanged:
|
|
handleVariation();
|
|
break;
|
|
case kPrevVariation:
|
|
myVariationPopup->setSelected(myVariation - 1);
|
|
handleVariation();
|
|
break;
|
|
|
|
case kNextVariation:
|
|
myVariationPopup->setSelected(myVariation + 1);
|
|
handleVariation();
|
|
break;
|
|
|
|
case kDeleteSingle:
|
|
deleteRank(id);
|
|
updateWidgets();
|
|
break;
|
|
|
|
case GuiObject::kDefaultsCmd: // "Reset" button
|
|
for (int r = NUM_RANKS - 1; r >= 0; --r)
|
|
deleteRank(r);
|
|
updateWidgets();
|
|
break;
|
|
|
|
case kConfirmSave:
|
|
saveConfig();
|
|
[[fallthrough]];
|
|
case kCancelSave:
|
|
myDirty = false;
|
|
handleVariation();
|
|
break;
|
|
|
|
default:
|
|
Dialog::handleCommand(sender, cmd, data, 0);
|
|
}
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void HighScoresDialog::handleVariation(bool init)
|
|
{
|
|
if (handleDirty())
|
|
{
|
|
myVariation = myVariationPopup->getSelectedTag().toInt();
|
|
|
|
loadHighScores(myVariation);
|
|
|
|
myEditRank = -1;
|
|
|
|
if (myVariation == instance().highScores().variation() || myUserDefVar)
|
|
handlePlayedVariation();
|
|
|
|
updateWidgets(init);
|
|
}
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void HighScoresDialog::updateWidgets(bool init)
|
|
{
|
|
myPrevVarButton->setEnabled(myVariation > 1);
|
|
myNextVarButton->setEnabled(myVariation < instance().highScores().numVariations());
|
|
|
|
for (uInt32 r = 0; r < NUM_RANKS; ++r)
|
|
{
|
|
ostringstream buf;
|
|
|
|
if (myHighScores[r] > 0)
|
|
{
|
|
myRankWidgets[r]->clearFlags(Widget::FLAG_INVISIBLE);
|
|
myDeleteButtons[r]->clearFlags(Widget::FLAG_INVISIBLE);
|
|
myDeleteButtons[r]->setEnabled(true);
|
|
}
|
|
else
|
|
{
|
|
myRankWidgets[r]->setFlags(Widget::FLAG_INVISIBLE);
|
|
myDeleteButtons[r]->setFlags(Widget::FLAG_INVISIBLE);
|
|
myDeleteButtons[r]->setEnabled(false);
|
|
}
|
|
myScoreWidgets[r]->setLabel(instance().highScores().formattedScore(myHighScores[r],
|
|
HSM::MAX_SCORE_DIGITS));
|
|
|
|
if (mySpecials[r] > 0)
|
|
buf << std::setw(HSM::MAX_SPECIAL_DIGITS) << std::setfill(' ') << mySpecials[r];
|
|
mySpecialWidgets[r]->setLabel(buf.str());
|
|
|
|
myNameWidgets[r]->setLabel(myNames[r]);
|
|
myDateWidgets[r]->setLabel(myDates[r]);
|
|
|
|
if (static_cast<Int32>(r) == myEditRank)
|
|
{
|
|
myNameWidgets[r]->setFlags(EditTextWidget::FLAG_INVISIBLE);
|
|
myEditNameWidgets[r]->clearFlags(EditTextWidget::FLAG_INVISIBLE);
|
|
myEditNameWidgets[r]->setEnabled(true);
|
|
myEditNameWidgets[r]->setEditable(true);
|
|
if (init)
|
|
myEditNameWidgets[r]->setText(myInitials);
|
|
}
|
|
else
|
|
{
|
|
myNameWidgets[r]->clearFlags(EditTextWidget::FLAG_INVISIBLE);
|
|
myEditNameWidgets[r]->setFlags(EditTextWidget::FLAG_INVISIBLE);
|
|
myEditNameWidgets[r]->setEnabled(false);
|
|
myEditNameWidgets[r]->setEditable(false);
|
|
}
|
|
}
|
|
_defaultWidget->setEnabled(myHighScores[0] > 0);
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void HighScoresDialog::handlePlayedVariation()
|
|
{
|
|
Int32 newScore = instance().highScores().score();
|
|
|
|
if (!myHighScoreSaved && newScore > 0)
|
|
{
|
|
Int32 newSpecial = instance().highScores().special();
|
|
bool scoreInvert = instance().highScores().scoreInvert();
|
|
|
|
for (myHighScoreRank = 0; myHighScoreRank < static_cast<Int32>(NUM_RANKS); ++myHighScoreRank)
|
|
{
|
|
if ((!scoreInvert && newScore > myHighScores[myHighScoreRank]) ||
|
|
((scoreInvert && newScore < myHighScores[myHighScoreRank]) || myHighScores[myHighScoreRank] == 0))
|
|
break;
|
|
if (newScore == myHighScores[myHighScoreRank] && newSpecial > mySpecials[myHighScoreRank])
|
|
break;
|
|
}
|
|
|
|
if (myHighScoreRank < static_cast<Int32>(NUM_RANKS))
|
|
{
|
|
myEditRank = myHighScoreRank;
|
|
for (uInt32 r = NUM_RANKS - 1; static_cast<Int32>(r) > myHighScoreRank; --r)
|
|
{
|
|
myHighScores[r] = myHighScores[r - 1];
|
|
mySpecials[r] = mySpecials[r - 1];
|
|
myNames[r] = myNames[r - 1];
|
|
myDates[r] = myDates[r - 1];
|
|
}
|
|
myHighScores[myHighScoreRank] = newScore;
|
|
mySpecials[myHighScoreRank] = newSpecial;
|
|
myDates[myHighScoreRank] = myNow;
|
|
myDirty |= !myUserDefVar; // only ask when the variation was read by defintion
|
|
}
|
|
else
|
|
myHighScoreRank = -1;
|
|
}
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void HighScoresDialog::deleteRank(int rank)
|
|
{
|
|
for (uInt32 r = rank; r < NUM_RANKS - 1; ++r)
|
|
{
|
|
myHighScores[r] = myHighScores[r + 1];
|
|
mySpecials[r] = mySpecials[r + 1];
|
|
myNames[r] = myNames[r + 1];
|
|
myDates[r] = myDates[r + 1];
|
|
}
|
|
myHighScores[NUM_RANKS - 1] = 0;
|
|
mySpecials[NUM_RANKS - 1] = 0;
|
|
myNames[NUM_RANKS - 1] = "";
|
|
myDates[NUM_RANKS - 1] = "";
|
|
|
|
if (myEditRank == rank)
|
|
{
|
|
myHighScoreRank = myEditRank = -1;
|
|
}
|
|
if (myEditRank > rank)
|
|
{
|
|
myHighScoreRank--;
|
|
myEditRank--;
|
|
myEditNameWidgets[myEditRank]->setText(myEditNameWidgets[myEditRank + 1]->getText());
|
|
}
|
|
myDirty = true;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
bool HighScoresDialog::handleDirty()
|
|
{
|
|
if (myDirty)
|
|
{
|
|
if (!myConfirmMsg)
|
|
{
|
|
StringList msg;
|
|
|
|
msg.push_back("Do you want to save the changes");
|
|
msg.push_back("for this variation?");
|
|
msg.push_back("");
|
|
myConfirmMsg = make_unique<GUI::MessageBox>
|
|
(this, _font, msg, _max_w, _max_h, kConfirmSave, kCancelSave,
|
|
"Yes", "No", "Save High Scores", false);
|
|
}
|
|
myConfirmMsg->show();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
string HighScoresDialog::cartName() const
|
|
{
|
|
if(instance().hasConsole())
|
|
return instance().console().properties().get(PropType::Cart_Name);
|
|
else
|
|
{
|
|
Properties props;
|
|
|
|
instance().propSet().getMD5(myMD5, props);
|
|
if(props.get(PropType::Cart_Name).empty())
|
|
return instance().launcher().currentNode().getNameWithExt("");
|
|
else
|
|
return props.get(PropType::Cart_Name);
|
|
}
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void HighScoresDialog::saveHighScores(Int32 variation) const
|
|
{
|
|
ostringstream buf;
|
|
|
|
buf << instance().stateDir() << cartName() << ".hs" << variation;
|
|
|
|
// Make sure the file can be opened for writing
|
|
Serializer out(buf.str());
|
|
|
|
if(!out)
|
|
{
|
|
buf.str("");
|
|
buf << "Can't open/save to high scores file for variation " << variation;
|
|
instance().frameBuffer().showMessage(buf.str());
|
|
}
|
|
|
|
// Do a complete high scores save
|
|
if(!save(out, variation))
|
|
{
|
|
buf.str("");
|
|
buf << "Error saving high scores for variation" << variation;
|
|
instance().frameBuffer().showMessage(buf.str());
|
|
}
|
|
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void HighScoresDialog::loadHighScores(Int32 variation)
|
|
{
|
|
for (uInt32 r = 0; r < NUM_RANKS; ++r)
|
|
{
|
|
myHighScores[r] = 0;
|
|
mySpecials[r] = 0;
|
|
myNames[r] = "";
|
|
myDates[r] = "";
|
|
}
|
|
|
|
ostringstream buf;
|
|
|
|
buf << instance().stateDir() << cartName() << ".hs" << variation;
|
|
|
|
// Make sure the file can be opened in read-only mode
|
|
Serializer in(buf.str(), Serializer::Mode::ReadOnly);
|
|
|
|
if(!in)
|
|
return;
|
|
|
|
// First test if we have a valid header
|
|
// If so, do a complete high scores load
|
|
buf.str("");
|
|
try
|
|
{
|
|
if (in.getString() != HIGHSCORE_HEADER)
|
|
buf << "Incompatible high scores for variation " << variation << " file";
|
|
else
|
|
{
|
|
if (load(in, variation))
|
|
return;
|
|
else
|
|
buf << "Invalid data in high scores for variation " << variation << " file";
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
buf << "Invalid data in high scores for variation " << variation << " file";
|
|
}
|
|
|
|
instance().frameBuffer().showMessage(buf.str());
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
bool HighScoresDialog::save(Serializer& out, Int32 variation) const
|
|
{
|
|
try
|
|
{
|
|
// 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
|
|
out.putString(HIGHSCORE_HEADER);
|
|
|
|
out.putString(myMD5);
|
|
out.putInt(variation);
|
|
for (uInt32 r = 0; r < NUM_RANKS; ++r)
|
|
{
|
|
out.putInt(myHighScores[r]);
|
|
out.putInt(mySpecials[r]);
|
|
out.putString(myNames[r]);
|
|
out.putString(myDates[r]);
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
cerr << "ERROR: HighScoresDialog::save() exception\n";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
bool HighScoresDialog::load(Serializer& in, Int32 variation)
|
|
{
|
|
try
|
|
{
|
|
if (in.getString() != myMD5)
|
|
return false;
|
|
if (Int32(in.getInt()) != variation)
|
|
return false;
|
|
|
|
for (uInt32 r = 0; r < NUM_RANKS; ++r)
|
|
{
|
|
myHighScores[r] = in.getInt();
|
|
mySpecials[r] = in.getInt();
|
|
myNames[r] = in.getString();
|
|
myDates[r] = in.getString();
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
cerr << "ERROR: HighScoresDialog::load() exception\n";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
string HighScoresDialog::now() const
|
|
{
|
|
std::tm now = BSPF::localTime();
|
|
ostringstream ss;
|
|
|
|
ss << std::setfill('0') << std::right
|
|
<< std::setw(2) << (now.tm_year - 100) << '-'
|
|
<< std::setw(2) << (now.tm_mon + 1) << '-'
|
|
<< std::setw(2) << now.tm_mday << " "
|
|
<< std::setw(2) << now.tm_hour << ":"
|
|
<< std::setw(2) << now.tm_min;
|
|
|
|
return ss.str();
|
|
}
|