diff options
Diffstat (limited to 'engines/sword1/control.cpp')
-rw-r--r-- | engines/sword1/control.cpp | 1301 |
1 files changed, 1301 insertions, 0 deletions
diff --git a/engines/sword1/control.cpp b/engines/sword1/control.cpp new file mode 100644 index 0000000000..bf101e9638 --- /dev/null +++ b/engines/sword1/control.cpp @@ -0,0 +1,1301 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2003-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "common/file.h" +#include "common/util.h" +#include "common/savefile.h" +#include "common/system.h" + +#include "gui/message.h" + +#include "sword1/control.h" +#include "sword1/logic.h" +#include "sword1/mouse.h" +#include "sword1/music.h" +#include "sword1/objectman.h" +#include "sword1/resman.h" +#include "sword1/sound.h" +#include "sword1/sword1.h" +#include "sword1/sworddefs.h" +#include "sword1/swordres.h" + +namespace Sword1 { + +enum { + kKeyRepeatInitialDelay = 400, + kKeyRepeatSustainDelay = 100 +}; + +enum LangStrings { + STR_PAUSED = 0, + STR_INSERT_CD_A, + STR_INSERT_CD_B, + STR_INCORRECT_CD, + STR_SAVE, + STR_RESTORE, + STR_RESTART, + STR_START, + STR_QUIT, + STR_SPEED, + STR_VOLUME, + STR_TEXT, + STR_DONE, + STR_OK, + STR_CANCEL, + STR_MUSIC, + STR_SPEECH, + STR_FX, + STR_THE_END, + STR_DRIVE_FULL +}; + +enum ButtonIds { + BUTTON_DONE = 1, + BUTTON_MAIN_PANEL, + BUTTON_SAVE_PANEL, + BUTTON_RESTORE_PANEL, + BUTTON_RESTART, + BUTTON_QUIT, + BUTTON_SPEED, + BUTTON_VOLUME_PANEL, + BUTTON_TEXT, + BUTTON_CONFIRM, +//- + BUTTON_SCROLL_UP_FAST, + BUTTON_SCROLL_UP_SLOW, + BUTTON_SCROLL_DOWN_SLOW, + BUTTON_SCROLL_DOWN_FAST, + BUTTON_SAVE_SELECT1, + BUTTON_SAVE_SELECT2, + BUTTON_SAVE_SELECT3, + BUTTON_SAVE_SELECT4, + BUTTON_SAVE_SELECT5, + BUTTON_SAVE_SELECT6, + BUTTON_SAVE_SELECT7, + BUTTON_SAVE_SELECT8, + BUTTON_SAVE_RESTORE_OKAY, + BUTTON_SAVE_CANCEL, +//- + CONFIRM_OKAY, + CONFIRM_CANCEL +}; + +enum TextModes { + TEXT_LEFT_ALIGN = 0, + TEXT_CENTER, + TEXT_RIGHT_ALIGN, + TEXT_RED_FONT = 128 +}; + +ControlButton::ControlButton(uint16 x, uint16 y, uint32 resId, uint8 id, uint8 flag, ResMan *pResMan, uint8 *screenBuf, OSystem *system) { + _x = x; + _y = y; + _id = id; + _flag = flag; + _resId = resId; + _resMan = pResMan; + _frameIdx = 0; + _resMan->resOpen(_resId); + FrameHeader *tmp = _resMan->fetchFrame(_resMan->fetchRes(_resId), 0); + _width = FROM_LE_16(tmp->width); + _height = FROM_LE_16(tmp->height); + if ((x == 0) && (y == 0)) { // center the frame (used for panels); + _x = (640 - _width) / 2; + _y = (480 - _height) / 2; + } + _dstBuf = screenBuf + _y * SCREEN_WIDTH + _x; + _system = system; +} + +ControlButton::~ControlButton(void) { + _resMan->resClose(_resId); +} + +bool ControlButton::isSaveslot(void) { + return ((_resId >= SR_SLAB1) && (_resId <= SR_SLAB4)); +} + +void ControlButton::draw(void) { + FrameHeader *fHead = _resMan->fetchFrame(_resMan->fetchRes(_resId), _frameIdx); + uint8 *src = (uint8*)fHead + sizeof(FrameHeader); + uint8 *dst = _dstBuf; + for (uint16 cnt = 0; cnt < FROM_LE_16(fHead->height); cnt++) { + for (uint16 cntx = 0; cntx < FROM_LE_16(fHead->width); cntx++) + if (src[cntx]) + dst[cntx] = src[cntx]; + dst += SCREEN_WIDTH; + src += FROM_LE_16(fHead->width); + } + _system->copyRectToScreen(_dstBuf, SCREEN_WIDTH, _x, _y, _width, _height); +} + +bool ControlButton::wasClicked(uint16 mouseX, uint16 mouseY) { + if ((_x <= mouseX) && (_y <= mouseY) && (_x + _width >= mouseX) && (_y + _height >= mouseY)) + return true; + else + return false; +} + +void ControlButton::setSelected(uint8 selected) { + _frameIdx = selected; + draw(); +} + +Control::Control(Common::SaveFileManager *saveFileMan, ResMan *pResMan, ObjectMan *pObjMan, OSystem *system, Mouse *pMouse, Sound *pSound, Music *pMusic) { + _saveFileMan = saveFileMan; + _resMan = pResMan; + _objMan = pObjMan; + _system = system; + _mouse = pMouse; + _music = pMusic; + _sound = pSound; + _lStrings = _languageStrings + SwordEngine::_systemVars.language * 20; + _keyRepeat = 0; + _keyRepeatTime = 0; +} + +void Control::askForCd(void) { + _screenBuf = (uint8*)malloc(640 * 480); + uint32 fontId = SR_FONT; + if (SwordEngine::_systemVars.language == BS1_CZECH) + fontId = CZECH_SR_FONT; + _font = (uint8*)_resMan->openFetchRes(fontId); + uint8 *pal = (uint8*)_resMan->openFetchRes(SR_PALETTE); + uint8 *palOut = (uint8*)malloc(256 * 4); + for (uint16 cnt = 1; cnt < 256; cnt++) { + palOut[cnt * 4 + 0] = pal[cnt * 3 + 0] << 2; + palOut[cnt * 4 + 1] = pal[cnt * 3 + 1] << 2; + palOut[cnt * 4 + 2] = pal[cnt * 3 + 2] << 2; + } + palOut[0] = palOut[1] = palOut[2] = palOut[3] = 0; + _resMan->resClose(SR_PALETTE); + _system->setPalette(palOut, 0, 256); + free(palOut); + + Common::File test; + char fName[10]; + uint8 textA[50]; + sprintf(fName, "cd%d.id", SwordEngine::_systemVars.currentCD); + sprintf((char*)textA, "%s%d", _lStrings[STR_INSERT_CD_A], SwordEngine::_systemVars.currentCD); + bool notAccepted = true; + bool refreshText = true; + do { + if (refreshText) { + memset(_screenBuf, 0, 640 * 480); + renderText(textA, 320, 220, TEXT_CENTER); + renderText(_lStrings[STR_INSERT_CD_B], 320, 240, TEXT_CENTER); + _system->copyRectToScreen(_screenBuf, 640, 0, 0, 640, 480); + _system->updateScreen(); + } + delay(300); + if (_keyPressed) { + test.open(fName); + if (!test.isOpen()) { + memset(_screenBuf, 0, 640 * 480); + renderText(_lStrings[STR_INCORRECT_CD], 320, 230, TEXT_CENTER); + _system->copyRectToScreen(_screenBuf, 640, 0, 0, 640, 480); + _system->updateScreen(); + delay(2000); + refreshText = true; + } else { + test.close(); + notAccepted = false; + } + } + } while (notAccepted && (!SwordEngine::_systemVars.engineQuit)); + + _resMan->resClose(fontId); + free(_screenBuf); +} + +uint8 Control::runPanel(void) { + _mouseDown = false; + _restoreBuf = NULL; + _keyPressed = _numButtons = 0; + _screenBuf = (uint8*)malloc(640 * 480); + memset(_screenBuf, 0, 640 * 480); + _system->copyRectToScreen(_screenBuf, 640, 0, 0, 640, 480); + _sound->quitScreen(); + + uint32 fontId = SR_FONT, redFontId = SR_REDFONT; + if (SwordEngine::_systemVars.language == BS1_CZECH) { + fontId = CZECH_SR_FONT; + redFontId = CZECH_SR_REDFONT; + } + _font = (uint8*)_resMan->openFetchRes(fontId); + _redFont = (uint8*)_resMan->openFetchRes(redFontId); + + uint8 *pal = (uint8*)_resMan->openFetchRes(SR_PALETTE); + uint8 *palOut = (uint8*)malloc(256 * 4); + for (uint16 cnt = 1; cnt < 256; cnt++) { + palOut[cnt * 4 + 0] = pal[cnt * 3 + 0] << 2; + palOut[cnt * 4 + 1] = pal[cnt * 3 + 1] << 2; + palOut[cnt * 4 + 2] = pal[cnt * 3 + 2] << 2; + } + palOut[0] = palOut[1] = palOut[2] = palOut[3] = 0; + _resMan->resClose(SR_PALETTE); + _system->setPalette(palOut, 0, 256); + free(palOut); + uint8 mode = 0, newMode = BUTTON_MAIN_PANEL; + bool fullRefresh = false; + _mouse->controlPanel(true); + uint8 retVal = CONTROL_NOTHING_DONE; + _music->startMusic(61, 1); + + do { + if (newMode) { + mode = newMode; + fullRefresh = true; + destroyButtons(); + memset(_screenBuf, 0, 640 * 480); + if (mode != BUTTON_SAVE_PANEL) + _cursorVisible = false; + } + switch (mode) { + case BUTTON_MAIN_PANEL: + if (fullRefresh) + setupMainPanel(); + break; + case BUTTON_SAVE_PANEL: + if (fullRefresh) { + setupSaveRestorePanel(true); + } + if (_selectedSavegame < 255) { + _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); + bool visible = _cursorVisible; + _cursorTick++; + if (_cursorTick == 7) + _cursorVisible = true; + else if (_cursorTick == 14) { + _cursorVisible = false; + _cursorTick = 0; + } + if (_keyPressed) + handleSaveKey(_keyPressed); + else if (_cursorVisible != visible) + showSavegameNames(); + } else { + _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); + } + break; + case BUTTON_RESTORE_PANEL: + if (fullRefresh) + setupSaveRestorePanel(false); + break; + case BUTTON_VOLUME_PANEL: + if (fullRefresh) + setupVolumePanel(); + break; + default: + break; + } + if (fullRefresh) { + fullRefresh = false; + _system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, 480); + } + _system->updateScreen(); + delay(1000 / 12); + newMode = getClicks(mode, &retVal); + } while ((newMode != BUTTON_DONE) && (retVal == 0) && (!SwordEngine::_systemVars.engineQuit)); + destroyButtons(); + _resMan->resClose(fontId); + _resMan->resClose(redFontId); + memset(_screenBuf, 0, 640 * 480); + _system->copyRectToScreen(_screenBuf, 640, 0, 0, 640, 480); + free(_screenBuf); + _mouse->controlPanel(false); + _music->startMusic(Logic::_scriptVars[CURRENT_MUSIC], 1); + return retVal; +} + +uint8 Control::getClicks(uint8 mode, uint8 *retVal) { + uint8 checkButtons = _numButtons; + if (mode == BUTTON_VOLUME_PANEL) { + handleVolumeClicks(); + checkButtons = 1; + } + + uint8 flag = 0; + if (_keyPressed == 27) + flag = kButtonCancel; + else if (_keyPressed == '\r' || _keyPressed == '\n') + flag = kButtonOk; + + if (flag) { + for (uint8 cnt = 0; cnt < checkButtons; cnt++) + if (_buttons[cnt]->_flag == flag) + return handleButtonClick(_buttons[cnt]->_id, mode, retVal); + } + + if (!_mouseState) + return 0; + if (_mouseState & BS1L_BUTTON_DOWN) + for (uint8 cnt = 0; cnt < checkButtons; cnt++) + if (_buttons[cnt]->wasClicked(_mouseX, _mouseY)) { + _selectedButton = cnt; + _buttons[cnt]->setSelected(1); + if (_buttons[cnt]->isSaveslot()) + showSavegameNames(); + } + if (_mouseState & BS1L_BUTTON_UP) { + for (uint8 cnt = 0; cnt < checkButtons; cnt++) + if (_buttons[cnt]->wasClicked(_mouseX, _mouseY)) + if (_selectedButton == cnt) { + // saveslots stay selected after clicking + if (!_buttons[cnt]->isSaveslot()) + _buttons[cnt]->setSelected(0); + _selectedButton = 255; + return handleButtonClick(_buttons[cnt]->_id, mode, retVal); + } + if (_selectedButton < checkButtons) { + _buttons[_selectedButton]->setSelected(0); + if (_buttons[_selectedButton]->isSaveslot()) + showSavegameNames(); + } + _selectedButton = 255; + } + if (_mouseState & BS1_WHEEL_UP) { + for (uint8 cnt = 0; cnt < checkButtons; cnt++) + if (_buttons[cnt]->_id == BUTTON_SCROLL_UP_SLOW) + return handleButtonClick(_buttons[cnt]->_id, mode, retVal); + } + if (_mouseState & BS1_WHEEL_DOWN) { + for (uint8 cnt = 0; cnt < checkButtons; cnt++) + if (_buttons[cnt]->_id == BUTTON_SCROLL_DOWN_SLOW) + return handleButtonClick(_buttons[cnt]->_id, mode, retVal); + } + return 0; +} + +uint8 Control::handleButtonClick(uint8 id, uint8 mode, uint8 *retVal) { + switch (mode) { + case BUTTON_MAIN_PANEL: + if (id == BUTTON_RESTART) { + if (SwordEngine::_systemVars.controlPanelMode) // if player is dead or has just started, don't ask for confirmation + *retVal |= CONTROL_RESTART_GAME; + else if (getConfirm(_lStrings[STR_RESTART])) + *retVal |= CONTROL_RESTART_GAME; + else + return mode; + } else if ((id == BUTTON_RESTORE_PANEL) || (id == BUTTON_SAVE_PANEL) || + (id == BUTTON_DONE) || (id == BUTTON_VOLUME_PANEL)) + return id; + else if (id == BUTTON_TEXT) { + SwordEngine::_systemVars.showText ^= 1; + _buttons[5]->setSelected(SwordEngine::_systemVars.showText); + } else if (id == BUTTON_QUIT) { + if (getConfirm(_lStrings[STR_QUIT])) + SwordEngine::_systemVars.engineQuit = true; + return mode; + } + break; + case BUTTON_SAVE_PANEL: + case BUTTON_RESTORE_PANEL: + if ((id >= BUTTON_SCROLL_UP_FAST) && (id <= BUTTON_SCROLL_DOWN_FAST)) + saveNameScroll(id, mode == BUTTON_SAVE_PANEL); + else if ((id >= BUTTON_SAVE_SELECT1) && (id <= BUTTON_SAVE_SELECT8)) + saveNameSelect(id, mode == BUTTON_SAVE_PANEL); + else if (id == BUTTON_SAVE_RESTORE_OKAY) { + if (mode == BUTTON_SAVE_PANEL) { + _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); + if (saveToFile()) // don't go back to main panel if save fails. + return BUTTON_DONE; + } else { + if (restoreFromFile()) { // don't go back to main panel if restore fails. + *retVal |= CONTROL_GAME_RESTORED; + return BUTTON_MAIN_PANEL; + } + } + } else if (id == BUTTON_SAVE_CANCEL) { + _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); + return BUTTON_MAIN_PANEL; // mode down to main panel + } + break; + case BUTTON_VOLUME_PANEL: + return id; + } + return 0; +} + +void Control::deselectSaveslots(void) { + for (uint8 cnt = 0; cnt < 8; cnt++) + _buttons[cnt]->setSelected(0); +} + +void Control::setupMainPanel(void) { + uint32 panelId; + + if (SwordEngine::_systemVars.controlPanelMode == CP_DEATHSCREEN) + panelId = SR_DEATHPANEL; + else { + if (SwordEngine::_systemVars.language <= BS1_SPANISH) + panelId = SR_PANEL_ENGLISH + SwordEngine::_systemVars.language; + else + panelId = SR_PANEL_ENGLISH; + } + + ControlButton *panel = new ControlButton(0, 0, panelId, 0, 0, _resMan, _screenBuf, _system); + panel->draw(); + delete panel; + + if (SwordEngine::_systemVars.controlPanelMode != CP_NORMAL) + createButtons(_deathButtons, 3); + else { + createButtons(_panelButtons, 7); + _buttons[5]->setSelected(SwordEngine::_systemVars.showText); + } + + if (SwordEngine::_systemVars.controlPanelMode == CP_THEEND) // end of game + renderText(_lStrings[STR_THE_END], 480, 188 + 40, TEXT_RIGHT_ALIGN); + + if (SwordEngine::_systemVars.controlPanelMode == CP_NORMAL) { // normal panel + renderText(_lStrings[STR_SAVE], 180, 188 + 40, TEXT_LEFT_ALIGN); + renderText(_lStrings[STR_DONE], 460, 332 + 40, TEXT_RIGHT_ALIGN); + renderText(_lStrings[STR_RESTORE], 180, 224 + 40, TEXT_LEFT_ALIGN); + renderText(_lStrings[STR_RESTART], 180, 260 + 40, TEXT_LEFT_ALIGN); + renderText(_lStrings[STR_QUIT], 180, 296 + 40, TEXT_LEFT_ALIGN); + + renderText(_lStrings[STR_VOLUME], 460, 188 + 40, TEXT_RIGHT_ALIGN); + renderText(_lStrings[STR_TEXT], 460, 224 + 40, TEXT_RIGHT_ALIGN); + } else { + renderText(_lStrings[STR_RESTORE], 285, 224 + 40, TEXT_LEFT_ALIGN); + if (SwordEngine::_systemVars.controlPanelMode == CP_NEWGAME) // just started game + renderText(_lStrings[STR_START], 285, 260 + 40, TEXT_LEFT_ALIGN); + else + renderText(_lStrings[STR_RESTART], 285, 260 + 40, TEXT_LEFT_ALIGN); + renderText(_lStrings[STR_QUIT], 285, 296 + 40, TEXT_LEFT_ALIGN); + } +} + +void Control::setupSaveRestorePanel(bool saving) { + FrameHeader *savePanel = _resMan->fetchFrame(_resMan->openFetchRes(SR_WINDOW), 0); + uint16 panelX = (640 - FROM_LE_16(savePanel->width)) / 2; + uint16 panelY = (480 - FROM_LE_16(savePanel->height)) / 2; + ControlButton *panel = new ControlButton(panelX, panelY, SR_WINDOW, 0, 0, _resMan, _screenBuf, _system); + panel->draw(); + delete panel; + _resMan->resClose(SR_WINDOW); + createButtons(_saveButtons, 14); + renderText(_lStrings[STR_CANCEL], _saveButtons[13].x - 10, _saveButtons[13].y, TEXT_RIGHT_ALIGN); + if (saving) { + renderText(_lStrings[STR_SAVE], _saveButtons[12].x + 30, _saveButtons[13].y, TEXT_LEFT_ALIGN); + } else { + renderText(_lStrings[STR_RESTORE], _saveButtons[12].x + 30, _saveButtons[13].y, TEXT_LEFT_ALIGN); + } + readSavegameDescriptions(); + _selectedSavegame = 255; + showSavegameNames(); +} + +void Control::setupVolumePanel(void) { + ControlButton *panel = new ControlButton(0, 0, SR_VOLUME, 0, 0, _resMan, _screenBuf, _system); + panel->draw(); + delete panel; + + renderText(_lStrings[STR_MUSIC], 149, 39 + 40, TEXT_LEFT_ALIGN); + renderText(_lStrings[STR_SPEECH], 320, 39 + 40, TEXT_CENTER); + renderText(_lStrings[STR_FX], 438, 39 + 40, TEXT_LEFT_ALIGN); + + createButtons(_volumeButtons, 4); + renderText(_lStrings[STR_DONE], _volumeButtons[0].x - 10, _volumeButtons[0].y, TEXT_RIGHT_ALIGN); + + uint8 volL, volR; + _music->giveVolume(&volL, &volR); + renderVolumeBar(1, volL, volR); + _sound->giveSpeechVol(&volL, &volR); + renderVolumeBar(2, volL, volR); + _sound->giveSfxVol(&volL, &volR); + renderVolumeBar(3, volL, volR); +} + +void Control::handleVolumeClicks(void) { + if (_mouseDown) { + uint8 clickedId = 0; + for (uint8 cnt = 1; cnt < 4; cnt++) + if (_buttons[cnt]->wasClicked(_mouseX, _mouseY)) + clickedId = cnt; + if (clickedId) { // these are circle shaped, so check again if it was clicked. + uint8 clickDest = 0; + int16 mouseDiffX = _mouseX - (_volumeButtons[clickedId].x + 48); + int16 mouseDiffY = _mouseY - (_volumeButtons[clickedId].y + 48); + int16 mouseOffs = (int16)sqrt((double)(mouseDiffX * mouseDiffX + mouseDiffY * mouseDiffY)); + // check if the player really hit the button (but not the center). + if ((mouseOffs <= 42) && (mouseOffs >= 8)) { + if (mouseDiffX > 8) { // right part + if (mouseDiffY < -8) // upper right + clickDest = 2; + else if (ABS(mouseDiffY) <= 8) // right + clickDest = 3; + else // lower right + clickDest = 4; + } else if (mouseDiffX < -8) { // left part + if (mouseDiffY < -8) // upper left + clickDest = 8; + else if (ABS(mouseDiffY) <= 8) // left + clickDest = 7; + else // lower left + clickDest = 6; + } else { // middle + if (mouseDiffY < -8) + clickDest = 1; // upper + else if (mouseDiffY > 8) + clickDest = 5; // lower + } + } + _buttons[clickedId]->setSelected(clickDest); + changeVolume(clickedId, clickDest); + } + } else if (_mouseState & BS1L_BUTTON_UP) { + _buttons[1]->setSelected(0); + _buttons[2]->setSelected(0); + _buttons[3]->setSelected(0); + } +} + +void Control::changeVolume(uint8 id, uint8 action) { + // ids: 1 = music, 2 = speech, 3 = sfx + uint8 volL = 0, volR = 0; + if (id == 1) + _music->giveVolume(&volL, &volR); + else if (id == 2) + _sound->giveSpeechVol(&volL, &volR); + else if (id == 3) + _sound->giveSfxVol(&volL, &volR); + + int8 direction = 0; + if ((action >= 4) && (action <= 6)) // lower part of the button => decrease volume + direction = -1; + else if ((action == 8) || (action == 1) || (action == 2)) // upper part => increase volume + direction = 1; + else if ((action == 3) || (action == 7)) // middle part => pan volume + direction = 1; + int8 factorL = 8, factorR = 8; + if ((action >= 6) && (action <= 8)) { // left part => left pan + factorL = 8; + factorR = (action == 7) ? -8 : 0; + } else if ((action >= 2) && (action <= 4)) { // right part + factorR = 8; + factorL = (action == 3) ? -8 : 0; + } + int16 resVolL = volL + direction * factorL; + int16 resVolR = volR + direction * factorR; + + volL = (uint8)MAX((int16)0, MIN(resVolL, (int16)255)); + volR = (uint8)MAX((int16)0, MIN(resVolR, (int16)255)); + + if (id == 1) + _music->setVolume(volL, volR); + else if (id == 2) + _sound->setSpeechVol(volL, volR); + else if (id == 3) + _sound->setSfxVol(volL, volR); + + renderVolumeBar(id, volL, volR); +} + +bool Control::getConfirm(const uint8 *title) { + ControlButton *panel = new ControlButton(0, 0, SR_CONFIRM, 0, 0, _resMan, _screenBuf, _system); + panel->draw(); + delete panel; + renderText(title, 320, 160, TEXT_CENTER); + ControlButton *buttons[2]; + buttons[0] = new ControlButton(260, 192 + 40, SR_BUTTON, 0, 0, _resMan, _screenBuf, _system); + renderText(_lStrings[STR_OK], 640 - 260, 192 + 40, TEXT_RIGHT_ALIGN); + buttons[1] = new ControlButton(260, 256 + 40, SR_BUTTON, 0, 0, _resMan, _screenBuf, _system); + renderText(_lStrings[STR_CANCEL], 640 - 260, 256 + 40, TEXT_RIGHT_ALIGN); + uint8 retVal = 0; + uint8 clickVal = 0; + do { + buttons[0]->draw(); + buttons[1]->draw(); + _system->updateScreen(); + delay(1000 / 12); + if (_keyPressed == 27) + retVal = 2; + else if (_keyPressed == '\r' || _keyPressed == '\n') + retVal = 1; + if (_mouseState & BS1L_BUTTON_DOWN) { + if (buttons[0]->wasClicked(_mouseX, _mouseY)) + clickVal = 1; + else if (buttons[1]->wasClicked(_mouseX, _mouseY)) + clickVal = 2; + else + clickVal = 0; + if (clickVal) + buttons[clickVal - 1]->setSelected(1); + } + if ((_mouseState & BS1L_BUTTON_UP) && (clickVal)) { + if (buttons[clickVal - 1]->wasClicked(_mouseX, _mouseY)) + retVal = clickVal; + else + buttons[clickVal - 1]->setSelected(0); + clickVal = 0; + } + } while (!retVal); + delete buttons[0]; + delete buttons[1]; + return retVal == 1; +} + +bool Control::keyAccepted(uint8 key) { + // this routine needs changes for Czech keys... No idea how to do that, though. + // FIXME: It is not a good idea to put non-ASCII chars into a C source file, + // since there is no way to specify which encoding you are using. + // It is better to encode them as hex/octal. Although in this particular + // case, it seems questionable to do this at all, since we currently + // do not at all specify which encoding keyboard events use, so this + // check here is probably not portable anyway... + static const char allowedSpecials[] = "éèáàúùäöüÄÖÜß,.:-()?! \"\'"; + if (((key >= 'A') && (key <= 'Z')) || + ((key >= 'a') && (key <= 'z')) || + ((key >= '0') && (key <= '9')) || + strchr(allowedSpecials, key)) + return true; + else + return false; +} + +void Control::handleSaveKey(uint8 key) { + if (_selectedSavegame < 255) { + uint8 len = strlen((char*)_saveNames[_selectedSavegame]); + if ((key == 8) && len) // backspace + _saveNames[_selectedSavegame][len - 1] = '\0'; + else if (keyAccepted(key) && (len < 31)) { + _saveNames[_selectedSavegame][len] = key; + _saveNames[_selectedSavegame][len + 1] = '\0'; + } + showSavegameNames(); + } +} + +bool Control::saveToFile(void) { + if ((_selectedSavegame == 255) || !strlen((char*)_saveNames[_selectedSavegame])) + return false; // no saveslot selected or no name entered + saveGameToFile(_selectedSavegame); + writeSavegameDescriptions(); + return true; +} + +bool Control::restoreFromFile(void) { + if (_selectedSavegame < 255) { + return restoreGameFromFile(_selectedSavegame); + } else + return false; +} + +void Control::readSavegameDescriptions(void) { + Common::InSaveFile *inf; + inf = _saveFileMan->openForLoading("SAVEGAME.INF"); + _saveScrollPos = _saveFiles = 0; + _selectedSavegame = 255; + if (inf) { + uint8 curFileNum = 0; + uint8 ch; + do { + uint8 pos = 0; + do { + ch = inf->readByte(); + if ((ch == 10) || (ch == 255)) + _saveNames[curFileNum][pos] = '\0'; + else + _saveNames[curFileNum][pos] = ch; + pos++; + } while ((ch != 10) && (ch != 255)); + curFileNum++; + } while (ch != 255); + _saveFiles = curFileNum; + for (uint8 cnt = _saveFiles; cnt < 64; cnt++) + _saveNames[cnt][0] = '\0'; + } else + for (uint8 cnt = 0; cnt < 64; cnt++) + _saveNames[cnt][0] = '\0'; + delete inf; +} + +int Control::displayMessage(const char *altButton, const char *message, ...) { + char buf[STRINGBUFLEN]; + va_list va; + + va_start(va, message); + vsnprintf(buf, STRINGBUFLEN, message, va); + va_end(va); + + GUI::MessageDialog dialog(buf, "OK", altButton); + int result = dialog.runModal(); + _mouse->setPointer(MSE_POINTER, 0); + return result; +} + +void Control::writeSavegameDescriptions(void) { + Common::OutSaveFile *outf; + outf = _saveFileMan->openForSaving("SAVEGAME.INF"); + + if (!outf) { + // Display an error message, and do nothing + displayMessage(0, "Can't create SAVEGAME.INF in directory '%s'", _saveFileMan->getSavePath()); + return; + } + + // if the player accidently clicked the last slot and then deselected it again, + // we'd still have _saveFiles == 64, so get rid of the empty end. + while (strlen((char*)_saveNames[_saveFiles - 1]) == 0) + _saveFiles--; + for (uint8 cnt = 0; cnt < _saveFiles; cnt++) { + int len = strlen((char*)_saveNames[cnt]); + if (len > 0) + outf->write(_saveNames[cnt], len); + if (cnt < _saveFiles - 1) + outf->writeByte(10); + else + outf->writeByte(255); + } + outf->flush(); + if (outf->ioFailed()) + displayMessage(0, "Can't write to SAVEGAME.INF in directory '%s'. Device full?", _saveFileMan->getSavePath()); + delete outf; +} + +bool Control::savegamesExist(void) { + bool retVal = false; + Common::InSaveFile *inf; + inf = _saveFileMan->openForLoading("SAVEGAME.INF"); + if (inf) + retVal = true; + delete inf; + return retVal; +} + +void Control::showSavegameNames(void) { + for (uint8 cnt = 0; cnt < 8; cnt++) { + _buttons[cnt]->draw(); + uint8 textMode = TEXT_LEFT_ALIGN; + uint16 ycoord = _saveButtons[cnt].y + 2; + uint8 str[40]; + sprintf((char*)str, "%d. %s", cnt + _saveScrollPos + 1, _saveNames[cnt + _saveScrollPos]); + if (cnt + _saveScrollPos == _selectedSavegame) { + textMode |= TEXT_RED_FONT; + ycoord += 2; + if (_cursorVisible) + strcat((char*)str, "_"); + } + renderText(str, _saveButtons[cnt].x + 6, ycoord, textMode); + } +} + +void Control::saveNameSelect(uint8 id, bool saving) { + deselectSaveslots(); + _buttons[id - BUTTON_SAVE_SELECT1]->setSelected(1); + uint8 num = (id - BUTTON_SAVE_SELECT1) + _saveScrollPos; + if (saving && (_selectedSavegame != 255)) // the player may have entered something, clear it again + strcpy((char*)_saveNames[_selectedSavegame], (char*)_oldName); + if (num < _saveFiles) { + _selectedSavegame = num; + strcpy((char*)_oldName, (char*)_saveNames[num]); // save for later + } else { + if (!saving) + _buttons[id - BUTTON_SAVE_SELECT1]->setSelected(0); // no save in slot, deselect it + else { + if (_saveFiles <= num) + _saveFiles = num + 1; + _selectedSavegame = num; + _oldName[0] = '\0'; + } + } + if (_selectedSavegame < 255) + _cursorTick = 0; + showSavegameNames(); +} + +void Control::saveNameScroll(uint8 scroll, bool saving) { + uint16 maxScroll; + if (saving) + maxScroll = 64; + else + maxScroll = _saveFiles; // for loading, we can only scroll as far as there are savegames + if (scroll == BUTTON_SCROLL_UP_FAST) { + if (_saveScrollPos >= 8) + _saveScrollPos -= 8; + else + _saveScrollPos = 0; + } else if (scroll == BUTTON_SCROLL_UP_SLOW) { + if (_saveScrollPos >= 1) + _saveScrollPos--; + } else if (scroll == BUTTON_SCROLL_DOWN_SLOW) { + if (_saveScrollPos + 8 < maxScroll) + _saveScrollPos++; + } else if (scroll == BUTTON_SCROLL_DOWN_FAST) { + if (_saveScrollPos + 16 < maxScroll) + _saveScrollPos += 8; + else { + if (maxScroll >= 8) + _saveScrollPos = maxScroll - 8; + else + _saveScrollPos = 0; + } + } + _selectedSavegame = 255; // deselect savegame + deselectSaveslots(); + showSavegameNames(); +} + +void Control::createButtons(const ButtonInfo *buttons, uint8 num) { + for (uint8 cnt = 0; cnt < num; cnt++) { + _buttons[cnt] = new ControlButton(buttons[cnt].x, buttons[cnt].y, buttons[cnt].resId, buttons[cnt].id, buttons[cnt].flag, _resMan, _screenBuf, _system); + _buttons[cnt]->draw(); + } + _numButtons = num; +} + +void Control::destroyButtons(void) { + for (uint8 cnt = 0; cnt < _numButtons; cnt++) + delete _buttons[cnt]; + _numButtons = 0; +} + +uint16 Control::getTextWidth(const uint8 *str) { + uint16 width = 0; + while (*str) { + width += FROM_LE_16(_resMan->fetchFrame(_font, *str - 32)->width) - 3; + str++; + } + return width; +} + +void Control::renderText(const uint8 *str, uint16 x, uint16 y, uint8 mode) { + uint8 *font = _font; + if (mode & TEXT_RED_FONT) { + mode &= ~TEXT_RED_FONT; + font = _redFont; + } + + if (mode == TEXT_RIGHT_ALIGN) // negative x coordinate means right-aligned. + x -= getTextWidth(str); + else if (mode == TEXT_CENTER) + x -= getTextWidth(str) / 2; + + uint16 destX = x; + while (*str) { + uint8 *dst = _screenBuf + y * SCREEN_WIDTH + destX; + + FrameHeader *chSpr = _resMan->fetchFrame(font, *str - 32); + uint8 *sprData = (uint8*)chSpr + sizeof(FrameHeader); + for (uint16 cnty = 0; cnty < FROM_LE_16(chSpr->height); cnty++) { + for (uint16 cntx = 0; cntx < FROM_LE_16(chSpr->width); cntx++) { + if (sprData[cntx]) + dst[cntx] = sprData[cntx]; + } + sprData += FROM_LE_16(chSpr->width); + dst += SCREEN_WIDTH; + } + destX += FROM_LE_16(chSpr->width) - 3; + str++; + } + _system->copyRectToScreen(_screenBuf + y * SCREEN_WIDTH + x, SCREEN_WIDTH, x, y, (destX - x) + 3, 28); +} + +void Control::renderVolumeBar(uint8 id, uint8 volL, uint8 volR) { + uint16 destX = _volumeButtons[id].x + 20; + uint16 destY = _volumeButtons[id].y + 116; + + for (uint8 chCnt = 0; chCnt < 2; chCnt++) { + uint8 vol = (chCnt == 0) ? volL : volR; + FrameHeader *frHead = _resMan->fetchFrame(_resMan->openFetchRes(SR_VLIGHT), (vol + 15) >> 4); + uint8 *destMem = _screenBuf + destY * SCREEN_WIDTH + destX; + uint8 *srcMem = (uint8*)frHead + sizeof(FrameHeader); + for (uint16 cnty = 0; cnty < FROM_LE_16(frHead->height); cnty++) { + memcpy(destMem, srcMem, FROM_LE_16(frHead->width)); + srcMem += FROM_LE_16(frHead->width); + destMem += SCREEN_WIDTH; + } + _system->copyRectToScreen(_screenBuf + destY * SCREEN_WIDTH + destX, SCREEN_WIDTH, destX, destY, FROM_LE_16(frHead->width), FROM_LE_16(frHead->height)); + _resMan->resClose(SR_VLIGHT); + destX += 32; + } +} + +void Control::saveGameToFile(uint8 slot) { + char fName[15]; + uint16 cnt; + sprintf(fName, "SAVEGAME.%03d", slot); + uint16 liveBuf[TOTAL_SECTIONS]; + Common::OutSaveFile *outf; + outf = _saveFileMan->openForSaving(fName); + if (!outf) { + // Display an error message and do nothing + displayMessage(0, "Unable to create file '%s' in directory '%s'", fName, _saveFileMan->getSavePath()); + return; + } + + _objMan->saveLiveList(liveBuf); + for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++) + outf->writeUint16LE(liveBuf[cnt]); + + Object *cpt = _objMan->fetchObject(PLAYER); + Logic::_scriptVars[CHANGE_DIR] = cpt->o_dir; + Logic::_scriptVars[CHANGE_X] = cpt->o_xcoord; + Logic::_scriptVars[CHANGE_Y] = cpt->o_ycoord; + Logic::_scriptVars[CHANGE_STANCE] = STAND; + Logic::_scriptVars[CHANGE_PLACE] = cpt->o_place; + + for (cnt = 0; cnt < NUM_SCRIPT_VARS; cnt++) + outf->writeUint32LE(Logic::_scriptVars[cnt]); + + uint32 playerSize = (sizeof(Object) - 12000) / 4; + uint32 *playerRaw = (uint32*)cpt; + for (uint32 cnt2 = 0; cnt2 < playerSize; cnt2++) + outf->writeUint32LE(playerRaw[cnt2]); + outf->flush(); + if (outf->ioFailed()) + displayMessage(0, "Couldn't write to file '%s' in directory '%s'. Device full?", fName, _saveFileMan->getSavePath()); + delete outf; +} + +bool Control::restoreGameFromFile(uint8 slot) { + char fName[15]; + uint16 cnt; + sprintf(fName, "SAVEGAME.%03d", slot); + Common::InSaveFile *inf; + inf = _saveFileMan->openForLoading(fName); + if (!inf) { + // Display an error message, and do nothing + displayMessage(0, "Can't open file '%s' in directory '%s'", fName, _saveFileMan->getSavePath()); + return false; + } + + _restoreBuf = (uint8*)malloc( + TOTAL_SECTIONS * 2 + + NUM_SCRIPT_VARS * 4 + + (sizeof(Object) - 12000)); + + uint16 *liveBuf = (uint16*)_restoreBuf; + uint32 *scriptBuf = (uint32*)(_restoreBuf + 2 * TOTAL_SECTIONS); + uint32 *playerBuf = (uint32*)(_restoreBuf + 2 * TOTAL_SECTIONS + 4 * NUM_SCRIPT_VARS); + + for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++) + liveBuf[cnt] = inf->readUint16LE(); + + for (cnt = 0; cnt < NUM_SCRIPT_VARS; cnt++) + scriptBuf[cnt] = inf->readUint32LE(); + + uint32 playerSize = (sizeof(Object) - 12000) / 4; + for (uint32 cnt2 = 0; cnt2 < playerSize; cnt2++) + playerBuf[cnt2] = inf->readUint32LE(); + + if (inf->ioFailed()) { + displayMessage(0, "Can't read from file '%s' in directory '%s'", fName, _saveFileMan->getSavePath()); + delete inf; + free(_restoreBuf); + _restoreBuf = NULL; + return false; + } + delete inf; + return true; +} + +void Control::doRestore(void) { + uint8 *bufPos = _restoreBuf; + _objMan->loadLiveList((uint16*)bufPos); + bufPos += TOTAL_SECTIONS * 2; + for (uint16 cnt = 0; cnt < NUM_SCRIPT_VARS; cnt++) { + Logic::_scriptVars[cnt] = *(uint32*)bufPos; + bufPos += 4; + } + uint32 playerSize = (sizeof(Object) - 12000) / 4; + uint32 *playerRaw = (uint32*)_objMan->fetchObject(PLAYER); + Object *cpt = _objMan->fetchObject(PLAYER); + for (uint32 cnt2 = 0; cnt2 < playerSize; cnt2++) { + *playerRaw = *(uint32*)bufPos; + playerRaw++; + bufPos += 4; + } + free(_restoreBuf); + Logic::_scriptVars[CHANGE_DIR] = cpt->o_dir; + Logic::_scriptVars[CHANGE_X] = cpt->o_xcoord; + Logic::_scriptVars[CHANGE_Y] = cpt->o_ycoord; + Logic::_scriptVars[CHANGE_STANCE] = STAND; + Logic::_scriptVars[CHANGE_PLACE] = cpt->o_place; + SwordEngine::_systemVars.justRestoredGame = 1; + if (SwordEngine::_systemVars.isDemo) + Logic::_scriptVars[PLAYINGDEMO] = 1; +} + +void Control::delay(uint32 msecs) { + OSystem::Event event; + + uint32 now = _system->getMillis(); + uint32 endTime = now + msecs; + _keyPressed = 0; //reset + _mouseState = 0; + + do { + while (_system->pollEvent(event)) { + switch (event.type) { + case OSystem::EVENT_KEYDOWN: + + // Make sure backspace works right (this fixes a small issue on OS X) + if (event.kbd.keycode == 8) + _keyPressed = 8; + else + _keyPressed = (byte)event.kbd.ascii; + _keyRepeatTime = now + kKeyRepeatInitialDelay; + _keyRepeat = _keyPressed; + // we skip the rest of the delay and return immediately + // to handle keyboard input + return; + case OSystem::EVENT_KEYUP: + _keyRepeatTime = 0; + _keyRepeat = 0; + break; + case OSystem::EVENT_MOUSEMOVE: + _mouseX = event.mouse.x; + _mouseY = event.mouse.y; + break; + case OSystem::EVENT_LBUTTONDOWN: + _mouseDown = true; + _mouseState |= BS1L_BUTTON_DOWN; +#if defined(_WIN32_WCE) || defined(PALMOS_MODE) + _mouseX = event.mouse.x; + _mouseY = event.mouse.y; +#endif + break; + case OSystem::EVENT_LBUTTONUP: + _mouseDown = false; + _mouseState |= BS1L_BUTTON_UP; + break; + case OSystem::EVENT_WHEELUP: + _mouseDown = false; + _mouseState |= BS1_WHEEL_UP; + break; + case OSystem::EVENT_WHEELDOWN: + _mouseDown = false; + _mouseState |= BS1_WHEEL_DOWN; + break; + case OSystem::EVENT_QUIT: + SwordEngine::_systemVars.engineQuit = true; + break; + default: + break; + } + } + if (_keyRepeatTime && now > _keyRepeatTime) { + _keyRepeatTime += kKeyRepeatSustainDelay; + _keyPressed = _keyRepeat; + } + + _system->delayMillis(10); + } while (_system->getMillis() < endTime); +} + +const ButtonInfo Control::_deathButtons[3] = { + {250, 224 + 40, SR_BUTTON, BUTTON_RESTORE_PANEL, 0 }, + {250, 260 + 40, SR_BUTTON, BUTTON_RESTART, kButtonOk }, + {250, 296 + 40, SR_BUTTON, BUTTON_QUIT, kButtonCancel } +}; + +const ButtonInfo Control::_panelButtons[7] = { + {145, 188 + 40, SR_BUTTON, BUTTON_SAVE_PANEL, 0 }, + {145, 224 + 40, SR_BUTTON, BUTTON_RESTORE_PANEL, 0 }, + {145, 260 + 40, SR_BUTTON, BUTTON_RESTART, 0 }, + {145, 296 + 40, SR_BUTTON, BUTTON_QUIT, kButtonCancel }, + {475, 188 + 40, SR_BUTTON, BUTTON_VOLUME_PANEL, 0 }, + {475, 224 + 40, SR_TEXT_BUTTON, BUTTON_TEXT, 0 }, + {475, 332 + 40, SR_BUTTON, BUTTON_DONE, kButtonOk } +}; + +const ButtonInfo Control::_saveButtons[16] = { + {114, 32 + 40, SR_SLAB1, BUTTON_SAVE_SELECT1, 0 }, + {114, 68 + 40, SR_SLAB2, BUTTON_SAVE_SELECT2, 0 }, + {114, 104 + 40, SR_SLAB3, BUTTON_SAVE_SELECT3, 0 }, + {114, 140 + 40, SR_SLAB4, BUTTON_SAVE_SELECT4, 0 }, + {114, 176 + 40, SR_SLAB1, BUTTON_SAVE_SELECT5, 0 }, + {114, 212 + 40, SR_SLAB2, BUTTON_SAVE_SELECT6, 0 }, + {114, 248 + 40, SR_SLAB3, BUTTON_SAVE_SELECT7, 0 }, + {114, 284 + 40, SR_SLAB4, BUTTON_SAVE_SELECT8, 0 }, + + {516, 25 + 40, SR_BUTUF, BUTTON_SCROLL_UP_FAST, 0 }, + {516, 45 + 40, SR_BUTUS, BUTTON_SCROLL_UP_SLOW, 0 }, + {516, 289 + 40, SR_BUTDS, BUTTON_SCROLL_DOWN_SLOW, 0 }, + {516, 310 + 40, SR_BUTDF, BUTTON_SCROLL_DOWN_FAST, 0 }, + + {125, 338 + 40, SR_BUTTON, BUTTON_SAVE_RESTORE_OKAY, kButtonOk}, + {462, 338 + 40, SR_BUTTON, BUTTON_SAVE_CANCEL, kButtonCancel } +}; + +const ButtonInfo Control::_volumeButtons[4] = { + { 478, 338 + 40, SR_BUTTON, BUTTON_MAIN_PANEL, kButtonOk }, + { 138, 135, SR_VKNOB, 0, 0 }, + { 273, 135, SR_VKNOB, 0, 0 }, + { 404, 135, SR_VKNOB, 0, 0 }, +}; + +const uint8 Control::_languageStrings[8 * 20][43] = { + // BS1_ENGLISH: + "PAUSED", + "PLEASE INSERT CD-", + "THEN PRESS A KEY", + "INCORRECT CD", + "Save", + "Restore", + "Restart", + "Start", + "Quit", + "Speed", + "Volume", + "Text", + "Done", + "OK", + "Cancel", + "Music", + "Speech", + "Fx", + "The End", + "DRIVE FULL!", +// BS1_FRENCH: + "PAUSE", + "INS\xC9REZ LE CD-", + "ET APPUYES SUR UNE TOUCHE", + "CD INCORRECT", + "Sauvegarder", + "Recharger", + "Recommencer", + "Commencer", + "Quitter", + "Vitesse", + "Volume", + "Texte", + "Termin\xE9", + "OK", + "Annuler", + "Musique", + "Voix", + "Fx", + "Fin", + "DISQUE PLEIN!", +//BS1_GERMAN: + "PAUSE", + "BITTE LEGEN SIE CD-", + "EIN UND DR\xDC CKEN SIE EINE BELIEBIGE TASTE", + "FALSCHE CD", + "Speichern", + "Laden", + "Neues Spiel", + "Start", + "Beenden", + "Geschwindigkeit", + "Lautst\xE4rke", + "Text", + "Fertig", + "OK", + "Abbrechen", + "Musik", + "Sprache", + "Fx", + "Ende", + "DRIVE FULL!", +//BS1_ITALIAN: + "PAUSA", + "INSERITE IL CD-", + "E PREMETE UN TASTO", + "CD ERRATO", + "Salva", + "Ripristina", + "Ricomincia", + "Inizio", + "Esci", + "Velocit\xE0", + "Volume", + "Testo", + "Fatto", + "OK", + "Annula", + "Musica", + "Parlato", + "Fx", + "Fine", + "DISCO PIENO!", +//BS1_SPANISH: + "PAUSA", + "POR FAVOR INTRODUCE EL CD-", + "Y PULSA UNA TECLA", + "CD INCORRECTO", + "Guardar", + "Recuperar", + "Reiniciar", + "Empezar", + "Abandonar", + "Velocidad", + "Volumen", + "Texto", + "Hecho", + "OK", + "Cancelar", + "M\xFAsica", + "Di\xE1logo", + "Fx", + "Fin", + "DISCO LLENO", +// BS1_CZECH: + "\xAC\x41S SE ZASTAVIL", + "VLO\xA6TE DO MECHANIKY CD DISK", + "PAK STISKN\xB7TE LIBOVOLNOU KL\xB5VESU", + "TO NEBUDE TO SPR\xB5VN\x90 CD", + "Ulo\xA7it pozici", + "Nahr\xA0t pozici", + "Za\x9F\xA1t znovu", + "Start", + "Ukon\x9Fit hru", + "Rychlost", + "Hlasitost", + "Titulky", + "Souhlas\xA1m", + "Ano", + "Ne", + "Hudba", + "Mluven, slovo", + "Zvuky", + "Konec", + "Disk pln\xEC", +//BS1_PORTUGESE: + "PAUSA", + "FAVOR INSERIR CD", + "E DIGITAR UMA TECLA", + "CD INCORRETO", + "Salvar", + "Restaurar", + "Reiniciar", + "Iniciar", + "Sair", + "Velocidade", + "Volume", + "Texto", + "Feito", + "OK", + "Cancelar", + "M\xFAsica", + "Voz", + "Efeitos", + "Fim", + "UNIDADE CHEIA!", +}; + +} // End of namespace Sword1 |