Added a save/restore game dialog class

svn-id: r24071
This commit is contained in:
Paul Gilbert 2006-10-02 12:49:57 +00:00
parent 1a96e26bf6
commit 99655b59d4
2 changed files with 248 additions and 15 deletions

View File

@ -25,6 +25,7 @@
#include "lure/system.h"
#include "lure/events.h"
#include "lure/screen.h"
#include "lure/lure.h"
#include "lure/room.h"
#include "lure/strings.h"
#include "common/endian.h"
@ -358,7 +359,7 @@ Surface *Surface::newDialog(uint16 width, uint8 numLines, const char **lines, bo
s->createDialog();
for (uint8 ctr = 0; ctr < numLines; ++ctr)
s->writeString(DIALOG_EDGE_SIZE + 3, DIALOG_EDGE_SIZE + 3 +
s->writeString(DIALOG_EDGE_SIZE + 3, DIALOG_EDGE_SIZE + 2 +
(ctr * (FONT_HEIGHT - 1)), lines[ctr], true, colour, varLength);
return s;
}
@ -387,6 +388,84 @@ Surface *Surface::getScreen(uint16 resourceId) {
return new Surface(decodedData, FULL_SCREEN_WIDTH, decodedData->size() / FULL_SCREEN_WIDTH);
}
bool Surface::getString(Common::String &line, uint32 maxSize, bool isNumeric, bool varLength, int16 x, int16 y) {
OSystem &system = System::getReference();
Mouse &mouse = Mouse::getReference();
Events &events = Events::getReference();
Screen &screen = Screen::getReference();
uint8 bgColour = *(screen.screen().data().data() + (y * FULL_SCREEN_WIDTH) + x);
String newLine(line);
bool abortFlag = false;
bool refreshFlag = false;
mouse.cursorOff();
// Insert a cursor character at the end of the string
newLine.insertChar('_', newLine.size());
while (!abortFlag) {
// Display the string
screen.screen().writeString(x, y, newLine, true, DIALOG_TEXT_COLOUR, varLength);
screen.update();
int stringSize = screen.screen().textWidth(newLine.c_str());
// Loop until the input string changes
refreshFlag = false;
while (!refreshFlag && !abortFlag) {
abortFlag = events.quitFlag;
if (abortFlag) break;
if (events.pollEvent()) {
if (events.type() == OSystem::EVENT_KEYDOWN) {
char ch = events.event().kbd.ascii;
uint16 keycode = events.event().kbd.keycode;
if ((ch == 13) || (keycode == 0x10f)) {
// Return character
screen.screen().fillRect(
Rect(x, y, x + stringSize + 8, y + FONT_HEIGHT), bgColour);
screen.update();
newLine.deleteLastChar();
line = newLine;
mouse.cursorOn();
return true;
}
else if (ch == 27) {
// Escape character
screen.screen().fillRect(
Rect(x, y, x + stringSize + 8, y + FONT_HEIGHT), bgColour);
screen.update();
abortFlag = true;
} else if (ch == 8) {
// Delete the last character
if (newLine.size() == 1) continue;
screen.screen().fillRect(
Rect(x, y, x + stringSize + 8, y + FONT_HEIGHT), bgColour);
newLine.deleteChar(newLine.size() - 2);
refreshFlag = true;
} else if ((ch >= ' ') && (newLine.size() < maxSize)) {
if (((ch >= '0') && (ch <= '9')) || !isNumeric) {
screen.screen().fillRect(
Rect(x, y, x + stringSize + 8, y + FONT_HEIGHT), bgColour);
newLine.insertChar(ch, newLine.size() - 1);
refreshFlag = true;
}
}
}
}
system.updateScreen();
system.delayMillis(10);
}
}
mouse.cursorOn();
return false;
}
/*--------------------------------------------------------------------------*/
void Dialog::show(const char *text) {
@ -520,23 +599,174 @@ TalkDialog::~TalkDialog() {
/*--------------------------------------------------------------------------*/
bool SaveRestoreDialog::show(bool save, Common::String &filename) {
#define SR_SEPARATOR_Y 21
#define SR_SEPARATOR_X 5
#define SR_SEPARATOR_HEIGHT 5
#define SR_SAVEGAME_NAMES_Y (SR_SEPARATOR_Y + SR_SEPARATOR_HEIGHT + 1)
void SaveRestoreDialog::toggleHightlight(int xs, int xe, int ys, int ye) {
Screen &screen = Screen::getReference();
Mouse &mouse = Mouse::getReference();
Room &room = Room::getReference();
mouse.cursorOff();
byte *addr = screen.screen().data().data() + FULL_SCREEN_WIDTH * ys + xs;
room.update();
Surface *s = new Surface(INFO_DIALOG_WIDTH, 100);
s->createDialog();
s->copyToScreen(SAVE_DIALOG_X, SAVE_DIALOG_Y);
// Wait for a keypress or mouse button
Events::getReference().waitForPress();
for (int y = 0; y < ye - ys + 1; ++y, addr += FULL_SCREEN_WIDTH) {
for (int x = 0; x < xe - xs + 1; ++x) {
if (addr[x] == DIALOG_TEXT_COLOUR) addr[x] = DIALOG_WHITE_COLOUR;
else if (addr[x] == DIALOG_WHITE_COLOUR) addr[x] = DIALOG_TEXT_COLOUR;
}
}
screen.update();
mouse.cursorOn();
return false;
}
bool SaveRestoreDialog::show(bool saveDialog) {
OSystem &system = System::getReference();
Screen &screen = Screen::getReference();
Mouse &mouse = Mouse::getReference();
Events &events = Events::getReference();
Room &room = Room::getReference();
Resources &res = Resources::getReference();
LureEngine &engine = LureEngine::getReference();
int selectedLine = -1;
int index;
// Figure out a list of present savegames
String **saveNames = (String **)Memory::alloc(sizeof(String *) * MAX_SAVEGAME_SLOTS);
int numSaves = 0;
while ((numSaves < MAX_SAVEGAME_SLOTS) &&
((saveNames[numSaves] = engine.detectSave(numSaves + 1)) != NULL))
++numSaves;
// For the save dialog, if all the slots have not been used up, create a
// blank entry for a new savegame
if (saveDialog && (numSaves < MAX_SAVEGAME_SLOTS))
saveNames[numSaves++] = new String();
// For the restore dialog, if there are no savegames, return immediately
if (!saveDialog && (numSaves == 0)) {
Memory::dealloc(saveNames);
return false;
}
room.update();
Surface *s = new Surface(INFO_DIALOG_WIDTH, SR_SAVEGAME_NAMES_Y +
numSaves * FONT_HEIGHT + FONT_HEIGHT + 2);
// Create the outer dialog and dividing line
s->createDialog();
byte *pDest = s->data().data() + (s->width() * SR_SEPARATOR_Y) + SR_SEPARATOR_X;
uint8 rowColours[5] = {*(pDest-2), *(pDest-1), *(pDest-1), *(pDest-2), *(pDest+1)};
for (int y = 0; y < SR_SEPARATOR_HEIGHT; ++y, pDest += s->width())
memset(pDest, rowColours[y], s->width() - 12);
// Create title line
Common::String title(res.stringList().getString(
saveDialog ? S_SAVE_GAME : S_RESTORE_GAME));
s->writeString((s->width() - s->textWidth(title.c_str())) / 2, FONT_HEIGHT+2, title, true);
// Write out any existing save names
for (index = 0; index < numSaves; ++index)
s->writeString(DIALOG_EDGE_SIZE, SR_SAVEGAME_NAMES_Y, saveNames[index]->c_str(), true);
// Display the dialog
s->copyTo(&screen.screen(), SAVE_DIALOG_X, SAVE_DIALOG_Y);
screen.update();
mouse.pushCursorNum(CURSOR_ARROW);
bool abortFlag = false;
bool doneFlag = false;
while (!abortFlag && !doneFlag) {
// Provide highlighting of lines to select a save slot
while (!(mouse.lButton() && (selectedLine != -1)) && !mouse.rButton()) {
abortFlag = events.quitFlag;
if (abortFlag) break;
if (events.pollEvent()) {
if ((events.type() == OSystem::EVENT_KEYDOWN) &&
(events.event().kbd.ascii == 27)) {
abortFlag = true;
break;
}
if (events.type() == OSystem::EVENT_MOUSEMOVE) {
// Mouse movement
int lineNum;
if ((mouse.x() < (SAVE_DIALOG_X + DIALOG_EDGE_SIZE)) ||
(mouse.x() >= (SAVE_DIALOG_X + s->width() - DIALOG_EDGE_SIZE)) ||
(mouse.y() < SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y) ||
(mouse.y() >= SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y + numSaves * FONT_HEIGHT))
// Outside displayed lines
lineNum = -1;
else
lineNum = (mouse.y() - (SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y)) / FONT_HEIGHT;
if (lineNum != selectedLine) {
if (selectedLine != -1)
// Deselect previously selected line
toggleHightlight(SAVE_DIALOG_X + DIALOG_EDGE_SIZE,
SAVE_DIALOG_X + s->width() - DIALOG_EDGE_SIZE,
SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y + selectedLine * FONT_HEIGHT,
SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y + (selectedLine + 1) * FONT_HEIGHT - 1);
// Highlight new line
selectedLine = lineNum;
if (selectedLine != -1)
toggleHightlight(SAVE_DIALOG_X + DIALOG_EDGE_SIZE,
SAVE_DIALOG_X + s->width() - DIALOG_EDGE_SIZE,
SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y + selectedLine * FONT_HEIGHT,
SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y + (selectedLine + 1) * FONT_HEIGHT - 1);
}
}
}
system.updateScreen();
system.delayMillis(10);
}
// Deselect selected row
if (selectedLine != -1)
toggleHightlight(SAVE_DIALOG_X + DIALOG_EDGE_SIZE,
SAVE_DIALOG_X + s->width() - DIALOG_EDGE_SIZE,
SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y + selectedLine * FONT_HEIGHT,
SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y + (selectedLine + 1) * FONT_HEIGHT - 1);
if (mouse.lButton() || mouse.rButton()) {
abortFlag = mouse.rButton();
mouse.waitForRelease();
}
if (abortFlag) break;
// If in save mode, allow the entry of a new savename
if (saveDialog) {
if (!screen.screen().getString(*saveNames[selectedLine], 40,
false, true, SAVE_DIALOG_X + DIALOG_EDGE_SIZE,
SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y + selectedLine * FONT_HEIGHT)) {
// Aborted out of name selection, so restore old name and
// go back to slot selection
screen.screen().writeString(
SAVE_DIALOG_X + DIALOG_EDGE_SIZE,
SAVE_DIALOG_Y + SR_SAVEGAME_NAMES_Y + selectedLine * FONT_HEIGHT,
saveNames[selectedLine]->c_str(), true, DIALOG_TEXT_COLOUR, true);
selectedLine = -1;
continue;
}
}
doneFlag = true;
}
if (doneFlag) {
// Handle save or restore
if (saveDialog)
doneFlag = engine.saveGame(selectedLine + 1, *saveNames[selectedLine]);
else
doneFlag = engine.loadGame(selectedLine + 1);
}
mouse.popCursor();
// Free savegame caption list
for (index = 0; index < numSaves; ++index) delete saveNames[index];
Memory::dealloc(saveNames);
return doneFlag;
}
} // end of namespace Lure

View File

@ -70,6 +70,7 @@ public:
static Surface *newDialog(uint16 width, uint8 numLines, const char **lines, bool varLength = true, uint8 colour = DIALOG_TEXT_COLOUR);
static Surface *newDialog(uint16 width, const char *lines, uint8 colour = DIALOG_TEXT_COLOUR);
static Surface *getScreen(uint16 resourceId);
bool getString(Common::String &line, uint32 maxSize, bool isNumeric, bool varLength, int16 x, int16 y);
};
class Dialog {
@ -93,8 +94,10 @@ public:
};
class SaveRestoreDialog {
private:
static void toggleHightlight(int xs, int xe, int ys, int ye);
public:
static bool show(bool save, Common::String &filename);
static bool show(bool saveDialog);
};
} // End of namespace Lure