mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-05 01:38:36 +00:00
3725 lines
104 KiB
C++
3725 lines
104 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/file.h"
|
|
#include "common/util.h"
|
|
#include "common/savefile.h"
|
|
#include "common/events.h"
|
|
#include "common/system.h"
|
|
#include "common/config-manager.h"
|
|
#include "common/textconsole.h"
|
|
#include "common/translation.h"
|
|
#include "common/memstream.h"
|
|
|
|
#include "graphics/thumbnail.h"
|
|
#include "gui/message.h"
|
|
|
|
#include "sword1/control.h"
|
|
#include "sword1/logic.h"
|
|
#include "sword1/mouse.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"
|
|
#include "sword1/screen.h"
|
|
|
|
namespace Sword1 {
|
|
|
|
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
|
|
};
|
|
|
|
const Button Control::panelButtons[8] = {
|
|
{ 145, 188, 165, 214 },
|
|
{ 145, 224, 165, 250 },
|
|
{ 145, 260, 165, 286 },
|
|
{ 145, 296, 165, 322 },
|
|
{ 475, 188, 495, 214 },
|
|
{ 475, 224, 495, 250 },
|
|
{ 475, 260, 495, 286 },
|
|
{ 475, 332, 495, 358 }
|
|
};
|
|
|
|
const Button Control::deathButtons[8] = {
|
|
{ 0, 0, 0, 0 },
|
|
{ 250, 224, 270, 250 },
|
|
{ 250, 260, 270, 286 },
|
|
{ 250, 296, 270, 322 },
|
|
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
|
|
const Button Control::confirmButtons[2] = {
|
|
{ 260, 192, 284, 216 },
|
|
{ 260, 256, 284, 280 }
|
|
};
|
|
|
|
const Button Control::speedButtons[3] = {
|
|
{ 240, 136, 264, 160 },
|
|
{ 240, 200, 264, 224 },
|
|
{ 380, 256, 404, 280 }
|
|
};
|
|
|
|
const Button Control::saveButtons[SAVEBUTTONS] = {
|
|
{ 114, 32, 490, 67 },
|
|
{ 114, 68, 490, 103 },
|
|
{ 114, 104, 490, 139 },
|
|
{ 114, 140, 490, 175 },
|
|
{ 114, 176, 490, 211 },
|
|
{ 114, 212, 490, 247 },
|
|
{ 114, 248, 490, 283 },
|
|
{ 114, 284, 490, 319 },
|
|
|
|
{ 516, 25, 532, 40 },
|
|
{ 516, 45, 532, 60 },
|
|
{ 516, 289, 532, 305 },
|
|
{ 516, 310, 532, 325 },
|
|
|
|
{ 125, 338, 149, 366 },
|
|
{ 462, 338, 485, 366 }
|
|
};
|
|
|
|
const Button Control::restoreButtons[SAVEBUTTONS] = {
|
|
{ 110, 100, SCREEN_FULL_DEPTH, 140 },
|
|
|
|
{ 516, 45, 532, 60 },
|
|
{ 516, 25, 532, 40 },
|
|
{ 516, 289, 532, 305 },
|
|
{ 516, 310, 532, 325 },
|
|
|
|
{ 125, 338, 149, 366 },
|
|
{ 462, 338, 485, 366 },
|
|
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
|
|
const Button Control::volumeButtons[25] = {
|
|
|
|
{ VD1X + 30, VDY, VD1X + 60, VDY + 30 },
|
|
{ VD1X + 60, VDY + 10, VD1X + 80, VDY + 30 },
|
|
{ VD1X + 60, VDY + 30, VD1X + 90, VDY + 60 },
|
|
{ VD1X + 60, VDY + 60, VD1X + 80, VDY + 80 },
|
|
{ VD1X + 30, VDY + 60, VD1X + 60, VDY + 90 },
|
|
{ VD1X + 10, VDY + 60, VD1X + 30, VDY + 80 },
|
|
{ VD1X + 0, VDY + 30, VD1X + 30, VDY + 60 },
|
|
{ VD1X + 10, VDY + 10, VD1X + 30, VDY + 30 },
|
|
|
|
{ VD2X + 30, VDY, VD2X + 60, VDY + 30 },
|
|
{ VD2X + 60, VDY + 10, VD2X + 80, VDY + 30 },
|
|
{ VD2X + 60, VDY + 30, VD2X + 90, VDY + 60 },
|
|
{ VD2X + 60, VDY + 60, VD2X + 80, VDY + 80 },
|
|
{ VD2X + 30, VDY + 60, VD2X + 60, VDY + 90 },
|
|
{ VD2X + 10, VDY + 60, VD2X + 30, VDY + 80 },
|
|
{ VD2X + 0, VDY + 30, VD2X + 30, VDY + 60 },
|
|
{ VD2X + 10, VDY + 10, VD2X + 30, VDY + 30 },
|
|
|
|
{ VD3X + 30, VDY, VD3X + 60, VDY + 30 },
|
|
{ VD3X + 60, VDY + 10, VD3X + 80, VDY + 30 },
|
|
{ VD3X + 60, VDY + 30, VD3X + 90, VDY + 60 },
|
|
{ VD3X + 60, VDY + 60, VD3X + 80, VDY + 80 },
|
|
{ VD3X + 30, VDY + 60, VD3X + 60, VDY + 90 },
|
|
{ VD3X + 10, VDY + 60, VD3X + 30, VDY + 80 },
|
|
{ VD3X + 0, VDY + 30, VD3X + 30, VDY + 60 },
|
|
{ VD3X + 10, VDY + 10, VD3X + 30, VDY + 30 },
|
|
|
|
{ 472, 340, 496, 364 }
|
|
|
|
};
|
|
|
|
Control::Control(SwordEngine *vm, Common::SaveFileManager *saveFileMan, ResMan *pResMan, ObjectMan *pObjMan, OSystem *system, Mouse *pMouse, Sound *pSound, Screen *pScreen, Logic *pLogic) {
|
|
_vm = vm;
|
|
_saveFileMan = saveFileMan;
|
|
_resMan = pResMan;
|
|
_objMan = pObjMan;
|
|
_system = system;
|
|
_mouse = pMouse;
|
|
_sound = pSound;
|
|
_screen = pScreen;
|
|
_logic = pLogic;
|
|
|
|
if (gameVersionIsAkella()) {
|
|
_lStrings = _akellaLanguageStrings;
|
|
} else if (gameVersionIsMediaHouse()) {
|
|
_lStrings = _mediaHouseLanguageStrings;
|
|
} else if (vm->_systemVars.realLanguage == Common::Language::PL_POL) {
|
|
_lStrings = _polishTranslationLanguageStrings;
|
|
} else {
|
|
_lStrings = loadCustomStrings("strings.txt") ? _customStrings : _languageStrings + SwordEngine::_systemVars.language * 20;
|
|
}
|
|
|
|
_selectedButton = 255;
|
|
_panelShown = false;
|
|
_tempThumbnail = 0;
|
|
|
|
for (int i = 0; i < ARRAYSIZE(_slabs); i++) {
|
|
_slabs[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
bool Control::savegamesExist() {
|
|
Common::String pattern = "sword1.???";
|
|
Common::StringArray saveNames = _saveFileMan->listSavefiles(pattern);
|
|
return saveNames.size() > 0;
|
|
}
|
|
|
|
bool Control::isPanelShown() {
|
|
return _panelShown;
|
|
}
|
|
|
|
void Control::getPlayerOptions() {
|
|
debug(1, "Control::getPlayerOptions(): Entering Control Panel");
|
|
_panelShown = true;
|
|
|
|
_screenBuf = (uint8 *)malloc(SCREEN_WIDTH * SCREEN_FULL_DEPTH);
|
|
// Make a thumbnail of the screen before displaying the menu
|
|
// in case we want to save the game from the menu.
|
|
_tempThumbnail = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
|
|
Graphics::saveThumbnail(*_tempThumbnail);
|
|
|
|
// Reset because it was previously used when 'F5' or 'ESC' were pressed
|
|
SwordEngine::_systemVars.saveGameFlag = SGF_DONE;
|
|
|
|
_logic->fnWipeHands(nullptr, 0, 0, 0, 0, 0, 0, 0);
|
|
_logic->fnEndMenu(nullptr, 0, 0, 0, 0, 0, 0, 0);
|
|
|
|
int safeCurrentMusic = Logic::_scriptVars[CURRENT_MUSIC];
|
|
|
|
// Play music only if we actually have a music file to run..
|
|
if (!SwordEngine::_systemVars.runningFromCd || SwordEngine::_systemVars.currentCD)
|
|
_logic->fnPlayMusic(nullptr, 0, 61, LOOPED, 0, 0, 0, 0); // Control panel music ("2m29")
|
|
|
|
Logic::_scriptVars[CURRENT_MUSIC] = safeCurrentMusic;
|
|
|
|
_vm->startFadePaletteDown(1);
|
|
_vm->waitForFade();
|
|
_sound->clearAllFx();
|
|
_keyPressed.reset();
|
|
|
|
while (SwordEngine::_systemVars.snrStatus != SNR_BLANK && !Engine::shouldQuit()) {
|
|
delay(DEFAULT_FRAME_TIME / 2);
|
|
|
|
_sound->setCrossFadeIncrement();
|
|
|
|
_mouse->animate();
|
|
_sound->updateMusicStreaming();
|
|
saveRestoreScreen();
|
|
}
|
|
|
|
_keyPressed.reset();
|
|
|
|
saveRestoreScreen();
|
|
|
|
debug(1, "Control::getPlayerOptions(): Returning from Control Panel: saveGameFlag = %d",
|
|
SwordEngine::_systemVars.saveGameFlag);
|
|
|
|
// Stop music now, if we're not returning to any in-game music...
|
|
bool wontReloadMusic =
|
|
SwordEngine::_systemVars.saveGameFlag == SGF_RESTORE ||
|
|
SwordEngine::_systemVars.saveGameFlag == SGF_RESTART ||
|
|
SwordEngine::_systemVars.saveGameFlag == SGF_QUIT;
|
|
|
|
if (wontReloadMusic || (Logic::_scriptVars[CURRENT_MUSIC] == 0)) {
|
|
_logic->fnStopMusic(nullptr, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
|
|
_vm->startFadePaletteDown(1);
|
|
_vm->waitForFade();
|
|
|
|
_logic->fnNormalMouse(nullptr, 0, 0, 0, 0, 0, 0, 0);
|
|
Logic::_scriptVars[NEW_PALETTE] = 1;
|
|
|
|
if (SwordEngine::_systemVars.saveGameFlag == SGF_SAVE) {
|
|
saveGame();
|
|
} else if (SwordEngine::_systemVars.saveGameFlag == SGF_QUIT) {
|
|
_sound->fadeMusicDown(1);
|
|
|
|
Engine::quitGame();
|
|
}
|
|
|
|
// Reset again (because it may have been set in fnDeathScreen())
|
|
SwordEngine::_systemVars.controlPanelMode = CP_NORMAL;
|
|
|
|
// If DONE or SAVE was selected, try restoring audio...
|
|
if (SwordEngine::_systemVars.saveGameFlag == SGF_DONE || SwordEngine::_systemVars.saveGameFlag == SGF_SAVE) {
|
|
// Restore sound effects...
|
|
for (int j = 0; j < TOTAL_FX_PER_ROOM; j++) {
|
|
if (int32 fxNo = Sound::_roomsFixedFx[Logic::_scriptVars[SCREEN]][j]) { // search the room's fixed fx list (see 'fx_list.c')
|
|
if (Sound::_fxList[fxNo].type == FX_LOOP)
|
|
_logic->fnPlayFx(nullptr, 0, fxNo, 0, 0, 0, 0, 0);
|
|
} else {
|
|
break; // Drop out as soon as we come across a zero, rather than searching the whole list...
|
|
}
|
|
}
|
|
// Restore in-game music...
|
|
if (Logic::_scriptVars[CURRENT_MUSIC]) {
|
|
_logic->fnPlayMusic(nullptr, 0, Logic::_scriptVars[CURRENT_MUSIC], LOOPED, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
_screen->clearScreen();
|
|
free(_screenBuf);
|
|
|
|
debug(1, "Control::getPlayerOptions(): Finished getPlayerOptions()");
|
|
_panelShown = false;
|
|
|
|
// Was being set to true in initialiseControlPanel(),
|
|
// but we have to wait until here to set it to false
|
|
_mouse->controlPanel(false);
|
|
|
|
// Delete the temporary thumbnail
|
|
delete _tempThumbnail;
|
|
_tempThumbnail = nullptr;
|
|
}
|
|
|
|
void Control::askForCdMessage(uint32 needCD, bool incorrectCDPhase) {
|
|
uint8 buf[255];
|
|
_screenBuf = (uint8 *)malloc(SCREEN_WIDTH * SCREEN_FULL_DEPTH);
|
|
if (!_screenBuf)
|
|
return;
|
|
|
|
if (!incorrectCDPhase) {
|
|
//ScreenOpen(640 / XBLOCKSIZE, 400 / YBLOCKSIZE); // sets up global structure screenDef
|
|
memset(_screenBuf, 0, SCREEN_WIDTH * SCREEN_DEPTH);
|
|
|
|
Common::sprintf_s(buf, "%s%d", _lStrings[STR_INSERT_CD_A], needCD);
|
|
renderText(buf, (640 - getTextLength(buf, true)) / 2, 190, true);
|
|
|
|
Common::sprintf_s(buf, "%s", _lStrings[STR_INSERT_CD_B]);
|
|
renderText(buf, (640 - getTextLength(buf, true)) / 2, 210, true);
|
|
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
} else {
|
|
//if (displayInfo.backBuffer == 0) {
|
|
memset(_screenBuf, 0, SCREEN_WIDTH * SCREEN_DEPTH);
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
//}
|
|
|
|
memset(_screenBuf, 0, SCREEN_WIDTH * SCREEN_DEPTH);
|
|
|
|
Common::sprintf_s(buf, "%s", _lStrings[STR_INCORRECT_CD]);
|
|
renderText(buf, (640 - getTextLength(buf, true)) / 2, 160, true);
|
|
|
|
Common::sprintf_s(buf, "%s%d", _lStrings[STR_INSERT_CD_A], needCD);
|
|
renderText(buf, (640 - getTextLength(buf, true)) / 2, 190, true);
|
|
|
|
Common::sprintf_s(buf, "%s", _lStrings[STR_INSERT_CD_B]);
|
|
renderText(buf, (640 - getTextLength(buf, true)) / 2, 210, true);
|
|
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
}
|
|
free(_screenBuf);
|
|
}
|
|
|
|
void Control::saveRestoreScreen() {
|
|
int32 rv;
|
|
|
|
if (_oldSnrStatus != SwordEngine::_systemVars.snrStatus) {
|
|
// Tidy up after snr section
|
|
if (_oldSnrStatus == SNR_BLANK) {
|
|
memset(_screenBuf, 0, SCREEN_WIDTH * SCREEN_FULL_DEPTH);
|
|
_newPal = true;
|
|
}
|
|
|
|
switch (_oldSnrStatus) {
|
|
case SNR_BLANK:
|
|
memset(_screenBuf, 0, SCREEN_WIDTH * SCREEN_FULL_DEPTH);
|
|
break;
|
|
case SNR_MAINPANEL:
|
|
removeControlPanel();
|
|
_sound->setVolumes();
|
|
break;
|
|
case SNR_SAVE:
|
|
removeSave();
|
|
break;
|
|
case SNR_RESTORE:
|
|
removeRestore();
|
|
break;
|
|
case SNR_RESTART:
|
|
case SNR_QUIT:
|
|
removeConfirmation();
|
|
break;
|
|
case SNR_SPEED:
|
|
removeSpeed();
|
|
break;
|
|
case SNR_VOLUME:
|
|
removeVolume();
|
|
_sound->setVolumes();
|
|
break;
|
|
case SNR_DRIVEFULL:
|
|
removeConfirmation();
|
|
break;
|
|
}
|
|
|
|
// Initialise new snr section
|
|
switch (SwordEngine::_systemVars.snrStatus) {
|
|
case SNR_BLANK:
|
|
releaseResources();
|
|
break;
|
|
case SNR_MAINPANEL:
|
|
if (_oldSnrStatus == SNR_BLANK) {
|
|
initialiseResources();
|
|
}
|
|
|
|
_sound->getVolumes();
|
|
initialiseControlPanel();
|
|
break;
|
|
case SNR_SAVE:
|
|
initialiseSave();
|
|
break;
|
|
case SNR_RESTORE:
|
|
initialiseRestore();
|
|
break;
|
|
case SNR_RESTART:
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_NEWGAME) {
|
|
SwordEngine::_systemVars.snrStatus = SNR_BLANK;
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
} else {
|
|
initialiseConfirmation(_lStrings[STR_RESTART]);
|
|
}
|
|
|
|
break;
|
|
case SNR_QUIT:
|
|
initialiseConfirmation(_lStrings[STR_QUIT]);
|
|
break;
|
|
case SNR_SPEED:
|
|
initialiseSpeed();
|
|
break;
|
|
case SNR_VOLUME:
|
|
_sound->getVolumes();
|
|
initialiseVolume();
|
|
break;
|
|
case SNR_DRIVEFULL:
|
|
initialiseConfirmation(_lStrings[STR_DRIVE_FULL]);
|
|
break;
|
|
}
|
|
|
|
_oldSnrStatus = SwordEngine::_systemVars.snrStatus;
|
|
}
|
|
|
|
// Implement snr section
|
|
|
|
switch (SwordEngine::_systemVars.snrStatus) {
|
|
case SNR_BLANK:
|
|
break;
|
|
case SNR_MAINPANEL:
|
|
implementControlPanel();
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
|
|
if (_newPal) {
|
|
_newPal = false;
|
|
_vm->startFadePaletteUp(1);
|
|
}
|
|
|
|
break;
|
|
case SNR_SAVE:
|
|
implementSave();
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
|
|
break;
|
|
case SNR_RESTORE:
|
|
implementRestore();
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
|
|
break;
|
|
case SNR_RESTART:
|
|
rv = implementConfirmation();
|
|
if (rv) {
|
|
if (rv == 1) {
|
|
SwordEngine::_systemVars.saveGameFlag = SGF_RESTART;
|
|
SwordEngine::_systemVars.snrStatus = SNR_BLANK;
|
|
} else {
|
|
SwordEngine::_systemVars.snrStatus = SNR_MAINPANEL;
|
|
}
|
|
}
|
|
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
|
|
break;
|
|
case SNR_QUIT:
|
|
rv = implementConfirmation();
|
|
if (rv) {
|
|
if (rv == 1) {
|
|
SwordEngine::_systemVars.saveGameFlag = SGF_QUIT;
|
|
SwordEngine::_systemVars.snrStatus = SNR_BLANK;
|
|
} else {
|
|
SwordEngine::_systemVars.snrStatus = SNR_MAINPANEL;
|
|
}
|
|
}
|
|
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
|
|
break;
|
|
case SNR_SPEED:
|
|
implementSpeed();
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
break;
|
|
case SNR_VOLUME:
|
|
implementVolume();
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
break;
|
|
case SNR_SUBTITLES:
|
|
SwordEngine::_systemVars.snrStatus = SNR_MAINPANEL;
|
|
break;
|
|
case SNR_DONE:
|
|
SwordEngine::_systemVars.snrStatus = SNR_BLANK;
|
|
break;
|
|
case SNR_DRIVEFULL:
|
|
rv = implementConfirmation();
|
|
|
|
if (rv == 1) {
|
|
SwordEngine::_systemVars.snrStatus = SNR_SAVE;
|
|
}
|
|
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Control::renderSlab(int32 start, int32 i) {
|
|
uint8 *src, *dst;
|
|
FrameHeader *f;
|
|
|
|
if (start + 1 == _slabSelected) {
|
|
f = (FrameHeader *)((uint8 *)_slabs[start] + _resMan->getUint32(_slabs[start]->spriteOffset[1]));
|
|
} else {
|
|
f = (FrameHeader *)((uint8 *)_slabs[start] + _resMan->getUint32(_slabs[start]->spriteOffset[0]));
|
|
}
|
|
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
|
|
if (start + 1 == _slabSelected) {
|
|
dst = _screenBuf + saveButtons[i].x1 + SCREEN_WIDTH * (saveButtons[i].y1 - 1);
|
|
} else {
|
|
dst = _screenBuf + saveButtons[i].x1 + SCREEN_WIDTH * saveButtons[i].y1;
|
|
}
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_SLAB, src, dst, f);
|
|
} else {
|
|
for (int j = 0; j < _resMan->getUint16(f->height); j++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::renderSlabs() {
|
|
uint8 *src, *dst;
|
|
int32 start;
|
|
FrameHeader *f;
|
|
|
|
start = _firstDescription;
|
|
while (start >= (SAVEBUTTONS - 6))
|
|
start -= (SAVEBUTTONS - 6);
|
|
|
|
for (int i = 0; i < SAVEBUTTONS - 6; i++) {
|
|
if (i + 1 == _slabSelected)
|
|
continue;
|
|
|
|
f = (FrameHeader *)((uint8 *)_slabs[start] + _resMan->getUint32(_slabs[start]->spriteOffset[0]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf + saveButtons[i].x1 + SCREEN_WIDTH * saveButtons[i].y1;
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_SLAB, src, dst, f);
|
|
} else {
|
|
for (int j = 0; j < _resMan->getUint16(f->height); j++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
|
|
start += 1;
|
|
if (start == SAVEBUTTONS - 6)
|
|
start = 0;
|
|
}
|
|
|
|
if (_slabSelected) {
|
|
start = _firstDescription;
|
|
while (start >= (SAVEBUTTONS - 6))
|
|
start -= (SAVEBUTTONS - 6);
|
|
|
|
start += (_slabSelected - 1);
|
|
if (start >= (SAVEBUTTONS - 6))
|
|
start -= (SAVEBUTTONS - 6);
|
|
|
|
f = (FrameHeader *)((uint8 *)_slabs[start] + _resMan->getUint32(_slabs[start]->spriteOffset[1]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf + saveButtons[_slabSelected - 1].x1 + SCREEN_WIDTH * (saveButtons[_slabSelected - 1].y1 - 1);
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_SLAB, src, dst, f);
|
|
} else {
|
|
for (int j = 0; j < _resMan->getUint16(f->height); j++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::renderText(const uint8 *str, int32 x, int32 y, bool useSpeechFont) {
|
|
uint8 *src, *dst;
|
|
int32 i, l;
|
|
FrameHeader *f;
|
|
Sprite *srFont;
|
|
|
|
if (useSpeechFont) {
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
srFont = (Sprite *)_resMan->fetchRes(CZECH_GAME_FONT);
|
|
} else {
|
|
srFont = (Sprite *)_resMan->fetchRes(GAME_FONT);
|
|
}
|
|
} else {
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_DEATHSCREEN) {
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
srFont = (Sprite *)_resMan->fetchRes(CZECH_SR_DEATHFONT);
|
|
} else {
|
|
srFont = (Sprite *)_resMan->fetchRes(_resMan->getDeathFontId());
|
|
}
|
|
} else {
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
srFont = (Sprite *)_resMan->fetchRes(CZECH_SR_FONT);
|
|
} else {
|
|
srFont = (Sprite *)_resMan->fetchRes(SR_FONT);
|
|
}
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
l = 0;
|
|
|
|
while (str[i] != 0) {
|
|
f = (FrameHeader *)((uint8 *)srFont + _resMan->getUint32(srFont->spriteOffset[str[i] - 32]));
|
|
dst = _screenBuf + SCREEN_WIDTH * y + x + l;
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
src = decompressPsxGfx(src, f);
|
|
uint8 *initialPtr = src;
|
|
|
|
for (int k = 0; k < _resMan->getUint16(f->height); k++) {
|
|
for (int j = 0; j < _resMan->getUint16(f->width); j++) {
|
|
if (src[j])
|
|
dst[j] = src[j];
|
|
}
|
|
|
|
// On PSX version we need to double horizontal lines
|
|
if (SwordEngine::isPsx()) {
|
|
dst += SCREEN_WIDTH;
|
|
for (int j = 0; j < _resMan->getUint16(f->width); j++)
|
|
if (src[j])
|
|
dst[j] = src[j];
|
|
}
|
|
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
|
|
free(initialPtr);
|
|
} else {
|
|
// Copy the data onto the sprite
|
|
for (int k = 0; k < _resMan->getUint16(f->height); k++) {
|
|
for (int j = 0; j < _resMan->getUint16(f->width); j++) {
|
|
if (*src) {
|
|
*dst = *src;
|
|
}
|
|
|
|
dst += 1;
|
|
src += 1;
|
|
}
|
|
|
|
dst += SCREEN_WIDTH - _resMan->getUint16(f->width);
|
|
}
|
|
}
|
|
|
|
l += _resMan->getUint16(f->width);
|
|
|
|
if (!SwordEngine::_systemVars.isDemo)
|
|
l -= useSpeechFont ? SP_OVERLAP : OVERLAP;
|
|
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
void Control::renderRedText(const uint8 *str, int32 x, int32 y) {
|
|
uint8 *src, *dst;
|
|
int32 i, l;
|
|
FrameHeader *f;
|
|
Sprite *srRedfont;
|
|
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
srRedfont = (Sprite *)_resMan->fetchRes(CZECH_SR_REDFONT);
|
|
} else {
|
|
srRedfont = (Sprite *)_resMan->fetchRes(SR_REDFONT);
|
|
}
|
|
|
|
i = 0;
|
|
l = 0;
|
|
while (str[i] != 0) {
|
|
f = (FrameHeader *)((uint8 *)srRedfont + _resMan->getUint32(srRedfont->spriteOffset[str[i] - 32]));
|
|
dst = _screenBuf + SCREEN_WIDTH * y + x + l;
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_TEXT, src, dst, f);
|
|
} else {
|
|
// Copy the data onto the sprite
|
|
for (int k = 0; k < _resMan->getUint16(f->height); k++) {
|
|
for (int j = 0; j < _resMan->getUint16(f->width); j++) {
|
|
if (*src) {
|
|
*dst = *src;
|
|
}
|
|
dst += 1;
|
|
src += 1;
|
|
}
|
|
dst += SCREEN_WIDTH - _resMan->getUint16(f->width);
|
|
}
|
|
}
|
|
|
|
l += _resMan->getUint16(f->width);
|
|
|
|
if (!SwordEngine::_systemVars.isDemo)
|
|
l -= OVERLAP;
|
|
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
void Control::renderTexts() {
|
|
char string[40];
|
|
|
|
for (int i = 0; i < SAVEBUTTONS - 6; i++) {
|
|
Common::sprintf_s(string, "%d", _firstDescription + i + 1);
|
|
if (_slabSelected == i + 1) {
|
|
renderRedText((const uint8 *)string, saveButtons[i].x1 + 12, saveButtons[i].y1 + 5);
|
|
renderRedText((const uint8 *)_fileDescriptions[_firstDescription + i], saveButtons[i].x1 + 42, saveButtons[i].y1 + 5);
|
|
} else {
|
|
renderText((const uint8 *)string, saveButtons[i].x1 + 12, saveButtons[i].y1 + 5);
|
|
renderText((const uint8 *)_fileDescriptions[_firstDescription + i], saveButtons[i].x1 + 42, saveButtons[i].y1 + 5);
|
|
}
|
|
}
|
|
}
|
|
|
|
int32 Control::getTextLength(const uint8 *str, bool useSpeechFont) {
|
|
int32 i;
|
|
int32 l;
|
|
FrameHeader *f;
|
|
Sprite *srFont;
|
|
|
|
if (useSpeechFont) {
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
srFont = (Sprite *)_resMan->fetchRes(CZECH_GAME_FONT);
|
|
} else {
|
|
srFont = (Sprite *)_resMan->fetchRes(GAME_FONT);
|
|
}
|
|
} else {
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_DEATHSCREEN) {
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
srFont = (Sprite *)_resMan->fetchRes(CZECH_SR_DEATHFONT);
|
|
} else {
|
|
srFont = (Sprite *)_resMan->fetchRes(_resMan->getDeathFontId());
|
|
}
|
|
} else {
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
srFont = (Sprite *)_resMan->fetchRes(CZECH_SR_FONT);
|
|
} else {
|
|
srFont = (Sprite *)_resMan->fetchRes(SR_FONT);
|
|
}
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
l = 0;
|
|
|
|
while (str[i] != 0) {
|
|
f = (FrameHeader *)((uint8 *)srFont + _resMan->getUint32(srFont->spriteOffset[str[i] - 32]));
|
|
l += _resMan->getUint16(f->width);
|
|
|
|
if (!SwordEngine::_systemVars.isDemo)
|
|
l -= useSpeechFont ? SP_OVERLAP : OVERLAP;
|
|
|
|
i += 1;
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
void Control::putButton(int32 x, int32 y, int32 index) {
|
|
uint8 *src, *dst;
|
|
FrameHeader *f;
|
|
Sprite *srButton;
|
|
|
|
srButton = (Sprite *)_resMan->fetchRes(SR_BUTTON);
|
|
|
|
f = (FrameHeader *)((uint8 *)srButton + _resMan->getUint32(srButton->spriteOffset[index]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf + SCREEN_WIDTH * y + x;
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_BUTTON, src, dst, f);
|
|
} else {
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
for (int j = 0; j < _resMan->getUint16(f->width); j++)
|
|
if (*(src + j))
|
|
*(dst + j) = *(src + j);
|
|
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::putSpriteButton(Sprite *spr, int32 x, int32 y, int32 index) {
|
|
uint8 *src, *dst;
|
|
FrameHeader *f;
|
|
|
|
f = (FrameHeader *)((uint8 *)spr + _resMan->getUint32(spr->spriteOffset[index]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf + SCREEN_WIDTH * y + x;
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_BUTTON, src, dst, f);
|
|
} else {
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
for (int j = 0; j < _resMan->getUint16(f->width); j++)
|
|
if (*(src + j))
|
|
*(dst + j) = *(src + j);
|
|
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::putTextButton(int32 index) {
|
|
uint8 *src, *dst;
|
|
int32 x, y;
|
|
FrameHeader *f;
|
|
Sprite *srTextButton;
|
|
|
|
srTextButton = (Sprite *)_resMan->fetchRes(SR_TEXT_BUTTON);
|
|
|
|
x = 475;
|
|
y = 260;
|
|
|
|
f = (FrameHeader *)((uint8 *)srTextButton + _resMan->getUint32(srTextButton->spriteOffset[index]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf + SCREEN_WIDTH * y + x;
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_BUTTON, src, dst, f);
|
|
} else {
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
}
|
|
|
|
int32 Control::getCurrentButton(const Button b[]) {
|
|
for (int i = 0; i < _numButtons; i++) {
|
|
if ((_mouseCoord.x > b[i].x1) && (_mouseCoord.y - 40 > b[i].y1) &&
|
|
(_mouseCoord.x < b[i].x2) && (_mouseCoord.y - 40 < b[i].y2)) {
|
|
return i + 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void Control::initialiseConfirmation(const uint8 *title) {
|
|
uint8 *src, *dst;
|
|
FrameHeader *f;
|
|
Sprite *srConfirm;
|
|
|
|
srConfirm = (Sprite *)_resMan->openFetchRes(SR_CONFIRM);
|
|
|
|
f = (FrameHeader *)((uint8 *)srConfirm + _resMan->getUint32(srConfirm->spriteOffset[0]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf +
|
|
((SCREEN_WIDTH - _resMan->getUint16(f->width)) / 2) +
|
|
(SCREEN_WIDTH * ((SCREEN_DEPTH - _resMan->getUint16(f->height)) / 2));
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_CONFIRM, src, dst, f);
|
|
} else {
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
|
|
_resMan->resClose(SR_CONFIRM);
|
|
|
|
renderText(title, (SCREEN_WIDTH - getTextLength(title)) / 2, 120);
|
|
|
|
if (SwordEngine::_systemVars.snrStatus == SNR_DRIVEFULL) {
|
|
_numButtons = 1; // only top (OK) button used
|
|
} else {
|
|
_numButtons = 2;
|
|
}
|
|
|
|
for (int i = 0; i < _numButtons; i++)
|
|
putButton(confirmButtons[i].x1, confirmButtons[i].y1, 0);
|
|
|
|
renderText(_lStrings[STR_OK], SCREEN_WIDTH - confirmButtons[0].x1 - getTextLength(_lStrings[STR_OK]), confirmButtons[0].y1);
|
|
|
|
if (SwordEngine::_systemVars.snrStatus != SNR_DRIVEFULL)
|
|
renderText(_lStrings[STR_CANCEL], SCREEN_WIDTH - confirmButtons[1].x1 - getTextLength(_lStrings[STR_CANCEL]), confirmButtons[1].y1);
|
|
}
|
|
|
|
int32 Control::implementConfirmation() {
|
|
_currentButton = getCurrentButton(&confirmButtons[0]);
|
|
|
|
if ((_buttonPressed) && (!_currentButton)) {
|
|
// Reset button pressed
|
|
putButton(confirmButtons[_buttonPressed - 1].x1, confirmButtons[_buttonPressed - 1].y1, 0);
|
|
_buttonPressed = 0;
|
|
}
|
|
|
|
if (_mouseState != 0) {
|
|
if ((_mouseState & BS1L_BUTTON_DOWN) && (_currentButton)) {
|
|
// Set button pressed
|
|
_buttonPressed = _currentButton;
|
|
putButton(confirmButtons[_buttonPressed - 1].x1, confirmButtons[_buttonPressed - 1].y1, 1);
|
|
}
|
|
|
|
if ((_mouseState & BS1L_BUTTON_UP) && (_buttonPressed)) {
|
|
if (_buttonPressed == 1) {
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void Control::removeConfirmation() {
|
|
// Dummy in the original
|
|
}
|
|
|
|
void Control::renderVolumeLight(int32 i) {
|
|
uint8 *src, *dst;
|
|
uint8 vol[2] = { 0, 0 };
|
|
int32 x;
|
|
FrameHeader *f;
|
|
Sprite *srVlight;
|
|
|
|
switch (i) {
|
|
case 0:
|
|
vol[0] = _sound->_volMusic[0];
|
|
vol[1] = _sound->_volMusic[1];
|
|
x = 158;
|
|
break;
|
|
case 1:
|
|
vol[0] = _sound->_volSpeech[0];
|
|
vol[1] = _sound->_volSpeech[1];
|
|
x = 291;
|
|
break;
|
|
case 2:
|
|
vol[0] = _sound->_volFX[0];
|
|
vol[1] = _sound->_volFX[1];
|
|
x = 424;
|
|
break;
|
|
default:
|
|
x = 0;
|
|
break;
|
|
}
|
|
|
|
srVlight = (Sprite *)_resMan->fetchRes(SR_VLIGHT);
|
|
|
|
// Render left light
|
|
f = (FrameHeader *)((uint8 *)srVlight + _resMan->getUint32(srVlight->spriteOffset[vol[0]]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf + x + 211 * SCREEN_WIDTH;
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_BUTTON, src, dst, f);
|
|
} else {
|
|
for (int y = 0; y < _resMan->getUint16(f->height); y++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
|
|
// Render right light
|
|
f = (FrameHeader *)((uint8 *)srVlight + _resMan->getUint32(srVlight->spriteOffset[vol[1]]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf + x + 32 + 211 * SCREEN_WIDTH;
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_BUTTON, src, dst, f);
|
|
} else {
|
|
for (int y = 0; y < _resMan->getUint16(f->height); y++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::volUp(int32 i, int32 j) {
|
|
uint32 *vol = nullptr;
|
|
|
|
switch (i) {
|
|
case 0:
|
|
vol = &_sound->_volMusic[j];
|
|
break;
|
|
case 1:
|
|
vol = &_sound->_volSpeech[j];
|
|
break;
|
|
case 2:
|
|
vol = &_sound->_volFX[j];
|
|
break;
|
|
}
|
|
|
|
if (vol && *vol < 16)
|
|
*vol += 1;
|
|
}
|
|
|
|
void Control::volDown(int32 i, int32 j) {
|
|
uint32 *vol = nullptr;
|
|
|
|
switch (i) {
|
|
case 0:
|
|
vol = &_sound->_volMusic[j];
|
|
break;
|
|
case 1:
|
|
vol = &_sound->_volSpeech[j];
|
|
break;
|
|
case 2:
|
|
vol = &_sound->_volFX[j];
|
|
break;
|
|
}
|
|
|
|
if (vol && *vol > 0)
|
|
*vol -= 1;
|
|
}
|
|
|
|
void Control::renderVolumeDisc(int32 i, int32 j) {
|
|
uint8 *src, *dst;
|
|
int32 x = 0;
|
|
FrameHeader *f;
|
|
Sprite *srVnob;
|
|
|
|
switch (i) {
|
|
case 0:
|
|
x = VD1X;
|
|
break;
|
|
case 1:
|
|
x = VD2X;
|
|
break;
|
|
case 2:
|
|
x = VD3X;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
srVnob = (Sprite *)_resMan->fetchRes(SR_VKNOB);
|
|
|
|
// Render the disc
|
|
f = (FrameHeader *)((uint8 *)srVnob + _resMan->getUint32(srVnob->spriteOffset[j]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf + x + VDY * SCREEN_WIDTH;
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_BUTTON, src, dst, f);
|
|
} else {
|
|
for (int y = 0; y < _resMan->getUint16(f->height); y++) {
|
|
for (int z = 0; z < _resMan->getUint16(f->width); z++)
|
|
if (*(src + z))
|
|
*(dst + z) = *(src + z);
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::initialiseVolume() {
|
|
uint8 *src, *dst;
|
|
FrameHeader *f;
|
|
Sprite *srVolume;
|
|
|
|
_resMan->resOpen(SR_VLIGHT);
|
|
_resMan->resOpen(SR_VKNOB);
|
|
|
|
srVolume = (Sprite *)_resMan->openFetchRes(SR_VOLUME);
|
|
f = (FrameHeader *)((uint8 *)srVolume + _resMan->getUint32(srVolume->spriteOffset[0]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf +
|
|
((SCREEN_WIDTH - _resMan->getUint16(f->width)) / 2) +
|
|
(SCREEN_WIDTH * ((SCREEN_DEPTH - _resMan->getUint16(f->height)) / 2));
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_PANEL, src, dst, f);
|
|
} else {
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
|
|
_resMan->resClose(SR_VOLUME);
|
|
|
|
renderText(_lStrings[STR_MUSIC], 149, 39);
|
|
renderText(_lStrings[STR_SPEECH], (SCREEN_WIDTH - getTextLength(_lStrings[STR_SPEECH])) / 2, 39);
|
|
renderText(_lStrings[STR_FX], 438, 39);
|
|
_numButtons = 25;
|
|
putButton(volumeButtons[24].x1, volumeButtons[24].y1, 0);
|
|
|
|
renderText(_lStrings[STR_DONE], (volumeButtons[24].x1 - getTextLength(_lStrings[STR_DONE]) - 20), volumeButtons[24].y1);
|
|
|
|
renderVolumeLight(0);
|
|
renderVolumeLight(1);
|
|
renderVolumeLight(2);
|
|
|
|
renderVolumeDisc(0, 0);
|
|
renderVolumeDisc(1, 0);
|
|
renderVolumeDisc(2, 0);
|
|
}
|
|
|
|
void Control::implementVolume() {
|
|
int32 i, j;
|
|
|
|
_currentButton = getCurrentButton(&volumeButtons[0]);
|
|
|
|
if (_buttonPressed) {
|
|
if (!_currentButton) {
|
|
// Reset button pressed
|
|
if (_buttonPressed == 25)
|
|
putButton(volumeButtons[_buttonPressed - 1].x1, volumeButtons[_buttonPressed - 1].y1, 0);
|
|
|
|
_buttonPressed = 0;
|
|
} else {
|
|
if (_buttonPressed != 25) {
|
|
if (--_buttonHold == 0) {
|
|
_buttonHold = 4;
|
|
i = (_buttonPressed - 1) / 8;
|
|
j = _buttonPressed - i * 8;
|
|
|
|
switch (j) {
|
|
case 1:
|
|
volUp(i, 0);
|
|
volUp(i, 1);
|
|
break;
|
|
case 2:
|
|
volUp(i, 1);
|
|
break;
|
|
case 3:
|
|
volDown(i, 0);
|
|
volUp(i, 1);
|
|
break;
|
|
case 4:
|
|
volDown(i, 1);
|
|
break;
|
|
case 5:
|
|
volDown(i, 0);
|
|
volDown(i, 1);
|
|
break;
|
|
case 6:
|
|
volDown(i, 0);
|
|
break;
|
|
case 7:
|
|
volUp(i, 0);
|
|
volDown(i, 1);
|
|
break;
|
|
case 8:
|
|
volUp(i, 0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
renderVolumeLight(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_mouseState) {
|
|
if ((_mouseState & BS1L_BUTTON_DOWN) && (_currentButton)) {
|
|
// Set button pressed
|
|
_buttonPressed = _currentButton;
|
|
_buttonHold = 15;
|
|
|
|
if (_buttonPressed == 25) {
|
|
putButton(volumeButtons[_buttonPressed - 1].x1, volumeButtons[_buttonPressed - 1].y1, 1);
|
|
} else {
|
|
i = (_buttonPressed - 1) / 8;
|
|
j = _buttonPressed - i * 8;
|
|
renderVolumeDisc(i, _buttonPressed - i * 8);
|
|
|
|
switch (j) {
|
|
case 1:
|
|
volUp(i, 0);
|
|
volUp(i, 1);
|
|
break;
|
|
case 2:
|
|
volUp(i, 1);
|
|
break;
|
|
case 3:
|
|
volDown(i, 0);
|
|
volUp(i, 1);
|
|
break;
|
|
case 4:
|
|
volDown(i, 1);
|
|
break;
|
|
case 5:
|
|
volDown(i, 0);
|
|
volDown(i, 1);
|
|
break;
|
|
case 6:
|
|
volDown(i, 0);
|
|
break;
|
|
case 7:
|
|
volUp(i, 0);
|
|
volDown(i, 1);
|
|
break;
|
|
case 8:
|
|
volUp(i, 0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
renderVolumeLight(i);
|
|
}
|
|
}
|
|
|
|
if (_mouseState & BS1L_BUTTON_UP) {
|
|
if (_buttonPressed) {
|
|
if (_buttonPressed == 25) {
|
|
SwordEngine::_systemVars.snrStatus = SNR_MAINPANEL;
|
|
} else {
|
|
i = (_buttonPressed - 1) / 8;
|
|
renderVolumeDisc(i, 0);
|
|
}
|
|
|
|
_buttonPressed = 0;
|
|
} else {
|
|
// Avoid stuck volume discs
|
|
renderVolumeDisc(0, 0);
|
|
renderVolumeDisc(1, 0);
|
|
renderVolumeDisc(2, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::removeVolume() {
|
|
_resMan->resClose(SR_VLIGHT);
|
|
_resMan->resClose(SR_VKNOB);
|
|
}
|
|
|
|
void Control::renderScrolls() {
|
|
uint8 *src, *dst;
|
|
FrameHeader *f;
|
|
Sprite *srScroll1, *srScroll2;
|
|
|
|
srScroll1 = (Sprite *)_resMan->fetchRes(SR_SCROLL1);
|
|
srScroll2 = (Sprite *)_resMan->fetchRes(SR_SCROLL2);
|
|
|
|
f = (FrameHeader *)((uint8 *)srScroll1 + _resMan->getUint32(srScroll1->spriteOffset[_scrollIndex[0]]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf + SCROLL1X + SCREEN_WIDTH * SCROLL1Y;
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_CONFIRM, src, dst, f);
|
|
} else {
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
|
|
f = (FrameHeader *)((uint8 *)srScroll2 + _resMan->getUint32(srScroll2->spriteOffset[_scrollIndex[1]]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf + SCROLL2X + SCREEN_WIDTH * SCROLL2Y;
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_CONFIRM, src, dst, f);
|
|
} else {
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::initialiseSpeed() {
|
|
uint8 *src, *dst;
|
|
FrameHeader *f;
|
|
Sprite *srSpeed;
|
|
|
|
_resMan->resOpen(SR_SCROLL1);
|
|
_resMan->resOpen(SR_SCROLL2);
|
|
|
|
srSpeed = (Sprite *)_resMan->openFetchRes(SR_SPEED);
|
|
|
|
f = (FrameHeader *)((uint8 *)srSpeed + _resMan->getUint32(srSpeed->spriteOffset[0]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf +
|
|
((SCREEN_WIDTH - _resMan->getUint16(f->width)) / 2) +
|
|
(SCREEN_WIDTH * ((SCREEN_DEPTH - _resMan->getUint16(f->height)) / 2));
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_PANEL, src, dst, f);
|
|
} else {
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
|
|
_resMan->resClose(SR_SPEED);
|
|
|
|
_scrollIndex[0] = 0;
|
|
_scrollIndex[1] = 0;
|
|
|
|
renderText(_lStrings[STR_SPEED], 216, 100);
|
|
_numButtons = 3;
|
|
putButton(speedButtons[0].x1, speedButtons[0].y1, _speedFlag);
|
|
putButton(speedButtons[1].x1, speedButtons[1].y1, 1 - _speedFlag);
|
|
putButton(speedButtons[2].x1, speedButtons[2].y1, 0);
|
|
|
|
renderText(_lStrings[STR_DONE], (speedButtons[2].x1 - getTextLength(_lStrings[STR_DONE]) - 20), speedButtons[2].y1);
|
|
renderScrolls();
|
|
}
|
|
|
|
void Control::implementSpeed() {
|
|
Sprite *srScroll1, *srScroll2;
|
|
|
|
srScroll1 = (Sprite *)_resMan->fetchRes(SR_SCROLL1);
|
|
srScroll2 = (Sprite *)_resMan->fetchRes(SR_SCROLL2);
|
|
|
|
if (++_scrollIndex[0] == (int32)_resMan->getUint32(srScroll1->totalSprites))
|
|
_scrollIndex[0] = 0;
|
|
if (++_scrollIndex[1] == (int32)_resMan->getUint32(srScroll2->totalSprites))
|
|
_scrollIndex[1] = 0;
|
|
|
|
renderScrolls();
|
|
|
|
_currentButton = getCurrentButton(&speedButtons[0]);
|
|
|
|
if ((_buttonPressed == 3) && (!_currentButton)) {
|
|
//Reset button pressed
|
|
putButton(speedButtons[_buttonPressed - 1].x1, speedButtons[_buttonPressed - 1].y1, 0);
|
|
_buttonPressed = 0;
|
|
}
|
|
|
|
if (_mouseState) {
|
|
if ((_mouseState & BS1L_BUTTON_DOWN) && (_currentButton)) {
|
|
//Set button pressed
|
|
_buttonPressed = _currentButton;
|
|
if (_buttonPressed == 3) {
|
|
putButton(speedButtons[2].x1, speedButtons[2].y1, 1);
|
|
} else {
|
|
if (_speedFlag == _buttonPressed - 1) {
|
|
_speedFlag = 2 - _buttonPressed;
|
|
putButton(speedButtons[0].x1, speedButtons[0].y1, _speedFlag);
|
|
putButton(speedButtons[1].x1, speedButtons[1].y1, 1 - _speedFlag);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((_mouseState & BS1L_BUTTON_UP) && (_buttonPressed)) {
|
|
if (_buttonPressed == 3) {
|
|
SwordEngine::_systemVars.snrStatus = SNR_MAINPANEL;
|
|
}
|
|
|
|
_buttonPressed = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::removeSpeed() {
|
|
_resMan->resClose(SR_SCROLL1);
|
|
_resMan->resClose(SR_SCROLL2);
|
|
|
|
SwordEngine::_systemVars.parallaxOn = 1 - _speedFlag;
|
|
}
|
|
|
|
int16 Control::readFileDescriptions() {
|
|
char saveName[40];
|
|
Common::String pattern = "sword1.???";
|
|
Common::StringArray filenames = _saveFileMan->listSavefiles(pattern);
|
|
sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically...)
|
|
|
|
int16 totalFiles = 0;
|
|
int slotNum = 0;
|
|
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
|
|
// Obtain the last 3 digits of the filename, since they correspond to the save slot
|
|
slotNum = atoi(file->c_str() + file->size() - 3);
|
|
|
|
while (totalFiles < slotNum) {
|
|
Common::strcpy_s((char *)_fileDescriptions[totalFiles], 1, "");
|
|
totalFiles++;
|
|
}
|
|
|
|
if (slotNum >= 0 && slotNum < MAXSAVEGAMES) {
|
|
Common::InSaveFile *in = _saveFileMan->openForLoading(*file);
|
|
if (in) {
|
|
in->readUint32LE(); // header
|
|
in->read(saveName, 40);
|
|
Common::strcpy_s((char *)_fileDescriptions[totalFiles], sizeof(_fileDescriptions[totalFiles]), saveName);
|
|
delete in;
|
|
}
|
|
|
|
totalFiles++;
|
|
}
|
|
}
|
|
|
|
for (int i = totalFiles; i < MAXSAVEGAMES; i++)
|
|
Common::strcpy_s((char *)_fileDescriptions[i], 1, "");
|
|
|
|
return totalFiles;
|
|
}
|
|
|
|
void Control::setEditDescription(int32 line) {
|
|
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
|
|
|
|
_editingDescription = line;
|
|
_textCursor = 0;
|
|
_curCharCount = 1;
|
|
|
|
Common::strcpy_s(_oldString, sizeof(_oldString), (const char *)_fileDescriptions[_editingDescription + _firstDescription - 1]);
|
|
_slabSelected = line;
|
|
}
|
|
|
|
bool Control::driveSpaceAvailable() {
|
|
char fName[15];
|
|
int slot = _firstDescription + _editingDescription - 1;
|
|
Common::sprintf_s(fName, "sword1.%03d", slot);
|
|
|
|
// We are going to write a fake savegame file, to see if
|
|
// we are actually able to write anything with that size.
|
|
// Why are we even doing this? Can't we save right now?
|
|
// Turns out: no; we need to save at the end of getPlayerOptions(),
|
|
// after some clean-up operations are carried out. Right now,
|
|
// we only want to know if we are even able to save.
|
|
Common::OutSaveFile *outf;
|
|
outf = _saveFileMan->openForSaving(fName, false);
|
|
if (!outf) {
|
|
return false;
|
|
}
|
|
|
|
int sizeOfFakeSavegame = 30000;
|
|
outf->writeUint32LE(SAVEGAME_HEADER);
|
|
outf->write(_fileDescriptions[slot], 40);
|
|
outf->writeByte(SAVEGAME_VERSION);
|
|
|
|
for (int i = 0; i < sizeOfFakeSavegame; i++)
|
|
outf->writeByte(i % 256);
|
|
|
|
outf->finalize();
|
|
|
|
if (outf->err())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Control::attemptSave() {
|
|
// If this slot already has a savegame, or there's enough space for a new savegame
|
|
if (strlen(_oldString) || driveSpaceAvailable()) {
|
|
_selectedSavegame = _firstDescription + _editingDescription - 1;
|
|
if (_firstDescription + _editingDescription > _gamesSaved)
|
|
_gamesSaved = _firstDescription + _editingDescription;
|
|
|
|
uneditDescription();
|
|
|
|
SwordEngine::_systemVars.saveGameFlag = SGF_SAVE;
|
|
SwordEngine::_systemVars.snrStatus = SNR_BLANK;
|
|
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Control::editDescription() {
|
|
char string[40];
|
|
int32 len;
|
|
int32 index;
|
|
|
|
if (_keyPressed.keycode) {
|
|
uint16 ch = _keyPressed.ascii;
|
|
_keyPressed.reset();
|
|
|
|
index = _editingDescription + _firstDescription - 1;
|
|
len = Common::strnlen((char *)_fileDescriptions[index], sizeof(_fileDescriptions[index]));
|
|
if ((ch != CR) && (ch != ESCAPE)) {
|
|
if ((ch >= FIRSTFONTCHAR) && (ch <= LASTFONTCHAR)) {
|
|
if ((len < 32) && (getTextLength((const uint8 *)_fileDescriptions[index]) < 310)) {
|
|
_fileDescriptions[index][len] = ch;
|
|
_fileDescriptions[index][len + 1] = '\0';
|
|
_curCharCount = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ch == BACKSPACE) {
|
|
if (len) {
|
|
_fileDescriptions[index][len - 1] = '\0';
|
|
_curCharCount = 1;
|
|
}
|
|
}
|
|
|
|
if ((ch == ESCAPE) || (ch == CR)) {
|
|
if ((ch == ESCAPE) || ((ch == CR) && (len == 0))) {
|
|
_textCursor = 1;
|
|
_curCharCount = 10;
|
|
Common::strcpy_s((char *)_fileDescriptions[index], sizeof(_fileDescriptions[index]), _oldString);
|
|
uneditDescription();
|
|
} else {
|
|
if (!attemptSave())
|
|
SwordEngine::_systemVars.snrStatus = SNR_DRIVEFULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SwordEngine::_systemVars.snrStatus != SNR_BLANK) {
|
|
if (--_curCharCount == 0) {
|
|
_curCharCount = 10;
|
|
_textCursor ^= 1;
|
|
if (_textCursor) {
|
|
// Add cursor to line
|
|
Common::strcpy_s(string, sizeof(string), (const char *)_fileDescriptions[_editingDescription + _firstDescription - 1]);
|
|
len = strlen(string);
|
|
string[len] = '_';
|
|
string[len + 1] = '\0';
|
|
} else {
|
|
// Remove cursor from line
|
|
Common::strcpy_s(string, sizeof(string), (const char *)_fileDescriptions[_editingDescription + _firstDescription - 1]);
|
|
}
|
|
|
|
renderSlab(_slabSelected - 1, _editingDescription - 1);
|
|
renderRedText((const uint8 *)string, saveButtons[_editingDescription - 1].x1 + 42, saveButtons[_editingDescription - 1].y1 + 5);
|
|
Common::sprintf_s(string, sizeof(string), "%d", _firstDescription + _editingDescription);
|
|
renderRedText((const uint8 *)string, saveButtons[_editingDescription - 1].x1 + 12, saveButtons[_editingDescription - 1].y1 + 5);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::restoreSelected() {
|
|
if (_keyPressed.keycode) {
|
|
char ch = _keyPressed.ascii;
|
|
_keyPressed.reset();
|
|
|
|
if ((ch == ESCAPE) || (ch == CR)) {
|
|
if (ch == ESCAPE) {
|
|
uneditDescription();
|
|
} else {
|
|
// Restore the game here
|
|
_selectedSavegame = _editingDescription + _firstDescription - 1;
|
|
uneditDescription();
|
|
SwordEngine::_systemVars.saveGameFlag = SGF_RESTORE;
|
|
SwordEngine::_systemVars.snrStatus = SNR_BLANK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::uneditDescription(void) {
|
|
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
|
|
|
|
_slabSelected = 0;
|
|
|
|
renderSlabs();
|
|
renderTexts();
|
|
_textCursor = 0;
|
|
_editingDescription = 0;
|
|
}
|
|
|
|
bool Control::saveGame() {
|
|
if (Common::strnlen((char *)_fileDescriptions[_selectedSavegame], sizeof(_fileDescriptions[_selectedSavegame]) > 0)) {
|
|
saveGameToFile(_selectedSavegame);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Control::initialiseSave() {
|
|
uint8 *src, *dst;
|
|
int32 size;
|
|
FrameHeader *f;
|
|
Sprite *srWindow;
|
|
Sprite *srButuf, *srButus, *srButds, *srButdf;
|
|
Sprite *srSlab1, *srSlab2, *srSlab3, *srSlab4;
|
|
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH)
|
|
_resMan->resOpen(CZECH_SR_REDFONT);
|
|
else
|
|
_resMan->resOpen(SR_REDFONT);
|
|
|
|
srWindow = (Sprite *)_resMan->openFetchRes(SR_WINDOW);
|
|
|
|
f = (FrameHeader *)((uint8 *)srWindow + _resMan->getUint32(srWindow->spriteOffset[0]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf +
|
|
((SCREEN_WIDTH - _resMan->getUint16(f->width)) / 2) +
|
|
(SCREEN_WIDTH * ((SCREEN_DEPTH - _resMan->getUint16(f->height)) / 2));
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_PANEL, src, dst, f);
|
|
} else {
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
|
|
_resMan->resClose(SR_WINDOW);
|
|
|
|
_numButtons = SAVEBUTTONS;
|
|
putButton(saveButtons[SAVEBUTTONS - 2].x1, saveButtons[SAVEBUTTONS - 2].y1, 0);
|
|
putButton(saveButtons[SAVEBUTTONS - 1].x1, saveButtons[SAVEBUTTONS - 1].y1, 0);
|
|
|
|
srButuf = (Sprite *)_resMan->openFetchRes(SR_BUTUF);
|
|
putSpriteButton(srButuf, saveButtons[SAVEBUTTONS - 6].x1, saveButtons[SAVEBUTTONS - 6].y1, 0);
|
|
_resMan->resClose(SR_BUTUF);
|
|
|
|
srButus = (Sprite *)_resMan->openFetchRes(SR_BUTUS);
|
|
putSpriteButton(srButus, saveButtons[SAVEBUTTONS - 5].x1, saveButtons[SAVEBUTTONS - 5].y1, 0);
|
|
_resMan->resClose(SR_BUTUS);
|
|
|
|
srButds = (Sprite *)_resMan->openFetchRes(SR_BUTDS);
|
|
putSpriteButton(srButds, saveButtons[SAVEBUTTONS - 4].x1, saveButtons[SAVEBUTTONS - 4].y1, 0);
|
|
_resMan->resClose(SR_BUTDS);
|
|
|
|
srButdf = (Sprite *)_resMan->openFetchRes(SR_BUTDF);
|
|
putSpriteButton(srButdf, saveButtons[SAVEBUTTONS - 3].x1, saveButtons[SAVEBUTTONS - 3].y1, 0);
|
|
_resMan->resClose(SR_BUTDF);
|
|
|
|
renderText(_lStrings[STR_SAVE], saveButtons[SAVEBUTTONS - 2].x1 + 40, saveButtons[SAVEBUTTONS - 2].y1);
|
|
renderText(_lStrings[STR_CANCEL], saveButtons[SAVEBUTTONS - 1].x1 - 15 - getTextLength(_lStrings[STR_CANCEL]), saveButtons[SAVEBUTTONS - 1].y1);
|
|
|
|
_gamesSaved = readFileDescriptions();
|
|
|
|
// Create the slabs here
|
|
srSlab1 = (Sprite *)_resMan->openFetchRes(SR_SLAB1);
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
f = (FrameHeader *)((uint8 *)srSlab1 + _resMan->getUint32(srSlab1->spriteOffset[0]));
|
|
size = sizeof(Sprite) + sizeof(FrameHeader) + _resMan->getUint16(f->width) / 2 * _resMan->getUint16(f->height);
|
|
f = (FrameHeader *)((uint8 *)srSlab1 + _resMan->getUint32(srSlab1->spriteOffset[1]));
|
|
size += (sizeof(FrameHeader) + _resMan->getUint16(f->width) / 2 * _resMan->getUint16(f->height));
|
|
} else {
|
|
f = (FrameHeader *)((uint8 *)srSlab1 + _resMan->getUint32(srSlab1->spriteOffset[0]));
|
|
size = sizeof(Sprite) + sizeof(FrameHeader) + _resMan->getUint16(f->width) * _resMan->getUint16(f->height);
|
|
f = (FrameHeader *)((uint8 *)srSlab1 + _resMan->getUint32(srSlab1->spriteOffset[1]));
|
|
size += (sizeof(FrameHeader) + _resMan->getUint16(f->width) * _resMan->getUint16(f->height));
|
|
}
|
|
|
|
for (int i = 0; i < SAVEBUTTONS - 6; i++) {
|
|
_slabs[i] = (Sprite *)malloc(size);
|
|
}
|
|
|
|
memcpy((uint8 *)_slabs[0], (uint8 *)srSlab1, size);
|
|
memcpy((uint8 *)_slabs[4], (uint8 *)srSlab1, size);
|
|
_resMan->resClose(SR_SLAB1);
|
|
|
|
srSlab2 = (Sprite *)_resMan->openFetchRes(SR_SLAB2);
|
|
memcpy((uint8 *)_slabs[1], (uint8 *)srSlab2, size);
|
|
memcpy((uint8 *)_slabs[5], (uint8 *)srSlab2, size);
|
|
_resMan->resClose(SR_SLAB2);
|
|
|
|
srSlab3 = (Sprite *)_resMan->openFetchRes(SR_SLAB3);
|
|
memcpy((uint8 *)_slabs[2], (uint8 *)srSlab3, size);
|
|
memcpy((uint8 *)_slabs[6], (uint8 *)srSlab3, size);
|
|
_resMan->resClose(SR_SLAB3);
|
|
|
|
srSlab4 = (Sprite *)_resMan->openFetchRes(SR_SLAB4);
|
|
memcpy((uint8 *)_slabs[3], (uint8 *)srSlab4, size);
|
|
memcpy((uint8 *)_slabs[7], (uint8 *)srSlab4, size);
|
|
_resMan->resClose(SR_SLAB4);
|
|
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
|
|
void Control::implementSave() {
|
|
Sprite *srButuf, *srButus, *srButds, *srButdf;
|
|
|
|
_currentButton = getCurrentButton(&saveButtons[0]);
|
|
|
|
if ((_buttonPressed) && (!_currentButton)) {
|
|
// Reset button pressed
|
|
if (_buttonPressed > SAVEBUTTONS - 6) {
|
|
switch (_buttonPressed) {
|
|
case (SAVEBUTTONS - 5):
|
|
srButuf = (Sprite *)_resMan->openFetchRes(SR_BUTUF);
|
|
putSpriteButton(srButuf, saveButtons[SAVEBUTTONS - 6].x1, saveButtons[SAVEBUTTONS - 6].y1, 0);
|
|
_resMan->resClose(SR_BUTUF);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 4):
|
|
srButus = (Sprite *)_resMan->openFetchRes(SR_BUTUS);
|
|
putSpriteButton(srButus, saveButtons[SAVEBUTTONS - 5].x1, saveButtons[SAVEBUTTONS - 5].y1, 0);
|
|
_resMan->resClose(SR_BUTUS);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 3):
|
|
srButds = (Sprite *)_resMan->openFetchRes(SR_BUTDS);
|
|
putSpriteButton(srButds, saveButtons[SAVEBUTTONS - 4].x1, saveButtons[SAVEBUTTONS - 4].y1, 0);
|
|
_resMan->resClose(SR_BUTDS);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 2):
|
|
srButdf = (Sprite *)_resMan->openFetchRes(SR_BUTDF);
|
|
putSpriteButton(srButdf, saveButtons[SAVEBUTTONS - 3].x1, saveButtons[SAVEBUTTONS - 3].y1, 0);
|
|
_resMan->resClose(SR_BUTDF);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 1):
|
|
case (SAVEBUTTONS):
|
|
putButton(saveButtons[_buttonPressed - 1].x1, saveButtons[_buttonPressed - 1].y1, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
_buttonPressed = 0;
|
|
}
|
|
|
|
// Enhancement! Scrollable savegames list! :-)
|
|
bool useWheelScroll = false;
|
|
if (_mouseState && _currentButton >= 1 && _currentButton <= 8) {
|
|
if (_mouseState & BS1_WHEEL_DOWN) {
|
|
_buttonPressed = (SAVEBUTTONS - 3);
|
|
useWheelScroll = true;
|
|
} else if (_mouseState & BS1_WHEEL_UP) {
|
|
_buttonPressed = (SAVEBUTTONS - 4);
|
|
useWheelScroll = true;
|
|
}
|
|
}
|
|
|
|
if (_mouseState) {
|
|
if ((useWheelScroll || (_mouseState & BS1L_BUTTON_DOWN)) && (_currentButton)) {
|
|
// Set button pressed
|
|
if (!useWheelScroll)
|
|
_buttonPressed = _currentButton;
|
|
|
|
if (_buttonPressed) {
|
|
if (_buttonPressed > SAVEBUTTONS - 6) {
|
|
switch (_buttonPressed) {
|
|
case (SAVEBUTTONS - 5):
|
|
srButuf = (Sprite *)_resMan->openFetchRes(SR_BUTUF);
|
|
putSpriteButton(srButuf, saveButtons[SAVEBUTTONS - 6].x1, saveButtons[SAVEBUTTONS - 6].y1, 1);
|
|
_resMan->resClose(SR_BUTUF);
|
|
|
|
if (!_editingDescription) {
|
|
_scroll = 1;
|
|
_scrollCount = 10;
|
|
if (_firstDescription > 0) {
|
|
if (_firstDescription - (SAVEBUTTONS - 6) < 0)
|
|
_firstDescription = 0;
|
|
else
|
|
_firstDescription -= (SAVEBUTTONS - 6);
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
}
|
|
|
|
break;
|
|
case (SAVEBUTTONS - 4):
|
|
// Don't render the button as pressed when using wheel scrolling
|
|
if (!useWheelScroll) {
|
|
srButus = (Sprite *)_resMan->openFetchRes(SR_BUTUS);
|
|
putSpriteButton(srButus, saveButtons[SAVEBUTTONS - 5].x1, saveButtons[SAVEBUTTONS - 5].y1, 1);
|
|
_resMan->resClose(SR_BUTUS);
|
|
}
|
|
|
|
if (!_editingDescription) {
|
|
_scroll = 2;
|
|
_scrollCount = 10;
|
|
if (_firstDescription > 0) {
|
|
_firstDescription -= 1;
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
}
|
|
|
|
break;
|
|
case (SAVEBUTTONS - 3):
|
|
// Don't render the button as pressed when using wheel scrolling
|
|
if (!useWheelScroll) {
|
|
srButds = (Sprite *)_resMan->openFetchRes(SR_BUTDS);
|
|
putSpriteButton(srButds, saveButtons[SAVEBUTTONS - 4].x1, saveButtons[SAVEBUTTONS - 4].y1, 1);
|
|
_resMan->resClose(SR_BUTDS);
|
|
}
|
|
|
|
if (!_editingDescription) {
|
|
_scroll = 3;
|
|
_scrollCount = 10;
|
|
if (_firstDescription < MAXSAVEGAMES - (SAVEBUTTONS - 6)) {
|
|
_firstDescription += 1;
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
}
|
|
|
|
break;
|
|
case (SAVEBUTTONS - 2):
|
|
srButdf = (Sprite *)_resMan->openFetchRes(SR_BUTDF);
|
|
putSpriteButton(srButdf, saveButtons[SAVEBUTTONS - 3].x1, saveButtons[SAVEBUTTONS - 3].y1, 1);
|
|
_resMan->resClose(SR_BUTDF);
|
|
|
|
if (!_editingDescription) {
|
|
_scroll = 4;
|
|
_scrollCount = 10;
|
|
if (_firstDescription < MAXSAVEGAMES - (SAVEBUTTONS - 6)) {
|
|
if (_firstDescription + (SAVEBUTTONS - 6) > MAXSAVEGAMES - (SAVEBUTTONS - 6))
|
|
_firstDescription = MAXSAVEGAMES - (SAVEBUTTONS - 6);
|
|
else
|
|
_firstDescription += (SAVEBUTTONS - 6);
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
}
|
|
|
|
break;
|
|
case (SAVEBUTTONS - 1):
|
|
case (SAVEBUTTONS):
|
|
putButton(saveButtons[_buttonPressed - 1].x1, saveButtons[_buttonPressed - 1].y1, 1);
|
|
break;
|
|
}
|
|
} else {
|
|
if (_editingDescription) {
|
|
if (_buttonPressed != _editingDescription) {
|
|
Common::strcpy_s(
|
|
(char *)_fileDescriptions[_editingDescription + _firstDescription - 1],
|
|
sizeof(_fileDescriptions[_editingDescription + _firstDescription - 1]),
|
|
_oldString);
|
|
_slabSelected = 0;
|
|
uneditDescription();
|
|
|
|
setEditDescription(_buttonPressed);
|
|
}
|
|
} else {
|
|
setEditDescription(_buttonPressed);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (useWheelScroll)
|
|
_scroll = 0;
|
|
|
|
if ((_mouseState & BS1L_BUTTON_UP) && (_buttonPressed)) {
|
|
if (_buttonPressed > SAVEBUTTONS - 6) {
|
|
switch (_buttonPressed) {
|
|
case (SAVEBUTTONS - 5):
|
|
srButuf = (Sprite *)_resMan->openFetchRes(SR_BUTUF);
|
|
putSpriteButton(srButuf, saveButtons[SAVEBUTTONS - 6].x1, saveButtons[SAVEBUTTONS - 6].y1, 0);
|
|
_resMan->resClose(SR_BUTUF);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 4):
|
|
srButus = (Sprite *)_resMan->openFetchRes(SR_BUTUS);
|
|
putSpriteButton(srButus, saveButtons[SAVEBUTTONS - 5].x1, saveButtons[SAVEBUTTONS - 5].y1, 0);
|
|
_resMan->resClose(SR_BUTUS);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 3):
|
|
srButds = (Sprite *)_resMan->openFetchRes(SR_BUTDS);
|
|
putSpriteButton(srButds, saveButtons[SAVEBUTTONS - 4].x1, saveButtons[SAVEBUTTONS - 4].y1, 0);
|
|
_resMan->resClose(SR_BUTDS);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 2):
|
|
srButdf = (Sprite *)_resMan->openFetchRes(SR_BUTDF);
|
|
putSpriteButton(srButdf, saveButtons[SAVEBUTTONS - 3].x1, saveButtons[SAVEBUTTONS - 3].y1, 0);
|
|
_resMan->resClose(SR_BUTDF);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 1):
|
|
putButton(saveButtons[SAVEBUTTONS - 2].x1, saveButtons[SAVEBUTTONS - 1].y1, 0);
|
|
if ((_editingDescription) && (strlen((char *)_fileDescriptions[_editingDescription + _firstDescription - 1]))) {
|
|
if (!attemptSave())
|
|
SwordEngine::_systemVars.snrStatus = SNR_DRIVEFULL;
|
|
}
|
|
break;
|
|
case (SAVEBUTTONS):
|
|
putButton(saveButtons[SAVEBUTTONS - 1].x1, saveButtons[SAVEBUTTONS - 1].y1, 0);
|
|
if (_editingDescription)
|
|
uneditDescription();
|
|
SwordEngine::_systemVars.snrStatus = SNR_MAINPANEL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
_buttonPressed = 0;
|
|
}
|
|
}
|
|
|
|
if (_scroll) {
|
|
if (--_scrollCount == 0) {
|
|
|
|
_scrollCount = 2;
|
|
|
|
switch (_scroll) {
|
|
case 1:
|
|
if (_firstDescription > 0) {
|
|
if (_firstDescription - (SAVEBUTTONS - 6) < 0)
|
|
_firstDescription = 0;
|
|
else
|
|
_firstDescription -= (SAVEBUTTONS - 6);
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
break;
|
|
case 2:
|
|
if (_firstDescription > 0) {
|
|
_firstDescription -= 1;
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
break;
|
|
case 3:
|
|
if (_firstDescription < MAXSAVEGAMES - (SAVEBUTTONS - 6)) {
|
|
_firstDescription += 1;
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
break;
|
|
case 4:
|
|
if (_firstDescription < MAXSAVEGAMES - (SAVEBUTTONS - 6)) {
|
|
if (_firstDescription + (SAVEBUTTONS - 6) > MAXSAVEGAMES - (SAVEBUTTONS - 6))
|
|
_firstDescription = MAXSAVEGAMES - (SAVEBUTTONS - 6);
|
|
else
|
|
_firstDescription += (SAVEBUTTONS - 6);
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_editingDescription)
|
|
editDescription();
|
|
}
|
|
|
|
void Control::removeSave() {
|
|
for (int i = 0; i < ARRAYSIZE(_slabs); i++) {
|
|
free(_slabs[i]);
|
|
_slabs[i] = nullptr;
|
|
}
|
|
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
_resMan->resClose(CZECH_SR_REDFONT);
|
|
} else {
|
|
_resMan->resClose(SR_REDFONT);
|
|
}
|
|
|
|
_sound->setVolumes();
|
|
}
|
|
|
|
bool Control::restoreGame() {
|
|
if (_selectedSavegame < MAXSAVEGAMES) {
|
|
restoreGameFromFile(_selectedSavegame);
|
|
doRestore();
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Control::initialiseRestore() {
|
|
uint8 *src, *dst;
|
|
int32 size;
|
|
FrameHeader *f;
|
|
Sprite *srWindow;
|
|
Sprite *srButuf, *srButus, *srButds, *srButdf;
|
|
Sprite *srSlab1, *srSlab2, *srSlab3, *srSlab4;
|
|
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH)
|
|
_resMan->resOpen(CZECH_SR_REDFONT);
|
|
else
|
|
_resMan->resOpen(SR_REDFONT);
|
|
|
|
srWindow = (Sprite *)_resMan->openFetchRes(SR_WINDOW);
|
|
|
|
f = (FrameHeader *)((uint8 *)srWindow + _resMan->getUint32(srWindow->spriteOffset[0]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = _screenBuf +
|
|
((SCREEN_WIDTH - _resMan->getUint16(f->width)) / 2) +
|
|
(SCREEN_WIDTH * ((SCREEN_DEPTH - _resMan->getUint16(f->height)) / 2));
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
drawPsxComponent(PSX_PANEL, src, dst, f);
|
|
} else {
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
src += _resMan->getUint16(f->width);
|
|
dst += SCREEN_WIDTH;
|
|
}
|
|
}
|
|
|
|
_resMan->resClose(SR_WINDOW);
|
|
|
|
_numButtons = SAVEBUTTONS;
|
|
putButton(saveButtons[SAVEBUTTONS - 2].x1, saveButtons[SAVEBUTTONS - 2].y1, 0);
|
|
putButton(saveButtons[SAVEBUTTONS - 1].x1, saveButtons[SAVEBUTTONS - 1].y1, 0);
|
|
|
|
srButuf = (Sprite *)_resMan->openFetchRes(SR_BUTUF);
|
|
putSpriteButton(srButuf, saveButtons[SAVEBUTTONS - 6].x1, saveButtons[SAVEBUTTONS - 6].y1, 0);
|
|
_resMan->resClose(SR_BUTUF);
|
|
|
|
srButus = (Sprite *)_resMan->openFetchRes(SR_BUTUS);
|
|
putSpriteButton(srButus, saveButtons[SAVEBUTTONS - 5].x1, saveButtons[SAVEBUTTONS - 5].y1, 0);
|
|
_resMan->resClose(SR_BUTUS);
|
|
|
|
srButds = (Sprite *)_resMan->openFetchRes(SR_BUTDS);
|
|
putSpriteButton(srButds, saveButtons[SAVEBUTTONS - 4].x1, saveButtons[SAVEBUTTONS - 4].y1, 0);
|
|
_resMan->resClose(SR_BUTDS);
|
|
|
|
srButdf = (Sprite *)_resMan->openFetchRes(SR_BUTDF);
|
|
putSpriteButton(srButdf, saveButtons[SAVEBUTTONS - 3].x1, saveButtons[SAVEBUTTONS - 3].y1, 0);
|
|
_resMan->resClose(SR_BUTDF);
|
|
|
|
renderText(_lStrings[STR_RESTORE], saveButtons[SAVEBUTTONS - 2].x1 + 40, saveButtons[SAVEBUTTONS - 2].y1);
|
|
renderText(_lStrings[STR_CANCEL], saveButtons[SAVEBUTTONS - 1].x1 - 15 - getTextLength(_lStrings[STR_CANCEL]), saveButtons[SAVEBUTTONS - 1].y1);
|
|
|
|
_gamesSaved = readFileDescriptions();
|
|
|
|
// Create the slabs here
|
|
srSlab1 = (Sprite *)_resMan->openFetchRes(SR_SLAB1);
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
f = (FrameHeader *)((uint8 *)srSlab1 + _resMan->getUint32(srSlab1->spriteOffset[0]));
|
|
size = sizeof(Sprite) + sizeof(FrameHeader) + _resMan->getUint16(f->width) / 2 * _resMan->getUint16(f->height);
|
|
f = (FrameHeader *)((uint8 *)srSlab1 + _resMan->getUint32(srSlab1->spriteOffset[1]));
|
|
size += (sizeof(FrameHeader) + _resMan->getUint16(f->width) / 2 * _resMan->getUint16(f->height));
|
|
} else {
|
|
f = (FrameHeader *)((uint8 *)srSlab1 + _resMan->getUint32(srSlab1->spriteOffset[0]));
|
|
size = sizeof(Sprite) + sizeof(FrameHeader) + _resMan->getUint16(f->width) * _resMan->getUint16(f->height);
|
|
f = (FrameHeader *)((uint8 *)srSlab1 + _resMan->getUint32(srSlab1->spriteOffset[1]));
|
|
size += (sizeof(FrameHeader) + _resMan->getUint16(f->width) * _resMan->getUint16(f->height));
|
|
}
|
|
|
|
for (int i = 0; i < SAVEBUTTONS - 6; i++) {
|
|
_slabs[i] = (Sprite *)malloc(size);
|
|
}
|
|
|
|
memcpy((uint8 *)_slabs[0], (uint8 *)srSlab1, size);
|
|
memcpy((uint8 *)_slabs[4], (uint8 *)srSlab1, size);
|
|
_resMan->resClose(SR_SLAB1);
|
|
|
|
srSlab2 = (Sprite *)_resMan->openFetchRes(SR_SLAB2);
|
|
memcpy((uint8 *)_slabs[1], (uint8 *)srSlab2, size);
|
|
memcpy((uint8 *)_slabs[5], (uint8 *)srSlab2, size);
|
|
_resMan->resClose(SR_SLAB2);
|
|
|
|
srSlab3 = (Sprite *)_resMan->openFetchRes(SR_SLAB3);
|
|
memcpy((uint8 *)_slabs[2], (uint8 *)srSlab3, size);
|
|
memcpy((uint8 *)_slabs[6], (uint8 *)srSlab3, size);
|
|
_resMan->resClose(SR_SLAB3);
|
|
|
|
srSlab4 = (Sprite *)_resMan->openFetchRes(SR_SLAB4);
|
|
memcpy((uint8 *)_slabs[3], (uint8 *)srSlab4, size);
|
|
memcpy((uint8 *)_slabs[7], (uint8 *)srSlab4, size);
|
|
_resMan->resClose(SR_SLAB4);
|
|
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
|
|
void Control::implementRestore() {
|
|
char string[40];
|
|
|
|
Sprite *srButuf, *srButus, *srButds, *srButdf;
|
|
|
|
_currentButton = getCurrentButton(&saveButtons[0]);
|
|
|
|
if ((_buttonPressed) && (!_currentButton)) {
|
|
//Reset button pressed
|
|
if (_buttonPressed > SAVEBUTTONS - 6) {
|
|
switch (_buttonPressed) {
|
|
case (SAVEBUTTONS - 5):
|
|
srButuf = (Sprite *)_resMan->openFetchRes(SR_BUTUF);
|
|
putSpriteButton(srButuf, saveButtons[SAVEBUTTONS - 6].x1, saveButtons[SAVEBUTTONS - 6].y1, 0);
|
|
_resMan->resClose(SR_BUTUF);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 4):
|
|
srButus = (Sprite *)_resMan->openFetchRes(SR_BUTUS);
|
|
putSpriteButton(srButus, saveButtons[SAVEBUTTONS - 5].x1, saveButtons[SAVEBUTTONS - 5].y1, 0);
|
|
_resMan->resClose(SR_BUTUS);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 3):
|
|
srButds = (Sprite *)_resMan->openFetchRes(SR_BUTDS);
|
|
putSpriteButton(srButds, saveButtons[SAVEBUTTONS - 4].x1, saveButtons[SAVEBUTTONS - 4].y1, 0);
|
|
_resMan->resClose(SR_BUTDS);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 2):
|
|
srButdf = (Sprite *)_resMan->openFetchRes(SR_BUTDF);
|
|
putSpriteButton(srButdf, saveButtons[SAVEBUTTONS - 3].x1, saveButtons[SAVEBUTTONS - 3].y1, 0);
|
|
_resMan->resClose(SR_BUTDF);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 1):
|
|
case (SAVEBUTTONS):
|
|
putButton(saveButtons[_buttonPressed - 1].x1, saveButtons[_buttonPressed - 1].y1, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
_buttonPressed = 0;
|
|
}
|
|
|
|
// Enhancement! Scrollable savegames list! :-)
|
|
bool useWheelScroll = false;
|
|
if (_mouseState && _currentButton >= 1 && _currentButton <= 8) {
|
|
if (_mouseState & BS1_WHEEL_DOWN) {
|
|
_buttonPressed = (SAVEBUTTONS - 3);
|
|
useWheelScroll = true;
|
|
} else if (_mouseState & BS1_WHEEL_UP) {
|
|
_buttonPressed = (SAVEBUTTONS - 4);
|
|
useWheelScroll = true;
|
|
}
|
|
}
|
|
|
|
if (_mouseState) {
|
|
if ((useWheelScroll || (_mouseState & BS1L_BUTTON_DOWN)) && (_currentButton)) {
|
|
// Set button pressed
|
|
if (!useWheelScroll)
|
|
_buttonPressed = _currentButton;
|
|
|
|
if (_buttonPressed) {
|
|
if (_buttonPressed > SAVEBUTTONS - 6) {
|
|
switch (_buttonPressed) {
|
|
case (SAVEBUTTONS - 5):
|
|
srButuf = (Sprite *)_resMan->openFetchRes(SR_BUTUF);
|
|
putSpriteButton(srButuf, saveButtons[SAVEBUTTONS - 6].x1, saveButtons[SAVEBUTTONS - 6].y1, 1);
|
|
_resMan->resClose(SR_BUTUF);
|
|
|
|
if (_editingDescription) {
|
|
uneditDescription();
|
|
}
|
|
|
|
_scroll = 1;
|
|
_scrollCount = 10;
|
|
if (_firstDescription > 0) {
|
|
if (_firstDescription - (SAVEBUTTONS - 6) < 0)
|
|
_firstDescription = 0;
|
|
else
|
|
_firstDescription -= (SAVEBUTTONS - 6);
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
|
|
break;
|
|
case (SAVEBUTTONS - 4):
|
|
// Don't render the button as pressed when using wheel scrolling
|
|
if (!useWheelScroll) {
|
|
srButus = (Sprite *)_resMan->openFetchRes(SR_BUTUS);
|
|
putSpriteButton(srButus, saveButtons[SAVEBUTTONS - 5].x1, saveButtons[SAVEBUTTONS - 5].y1, 1);
|
|
_resMan->resClose(SR_BUTUS);
|
|
}
|
|
|
|
if (_editingDescription) {
|
|
uneditDescription();
|
|
}
|
|
|
|
_scroll = 2;
|
|
_scrollCount = 10;
|
|
if (_firstDescription > 0) {
|
|
_firstDescription -= 1;
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
|
|
break;
|
|
case (SAVEBUTTONS - 3):
|
|
// Don't render the button as pressed when using wheel scrolling
|
|
if (!useWheelScroll) {
|
|
srButds = (Sprite *)_resMan->openFetchRes(SR_BUTDS);
|
|
putSpriteButton(srButds, saveButtons[SAVEBUTTONS - 4].x1, saveButtons[SAVEBUTTONS - 4].y1, 1);
|
|
_resMan->resClose(SR_BUTDS);
|
|
}
|
|
|
|
if (_editingDescription) {
|
|
uneditDescription();
|
|
}
|
|
|
|
_scroll = 3;
|
|
_scrollCount = 10;
|
|
if (_firstDescription < MAXSAVEGAMES - (SAVEBUTTONS - 6)) {
|
|
_firstDescription += 1;
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
|
|
break;
|
|
case (SAVEBUTTONS - 2):
|
|
srButdf = (Sprite *)_resMan->openFetchRes(SR_BUTDF);
|
|
putSpriteButton(srButdf, saveButtons[SAVEBUTTONS - 3].x1, saveButtons[SAVEBUTTONS - 3].y1, 1);
|
|
_resMan->resClose(SR_BUTDF);
|
|
|
|
if (_editingDescription) {
|
|
uneditDescription();
|
|
}
|
|
|
|
_scroll = 4;
|
|
_scrollCount = 10;
|
|
if (_firstDescription < MAXSAVEGAMES - (SAVEBUTTONS - 6)) {
|
|
if (_firstDescription + (SAVEBUTTONS - 6) > MAXSAVEGAMES - (SAVEBUTTONS - 6))
|
|
_firstDescription = MAXSAVEGAMES - (SAVEBUTTONS - 6);
|
|
else
|
|
_firstDescription += (SAVEBUTTONS - 6);
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
|
|
break;
|
|
case (SAVEBUTTONS - 1):
|
|
case (SAVEBUTTONS):
|
|
putButton(saveButtons[_buttonPressed - 1].x1, saveButtons[_buttonPressed - 1].y1, 1);
|
|
break;
|
|
}
|
|
} else {
|
|
if (_editingDescription) {
|
|
if ((_buttonPressed != _editingDescription) && (strlen((char *)_fileDescriptions[_buttonPressed + _firstDescription - 1]))) {
|
|
Common::strcpy_s(_fileDescriptions[_editingDescription + _firstDescription - 1], _oldString);
|
|
_slabSelected = 0;
|
|
uneditDescription();
|
|
|
|
setEditDescription(_buttonPressed);
|
|
|
|
renderSlab(_slabSelected - 1, _editingDescription - 1);
|
|
Common::strcpy_s(string, (char *)_fileDescriptions[_editingDescription + _firstDescription - 1]);
|
|
renderRedText((const uint8 *)string, saveButtons[_editingDescription - 1].x1 + 42, saveButtons[_editingDescription - 1].y1 + 5);
|
|
Common::sprintf_s(string, "%d", _firstDescription + _editingDescription);
|
|
renderRedText((const uint8 *)string, saveButtons[_editingDescription - 1].x1 + 12, saveButtons[_editingDescription - 1].y1 + 5);
|
|
}
|
|
} else {
|
|
if (strlen((char *)_fileDescriptions[_buttonPressed + _firstDescription - 1])) {
|
|
setEditDescription(_buttonPressed);
|
|
renderSlab(_slabSelected - 1, _editingDescription - 1);
|
|
Common::strcpy_s(string, (char *)_fileDescriptions[_editingDescription + _firstDescription - 1]);
|
|
renderRedText((const uint8 *)string, saveButtons[_editingDescription - 1].x1 + 42, saveButtons[_editingDescription - 1].y1 + 5);
|
|
Common::sprintf_s(string, "%d", _firstDescription + _editingDescription);
|
|
renderRedText((const uint8 *)string, saveButtons[_editingDescription - 1].x1 + 12, saveButtons[_editingDescription - 1].y1 + 5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (useWheelScroll)
|
|
_scroll = 0;
|
|
|
|
if ((_mouseState & BS1L_BUTTON_UP) && (_buttonPressed)) {
|
|
if (_buttonPressed > SAVEBUTTONS - 6) {
|
|
switch (_buttonPressed) {
|
|
case (SAVEBUTTONS - 5):
|
|
srButuf = (Sprite *)_resMan->openFetchRes(SR_BUTUF);
|
|
putSpriteButton(srButuf, saveButtons[SAVEBUTTONS - 6].x1, saveButtons[SAVEBUTTONS - 6].y1, 0);
|
|
_resMan->resClose(SR_BUTUF);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 4):
|
|
srButus = (Sprite *)_resMan->openFetchRes(SR_BUTUS);
|
|
putSpriteButton(srButus, saveButtons[SAVEBUTTONS - 5].x1, saveButtons[SAVEBUTTONS - 5].y1, 0);
|
|
_resMan->resClose(SR_BUTUS);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 3):
|
|
srButds = (Sprite *)_resMan->openFetchRes(SR_BUTDS);
|
|
putSpriteButton(srButds, saveButtons[SAVEBUTTONS - 4].x1, saveButtons[SAVEBUTTONS - 4].y1, 0);
|
|
_resMan->resClose(SR_BUTDS);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 2):
|
|
srButdf = (Sprite *)_resMan->openFetchRes(SR_BUTDF);
|
|
putSpriteButton(srButdf, saveButtons[SAVEBUTTONS - 3].x1, saveButtons[SAVEBUTTONS - 3].y1, 0);
|
|
_resMan->resClose(SR_BUTDF);
|
|
_scroll = 0;
|
|
break;
|
|
case (SAVEBUTTONS - 1):
|
|
putButton(saveButtons[SAVEBUTTONS - 2].x1, saveButtons[SAVEBUTTONS - 1].y1, 0);
|
|
if ((_editingDescription) && (strlen((char *)_fileDescriptions[_editingDescription + _firstDescription - 1]))) {
|
|
//Restore game here
|
|
_selectedSavegame = _firstDescription + _editingDescription - 1;
|
|
//Common::sprintf_s(saveFilename, "savegame.%.3d", _firstDescription + _editingDescription - 1);
|
|
uneditDescription();
|
|
SwordEngine::_systemVars.saveGameFlag = SGF_RESTORE;
|
|
SwordEngine::_systemVars.snrStatus = SNR_BLANK;
|
|
}
|
|
break;
|
|
case (SAVEBUTTONS):
|
|
putButton(saveButtons[SAVEBUTTONS - 1].x1, saveButtons[SAVEBUTTONS - 1].y1, 0);
|
|
if (_editingDescription)
|
|
uneditDescription();
|
|
SwordEngine::_systemVars.snrStatus = SNR_MAINPANEL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
_buttonPressed = 0;
|
|
}
|
|
}
|
|
|
|
if (_scroll) {
|
|
if (--_scrollCount == 0) {
|
|
_scrollCount = 2;
|
|
|
|
switch (_scroll) {
|
|
case 1:
|
|
if (_firstDescription > 0) {
|
|
if (_firstDescription - (SAVEBUTTONS - 6) < 0)
|
|
_firstDescription = 0;
|
|
else
|
|
_firstDescription -= (SAVEBUTTONS - 6);
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
break;
|
|
case 2:
|
|
if (_firstDescription > 0) {
|
|
_firstDescription -= 1;
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
break;
|
|
case 3:
|
|
if (_firstDescription < MAXSAVEGAMES - (SAVEBUTTONS - 6)) {
|
|
_firstDescription += 1;
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
break;
|
|
case 4:
|
|
if (_firstDescription < MAXSAVEGAMES - (SAVEBUTTONS - 6)) {
|
|
if (_firstDescription + (SAVEBUTTONS - 6) > MAXSAVEGAMES - (SAVEBUTTONS - 6))
|
|
_firstDescription = MAXSAVEGAMES - (SAVEBUTTONS - 6);
|
|
else
|
|
_firstDescription += (SAVEBUTTONS - 6);
|
|
renderSlabs();
|
|
renderTexts();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_editingDescription)
|
|
restoreSelected();
|
|
}
|
|
|
|
void Control::removeRestore() {
|
|
for (int i = 0; i < ARRAYSIZE(_slabs); i++) {
|
|
free(_slabs[i]);
|
|
_slabs[i] = nullptr;
|
|
}
|
|
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
_resMan->resClose(CZECH_SR_REDFONT);
|
|
} else {
|
|
_resMan->resClose(SR_REDFONT);
|
|
}
|
|
|
|
_sound->setVolumes();
|
|
}
|
|
|
|
void Control::initialiseControlPanel() {
|
|
uint8 *src;
|
|
uint8 *dst;
|
|
FrameHeader *f;
|
|
Sprite *srPanel = nullptr;
|
|
|
|
_resMan->resOpen(SR_TEXT_BUTTON);
|
|
_mouse->controlPanel(true);
|
|
|
|
// Clear the render buffer and copy the control panel into it
|
|
memset(_screenBuf, 0, SCREEN_WIDTH * SCREEN_FULL_DEPTH);
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_FULL_DEPTH);
|
|
|
|
if (SwordEngine::_systemVars.controlPanelMode != CP_DEATHSCREEN) { // NOT THE DEATH SCREEN ie. start game panel, normal control panel, or end of game
|
|
switch (SwordEngine::_systemVars.language) {
|
|
case BS1_ENGLISH:
|
|
if (!SwordEngine::isPsx() && SwordEngine::_systemVars.realLanguage == Common::EN_USA) {
|
|
srPanel = (Sprite *)_resMan->openFetchRes(SR_PANEL_AMERICAN);
|
|
} else {
|
|
srPanel = (Sprite *)_resMan->openFetchRes(SR_PANEL_ENGLISH);
|
|
}
|
|
|
|
break;
|
|
case BS1_FRENCH:
|
|
srPanel = (Sprite *)_resMan->openFetchRes(SR_PANEL_FRENCH);
|
|
break;
|
|
case BS1_GERMAN:
|
|
srPanel = (Sprite *)_resMan->openFetchRes(SR_PANEL_GERMAN);
|
|
break;
|
|
case BS1_ITALIAN:
|
|
srPanel = (Sprite *)_resMan->openFetchRes(SR_PANEL_ITALIAN);
|
|
break;
|
|
case BS1_SPANISH:
|
|
srPanel = (Sprite *)_resMan->openFetchRes(SR_PANEL_SPANISH);
|
|
break;
|
|
case BS1_CZECH:
|
|
srPanel = (Sprite *)_resMan->openFetchRes(SR_PANEL_SPANISH);
|
|
break;
|
|
case BS1_PORT:
|
|
srPanel = (Sprite *)_resMan->openFetchRes(SR_PANEL_SPANISH);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
srPanel = (Sprite *)_resMan->openFetchRes(SR_DEATHPANEL);
|
|
}
|
|
|
|
if (srPanel) {
|
|
f = (FrameHeader *)((uint8 *)srPanel + _resMan->getUint32(srPanel->spriteOffset[0]));
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
|
|
if (SwordEngine::isPsx()) {
|
|
int component = SwordEngine::_systemVars.controlPanelMode == CP_DEATHSCREEN ? PSX_DEATHPANEL : PSX_PANEL;
|
|
dst = _screenBuf +
|
|
SCREEN_WIDTH * (SCREEN_DEPTH - _resMan->getUint16(f->height)) / 2 +
|
|
(SCREEN_WIDTH - _resMan->getUint16(f->width)) / 2;
|
|
|
|
if (component == PSX_DEATHPANEL)
|
|
dst = _screenBuf;
|
|
|
|
drawPsxComponent(component, src, dst, f);
|
|
} else {
|
|
dst = _screenBuf + SCREEN_WIDTH * (SCREEN_DEPTH - _resMan->getUint16(f->height)) / 2 + (SCREEN_WIDTH - _resMan->getUint16(f->width)) / 2;
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
memcpy(dst, src, _resMan->getUint16(f->width));
|
|
dst += SCREEN_WIDTH;
|
|
src += _resMan->getUint16(f->width);
|
|
}
|
|
}
|
|
|
|
_system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
|
|
}
|
|
|
|
if (SwordEngine::_systemVars.controlPanelMode != CP_DEATHSCREEN) {
|
|
switch (SwordEngine::_systemVars.language) {
|
|
case BS1_ENGLISH:
|
|
if (SwordEngine::_systemVars.realLanguage == Common::EN_USA) {
|
|
_resMan->resClose(SR_PANEL_AMERICAN);
|
|
} else {
|
|
_resMan->resClose(SR_PANEL_ENGLISH);
|
|
}
|
|
|
|
break;
|
|
case BS1_FRENCH:
|
|
_resMan->resClose(SR_PANEL_FRENCH);
|
|
break;
|
|
case BS1_GERMAN:
|
|
_resMan->resClose(SR_PANEL_GERMAN);
|
|
break;
|
|
case BS1_ITALIAN:
|
|
_resMan->resClose(SR_PANEL_ITALIAN);
|
|
break;
|
|
case BS1_SPANISH:
|
|
_resMan->resClose(SR_PANEL_SPANISH);
|
|
break;
|
|
case BS1_CZECH:
|
|
_resMan->resClose(SR_PANEL_SPANISH);
|
|
break;
|
|
case BS1_PORT:
|
|
_resMan->resClose(SR_PANEL_SPANISH);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
_resMan->resClose(SR_DEATHPANEL);
|
|
}
|
|
|
|
// Draw the buttons...
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_NORMAL) {
|
|
_numButtons = 8;
|
|
|
|
for (int i = 0; i < _numButtons; i++) {
|
|
putButton(panelButtons[i].x1, panelButtons[i].y1, 0);
|
|
}
|
|
|
|
putTextButton(SwordEngine::_systemVars.showText ? 1 : 0);
|
|
} else {
|
|
_numButtons = 4;
|
|
|
|
for (int i = 1; i < _numButtons; i++) {
|
|
putButton(deathButtons[i].x1, deathButtons[i].y1, 0);
|
|
}
|
|
}
|
|
|
|
// Render text elements...
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_THEEND)
|
|
renderText(_lStrings[STR_THE_END], (SCREEN_WIDTH - getTextLength(_lStrings[STR_THE_END])) / 2, 188);
|
|
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_NORMAL) {
|
|
renderText(_lStrings[STR_SAVE], 180, 188);
|
|
renderText(_lStrings[STR_DONE], 460 - getTextLength(_lStrings[STR_DONE]), 332);
|
|
|
|
renderText(_lStrings[STR_RESTORE], 180, 224);
|
|
renderText(_lStrings[STR_RESTART], 180, 260);
|
|
renderText(_lStrings[STR_QUIT], 180, 296);
|
|
} else { // Start-game panel, death panel & end-game panel
|
|
renderText(_lStrings[STR_RESTORE], 285, 224);
|
|
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_NEWGAME) { // Start-game panel
|
|
renderText(_lStrings[STR_START], 285, 260);
|
|
} else {
|
|
renderText(_lStrings[STR_RESTART], 285, 260);
|
|
}
|
|
|
|
renderText(_lStrings[STR_QUIT], 285, 296);
|
|
}
|
|
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_NORMAL) {
|
|
renderText(_lStrings[STR_SPEED], 460 - getTextLength(_lStrings[STR_SPEED]), 188);
|
|
renderText(_lStrings[STR_VOLUME], 460 - getTextLength(_lStrings[STR_VOLUME]), 224);
|
|
renderText(_lStrings[STR_TEXT], 460 - getTextLength(_lStrings[STR_TEXT]), 260);
|
|
}
|
|
}
|
|
|
|
void Control::implementControlPanel() {
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_NORMAL) {
|
|
_currentButton = getCurrentButton(&panelButtons[0]);
|
|
} else {
|
|
_currentButton = getCurrentButton(&deathButtons[0]);
|
|
}
|
|
|
|
if ((_buttonPressed) && (!_currentButton)) {
|
|
// Reset button pressed
|
|
if (_buttonPressed != TEXTBUTTONID) {
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_NORMAL) {
|
|
putButton(panelButtons[_buttonPressed - 1].x1, panelButtons[_buttonPressed - 1].y1, 0);
|
|
} else {
|
|
putButton(deathButtons[_buttonPressed - 1].x1, deathButtons[_buttonPressed - 1].y1, 0);
|
|
}
|
|
}
|
|
|
|
_buttonPressed = 0;
|
|
}
|
|
|
|
if (_mouseState) {
|
|
if ((_mouseState & BS1L_BUTTON_DOWN) && (_currentButton)) {
|
|
// Set button pressed
|
|
_buttonPressed = _currentButton;
|
|
if (_buttonPressed != TEXTBUTTONID) {
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_NORMAL) {
|
|
putButton(panelButtons[_buttonPressed - 1].x1, panelButtons[_buttonPressed - 1].y1, 1);
|
|
} else {
|
|
putButton(deathButtons[_buttonPressed - 1].x1, deathButtons[_buttonPressed - 1].y1, 1);
|
|
}
|
|
} else {
|
|
SwordEngine::_systemVars.showText = !SwordEngine::_systemVars.showText;
|
|
putTextButton(SwordEngine::_systemVars.showText ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
if ((_mouseState & BS1L_BUTTON_UP) && (_buttonPressed)) {
|
|
SwordEngine::_systemVars.snrStatus = _buttonPressed + 1;
|
|
_buttonPressed = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::removeControlPanel() {
|
|
_resMan->resClose(SR_TEXT_BUTTON);
|
|
}
|
|
|
|
void Control::initialiseResources() {
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_DEATHSCREEN) {
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
_resMan->resOpen(CZECH_SR_DEATHFONT);
|
|
} else {
|
|
_resMan->resOpen(_resMan->getDeathFontId());
|
|
}
|
|
} else {
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
_resMan->resOpen(CZECH_SR_FONT);
|
|
} else {
|
|
_resMan->resOpen(SR_FONT);
|
|
}
|
|
}
|
|
|
|
_resMan->resOpen(SR_BUTTON);
|
|
|
|
_screen->fnSetFadeTargetPalette(0, 256, SR_PALETTE);
|
|
_screen->fnSetFadeTargetPalette(0, 1, 0, BORDER_BLACK);
|
|
}
|
|
|
|
void Control::releaseResources() {
|
|
_resMan->resClose(SR_BUTTON);
|
|
|
|
if (SwordEngine::_systemVars.controlPanelMode == CP_DEATHSCREEN) {
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
_resMan->resClose(CZECH_SR_DEATHFONT);
|
|
} else {
|
|
_resMan->resClose(_resMan->getDeathFontId());
|
|
}
|
|
} else {
|
|
if (SwordEngine::_systemVars.language == BS1_CZECH) {
|
|
_resMan->resClose(CZECH_SR_FONT);
|
|
} else {
|
|
_resMan->resClose(SR_FONT);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Control::delay(uint32 msecs) {
|
|
Common::Event event;
|
|
|
|
uint32 now = _system->getMillis();
|
|
uint32 endTime = now + msecs;
|
|
_keyPressed.reset();
|
|
_mouseState = 0;
|
|
|
|
do {
|
|
Common::EventManager *eventMan = _system->getEventManager();
|
|
while (eventMan->pollEvent(event)) {
|
|
switch (event.type) {
|
|
case Common::EVENT_KEYDOWN:
|
|
_keyPressed = event.kbd;
|
|
// we skip the rest of the delay and return immediately
|
|
// to handle keyboard input
|
|
return;
|
|
case Common::EVENT_MOUSEMOVE:
|
|
_mouseCoord = event.mouse;
|
|
break;
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
_mouseState |= BS1L_BUTTON_DOWN;
|
|
_mouseCoord = event.mouse;
|
|
break;
|
|
case Common::EVENT_LBUTTONUP:
|
|
_mouseState |= BS1L_BUTTON_UP;
|
|
_mouseCoord = event.mouse;
|
|
break;
|
|
case Common::EVENT_WHEELUP:
|
|
_mouseState |= BS1_WHEEL_UP;
|
|
_mouseCoord = event.mouse;
|
|
break;
|
|
case Common::EVENT_WHEELDOWN:
|
|
_mouseState |= BS1_WHEEL_DOWN;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
_screen->_screenAccessMutex.lock();
|
|
_system->updateScreen();
|
|
_screen->_screenAccessMutex.unlock();
|
|
|
|
_system->delayMillis(10);
|
|
} while (_system->getMillis() < endTime);
|
|
}
|
|
|
|
uint8 *Control::decompressPsxGfx(uint8 *src, FrameHeader *f) {
|
|
uint8 *dst = (uint8 *)malloc(_resMan->getUint16(f->height) * _resMan->getUint16(f->width));
|
|
memset(dst, 0, _resMan->getUint16(f->height) * _resMan->getUint16(f->width));
|
|
Screen::decompressHIF(src, dst);
|
|
return dst;
|
|
}
|
|
|
|
void Control::drawPsxComponent(int componentType, uint8 *src, uint8 *dst, FrameHeader *f) {
|
|
src = decompressPsxGfx(src, f);
|
|
uint8 *initialPtr = src;
|
|
|
|
switch (componentType) {
|
|
case PSX_PANEL:
|
|
case PSX_SLAB:
|
|
// Draw the source image at double the resolution
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
for (int j = 0; j < _resMan->getUint16(f->width) / 2; j++) {
|
|
if (src[j]) {
|
|
dst[j * 2] = src[j];
|
|
dst[j * 2 + 1] = src[j];
|
|
}
|
|
}
|
|
|
|
dst += SCREEN_WIDTH;
|
|
|
|
for (int j = 0; j < _resMan->getUint16(f->width) / 2; j++) {
|
|
if (src[j]) {
|
|
dst[j * 2] = src[j];
|
|
dst[j * 2 + 1] = src[j];
|
|
}
|
|
}
|
|
|
|
dst += SCREEN_WIDTH;
|
|
|
|
src += _resMan->getUint16(f->width) / 2;
|
|
}
|
|
|
|
break;
|
|
case PSX_DEATHPANEL:
|
|
// The PSX death panel is 1/3 of the original width, so adjust for that...
|
|
for (int i = 0; i < _resMan->getUint16(f->height) / 2; i++) {
|
|
for (int j = 0; (j < (_resMan->getUint16(f->width)) / 3) && (j < (SCREEN_WIDTH - 3)); j++) {
|
|
if (src[j]) {
|
|
dst[j * 3] = src[j];
|
|
dst[j * 3 + 1] = src[j];
|
|
dst[j * 3 + 2] = src[j];
|
|
}
|
|
}
|
|
|
|
dst += SCREEN_WIDTH;
|
|
|
|
for (int j = 0; j < (_resMan->getUint16(f->width)) / 3; j++) {
|
|
if (src[j]) {
|
|
dst[j * 3] = src[j];
|
|
dst[j * 3 + 1] = src[j];
|
|
dst[j * 3 + 2] = src[j];
|
|
}
|
|
}
|
|
|
|
dst += SCREEN_WIDTH;
|
|
src += _resMan->getUint16(f->width) / 3;
|
|
}
|
|
|
|
break;
|
|
case PSX_TEXT:
|
|
case PSX_BUTTON:
|
|
case PSX_CONFIRM:
|
|
case PSX_SCROLL:
|
|
for (int i = 0; i < _resMan->getUint16(f->height); i++) {
|
|
for (int j = 0; j < _resMan->getUint16(f->width); j++) {
|
|
if (src[j])
|
|
dst[j] = src[j];
|
|
}
|
|
|
|
dst += SCREEN_WIDTH;
|
|
|
|
for (int j = 0; j < _resMan->getUint16(f->width); j++) {
|
|
if (src[j])
|
|
dst[j] = src[j];
|
|
}
|
|
|
|
dst += SCREEN_WIDTH;
|
|
src += _resMan->getUint16(f->width);
|
|
}
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
|
|
free(initialPtr);
|
|
}
|
|
|
|
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::checkForOldSaveGames() {
|
|
Common::InSaveFile *inf = _saveFileMan->openForLoading("SAVEGAME.INF");
|
|
|
|
if (!inf)
|
|
return;
|
|
|
|
GUI::MessageDialog dialog0(
|
|
_("ScummVM found that you have old saved games for Broken Sword 1 that should be converted.\n"
|
|
"The old saved game format is no longer supported, so you will not be able to load your games if you don't convert them.\n\n"
|
|
"Press OK to convert them now, otherwise you will be asked again the next time you start the game.\n"), _("OK"), _("Cancel"));
|
|
|
|
int choice = dialog0.runModal();
|
|
if (choice != GUI::kMessageOK) {
|
|
// user pressed cancel
|
|
return;
|
|
}
|
|
|
|
// Convert every save slot we find in the index file to the new format
|
|
uint8 saveName[32];
|
|
uint8 slot = 0;
|
|
uint8 ch;
|
|
|
|
memset(saveName, 0, sizeof(saveName));
|
|
|
|
do {
|
|
uint8 pos = 0;
|
|
do {
|
|
ch = inf->readByte();
|
|
if (pos < sizeof(saveName) - 1) {
|
|
if ((ch == 10) || (ch == 255) || (inf->eos()))
|
|
saveName[pos++] = '\0';
|
|
else if (ch >= 32)
|
|
saveName[pos++] = ch;
|
|
}
|
|
} while ((ch != 10) && (ch != 255) && (!inf->eos()));
|
|
|
|
if (pos > 1) // if the slot has a description
|
|
convertSaveGame(slot, (char *)saveName);
|
|
slot++;
|
|
} while ((ch != 255) && (!inf->eos()));
|
|
|
|
delete inf;
|
|
|
|
// Delete index file
|
|
_saveFileMan->removeSavefile("SAVEGAME.INF");
|
|
}
|
|
|
|
void Control::saveGameToFile(uint8 slot) {
|
|
char fName[15];
|
|
uint16 cnt;
|
|
Common::sprintf_s(fName, "sword1.%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'. (%s)", fName, _saveFileMan->popErrorDesc().c_str());
|
|
return;
|
|
}
|
|
|
|
outf->writeUint32LE(SAVEGAME_HEADER);
|
|
outf->write(_fileDescriptions[slot], 40);
|
|
outf->writeByte(SAVEGAME_VERSION);
|
|
|
|
// Saving can occur either delayed from the GMM (in which case the panel is now shown and we can make
|
|
// a thumbnail now) or from the game menu (the panel, in which case we created the _tempThumbnail just
|
|
// before showing the panel).
|
|
if (!isPanelShown())
|
|
Graphics::saveThumbnail(*outf);
|
|
else if (_tempThumbnail)
|
|
outf->write(_tempThumbnail->getData(), _tempThumbnail->size());
|
|
|
|
// Date / time
|
|
TimeDate curTime;
|
|
_system->getTimeAndDate(curTime);
|
|
|
|
uint32 saveDate = (curTime.tm_mday & 0xFF) << 24 | ((curTime.tm_mon + 1) & 0xFF) << 16 | ((curTime.tm_year + 1900) & 0xFFFF);
|
|
uint16 saveTime = (curTime.tm_hour & 0xFF) << 8 | ((curTime.tm_min) & 0xFF);
|
|
|
|
outf->writeUint32BE(saveDate);
|
|
outf->writeUint16BE(saveTime);
|
|
|
|
outf->writeUint32BE(g_engine->getTotalPlayTime() / 1000);
|
|
|
|
_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->finalize();
|
|
if (outf->err())
|
|
displayMessage(0, "Couldn't write to file '%s'. Device full? (%s)", fName, _saveFileMan->popErrorDesc().c_str());
|
|
delete outf;
|
|
}
|
|
|
|
bool Control::restoreGameFromFile(uint8 slot) {
|
|
char fName[15];
|
|
uint16 cnt;
|
|
Common::sprintf_s(fName, "sword1.%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'. (%s)", fName, _saveFileMan->popErrorDesc().c_str());
|
|
return false;
|
|
}
|
|
|
|
uint saveHeader = inf->readUint32LE();
|
|
if (saveHeader != SAVEGAME_HEADER) {
|
|
// Display an error message, and do nothing
|
|
displayMessage(0, "Saved game '%s' is corrupt", fName);
|
|
return false;
|
|
}
|
|
|
|
inf->skip(40); // skip description
|
|
uint8 saveVersion = inf->readByte();
|
|
|
|
if (saveVersion > SAVEGAME_VERSION) {
|
|
warning("Different saved game version");
|
|
return false;
|
|
}
|
|
|
|
if (saveVersion < 2) // These older version of the savegames used a flag to signal presence of thumbnail
|
|
inf->skip(1);
|
|
|
|
Graphics::skipThumbnail(*inf);
|
|
|
|
inf->readUint32BE(); // save date
|
|
inf->readUint16BE(); // save time
|
|
|
|
if (saveVersion < 2) { // Before version 2 we didn't had play time feature
|
|
g_engine->setTotalPlayTime(0);
|
|
} else {
|
|
g_engine->setTotalPlayTime(inf->readUint32BE() * 1000);
|
|
}
|
|
|
|
_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->err() || inf->eos()) {
|
|
displayMessage(0, "Can't read from file '%s'. (%s)", fName, _saveFileMan->popErrorDesc().c_str());
|
|
delete inf;
|
|
free(_restoreBuf);
|
|
_restoreBuf = nullptr;
|
|
return false;
|
|
}
|
|
delete inf;
|
|
return true;
|
|
}
|
|
|
|
bool Control::convertSaveGame(uint8 slot, char *desc) {
|
|
char oldFileName[15];
|
|
char newFileName[40];
|
|
Common::sprintf_s(oldFileName, "SAVEGAME.%03d", slot);
|
|
Common::sprintf_s(newFileName, "sword1.%03d", slot);
|
|
uint8 *saveData;
|
|
int dataSize;
|
|
|
|
// Check if the new file already exists
|
|
Common::InSaveFile *testSave = _saveFileMan->openForLoading(newFileName);
|
|
|
|
if (testSave) {
|
|
delete testSave;
|
|
|
|
Common::U32String msg = Common::U32String::format(_("Target new saved game already exists!\n"
|
|
"Would you like to keep the old saved game (%s) or the new one (%s)?\n"),
|
|
oldFileName, newFileName);
|
|
GUI::MessageDialog dialog0(msg, _("Keep the old one"), _("Keep the new one"));
|
|
|
|
int choice = dialog0.runModal();
|
|
if (choice == GUI::kMessageAlt) {
|
|
// User chose to keep the new game, so delete the old one
|
|
_saveFileMan->removeSavefile(oldFileName);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Common::InSaveFile *oldSave = _saveFileMan->openForLoading(oldFileName);
|
|
if (!oldSave) {
|
|
// Display a warning message and do nothing
|
|
warning("Can't open file '%s'", oldFileName);
|
|
return false;
|
|
}
|
|
|
|
// Read data from old type of save game
|
|
dataSize = oldSave->size();
|
|
saveData = new uint8[dataSize];
|
|
oldSave->read(saveData, dataSize);
|
|
delete oldSave;
|
|
|
|
// Now write the save data to a new type of save game
|
|
Common::OutSaveFile *newSave;
|
|
newSave = _saveFileMan->openForSaving(newFileName);
|
|
if (!newSave) {
|
|
// Display a warning message and do nothing
|
|
warning("Unable to create file '%s'. (%s)", newFileName, _saveFileMan->popErrorDesc().c_str());
|
|
delete[] saveData;
|
|
saveData = nullptr;
|
|
return false;
|
|
}
|
|
|
|
newSave->writeUint32LE(SAVEGAME_HEADER);
|
|
newSave->write(desc, 40);
|
|
newSave->writeByte(SAVEGAME_VERSION);
|
|
|
|
// Date / time
|
|
TimeDate curTime;
|
|
_system->getTimeAndDate(curTime);
|
|
|
|
uint32 saveDate = (curTime.tm_mday & 0xFF) << 24 | ((curTime.tm_mon + 1) & 0xFF) << 16 | ((curTime.tm_year + 1900) & 0xFFFF);
|
|
uint16 saveTime = (curTime.tm_hour & 0xFF) << 8 | ((curTime.tm_min) & 0xFF);
|
|
|
|
newSave->writeUint32BE(saveDate);
|
|
newSave->writeUint16BE(saveTime);
|
|
newSave->writeUint32BE(0); // We don't have playtime info when converting, so we start from 0.
|
|
|
|
newSave->write(saveData, dataSize);
|
|
|
|
newSave->finalize();
|
|
if (newSave->err())
|
|
warning("Couldn't write to file '%s'. Device full?", newFileName);
|
|
delete newSave;
|
|
|
|
// Delete old save
|
|
_saveFileMan->removeSavefile(oldFileName);
|
|
|
|
// Cleanup
|
|
delete[] saveData;
|
|
saveData = nullptr;
|
|
return true;
|
|
}
|
|
|
|
void Control::doRestore() {
|
|
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;
|
|
}
|
|
|
|
bool Control::gameVersionIsAkella() {
|
|
if (SwordEngine::_systemVars.realLanguage == Common::RU_RUS) {
|
|
uint32 resId = _resMan->getDeathFontId();
|
|
return resId == SR_DEATHFONT;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Control::gameVersionIsMediaHouse() {
|
|
if (SwordEngine::_systemVars.realLanguage == Common::RU_RUS) {
|
|
uint32 resId = _resMan->getDeathFontId();
|
|
return resId == SR_FONT;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Control::loadCustomStrings(const char *filename) {
|
|
Common::File f;
|
|
|
|
if (f.open(filename)) {
|
|
Common::String line;
|
|
|
|
for (int lineNo = 0; lineNo < 20; lineNo++) {
|
|
line = f.readLine();
|
|
|
|
if (f.eos())
|
|
return false;
|
|
|
|
memset((void*)_customStrings[lineNo], 0, 43);
|
|
strncpy((char*)_customStrings[lineNo], line.c_str(), 42);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const uint8 *Control::getPauseString() {
|
|
if (SwordEngine::isPsx()) {
|
|
switch (SwordEngine::_systemVars.language) {
|
|
case BS1_ENGLISH:
|
|
return _psxPauseStrings[0];
|
|
case BS1_GERMAN:
|
|
case BS1_FRENCH:
|
|
return _psxPauseStrings[1];
|
|
case BS1_ITALIAN:
|
|
case BS1_SPANISH:
|
|
return _psxPauseStrings[2];
|
|
default:
|
|
return _psxPauseStrings[0];
|
|
}
|
|
}
|
|
|
|
return _lStrings[STR_PAUSED];
|
|
}
|
|
|
|
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",
|
|
"Annulla",
|
|
"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!",
|
|
};
|
|
|
|
// Russian versions
|
|
const uint8 Control::_akellaLanguageStrings[20][43] = {
|
|
"\x20\x20\x20\x20\x20\x20", // "PAUSED",
|
|
"\x93\x91\x92\x80\x8D\x8E\x82\x88\x92\x85\x20\x84\x88\x91\x8A\x2D", // "PLEASE INSERT CD-",
|
|
"\x45\x4E\x54\x45\x52\x2D\xAF\xE0\xAE\xA4\xAE\xAB\xA6\xA8\xE2\xEC", // "THEN PRESS A KEY",
|
|
"\x8D\x85\x82\x85\x90\x8D\x9B\x89\x20\x43\x44", // "INCORRECT CD",
|
|
"\x40", // "Save",
|
|
"\x7F", // "Restore",
|
|
"\xD7", // "Restart",
|
|
"\xD7", // "Start",
|
|
"\xD8", // "Quit",
|
|
"\xDD", // "Speed",
|
|
"\xDE", // "Volume",
|
|
"\xF7", // "Text",
|
|
"\xFE", // "Done",
|
|
"OK",
|
|
"\x8E\xE2\xAC\xA5\xAD\xA0", // "Cancel",
|
|
"\x20\x20\x20\x20\x20", // "Music",
|
|
"\x20\x20\x20\x20\x20", // "Speech",
|
|
"\x20\x20", // "Fx",
|
|
"\x8A\xAE\xAD\xA5\xE6", // "The End",
|
|
"DRIVE FULL!",
|
|
};
|
|
|
|
const uint8 Control::_mediaHouseLanguageStrings[20][43] = {
|
|
"\x8F\x80\x93\x87\x80", // "PAUSED",
|
|
"\x82\x91\x92\x80\x82\x9C\x92\x85\x20\x43\x44\x2D", // "PLEASE INSERT CD-",
|
|
"\x88\x20\x8D\x80\x86\x8C\x88\x92\x85\x20\x8B\x9E\x81\x93\x9E\x20\x8A\x8B\x80\x82\x88\x98\x93", // "THEN PRESS A KEY",
|
|
"\x8D\x85\x20\x92\x8E\x92\x20\x84\x88\x91\x8A", // "INCORRECT CD",
|
|
"\x91\xAE\xE5\x70\xA0\xAD\xA8\xE2\xEC", // "Save",
|
|
"\x87\xA0\xA3\x70\xE3\xA7\xA8\xE2\xEC", // "Restore",
|
|
"\x90\xA5\xE1\xE2\xA0\x70\xE2", // "Restart",
|
|
"\x91\xE2\xA0\x70\xE2", // "Start",
|
|
"\x82\xEB\xE5\xAE\xA4", // "Quit",
|
|
"\x91\xAA\xAE\x70\xAE\xE1\xE2\xEC", // "Speed",
|
|
"\x83\x70\xAE\xAC\xAA\xAE\xE1\xE2\xEC", // "Volume",
|
|
"\x92\xA5\xAA\xE1\xE2", // "Text",
|
|
"\x82\xE1\xA5", // "Done",
|
|
"\x8E\xAA", // "OK",
|
|
"\x8E\xE2\xAC\xA5\xAD\xA0", // "Cancel",
|
|
"\x8C\xE3\xA7\xEB\xAA\xA0", // "Music",
|
|
"\x83\xAE\xAB\xAE\xE1", // "Speech",
|
|
"\x87\xA2\xE3\xAA", // "Fx",
|
|
"\x8A\xAE\xAD\xA5\xE6\x00\x45\x20\x43\x44\x2D\x00", // "The End",
|
|
"DRIVE FULL!",
|
|
};
|
|
|
|
const uint8 Control::_polishTranslationLanguageStrings[20][43] = {
|
|
"GRA ZATRZYMANA", // "PAUSED",
|
|
"PROSZ\xCA W\xA3O\xAFY\xC6 P\xA3YT\xCA CD-", // "PLEASE INSERT CD-",
|
|
"I NACISN\xA1\xC6 DOWOLNY KLAWISZ", // "THEN PRESS A KEY",
|
|
"NIEPRAWID\xA3OWA P\xA3YTA CD", // "INCORRECT CD",
|
|
"Zapisz", // "Save",
|
|
"Wczytaj", // "Restore",
|
|
"Nowa gra", // "Restart",
|
|
"Start", // "Start",
|
|
"Wyjd\xBC", // "Quit",
|
|
"Pr\xEA""dko\xB6\xE6", // "Speed", the double pair of "" is to avoid escaping the d after \xEA
|
|
"G\xB3o\xB6no\xB6\xE6", // "Volume",
|
|
"Napisy", // "Text",
|
|
"Gotowe", // "Done",
|
|
"OK", // "OK",
|
|
"Anuluj", // "Cancel",
|
|
"Muzyka", // "Music",
|
|
"Mowa", // "Speech",
|
|
"Efekty", // "Fx",
|
|
"Koniec", // "The End",
|
|
"DYSK PE\xA3NY!" // "DRIVE FULL!"
|
|
};
|
|
|
|
/* ---------- PSX CREDITS CODE ---------- */
|
|
|
|
int32 Control::getCreditsStringLength(uint8 *str, uint8 *font) {
|
|
int32 width = 0;
|
|
FrameHeader *f;
|
|
|
|
while (*str) {
|
|
f = (FrameHeader *)_resMan->fetchFrame(font, *str - 32);
|
|
width += f->width;
|
|
str++;
|
|
|
|
if (*str)
|
|
width += PSX_CREDITS_SPACING;
|
|
}
|
|
|
|
return width;
|
|
}
|
|
|
|
int32 Control::getCreditsFontHeight(uint8 *font) {
|
|
FrameHeader *f;
|
|
|
|
f = (FrameHeader *)_resMan->fetchFrame(font, 'A' - 32);
|
|
return (f->height / 2);
|
|
}
|
|
|
|
void Control::createCreditsTextSprite(uint8 *data, int32 pitch, uint8 *str, uint8 *font) {
|
|
uint16 x = 0;
|
|
FrameHeader *f;
|
|
uint8 *src, *dst;
|
|
|
|
while (*str) {
|
|
f = (FrameHeader *)_resMan->fetchFrame(font, *str - 32);
|
|
|
|
src = (uint8 *)f + sizeof(FrameHeader);
|
|
dst = data + x;
|
|
|
|
for (int i = 0; i < f->height / 2; i++) {
|
|
memcpy(dst, src, f->width);
|
|
src += f->width;
|
|
dst += pitch;
|
|
}
|
|
|
|
x += (f->width + PSX_CREDITS_SPACING);
|
|
str++;
|
|
}
|
|
}
|
|
|
|
void Control::renderCreditsTextSprite(uint8 *data, uint8 *screenBuf, int16 x, int16 y, int16 width, int16 height) {
|
|
// Clip the coordinates like the PSX code would do
|
|
y = (y + 1) & 0xFFFE;
|
|
x -= 129;
|
|
y -= (128 - 56);
|
|
|
|
// Boundary checks
|
|
if (x >= SCREEN_WIDTH || y >= SCREEN_FULL_DEPTH)
|
|
return;
|
|
|
|
if (x + width <= 0 || y + height <= 0)
|
|
return;
|
|
|
|
// Are there rows outside the screen?
|
|
// Calculate how many doubled rows of the sprite are outside the screen on the top
|
|
int16 skippedDoubledRows = (y < 0) ? -y : 0;
|
|
int16 skippedRowsInData = skippedDoubledRows / 2;
|
|
|
|
data += width * skippedRowsInData; // Adjust data pointer based on the number of skipped rows in the sprite
|
|
height -= skippedDoubledRows; // Adjust height based on the number of skipped doubled rows
|
|
|
|
if (y < 0) {
|
|
y = 0;
|
|
}
|
|
|
|
uint8 *dst = screenBuf + x + SCREEN_WIDTH * y;
|
|
|
|
for (int i = 0; i < height; i += 2) { // Increment by 2 for the doubled height
|
|
// Boundary check for y
|
|
if (y + i >= SCREEN_FULL_DEPTH)
|
|
break;
|
|
|
|
// First horizontal line
|
|
for (int j = 0; j < width; j++) {
|
|
// Boundary checks for x
|
|
if (x + j < 0)
|
|
continue;
|
|
|
|
if (x + j >= SCREEN_WIDTH)
|
|
break;
|
|
|
|
if (data[j])
|
|
dst[j] = data[j];
|
|
}
|
|
|
|
dst += SCREEN_WIDTH;
|
|
|
|
// Second horizontal line (duplicated)
|
|
for (int j = 0; j < width; j++) {
|
|
// Boundary checks for x
|
|
if (x + j < 0)
|
|
continue;
|
|
|
|
if (x + j >= SCREEN_WIDTH)
|
|
break;
|
|
|
|
if (data[j])
|
|
dst[j] = data[j];
|
|
}
|
|
|
|
dst += SCREEN_WIDTH; // Move to the next line
|
|
data += width; // Move to the next row of source sprite
|
|
}
|
|
}
|
|
|
|
void Control::psxEndCredits() {
|
|
int16 h;
|
|
int16 nextCredit = PSX_NUM_CREDITS + 1;
|
|
uint8 *creditLine = nullptr;
|
|
uint8 *titleLine = nullptr;
|
|
int32 *creditData = nullptr;
|
|
Common::File creditsFile;
|
|
|
|
int32 creditsFileSize = 0;
|
|
int32 totalCreditsNum = 0;
|
|
|
|
uint8 *creditSprite[PSX_NUM_CREDITS];
|
|
uint8 *titleSprite[PSX_NUM_CREDITS];
|
|
int16 creditWidth[PSX_NUM_CREDITS];
|
|
int16 titleWidth[PSX_NUM_CREDITS];
|
|
int16 creditsHeight[PSX_NUM_CREDITS] = {
|
|
400, 440, 480, 520, 560, 600, 640,
|
|
680, 720, 760, 800, 840, 880, 920
|
|
};
|
|
|
|
for (int i = 0; i < PSX_NUM_CREDITS; i++) {
|
|
creditSprite[i] = nullptr;
|
|
titleSprite[i] = nullptr;
|
|
creditWidth[i] = 0;
|
|
titleWidth[i] = 0;
|
|
}
|
|
|
|
// If we're here, the resource is already there, no need to open it
|
|
uint8 *font = (uint8 *)_resMan->fetchRes(GAME_FONT);
|
|
|
|
switch (SwordEngine::_systemVars.language) {
|
|
case BS1_ENGLISH:
|
|
totalCreditsNum = 101;
|
|
creditsFileSize = 2798;
|
|
break;
|
|
case BS1_GERMAN:
|
|
totalCreditsNum = 83;
|
|
creditsFileSize = 2382;
|
|
break;
|
|
case BS1_FRENCH:
|
|
totalCreditsNum = 83;
|
|
creditsFileSize = 2382;
|
|
break;
|
|
case BS1_SPANISH:
|
|
totalCreditsNum = 83;
|
|
creditsFileSize = 2412;
|
|
break;
|
|
case BS1_ITALIAN:
|
|
totalCreditsNum = 101;
|
|
creditsFileSize = 2823;
|
|
break;
|
|
default:
|
|
totalCreditsNum = 101;
|
|
creditsFileSize = 2798;
|
|
}
|
|
|
|
_sound->clearAllFx();
|
|
_screen->startFadePaletteUp(1);
|
|
|
|
for (int i = 0; i < PSX_NUM_CREDITS; i++)
|
|
creditsHeight[i] = 400 + i * 40;
|
|
|
|
h = getCreditsFontHeight(font);
|
|
_screen->fnSetFadeTargetPalette(193, 1, 0, TEXT_WHITE);
|
|
|
|
_sound->streamMusicFile(101, 1);
|
|
_sound->updateMusicStreaming();
|
|
|
|
uint8 *creditsScreenBuf = (uint8 *)malloc(SCREEN_WIDTH * SCREEN_FULL_DEPTH);
|
|
if (!creditsScreenBuf) {
|
|
warning("Control::psxEndCredits(): Couldn't allocate memory for credits screen buffer");
|
|
return;
|
|
}
|
|
|
|
memset(creditsScreenBuf, 0, SCREEN_WIDTH * SCREEN_FULL_DEPTH);
|
|
|
|
creditData = (int32 *)malloc(creditsFileSize);
|
|
if (!creditData) {
|
|
warning("Control::psxEndCredits(): Couldn't allocate memory for text data");
|
|
free(creditsScreenBuf);
|
|
return;
|
|
}
|
|
|
|
if (!creditsFile.exists("CREDITS.DAT")) {
|
|
debug(2, "Control::psxEndCredits(): Couldn't find CREDITS.DAT");
|
|
free(creditsScreenBuf);
|
|
free(creditData);
|
|
return;
|
|
}
|
|
|
|
creditsFile.open("CREDITS.DAT");
|
|
if (!creditsFile.isOpen()) {
|
|
debug(2, "Control::psxEndCredits(): Couldn't open CREDITS.DAT");
|
|
free(creditsScreenBuf);
|
|
free(creditData);
|
|
return;
|
|
}
|
|
|
|
creditsFile.read(creditData, creditsFileSize);
|
|
creditsFile.close();
|
|
|
|
bool allSet = true;
|
|
|
|
for (int i = 0; i < PSX_NUM_CREDITS; i++) {
|
|
_sound->updateMusicStreaming();
|
|
_sound->setCrossFadeIncrement();
|
|
|
|
creditLine = ((uint8 *)creditData + creditData[i + totalCreditsNum]);
|
|
titleLine = ((uint8 *)creditData + creditData[i]);
|
|
|
|
creditWidth[i] = (getCreditsStringLength(creditLine, font) + 1) & 0xFFFE;
|
|
titleWidth[i] = (getCreditsStringLength(titleLine, font) + 1) & 0xFFFE;
|
|
|
|
if (creditWidth[i]) {
|
|
creditSprite[i] = (uint8 *)malloc(h * creditWidth[i]);
|
|
if (!creditSprite[i]) {
|
|
warning("Control::psxEndCredits(): Couldn't allocate memory for text sprites");
|
|
allSet = false;
|
|
break; // Break so the clean-up code is executed
|
|
}
|
|
|
|
memset(creditSprite[i], 0, h * creditWidth[i]);
|
|
} else {
|
|
creditSprite[i] = nullptr;
|
|
}
|
|
|
|
if (titleWidth[i]) {
|
|
titleSprite[i] = (uint8 *)malloc(h * titleWidth[i]);
|
|
if (!titleSprite[i]) {
|
|
warning("Control::psxEndCredits(): Couldn't allocate memory for text sprites");
|
|
allSet = false;
|
|
break; // Break so the clean-up code is executed
|
|
}
|
|
|
|
memset(titleSprite[i], 0, h * titleWidth[i]);
|
|
} else {
|
|
titleSprite[i] = nullptr;
|
|
}
|
|
|
|
createCreditsTextSprite(creditSprite[i], creditWidth[i], creditLine, font);
|
|
createCreditsTextSprite(titleSprite[i], titleWidth[i], titleLine, font);
|
|
}
|
|
|
|
_keyPressed.reset();
|
|
|
|
while (allSet && creditsHeight[PSX_NUM_CREDITS - 1] > -120 &&
|
|
!Engine::shouldQuit() &&
|
|
_keyPressed.keycode != Common::KEYCODE_ESCAPE) {
|
|
memset(creditsScreenBuf, 0, SCREEN_WIDTH * SCREEN_FULL_DEPTH);
|
|
|
|
for (int i = 0; i < PSX_NUM_CREDITS; i++) {
|
|
// Name
|
|
renderCreditsTextSprite(
|
|
creditSprite[i],
|
|
creditsScreenBuf,
|
|
PSX_CREDITS_MIDDLE + Logic::_scriptVars[SCROLL_OFFSET_X],
|
|
PSX_CREDITS_OFFSET + creditsHeight[i],
|
|
creditWidth[i],
|
|
h * 2);
|
|
|
|
// Role
|
|
renderCreditsTextSprite(
|
|
titleSprite[i],
|
|
creditsScreenBuf,
|
|
PSX_CREDITS_MIDDLE + Logic::_scriptVars[SCROLL_OFFSET_X] - 30 - titleWidth[i],
|
|
PSX_CREDITS_OFFSET + creditsHeight[i],
|
|
titleWidth[i],
|
|
h * 2);
|
|
|
|
creditsHeight[i] -= 2;
|
|
}
|
|
|
|
_system->copyRectToScreen(creditsScreenBuf, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_FULL_DEPTH);
|
|
|
|
delay(33); // Run credits at about 30 FPS
|
|
|
|
// Always remember to update sound :-)
|
|
_sound->updateMusicStreaming();
|
|
_sound->setCrossFadeIncrement();
|
|
|
|
// Scroll the credits!
|
|
if (creditsHeight[0] < -120) {
|
|
if (nextCredit <= totalCreditsNum) {
|
|
for (int i = 0; i < PSX_NUM_CREDITS; i++) {
|
|
creditsHeight[i] += 40;
|
|
}
|
|
|
|
if (creditSprite[0] != nullptr)
|
|
free(creditSprite[0]);
|
|
|
|
if (titleSprite[0] != nullptr)
|
|
free(titleSprite[0]);
|
|
|
|
for (int i = 0; i < PSX_NUM_CREDITS - 1; i++) {
|
|
creditSprite[i] = creditSprite[i + 1];
|
|
titleSprite[i] = titleSprite[i + 1];
|
|
creditWidth[i] = creditWidth[i + 1];
|
|
titleWidth[i] = titleWidth[i + 1];
|
|
}
|
|
|
|
creditLine = ((uint8 *)creditData + creditData[nextCredit - 1 + totalCreditsNum]);
|
|
titleLine = ((uint8 *)creditData + creditData[nextCredit - 1]);
|
|
|
|
creditWidth[PSX_NUM_CREDITS - 1] = (getCreditsStringLength(creditLine, font) + 1) & 0xFFFE;
|
|
titleWidth[PSX_NUM_CREDITS - 1] = (getCreditsStringLength(titleLine, font) + 1) & 0xFFFE;
|
|
|
|
if (creditWidth[PSX_NUM_CREDITS - 1]) {
|
|
creditSprite[PSX_NUM_CREDITS - 1] = (uint8 *)malloc(h * creditWidth[PSX_NUM_CREDITS - 1]);
|
|
if (!creditSprite[PSX_NUM_CREDITS - 1]) {
|
|
warning("Control::psxEndCredits(): Couldn't allocate memory for text sprites");
|
|
break;
|
|
}
|
|
|
|
memset(creditSprite[PSX_NUM_CREDITS - 1], 0, h * creditWidth[PSX_NUM_CREDITS - 1]);
|
|
} else {
|
|
creditSprite[PSX_NUM_CREDITS - 1] = nullptr;
|
|
}
|
|
|
|
if (titleWidth[PSX_NUM_CREDITS - 1]) {
|
|
titleSprite[PSX_NUM_CREDITS - 1] = (uint8 *)malloc(h * titleWidth[PSX_NUM_CREDITS - 1]);
|
|
if (!titleSprite[PSX_NUM_CREDITS - 1]) {
|
|
warning("Control::psxEndCredits(): Couldn't allocate memory for text sprites");
|
|
break;
|
|
}
|
|
|
|
memset(titleSprite[PSX_NUM_CREDITS - 1], 0, h * titleWidth[PSX_NUM_CREDITS - 1]);
|
|
} else {
|
|
titleSprite[PSX_NUM_CREDITS - 1] = nullptr;
|
|
}
|
|
|
|
createCreditsTextSprite(creditSprite[PSX_NUM_CREDITS - 1], creditWidth[PSX_NUM_CREDITS - 1], creditLine, font);
|
|
createCreditsTextSprite(titleSprite[PSX_NUM_CREDITS - 1], titleWidth[PSX_NUM_CREDITS - 1], titleLine, font);
|
|
|
|
nextCredit += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < PSX_NUM_CREDITS; i++) {
|
|
if (creditSprite[i] != nullptr)
|
|
free(creditSprite[i]);
|
|
|
|
if (titleSprite[i] != nullptr)
|
|
free(titleSprite[i]);
|
|
}
|
|
|
|
free(creditData);
|
|
|
|
_screen->startFadePaletteDown(1);
|
|
_vm->waitForFade();
|
|
|
|
memset(creditsScreenBuf, 0, SCREEN_WIDTH * SCREEN_FULL_DEPTH);
|
|
_system->copyRectToScreen(creditsScreenBuf, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_FULL_DEPTH);
|
|
free(creditsScreenBuf);
|
|
|
|
_keyPressed.reset();
|
|
}
|
|
|
|
} // End of namespace Sword1
|