mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 21:59:17 +00:00
1844 lines
41 KiB
C++
1844 lines
41 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
|
|
* aint32 with this program; if not, write to the Free Software
|
|
*
|
|
*
|
|
* Based on the original sources
|
|
* Faery Tale II -- The Halls of the Dead
|
|
* (c) 1993-1996 The Wyrmkeep Entertainment Co.
|
|
*/
|
|
|
|
#include "common/config-manager.h"
|
|
#include "audio/mixer.h"
|
|
|
|
#include "saga2/saga2.h"
|
|
#include "saga2/intrface.h"
|
|
#include "saga2/grequest.h"
|
|
#include "saga2/gtextbox.h"
|
|
#include "saga2/saveload.h"
|
|
#include "saga2/script.h"
|
|
|
|
#include "saga2/uidialog.h"
|
|
#include "saga2/document.h"
|
|
#include "saga2/tilemode.h"
|
|
#include "saga2/display.h"
|
|
#include "saga2/uitext.h"
|
|
#include "saga2/vpal.h"
|
|
#include "saga2/palette.h"
|
|
|
|
#include "saga2/fontlib.h"
|
|
|
|
namespace Saga2 {
|
|
|
|
// dialog functions
|
|
APPFUNC(cmdDialogQuit);
|
|
APPFUNCV(cmdFileSave);
|
|
APPFUNCV(cmdFileLoad);
|
|
APPFUNC(cmdSaveDialogUp);
|
|
APPFUNC(cmdSaveDialogDown);
|
|
APPFUNC(cmdTextResponse);
|
|
APPFUNC(cmdOptionsSaveGame);
|
|
APPFUNC(cmdOptionsLoadGame);
|
|
APPFUNC(cmdOptionsNewGame);
|
|
APPFUNC(cmdQuitGame);
|
|
APPFUNC(cmdCredits);
|
|
APPFUNC(cmdAutoAggression);
|
|
APPFUNC(cmdAutoWeapon);
|
|
APPFUNC(cmdNight);
|
|
APPFUNC(cmdSpeechText);
|
|
|
|
// volume control functions
|
|
APPFUNC(cmdSetMIDIVolume);
|
|
APPFUNC(cmdSetDIGVolume);
|
|
APPFUNC(cmdSetSpeechVolume);
|
|
APPFUNC(cmdSetSoundVolume);
|
|
APPFUNCV(cmdSaveVolumeSettings);
|
|
|
|
#define SmallFont Helv11Font
|
|
|
|
/* ===================================================================== *
|
|
External declarations
|
|
* ===================================================================== */
|
|
extern BackWindow *mainWindow;
|
|
extern bool fullInitialized;
|
|
|
|
/* ===================================================================== *
|
|
Dialog Controls
|
|
* ===================================================================== */
|
|
|
|
// control pointers
|
|
gTextBox *textBox;
|
|
CTextWindow *editWin;
|
|
|
|
|
|
/* ===================================================================== *
|
|
User interface dialog metrics
|
|
* ===================================================================== */
|
|
|
|
enum fileProcessTypes {
|
|
typeSave = 0,
|
|
typeLoad
|
|
};
|
|
|
|
enum saveLoadImageResIDs {
|
|
SLTopPanelResID = 0,
|
|
SLMidPanelResID,
|
|
SLBotPanelResID
|
|
};
|
|
|
|
|
|
enum optionsImageResIDs {
|
|
optTopPanelResID = 0,
|
|
optMidPanelResID,
|
|
optBotPanelResID
|
|
};
|
|
|
|
enum messageImageResIDs {
|
|
mesPanelResID = 0
|
|
};
|
|
|
|
|
|
// panels
|
|
static const StaticRect SLTopPanel = {
|
|
kSLDBoxX,
|
|
kSLDBoxY,
|
|
kSLTPWidth,
|
|
kSLTPHeight
|
|
};
|
|
|
|
static const StaticRect SLMidPanel = {
|
|
kSLDBoxX,
|
|
kSLDBoxY + kSLTPHeight,
|
|
kSLMDWidth,
|
|
kSLMDHeight
|
|
};
|
|
|
|
static const StaticRect SLBotPanel = {
|
|
kSLDBoxX,
|
|
kSLDBoxY + kSLTPHeight + kSLMDHeight,
|
|
kSLBTWidth,
|
|
kSLBTHeight
|
|
};
|
|
|
|
|
|
// buttons
|
|
static const StaticRect SLQuitBtnRect = {
|
|
211,
|
|
kSLTPHeight + kSLMDHeight + 11,
|
|
122,
|
|
30
|
|
};
|
|
|
|
static const StaticRect SLBtnRect = {
|
|
31,
|
|
kSLTPHeight + kSLMDHeight + 11,
|
|
122,
|
|
30
|
|
};
|
|
|
|
static const StaticRect SLUpArrowBtnRect = {
|
|
327,
|
|
46,
|
|
32,
|
|
36
|
|
};
|
|
|
|
static const StaticRect SLDnArrowBtnRect = {
|
|
327,
|
|
121,
|
|
32,
|
|
36
|
|
};
|
|
|
|
// texts
|
|
|
|
static const StaticRect SLTitleRect = {
|
|
0,
|
|
0,
|
|
kSLDBoxXSzNS,
|
|
47
|
|
};
|
|
|
|
|
|
// save load window rect
|
|
|
|
static const StaticRect saveLoadWindowRect = {
|
|
kSLDBoxX,
|
|
kSLDBoxY,
|
|
kSLDBoxXSize,
|
|
kSLDBoxYSize
|
|
};
|
|
|
|
|
|
// indirections
|
|
|
|
static const StaticRect *saveLoadButtonRects[kNumSaveLoadBtns] = {
|
|
&SLQuitBtnRect,
|
|
&SLBtnRect,
|
|
&SLUpArrowBtnRect,
|
|
&SLDnArrowBtnRect
|
|
};
|
|
|
|
static const StaticRect *saveLoadTextRects[kNumSaveLoadTexts] = {
|
|
&SLTitleRect
|
|
};
|
|
|
|
|
|
|
|
// save/load dialog window decorations
|
|
|
|
static StaticWindow saveWindowDecorations[kNumSaveLoadPanels] = {
|
|
{SLTopPanel, nullptr, SLTopPanelResID},
|
|
{SLMidPanel, nullptr, SLMidPanelResID},
|
|
{SLBotPanel, nullptr, SLBotPanelResID}
|
|
};
|
|
|
|
|
|
|
|
// panels
|
|
|
|
static const StaticRect optTopPanel = {
|
|
kOptBoxX,
|
|
kOptBoxY,
|
|
kOptTPWidth,
|
|
kOptTPHeight
|
|
};
|
|
|
|
static const StaticRect optMidPanel = {
|
|
kOptBoxX,
|
|
kOptBoxY + kOptTPHeight,
|
|
kOptMDWidth,
|
|
kOptMDHeight
|
|
};
|
|
|
|
static const StaticRect optBotPanel = {
|
|
kOptBoxX,
|
|
kOptBoxY + kOptTPHeight + kOptMDHeight,
|
|
kOptBTWidth,
|
|
kOptBTHeight
|
|
};
|
|
|
|
|
|
static const StaticRect optResumeRect = {
|
|
kOptBoxXSzNS - (kPushButtonWidth + 14),
|
|
kButtonYOffset + kButtonSpace,
|
|
kPushButtonWidth,
|
|
kPushButtonHeight
|
|
};
|
|
|
|
static const StaticRect optSaveRect = {
|
|
kOptBoxXSzNS - (kPushButtonWidth + 14),
|
|
kButtonYOffset + ((kPushButtonHeight * 1) + kButtonSpace * 2),
|
|
kPushButtonWidth,
|
|
kPushButtonHeight
|
|
};
|
|
|
|
|
|
|
|
static const StaticRect optRestoreRect = {
|
|
kOptBoxXSzNS - (kPushButtonWidth + 14),
|
|
kButtonYOffset + ((kPushButtonHeight * 2) + kButtonSpace * 3),
|
|
kPushButtonWidth,
|
|
kPushButtonHeight
|
|
};
|
|
|
|
static const StaticRect optQuitRect = {
|
|
kOptBoxXSzNS - (kPushButtonWidth + 14),
|
|
kButtonYOffset + ((kPushButtonHeight * 3) + kButtonSpace * 4),
|
|
kPushButtonWidth,
|
|
kPushButtonHeight
|
|
};
|
|
|
|
static const StaticRect optCreditsRect = {
|
|
kOptBoxXSzNS - (kPushButtonWidth + 14),
|
|
kButtonYOffset + ((kPushButtonHeight * 4) + kButtonSpace * 5),
|
|
kPushButtonWidth,
|
|
kPushButtonHeight
|
|
};
|
|
|
|
static const StaticRect optAggressRect = {
|
|
14,
|
|
98 + kOptTPHeight,
|
|
18,
|
|
17
|
|
};
|
|
|
|
static const StaticRect optWeaponRect = {
|
|
14,
|
|
121 + kOptTPHeight,
|
|
18,
|
|
17
|
|
};
|
|
|
|
static const StaticRect optSpeechRect = {
|
|
14,
|
|
121 + 23 + kOptTPHeight,
|
|
18,
|
|
17
|
|
};
|
|
|
|
static const StaticRect optNightRect = {
|
|
14 + 200,
|
|
98 + kOptTPHeight,
|
|
18,
|
|
17
|
|
};
|
|
|
|
static const StaticRect optTopSliderRect = {
|
|
15,
|
|
15 + kOptTPHeight - 2,
|
|
kSliderWidth,
|
|
kImageHeight
|
|
};
|
|
|
|
static const StaticRect optMidSliderRect = {
|
|
15,
|
|
(int16)(optTopSliderRect.y + 32 - 2),
|
|
kSliderWidth,
|
|
kImageHeight
|
|
};
|
|
|
|
static const StaticRect optBotSliderRect = {
|
|
15,
|
|
(int16)(optMidSliderRect.y + 32 - 2),
|
|
kSliderWidth,
|
|
kImageHeight
|
|
};
|
|
|
|
static const StaticRect optTopFaceRect = {
|
|
optTopSliderRect.x,
|
|
optTopSliderRect.y,
|
|
28,
|
|
kImageHeight
|
|
};
|
|
|
|
static const StaticRect optMidFaceRect = {
|
|
optMidSliderRect.x,
|
|
optMidSliderRect.y,
|
|
28,
|
|
kImageHeight
|
|
};
|
|
|
|
static const StaticRect optBotFaceRect = {
|
|
optBotSliderRect.x,
|
|
optBotSliderRect.y,
|
|
28,
|
|
kImageHeight
|
|
};
|
|
|
|
|
|
// texts
|
|
|
|
static const StaticRect optTitleText = {
|
|
0,
|
|
0,
|
|
kOptBoxXSzNS,
|
|
kOptTPHeight
|
|
};
|
|
|
|
static const StaticRect optTopSlideText = {
|
|
16 + kSliderWidth,
|
|
(int16)(optTopSliderRect.y + 1),
|
|
kTextPixelLen,
|
|
20
|
|
};
|
|
|
|
static const StaticRect optMidSlideText = {
|
|
16 + kSliderWidth,
|
|
(int16)(optMidSliderRect.y + 1),
|
|
kTextPixelLen,
|
|
17
|
|
};
|
|
|
|
static const StaticRect optBotSlideText = {
|
|
16 + kSliderWidth,
|
|
(int16)(optBotSliderRect.y + 1),
|
|
kTextPixelLen,
|
|
17
|
|
};
|
|
|
|
static const StaticRect optTopCheckText = {
|
|
(int16)(optAggressRect.x + optAggressRect.width + 3),
|
|
optAggressRect.y,
|
|
kTextPixelLen - kSmallTextOffset,
|
|
17
|
|
};
|
|
|
|
static const StaticRect optMidCheckText = {
|
|
(int16)(optWeaponRect.x + optWeaponRect.width + 3),
|
|
optWeaponRect.y,
|
|
kTextPixelLen - kSmallTextOffset,
|
|
17
|
|
};
|
|
|
|
static const StaticRect optBotCheckText = {
|
|
(int16)(optSpeechRect.x + optSpeechRect.width + 3),
|
|
optSpeechRect.y,
|
|
kTextPixelLen - kSmallTextOffset,
|
|
17
|
|
};
|
|
|
|
static const StaticRect optTop2CheckText = {
|
|
(int16)(optNightRect.x + optNightRect.width + 3),
|
|
optNightRect.y,
|
|
kTextPixelLen - kSmallTextOffset,
|
|
17
|
|
};
|
|
|
|
// options window rect
|
|
|
|
static const StaticRect optionsWindowRect = {
|
|
kOptBoxX,
|
|
kOptBoxY,
|
|
kOptBoxXSize,
|
|
kOptBoxYSize
|
|
};
|
|
|
|
|
|
// indirections
|
|
|
|
static const StaticRect *optionsButtonRects[] = {
|
|
&optResumeRect,
|
|
&optSaveRect,
|
|
&optRestoreRect,
|
|
&optQuitRect,
|
|
&optCreditsRect,
|
|
&optAggressRect,
|
|
&optWeaponRect,
|
|
&optSpeechRect,
|
|
&optNightRect
|
|
};
|
|
|
|
static const StaticRect *optionsTextRects[] = {
|
|
&optTitleText,
|
|
&optTopSlideText,
|
|
&optMidSlideText,
|
|
&optBotSlideText,
|
|
&optTopCheckText,
|
|
&optMidCheckText,
|
|
&optBotCheckText,
|
|
&optTop2CheckText
|
|
};
|
|
|
|
|
|
// options dialog window decorations
|
|
|
|
static StaticWindow optionsDecorations[kNumOptionsPanels] = {
|
|
{optTopPanel, nullptr, optTopPanelResID},
|
|
{optMidPanel, nullptr, optMidPanelResID},
|
|
{optBotPanel, nullptr, optBotPanelResID}
|
|
};
|
|
|
|
|
|
// panels
|
|
static const StaticRect messagePanel = {
|
|
kMesBoxX,
|
|
kMesBoxY,
|
|
kMesBoxXSize,
|
|
kMesBoxYSize
|
|
};
|
|
|
|
|
|
// buttons
|
|
static const StaticRect mesCancelBtnRect = {
|
|
kMesBoxXSzNS - (kPushButtonWidth + kMesBtnOffset),
|
|
kMesBoxY - kMesBtnOffset,
|
|
kPushButtonWidth,
|
|
kPushButtonHeight
|
|
};
|
|
|
|
static const StaticRect mesOkBtnRect = {
|
|
kMesBtnOffset,
|
|
kMesBoxY - kMesBtnOffset,
|
|
kPushButtonWidth,
|
|
kPushButtonHeight
|
|
};
|
|
|
|
|
|
static const StaticRect mesBtn3Rect = {
|
|
kMesBoxXSzNS / 2 - kPushButtonWidth / 2,
|
|
kMesBoxY - kMesBtnOffset,
|
|
kPushButtonWidth,
|
|
kPushButtonHeight
|
|
};
|
|
|
|
|
|
|
|
|
|
// texts
|
|
static const StaticRect mesTitleRect = {
|
|
0,
|
|
0,
|
|
kMesBoxXSzNS,
|
|
47
|
|
};
|
|
|
|
static const StaticRect messageRect = {
|
|
0,
|
|
0,
|
|
kMesBoxXSzNS,
|
|
kMesBoxYSize
|
|
};
|
|
|
|
|
|
|
|
static const StaticRect *messageTextRects[kNumMessageTexts] = {
|
|
&mesTitleRect,
|
|
&messageRect
|
|
};
|
|
|
|
|
|
static const StaticRect *messageButtonRects[kNumMessageBtns] = {
|
|
&mesOkBtnRect,
|
|
&mesCancelBtnRect,
|
|
&mesBtn3Rect
|
|
};
|
|
|
|
|
|
|
|
// options window rect
|
|
static const StaticRect messageWindowRect = {
|
|
kMesBoxX,
|
|
kMesBoxY,
|
|
kMesBoxXSize,
|
|
kMesBoxYSize
|
|
};
|
|
|
|
|
|
|
|
|
|
// message dialog window decorations
|
|
static StaticWindow messageDecorations[kNumMessagePanels] = {
|
|
{messagePanel, nullptr, mesPanelResID}
|
|
};
|
|
|
|
|
|
// pointer to the auto aggression button
|
|
GfxOwnerSelCompButton *autoAggressBtn,
|
|
*autoWeaponBtn,
|
|
*nightBtn,
|
|
*speechTextBtn;
|
|
|
|
|
|
|
|
static int deferredLoadID = 0;
|
|
static bool deferredLoadFlag = false;
|
|
static bool deferredSaveFlag = false;
|
|
static char deferredSaveName[64];
|
|
|
|
inline bool isUserAction(gEvent ev) {
|
|
return (ev.eventType == kEventNewValue) || (ev.eventType == kEventKeyDown);
|
|
}
|
|
|
|
/* ===================================================================== *
|
|
Save game file name handling funtions
|
|
* ===================================================================== */
|
|
|
|
|
|
char **initFileFields() {
|
|
uint16 i;
|
|
SaveFileHeader header; // The save file header.
|
|
|
|
char **strings = new (char *[kNumEditLines]);
|
|
|
|
for (i = 0; i < kNumEditLines; i++) {
|
|
strings[i] = new char[kEditLen + 1];
|
|
|
|
if (getSaveName(i, header)) {
|
|
Common::strlcpy(strings[i], header.saveName.c_str(), kEditLen);
|
|
} else {
|
|
Common::strlcpy(strings[i], FILE_DIALOG_NONAME, kEditLen);
|
|
strings[i][0] |= 0x80;
|
|
}
|
|
|
|
// make sure this thing is caped
|
|
strings[i][kEditLen] = '\0';
|
|
}
|
|
|
|
return strings;
|
|
}
|
|
|
|
int numValid(char **names) {
|
|
int v = 0;
|
|
for (int i = 0; i < kNumEditLines; i++) {
|
|
if ((names[i][0] & 0x80) == 0) v++;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
void destroyFileFields(char **strings) {
|
|
uint16 i;
|
|
|
|
for (i = 0; i < kNumEditLines; i++) {
|
|
if (strings[i])
|
|
delete[] strings[i];
|
|
strings[i] = nullptr;
|
|
}
|
|
|
|
delete[] strings;
|
|
}
|
|
|
|
bool getSaveName(int8 saveNo, SaveFileHeader &header) {
|
|
Common::String fname = g_vm->getSavegameFile(saveNo);
|
|
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fname);
|
|
|
|
if (!in) {
|
|
debugC(1, kDebugSaveload, "Unable to load save %d (%s)", saveNo, fname.c_str());
|
|
return false;
|
|
}
|
|
|
|
header.read(in);
|
|
|
|
delete in;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/* ===================================================================== *
|
|
Dialog boxes
|
|
* ===================================================================== */
|
|
|
|
int16 FileDialog(int16 fileProcess) {
|
|
//const int strLen = kEditLen;
|
|
char **fieldStrings;
|
|
uint16 stringIndex;
|
|
bool displayOnly;
|
|
void **arrowUpIm = nullptr, **arrowDnIm = nullptr, **pushBtnIm = nullptr;
|
|
|
|
AppFunc *fileCommands[2] = { cmdFileSave, cmdFileLoad };
|
|
|
|
// text for dialog
|
|
const char *saveTextStrings[kNumSaveLoadTexts] = { SAVE_DIALOG_NAME };
|
|
const char *saveBtnStrings[kNumSaveLoadBtns] = { SAVE_DIALOG_BUTTON1, SAVE_DIALOG_BUTTON2 };
|
|
|
|
const char *loadTextStrings[kNumSaveLoadTexts] = { LOAD_DIALOG_NAME };
|
|
const char *loadBtnStrings[kNumSaveLoadBtns] = { LOAD_DIALOG_BUTTON1, LOAD_DIALOG_BUTTON2 };
|
|
|
|
const char **textStrings[] = { saveTextStrings, loadTextStrings };
|
|
const char **btnStrings[] = { saveBtnStrings, loadBtnStrings };
|
|
|
|
|
|
// make the text coloring object
|
|
textPallete pal(33 + 9, 36 + 9, 41 + 9, 34 + 9, 40 + 9, 43 + 9);
|
|
|
|
if (fileProcess == typeSave) {
|
|
stringIndex = 0;
|
|
displayOnly = false;
|
|
} else {
|
|
stringIndex = 1;
|
|
displayOnly = true;
|
|
}
|
|
|
|
// resource info
|
|
const int16 dialogPushResNum = 4;
|
|
const int16 upArrowResNum = 0;
|
|
const int16 dnArrowResNum = 2;
|
|
|
|
// requester info struct
|
|
requestInfo rInfo;
|
|
|
|
rInfo.result = -1;
|
|
rInfo.running = true;
|
|
|
|
// point to the modal window
|
|
ModalWindow *win;
|
|
|
|
// resource handle
|
|
hResContext *decRes;
|
|
|
|
// get the file fields names
|
|
fieldStrings = initFileFields();
|
|
|
|
|
|
#ifndef ALLOW_BAD_LOADS
|
|
if (displayOnly && numValid(fieldStrings) == 0) {
|
|
destroyFileFields(fieldStrings);
|
|
if (userDialog("Error", "No saved games to load!\n Would you like to start over?", "_Yes", "_No", nullptr) != 1) {
|
|
deferredLoadFlag = true;
|
|
deferredLoadID = 999;
|
|
return typeLoad;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
// init the resource context handle
|
|
decRes = resFile->newContext(kDialogGroupID, "dialog resources");
|
|
|
|
|
|
// get the graphics associated with the buttons
|
|
pushBtnIm = loadButtonRes(decRes, dialogPushResNum, kNumBtnImages);
|
|
arrowUpIm = loadButtonRes(decRes, upArrowResNum, kNumBtnImages);
|
|
arrowDnIm = loadButtonRes(decRes, dnArrowResNum, kNumBtnImages);
|
|
|
|
|
|
// create the window
|
|
win = new ModalWindow(saveLoadWindowRect, 0, nullptr);
|
|
|
|
// make the quit button
|
|
new GfxCompButton(*win, *saveLoadButtonRects[0], pushBtnIm, kNumBtnImages, btnStrings[stringIndex][0], pal, 0, cmdDialogQuit);
|
|
//t->_accelKey=0x1B;
|
|
|
|
// make the Save/Load button
|
|
new GfxCompButton(*win, *saveLoadButtonRects[1], pushBtnIm, kNumBtnImages, btnStrings[stringIndex][1], pal, fileProcess, fileCommands[fileProcess]);
|
|
//t->_accelKey=0x0D;
|
|
// make the up arrow
|
|
new GfxCompButton(*win, *saveLoadButtonRects[2], arrowUpIm, kNumBtnImages, 0, cmdSaveDialogUp);
|
|
//t->_accelKey=33+0x80;
|
|
// make the down arrow
|
|
new GfxCompButton(*win, *saveLoadButtonRects[3], arrowDnIm, kNumBtnImages, 0, cmdSaveDialogDown);
|
|
//t->_accelKey=34+0x80;
|
|
// attach the title
|
|
new CPlaqText(*win, *saveLoadTextRects[0], textStrings[stringIndex][0], &Plate18Font, 0, pal, 0, nullptr);
|
|
|
|
|
|
|
|
// attach the text box editing field object
|
|
textBox = new gTextBox(*win, editBaseRect, &Onyx10Font,
|
|
kTextHeight, kTextPen, kTextBackground, kTextHilite, kTextBackHilite, kCursorColor,
|
|
nullptr, "Error out", fieldStrings, kEditLen, 0, (uint16) - 1, displayOnly, nullptr,
|
|
fileCommands[fileProcess], cmdDialogQuit);
|
|
|
|
|
|
win->setDecorations(saveWindowDecorations,
|
|
ARRAYSIZE(saveWindowDecorations),
|
|
decRes, 'S', 'L', 'D');
|
|
|
|
win->_userData = &rInfo;
|
|
win->open();
|
|
|
|
if (GameMode::_newmodeFlag)
|
|
GameMode::update();
|
|
|
|
win->invalidate();
|
|
textBox->choose();
|
|
|
|
EventLoop(rInfo.running, true);
|
|
|
|
// remove the window all attatched controls
|
|
delete win;
|
|
win = nullptr;
|
|
|
|
// unload all image arrays
|
|
unloadImageRes(arrowUpIm, kNumBtnImages);
|
|
unloadImageRes(arrowDnIm, kNumBtnImages);
|
|
unloadImageRes(pushBtnIm, kNumBtnImages);
|
|
|
|
|
|
// remove the resource handle
|
|
if (decRes) resFile->disposeContext(decRes);
|
|
decRes = nullptr;
|
|
|
|
// destroy the file fields
|
|
destroyFileFields(fieldStrings);
|
|
|
|
// replace the damaged area
|
|
mainWindow->invalidate(&saveLoadWindowRect);
|
|
|
|
// return the result code
|
|
return rInfo.result;
|
|
}
|
|
|
|
|
|
/* ===================================================================== *
|
|
Options dialog box
|
|
* ===================================================================== */
|
|
void updateMainDisplay();
|
|
void drawMainDisplay();
|
|
void fadeUp();
|
|
void fadeDown();
|
|
void clearTileAreaPort();
|
|
void displayUpdate();
|
|
|
|
int16 OptionsDialog(bool disableSaveResume) {
|
|
// Save back buffer before opening the dialog
|
|
g_vm->_renderer->saveBackBuffer(kBeforeOpeningMenu);
|
|
|
|
// text for dialog
|
|
const char *btnStrings[kNumOptionsBtns] = {
|
|
OPTN_DIALOG_BUTTON1,
|
|
OPTN_DIALOG_BUTTON2,
|
|
OPTN_DIALOG_BUTTON3,
|
|
OPTN_DIALOG_BUTTON4,
|
|
OPTN_DIALOG_BUTTON5
|
|
};
|
|
|
|
|
|
const char *textStrings[kNumOptionsTexts] = {
|
|
OPTN_DIALOG_NAME,
|
|
OPTN_DIALOG_SLIDE1,
|
|
OPTN_DIALOG_SLIDE2,
|
|
OPTN_DIALOG_SLIDE3,
|
|
OPTN_DIALOG_CHECK1,
|
|
OPTN_DIALOG_CHECK2,
|
|
OPTN_DIALOG_CHECK3,
|
|
OPTN_DIALOG_CHECK4
|
|
};
|
|
|
|
// make the text coloring object
|
|
textPallete pal(33 + 9, 36 + 9, 41 + 9, 34 + 9, 40 + 9, 43 + 9);
|
|
|
|
// requester info struct
|
|
requestInfo rInfo;
|
|
|
|
rInfo.result = -1;
|
|
rInfo.running = true;
|
|
deferredLoadID = 0;
|
|
deferredLoadFlag = false;
|
|
deferredSaveFlag = false;
|
|
deferredSaveName[0] = '\0';
|
|
|
|
// point to the modal window
|
|
ModalWindow *win;
|
|
|
|
|
|
// resource handle
|
|
hResContext *decRes;
|
|
|
|
// resource info
|
|
const int16 dialogPushResNum = 4;
|
|
const int16 checkResNum = 6;
|
|
const int16 slideFaceResNum = 8;
|
|
const int16 numSlideFace = 4;
|
|
|
|
// compressed image arrays
|
|
void **dialogPushImag;
|
|
void **checkImag;
|
|
void **slideFaceImag;
|
|
if (!fullInitialized) return -1;
|
|
|
|
// init the resource context handle
|
|
decRes = resFile->newContext(kDialogGroupID, "dialog resources");
|
|
|
|
// get the graphics associated with the buttons
|
|
dialogPushImag = loadButtonRes(decRes, dialogPushResNum, kNumBtnImages);
|
|
checkImag = loadButtonRes(decRes, checkResNum, kNumBtnImages);
|
|
slideFaceImag = loadButtonRes(decRes, slideFaceResNum, numSlideFace);
|
|
|
|
// create the window
|
|
win = new ModalWindow(optionsWindowRect, 0, nullptr);
|
|
GfxCompButton *t;
|
|
|
|
// buttons
|
|
if (!disableSaveResume) {
|
|
t = new GfxCompButton(*win, *optionsButtonRects[0],
|
|
dialogPushImag, kNumBtnImages, btnStrings[0], pal, 0, cmdDialogQuit);
|
|
t->_accelKey = 0x1B;
|
|
|
|
t = new GfxCompButton(*win, *optionsButtonRects[1],
|
|
dialogPushImag, kNumBtnImages, btnStrings[1], pal, 0, cmdOptionsSaveGame); // make the quit button
|
|
t->_accelKey = 'S';
|
|
} else {
|
|
t = new GfxCompButton(*win, *optionsButtonRects[1],
|
|
dialogPushImag, kNumBtnImages, OPTN_DIALOG_BUTTON6, pal, 0, cmdOptionsNewGame);
|
|
t->_accelKey = 'N';
|
|
}
|
|
|
|
t = new GfxCompButton(*win, *optionsButtonRects[2],
|
|
dialogPushImag, kNumBtnImages, btnStrings[2], pal, 0, cmdOptionsLoadGame); // make the quit button
|
|
t->_accelKey = 'L';
|
|
|
|
t = new GfxCompButton(*win, *optionsButtonRects[3],
|
|
dialogPushImag, kNumBtnImages, btnStrings[3], pal, 0, cmdQuitGame);
|
|
t->_accelKey = 'Q';
|
|
|
|
t = new GfxCompButton(*win, *optionsButtonRects[4],
|
|
dialogPushImag, kNumBtnImages, btnStrings[4], pal, 0, cmdCredits);
|
|
t->_accelKey = 'C';
|
|
|
|
autoAggressBtn = new GfxOwnerSelCompButton(*win, *optionsButtonRects[5],
|
|
checkImag, kNumBtnImages, 0, cmdAutoAggression);
|
|
autoAggressBtn->select(isAutoAggressionSet());
|
|
|
|
autoWeaponBtn = new GfxOwnerSelCompButton(*win, *optionsButtonRects[6],
|
|
checkImag, kNumBtnImages, 0, cmdAutoWeapon);
|
|
autoWeaponBtn->select(isAutoWeaponSet());
|
|
|
|
speechTextBtn = new GfxOwnerSelCompButton(*win, *optionsButtonRects[7],
|
|
checkImag, kNumBtnImages, 0, cmdSpeechText);
|
|
speechTextBtn->select(g_vm->_speechText);
|
|
|
|
nightBtn = new GfxOwnerSelCompButton(*win, *optionsButtonRects[8],
|
|
checkImag, kNumBtnImages, 0, cmdNight);
|
|
nightBtn->select(g_vm->_showNight);
|
|
|
|
new GfxSlider(*win, optTopSliderRect, optTopFaceRect, 0,
|
|
Audio::Mixer::kMaxMixerVolume, slideFaceImag, numSlideFace, ConfMan.getInt("sfx_volume"),
|
|
0, cmdSetSoundVolume);
|
|
|
|
new GfxSlider(*win, optMidSliderRect, optMidFaceRect, 0,
|
|
Audio::Mixer::kMaxMixerVolume, slideFaceImag, numSlideFace, ConfMan.getInt("speech_volume"),
|
|
0, cmdSetSpeechVolume);
|
|
|
|
new GfxSlider(*win, optBotSliderRect, optBotFaceRect, 0,
|
|
Audio::Mixer::kMaxMixerVolume, slideFaceImag, numSlideFace, ConfMan.getInt("music_volume"),
|
|
0, cmdSetMIDIVolume);
|
|
|
|
new CPlaqText(*win, *optionsTextRects[0],
|
|
textStrings[0], &Plate18Font, 0, pal, 0, nullptr);
|
|
|
|
for (int i = 1; i < kNumOptionsTexts; i++) {
|
|
new CPlaqText(*win, *optionsTextRects[i], textStrings[i], &SmallFont, kTextPosLeft, pal, 0, nullptr);
|
|
}
|
|
|
|
win->setDecorations(optionsDecorations,
|
|
ARRAYSIZE(optionsDecorations),
|
|
decRes, 'O', 'P', 'T');
|
|
|
|
|
|
win->_userData = &rInfo;
|
|
win->open();
|
|
|
|
EventLoop(rInfo.running, true);
|
|
|
|
g_vm->saveConfig();
|
|
|
|
// remove the window all attatched controls
|
|
delete win;
|
|
win = nullptr;
|
|
|
|
// unload all image arrays
|
|
unloadImageRes(slideFaceImag, numSlideFace);
|
|
unloadImageRes(checkImag, kNumBtnImages);
|
|
unloadImageRes(dialogPushImag, kNumBtnImages);
|
|
|
|
// remove the resource handle
|
|
if (decRes) resFile->disposeContext(decRes);
|
|
decRes = nullptr;
|
|
|
|
// replace the damaged area
|
|
|
|
if (deferredLoadFlag) {
|
|
reDrawScreen();
|
|
|
|
disableUserControls();
|
|
cleanupGameState();
|
|
|
|
fadeDown();
|
|
|
|
if (deferredLoadID == 999)
|
|
loadRestartGame();
|
|
else {
|
|
loadSavedGameState(deferredLoadID);
|
|
}
|
|
if (GameMode::_newmodeFlag)
|
|
GameMode::update();
|
|
updateActiveRegions();
|
|
//displayUpdate();
|
|
enableUserControls();
|
|
updateMainDisplay();
|
|
drawMainDisplay();
|
|
enablePaletteChanges();
|
|
updateAllUserControls();
|
|
fadeUp();
|
|
reDrawScreen();
|
|
} else {
|
|
if (deferredSaveFlag) {
|
|
#ifdef IMMEDIATE_SAVE
|
|
g_vm->saveGameState(deferredLoadID, deferredSaveName, false);
|
|
#endif
|
|
}
|
|
mainWindow->invalidate(&optionsWindowRect);
|
|
}
|
|
|
|
// Pop back buffer
|
|
g_vm->_renderer->popSavedBackBuffer(kBeforeOpeningMenu);
|
|
|
|
// return the result code
|
|
return rInfo.result;
|
|
}
|
|
|
|
/* ===================================================================== *
|
|
message dialog box
|
|
* ===================================================================== */
|
|
|
|
static char stripAccel(char (&t)[32], const char *s) {
|
|
char accel = '\0';
|
|
char *underscore;
|
|
|
|
if (s == nullptr) return accel;
|
|
Common::strcpy_s(t, s);
|
|
|
|
if ((underscore = strchr(t, '_')) != nullptr) {
|
|
accel = toupper(underscore[1]);
|
|
Common::strcpy_s(underscore, sizeof(t) - (underscore - t), s + (underscore - t) + 1);
|
|
}
|
|
return accel;
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DYNALOAD_USERDIALOG
|
|
// requester info struct
|
|
requestInfo udrInfo;
|
|
|
|
// point to the modal window
|
|
ModalWindow *udWin;
|
|
|
|
// resource handle
|
|
hResContext *udDecRes;
|
|
|
|
// compressed image array
|
|
void **udDialogPushImag;
|
|
|
|
bool udInit = false;
|
|
|
|
bool initUserDialog() {
|
|
|
|
const int16 dialogPushResNum = 4;
|
|
// init the resource context handle
|
|
udDecRes = resFile->newContext(kDialogGroupID, "dialog resources");
|
|
|
|
|
|
// get the graphics associated with the buttons
|
|
udDialogPushImag = loadButtonRes(udDecRes, dialogPushResNum, kNumBtnImages);
|
|
|
|
// create the window
|
|
udWin = new ModalWindow(messageWindowRect, 0 nullptr);
|
|
|
|
udWin->setDecorations(messageDecorations,
|
|
ARRAYSIZE(messageDecorations),
|
|
udDecRes, 'M', 'E', 'S');
|
|
|
|
udWin->_userData = &udrInfo;
|
|
|
|
if (udDecRes) resFile->disposeContext(udDecRes);
|
|
udDecRes = nullptr;
|
|
|
|
udInit = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool userDialogAvailable() {
|
|
return udInit;
|
|
}
|
|
|
|
void cleanupUserDialog() {
|
|
udInit = false;
|
|
// remove the window all attatched controls
|
|
if (udWin) delete udWin;
|
|
udWin = nullptr;
|
|
|
|
// unload all image arrays
|
|
unloadImageRes(udDialogPushImag, kNumBtnImages);
|
|
|
|
}
|
|
|
|
int16 userDialog(const char *title, const char *msg, const char *bMsg1,
|
|
const char *bMsg2,
|
|
const char *bMsg3) {
|
|
const maxBtns = 3;
|
|
uint8 numBtns = 0;
|
|
|
|
char k1, k2, k3;
|
|
|
|
char btnMsg1[32];
|
|
char btnMsg2[32];
|
|
char btnMsg3[32];
|
|
|
|
if (bMsg1 && strlen(bMsg1)) numBtns++;
|
|
if (bMsg2 && strlen(bMsg2)) numBtns++;
|
|
if (bMsg3 && strlen(bMsg3)) numBtns++;
|
|
|
|
k1 = stripAccel(btnMsg1, bMsg1);
|
|
k2 = stripAccel(btnMsg2, bMsg2);
|
|
k3 = stripAccel(btnMsg3, bMsg3);
|
|
|
|
|
|
// make the text coloring object
|
|
textPallete pal(33 + 9, 36 + 9, 41 + 9, 34 + 9, 40 + 9, 43 + 9);
|
|
|
|
if (udWin == nullptr) return -1;
|
|
|
|
udrInfo.result = -1;
|
|
udrInfo.running = true;
|
|
|
|
GfxCompButton *t;
|
|
|
|
// button one
|
|
if (numBtns >= 1) {
|
|
t = new GfxCompButton(*udWin, messageButtonRects[0],
|
|
udDialogPushImag, kNumBtnImages, btnMsg1, pal, 10, cmdDialogQuit);
|
|
t->accel = k1;
|
|
}
|
|
|
|
// button two
|
|
if (numBtns >= 2) {
|
|
t = new GfxCompButton(*udWin, messageButtonRects[1],
|
|
udDialogPushImag, kNumBtnImages, btnMsg2, pal, 11, cmdDialogQuit);
|
|
t->accel = k2;
|
|
}
|
|
|
|
// button three
|
|
if (numBtns >= 3) {
|
|
t = new GfxCompButton(*udWin, messageButtonRects[2],
|
|
udDialogPushImag, kNumBtnImages, btnMsg3, pal, 12, cmdDialogQuit);
|
|
t->accel = k3;
|
|
}
|
|
|
|
// title for the box
|
|
new CPlaqText(*udWin, messageTextRects[0], title, &Plate18Font, nullptr, pal, 0, nullptr);
|
|
|
|
// message for box
|
|
new CPlacardPanel(*udWin, messageTextRects[1], msg, &Onyx10Font, nullptr, pal, 0, nullptr);
|
|
|
|
|
|
udWin->open();
|
|
|
|
EventLoop(udrInfo.running, true);
|
|
|
|
udWin->close();
|
|
|
|
udWin->removeControls();
|
|
|
|
// replace the damaged area
|
|
mainWindow->invalidate(messageWindowRect);
|
|
|
|
// return the result code
|
|
return (udrInfo.result % 10);
|
|
}
|
|
|
|
#else
|
|
|
|
/* ===================================================================== *
|
|
message dialog box
|
|
* ===================================================================== */
|
|
|
|
bool initUserDialog() {
|
|
return true;
|
|
}
|
|
bool userDialogAvailable() {
|
|
return true;
|
|
}
|
|
void cleanupUserDialog() {}
|
|
|
|
int16 userDialog(const char *title, const char *msg, const char *bMsg1,
|
|
const char *bMsg2,
|
|
const char *bMsg3) {
|
|
//const int maxBtns = 3;
|
|
uint8 numBtns = 0;
|
|
|
|
char k1, k2, k3;
|
|
|
|
char btnMsg1[32];
|
|
char btnMsg2[32];
|
|
char btnMsg3[32];
|
|
|
|
if (bMsg1 && strlen(bMsg1)) numBtns++;
|
|
if (bMsg2 && strlen(bMsg2)) numBtns++;
|
|
if (bMsg3 && strlen(bMsg3)) numBtns++;
|
|
|
|
k1 = stripAccel(btnMsg1, bMsg1);
|
|
k2 = stripAccel(btnMsg2, bMsg2);
|
|
k3 = stripAccel(btnMsg3, bMsg3);
|
|
|
|
|
|
// make the text coloring object
|
|
textPallete pal(33 + 9, 36 + 9, 41 + 9, 34 + 9, 40 + 9, 43 + 9);
|
|
|
|
// resource info
|
|
const int16 dialogPushResNum = 4;
|
|
|
|
// requester info struct
|
|
requestInfo rInfo;
|
|
|
|
// point to the modal window
|
|
ModalWindow *win;
|
|
|
|
|
|
// resource handle
|
|
hResContext *decRes;
|
|
|
|
// compressed image array
|
|
void **dialogPushImag;
|
|
|
|
rInfo.result = -1;
|
|
rInfo.running = true;
|
|
|
|
if (!fullInitialized)
|
|
return -1;
|
|
|
|
// init the resource context handle
|
|
decRes = resFile->newContext(kDialogGroupID, "dialog resources");
|
|
|
|
|
|
// get the graphics associated with the buttons
|
|
dialogPushImag = loadButtonRes(decRes, dialogPushResNum, kNumBtnImages);
|
|
|
|
// create the window
|
|
win = new ModalWindow(messageWindowRect, 0, nullptr);
|
|
|
|
GfxCompButton *t;
|
|
|
|
// button one
|
|
if (numBtns >= 1) {
|
|
t = new GfxCompButton(*win, *messageButtonRects[0],
|
|
dialogPushImag, kNumBtnImages, btnMsg1, pal, 10, cmdDialogQuit);
|
|
t->_accelKey = k1;
|
|
}
|
|
|
|
// button two
|
|
if (numBtns >= 2) {
|
|
t = new GfxCompButton(*win, *messageButtonRects[1],
|
|
dialogPushImag, kNumBtnImages, btnMsg2, pal, 11, cmdDialogQuit);
|
|
t->_accelKey = k2;
|
|
}
|
|
|
|
// button three
|
|
if (numBtns >= 3) {
|
|
t = new GfxCompButton(*win, *messageButtonRects[2],
|
|
dialogPushImag, kNumBtnImages, btnMsg3, pal, 12, cmdDialogQuit);
|
|
t->_accelKey = k3;
|
|
}
|
|
|
|
// title for the box
|
|
new CPlaqText(*win, *messageTextRects[0], title, &Plate18Font, 0, pal, 0, nullptr);
|
|
|
|
// message for box
|
|
new CPlacardPanel(*win, *messageTextRects[1], msg, &Onyx10Font, 0, pal, 0, nullptr);
|
|
|
|
win->setDecorations(messageDecorations,
|
|
ARRAYSIZE(messageDecorations),
|
|
decRes, 'M', 'E', 'S');
|
|
|
|
|
|
win->_userData = &rInfo;
|
|
win->open();
|
|
|
|
|
|
EventLoop(rInfo.running, true);
|
|
|
|
|
|
// remove the window all attatched controls
|
|
delete win;
|
|
|
|
// unload all image arrays
|
|
unloadImageRes(dialogPushImag, kNumBtnImages);
|
|
|
|
// remove the resource handle
|
|
if (decRes) resFile->disposeContext(decRes);
|
|
decRes = nullptr;
|
|
|
|
// replace the damaged area
|
|
mainWindow->invalidate(&messageWindowRect);
|
|
|
|
// return the result code
|
|
return rInfo.result % 10;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* ===================================================================== *
|
|
Placard thingus
|
|
* ===================================================================== */
|
|
|
|
CPlacardWindow::CPlacardWindow(
|
|
const Rect16 &r,
|
|
uint16 ident,
|
|
AppFunc *cmd,
|
|
char *windowText,
|
|
textPallete &pal,
|
|
gFont *font) :
|
|
ModalWindow(r, ident, cmd) {
|
|
_textPal = pal;
|
|
_textFont = font;
|
|
|
|
positionText(windowText, Rect16(0, 0, r.width, r.height));
|
|
}
|
|
|
|
void CPlacardWindow::positionText(
|
|
char *windowText,
|
|
const Rect16 &textArea) {
|
|
if (windowText) {
|
|
int16 i,
|
|
yPos,
|
|
maxY;
|
|
|
|
int16 fontHeight = _textFont->height;
|
|
|
|
// make a copy of the window text string
|
|
Common::sprintf_s(_titleBuf, "%s", windowText);
|
|
|
|
// break up the title text string
|
|
_titleCount = SplitString(_titleBuf, _titleStrings, kMaxLines, '\n');
|
|
|
|
yPos = textArea.y +
|
|
((textArea.height - _titleCount * fontHeight) >> 1);
|
|
yPos = MAX(yPos, textArea.y);
|
|
|
|
maxY = textArea.y + textArea.height - fontHeight;
|
|
|
|
for (i = 0; i < _titleCount; i++, yPos += fontHeight) {
|
|
if (yPos < maxY) {
|
|
_titlePos[i].y = yPos;
|
|
_titlePos[i].x =
|
|
textArea.x +
|
|
((textArea.width -
|
|
TextWidth(_textFont, _titleStrings[i], -1, 0))
|
|
>> 1);
|
|
} else _titleCount = i;
|
|
}
|
|
} else _titleCount = 0;
|
|
}
|
|
|
|
int16 CPlacardWindow:: SplitString(
|
|
char *text,
|
|
char *textStart[],
|
|
int16 maxStrings,
|
|
char delimiter) {
|
|
int16 count;
|
|
|
|
for (count = 0; count < maxStrings;) {
|
|
textStart[count++] = text;
|
|
if ((text = strchr(text, delimiter)) == nullptr) break;
|
|
*text++ = '\0';
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
// just exit if the user hit the screen.
|
|
bool CPlacardWindow::pointerHit(gPanelMessage &) {
|
|
gWindow *win;
|
|
requestInfo *ri;
|
|
|
|
win = getWindow(); // get the window pointer
|
|
ri = win ? (requestInfo *)win->_userData : nullptr;
|
|
|
|
if (ri) {
|
|
ri->running = 0;
|
|
ri->result = _id;
|
|
}
|
|
|
|
//activate( kEventMouseDown );
|
|
return true;
|
|
}
|
|
|
|
void CPlacardWindow::drawClipped(
|
|
gPort &port,
|
|
const Point16 &offset,
|
|
const Rect16 &r) {
|
|
if (!_extent.overlap(r)) return;
|
|
|
|
// do background drawing first...
|
|
ModalWindow::drawClipped(port, offset, r);
|
|
|
|
int16 i;
|
|
Point16 origin;
|
|
Rect16 rect;
|
|
|
|
SAVE_GPORT_STATE(port);
|
|
|
|
origin.x = _extent.x - offset.x;
|
|
origin.y = _extent.y - offset.y;
|
|
|
|
rect.x = origin.x;
|
|
rect.y = origin.y;
|
|
rect.width = _extent.width;
|
|
rect.height = _extent.height;
|
|
|
|
for (i = 0; i < _titleCount; i++) {
|
|
Point16 textPos = origin + _titlePos[i];
|
|
|
|
writePlaqTextPos(port,
|
|
textPos,
|
|
_textFont,
|
|
0,
|
|
_textPal,
|
|
false,
|
|
_titleStrings[i]);
|
|
}
|
|
}
|
|
|
|
CPlacardPanel::CPlacardPanel(gPanelList &gpl, const Rect16 &r, const char *t, gFont *f,
|
|
int16 i, textPallete &p, int16 i2, AppFunc *cmd) :
|
|
CPlaqText(gpl, r, t, f, i, p, i2, cmd) {
|
|
|
|
positionText(t, Rect16(0, 0, r.width, r.height));
|
|
}
|
|
|
|
|
|
|
|
void CPlacardPanel::positionText(const char *windowText, const Rect16 &textArea) {
|
|
if (windowText) {
|
|
int16 i,
|
|
yPos,
|
|
maxY;
|
|
|
|
int16 fontHeight = _buttonFont->height;
|
|
|
|
// make a copy of the window text string
|
|
Common::sprintf_s(_titleBuf, "%s", windowText);
|
|
|
|
// break up the title text string
|
|
_titleCount = SplitString(_titleBuf, _titleStrings, kMaxLines, '\n');
|
|
|
|
yPos = textArea.y +
|
|
((textArea.height - _titleCount * fontHeight) >> 1);
|
|
yPos = MAX(yPos, textArea.y);
|
|
|
|
maxY = textArea.y + textArea.height - fontHeight;
|
|
|
|
for (i = 0; i < _titleCount; i++, yPos += fontHeight) {
|
|
if (yPos < maxY) {
|
|
_titlePos[i].y = yPos;
|
|
_titlePos[i].x =
|
|
textArea.x +
|
|
((textArea.width -
|
|
TextWidth(_buttonFont, _titleStrings[i], -1, 0))
|
|
>> 1);
|
|
} else _titleCount = i;
|
|
}
|
|
} else _titleCount = 0;
|
|
}
|
|
|
|
int16 CPlacardPanel:: SplitString(
|
|
char *text,
|
|
char *textStart[],
|
|
int16 maxStrings,
|
|
char delimiter) {
|
|
int16 count;
|
|
|
|
for (count = 0; count < maxStrings;) {
|
|
textStart[count++] = text;
|
|
if ((text = strchr(text, delimiter)) == nullptr) break;
|
|
*text++ = '\0';
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void CPlacardPanel::drawClipped(
|
|
gPort &port,
|
|
const Point16 &offset,
|
|
const Rect16 &r) {
|
|
if (!_extent.overlap(r)) return;
|
|
|
|
// do background drawing first...
|
|
int16 i;
|
|
Point16 origin;
|
|
Rect16 rect;
|
|
|
|
SAVE_GPORT_STATE(port);
|
|
|
|
origin.x = _extent.x - offset.x;
|
|
origin.y = _extent.y - offset.y;
|
|
|
|
rect.x = origin.x;
|
|
rect.y = origin.y;
|
|
rect.width = _extent.width;
|
|
rect.height = _extent.height;
|
|
|
|
for (i = 0; i < _titleCount; i++) {
|
|
Point16 textPos = origin + _titlePos[i];
|
|
|
|
writePlaqTextPos(port,
|
|
textPos,
|
|
_buttonFont,
|
|
0,
|
|
_textFacePal,
|
|
false,
|
|
_titleStrings[i]);
|
|
}
|
|
}
|
|
|
|
|
|
void placardWindow(int8 type, char *text) {
|
|
|
|
Rect16 plaqRectWood = Rect16((640 - 238) / 2,
|
|
(480 - 145) / 3,
|
|
238,
|
|
145);
|
|
|
|
Rect16 plaqRectStone = Rect16((640 - 236) / 2,
|
|
(480 - 143) / 3,
|
|
236,
|
|
143);
|
|
|
|
Rect16 plaqRectBrass = Rect16((640 - 274) / 2,
|
|
(480 - 145) / 3,
|
|
274,
|
|
145);
|
|
|
|
// decoration information
|
|
WindowDecoration plaqDecWood[1] = {
|
|
WindowDecoration(plaqRectWood, 0)
|
|
};
|
|
|
|
WindowDecoration plaqDecStone[1] = {
|
|
WindowDecoration(plaqRectStone, 1)
|
|
};
|
|
|
|
WindowDecoration plaqDecBrass[2] = {
|
|
WindowDecoration(plaqRectBrass, 2),
|
|
WindowDecoration(plaqRectBrass, 2)
|
|
};
|
|
|
|
// used to hold the coloration of the text for a give type
|
|
textPallete pal;
|
|
|
|
// requester info struct
|
|
requestInfo rInfo;
|
|
|
|
rInfo.result = -1;
|
|
rInfo.running = true;
|
|
|
|
// point to the modal window
|
|
CPlacardWindow *win;
|
|
|
|
// resource handle
|
|
hResContext *resContext;
|
|
|
|
// init the resource context handle
|
|
resContext = resFile->newContext(MKTAG('I', 'M', 'A', 'G'), "Placard resources");
|
|
|
|
|
|
// do type related assignments
|
|
switch (type) {
|
|
case WOOD_TYPE:
|
|
|
|
// set wood text inlay color
|
|
pal.set(62, 64, 67, 11, 23, 17);
|
|
|
|
// create the window
|
|
win = new CPlacardWindow(plaqRectWood, 0, nullptr, text, pal, &Plate18Font);
|
|
|
|
// setup the background imagery
|
|
win->setDecorations(plaqDecWood,
|
|
ARRAYSIZE(plaqDecWood),
|
|
resContext, 'P', 'L', 'Q');
|
|
|
|
break;
|
|
|
|
case STONE_TYPE:
|
|
|
|
// set stone text inlay color
|
|
pal.set(16, 12, 18, 11, 23, 0x78);
|
|
|
|
// create the window
|
|
win = new CPlacardWindow(plaqRectStone, 0, nullptr, text, pal, &Plate18Font);
|
|
|
|
// setup the background imagery
|
|
win->setDecorations(plaqDecStone,
|
|
ARRAYSIZE(plaqDecStone),
|
|
resContext, 'P', 'L', 'Q');
|
|
|
|
break;
|
|
|
|
case BRASS_TYPE:
|
|
|
|
// set brass text inlay color
|
|
pal.set(89, 93, 95, 11, 23, 0x76);
|
|
|
|
// create the window
|
|
win = new CPlacardWindow(plaqRectBrass, 0, nullptr, text, pal, &Plate18Font);
|
|
|
|
// setup the background imagery
|
|
win->setDecorations(plaqDecBrass,
|
|
ARRAYSIZE(plaqDecBrass),
|
|
resContext, 'P', 'L', 'Q');
|
|
|
|
break;
|
|
|
|
default:
|
|
error("Unhandled placard type %d", type);
|
|
break;
|
|
}
|
|
|
|
|
|
win->_userData = &rInfo;
|
|
win->open();
|
|
|
|
|
|
EventLoop(rInfo.running, true);
|
|
|
|
|
|
// remove the window all attatched controls
|
|
delete win;
|
|
|
|
// remove the resource handle
|
|
if (resContext) resFile->disposeContext(resContext);
|
|
|
|
// replace the damaged area
|
|
mainWindow->invalidate(&plaqRectBrass); // brass just happens to be the largest rect....
|
|
|
|
// return the result code
|
|
//return rInfo.result;
|
|
}
|
|
|
|
|
|
void updateAutoAggressionButton(bool setting) {
|
|
if (autoAggressBtn != nullptr)
|
|
autoAggressBtn->select(setting);
|
|
}
|
|
|
|
void updateAutoWeaponButton(bool setting) {
|
|
if (autoWeaponBtn != nullptr)
|
|
autoWeaponBtn->select(setting);
|
|
}
|
|
|
|
// dialog appfuncs
|
|
APPFUNC(cmdDialogQuit) {
|
|
gWindow *win;
|
|
requestInfo *ri;
|
|
|
|
if (ev.panel && isUserAction(ev) && ev.value) {
|
|
win = ev.panel->getWindow(); // get the window pointer
|
|
ri = win ? (requestInfo *)win->_userData : nullptr;
|
|
|
|
if (ri) {
|
|
ri->running = 0;
|
|
ri->result = ev.panel->_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdFileSave) {
|
|
gWindow *win;
|
|
requestInfo *ri;
|
|
|
|
if (ev.panel && isUserAction(ev) && ev.value) {
|
|
// now close the window
|
|
win = ev.panel->getWindow(); // get the window pointer
|
|
ri = win ? (requestInfo *)win->_userData : nullptr;
|
|
|
|
if (ri) {
|
|
ri->running = 0;
|
|
ri->result = typeSave; //ev.panel->id;
|
|
}
|
|
|
|
textBox->keepChanges();
|
|
|
|
// get index of the game
|
|
int8 saveIndex = textBox->getIndex();
|
|
|
|
#ifndef IMMEDIATE_SAVE
|
|
// save game
|
|
g_vm->saveGameState(saveIndex, textBox->getLine(saveIndex), false);
|
|
#else
|
|
deferredLoadID = saveIndex;
|
|
deferredSaveFlag = true;
|
|
Common::strcpy_s(deferredSaveName, textBox->getLine(saveIndex));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdFileLoad) {
|
|
gWindow *win;
|
|
requestInfo *ri;
|
|
SaveFileHeader header;
|
|
int saveNo;
|
|
|
|
if (ev.panel && isUserAction(ev) && ev.value) {
|
|
// get the file index
|
|
saveNo = textBox->getIndex();
|
|
|
|
if (getSaveName(saveNo, header)) {
|
|
|
|
// close window
|
|
win = ev.panel->getWindow(); // get the window pointer
|
|
ri = win ? (requestInfo *)win->_userData : nullptr;
|
|
|
|
if (ri) {
|
|
ri->running = 0;
|
|
ri->result = typeLoad; //ev.panel->id;
|
|
}
|
|
|
|
deferredLoadID = saveNo;
|
|
deferredLoadFlag = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdSaveDialogUp) {
|
|
if (ev.panel && isUserAction(ev) && ev.value) {
|
|
if (textBox) {
|
|
textBox->scrollUp();
|
|
}
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdSaveDialogDown) {
|
|
if (ev.panel && isUserAction(ev) && ev.value) {
|
|
if (textBox) {
|
|
textBox->scrollDown();
|
|
}
|
|
}
|
|
}
|
|
|
|
APPFUNCV(cmdTextResponse) {
|
|
}
|
|
|
|
APPFUNC(cmdOptionsSaveGame) {
|
|
if (ev.panel && isUserAction(ev) && ev.value) {
|
|
FileDialog(typeSave);
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdOptionsNewGame) {
|
|
if (ev.panel && isUserAction(ev) && ev.value) {
|
|
gWindow *win;
|
|
requestInfo *ri;
|
|
win = ev.panel->getWindow(); // get the window pointer
|
|
ri = win ? (requestInfo *)win->_userData : nullptr;
|
|
|
|
if (ri) {
|
|
ri->running = 0;
|
|
ri->result = ev.panel->_id;
|
|
deferredLoadID = 999;
|
|
deferredLoadFlag = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdOptionsLoadGame) {
|
|
gWindow *win;
|
|
requestInfo *ri;
|
|
|
|
if (ev.panel && isUserAction(ev) && ev.value) {
|
|
|
|
// if the fileDialog actually did loading
|
|
if (FileDialog(typeLoad) == typeLoad) {
|
|
win = ev.panel->getWindow(); // get the window pointer
|
|
ri = win ? (requestInfo *)win->_userData : nullptr;
|
|
|
|
if (ri) {
|
|
ri->running = 0;
|
|
ri->result = ev.panel->_id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdQuitGame) {
|
|
gWindow *win;
|
|
requestInfo *ri;
|
|
|
|
if (ev.panel && isUserAction(ev) && ev.value) {
|
|
win = ev.panel->getWindow(); // get the window pointer
|
|
ri = win ? (requestInfo *)win->_userData : nullptr;
|
|
|
|
if (ri
|
|
&& userDialog(
|
|
VFYX_DIALOG_NAME,
|
|
VFYX_DIALOG_CAPTION,
|
|
VFYX_DIALOG_BUTTON1,
|
|
VFYX_DIALOG_BUTTON2, nullptr) == 0) {
|
|
endGame();
|
|
|
|
ri->running = false;
|
|
ri->result = ev.panel->_id;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
inline int16 quantizedVolume(uint16 trueVolume) {
|
|
int16 quantized = trueVolume & 0xFFF8;
|
|
quantized += (quantized / 16);
|
|
|
|
quantized = CLIP(quantized, (int16)0, (int16)255);
|
|
|
|
return quantized;
|
|
}
|
|
|
|
|
|
|
|
APPFUNC(cmdCredits) {
|
|
if (ev.panel && isUserAction(ev) && ev.value) {
|
|
//reDrawScreen();
|
|
openBook(resImports->reserved[0]);
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdAutoAggression) {
|
|
if (isUserAction(ev)) {
|
|
toggleAutoAggression();
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdAutoWeapon) {
|
|
if (isUserAction(ev)) {
|
|
toggleAutoWeapon();
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdNight) {
|
|
if (isUserAction(ev)) {
|
|
g_vm->_showNight = !g_vm->_showNight;
|
|
nightBtn->select(g_vm->_showNight);
|
|
}
|
|
}
|
|
|
|
APPFUNC(cmdSpeechText) {
|
|
if (isUserAction(ev)) {
|
|
g_vm->_speechText = !g_vm->_speechText;
|
|
speechTextBtn->select(g_vm->_speechText);
|
|
|
|
ConfMan.setBool("subtitles", g_vm->_speechText);
|
|
}
|
|
}
|
|
|
|
void volumeChanged();
|
|
|
|
// Set music volume
|
|
|
|
APPFUNC(cmdSetMIDIVolume) {
|
|
int16 v = quantizedVolume(ev.value);
|
|
ConfMan.setInt("music_volume", v);
|
|
g_vm->syncSoundSettings();
|
|
volumeChanged();
|
|
}
|
|
|
|
// Set DIG volume for DINO
|
|
|
|
APPFUNC(cmdSetDIGVolume) {
|
|
int16 v = quantizedVolume(ev.value);
|
|
ConfMan.setInt("music_volume", v);
|
|
g_vm->syncSoundSettings();
|
|
volumeChanged();
|
|
}
|
|
|
|
// Set DIG speech volume for FTA
|
|
|
|
APPFUNC(cmdSetSpeechVolume) {
|
|
int16 v = quantizedVolume(ev.value);
|
|
ConfMan.setInt("speech_volume", v);
|
|
g_vm->syncSoundSettings();
|
|
volumeChanged();
|
|
}
|
|
|
|
// Set DIG sound volume for FTA
|
|
|
|
APPFUNC(cmdSetSoundVolume) {
|
|
int16 v = quantizedVolume(ev.value);
|
|
ConfMan.setInt("sfx_volume", v);
|
|
g_vm->syncSoundSettings();
|
|
volumeChanged();
|
|
}
|
|
|
|
// Save volume settings
|
|
// This should be called when exiting the dialog to save the changes
|
|
|
|
APPFUNCV(cmdSaveVolumeSettings) {
|
|
g_vm->saveConfig();
|
|
}
|
|
|
|
} // end of namespace Saga2
|