2020-10-14 15:16:30 +02:00
|
|
|
/* 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 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "twine/menu.h"
|
|
|
|
#include "audio/mixer.h"
|
|
|
|
#include "backends/audiocd/audiocd.h"
|
2020-10-25 22:16:21 +01:00
|
|
|
#include "backends/keymapper/keymapper.h"
|
2020-10-14 15:16:30 +02:00
|
|
|
#include "common/config-manager.h"
|
2020-10-20 21:40:38 +02:00
|
|
|
#include "common/events.h"
|
2020-10-23 13:38:02 +02:00
|
|
|
#include "common/keyboard.h"
|
2020-10-14 15:16:30 +02:00
|
|
|
#include "common/scummsys.h"
|
|
|
|
#include "common/system.h"
|
2020-10-23 12:18:28 +02:00
|
|
|
#include "common/util.h"
|
2020-10-14 15:16:30 +02:00
|
|
|
#include "twine/actor.h"
|
|
|
|
#include "twine/animations.h"
|
|
|
|
#include "twine/gamestate.h"
|
|
|
|
#include "twine/grid.h"
|
|
|
|
#include "twine/hqrdepack.h"
|
2020-10-23 13:44:38 +02:00
|
|
|
#include "twine/input.h"
|
2020-10-23 20:09:33 +02:00
|
|
|
#include "twine/interface.h"
|
2020-10-14 15:16:30 +02:00
|
|
|
#include "twine/menuoptions.h"
|
|
|
|
#include "twine/movements.h"
|
|
|
|
#include "twine/music.h"
|
|
|
|
#include "twine/redraw.h"
|
|
|
|
#include "twine/renderer.h"
|
|
|
|
#include "twine/resources.h"
|
|
|
|
#include "twine/scene.h"
|
|
|
|
#include "twine/screens.h"
|
|
|
|
#include "twine/sound.h"
|
|
|
|
#include "twine/text.h"
|
|
|
|
#include "twine/twine.h"
|
|
|
|
|
|
|
|
namespace TwinE {
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
/** Main menu background image number
|
|
|
|
Used when returning from credit sequence to redraw the main menu background image */
|
2020-10-14 15:16:30 +02:00
|
|
|
static const uint32 kPlasmaEffectFilesize = 262176;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
/** Menu buttons width */
|
2020-10-14 15:16:30 +02:00
|
|
|
static const uint16 kMainMenuButtonWidth = 320;
|
2020-10-14 14:20:38 +02:00
|
|
|
/** Used to calculate the spanning between button and screen */
|
2020-10-14 15:16:30 +02:00
|
|
|
static const uint16 kMainMenuButtonSpan = 550;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-27 00:00:47 +01:00
|
|
|
namespace MenuButtonTypes {
|
|
|
|
enum _MenuButtonTypes {
|
2020-10-14 15:16:30 +02:00
|
|
|
kMusicVolume = 1,
|
|
|
|
kSoundVolume = 2,
|
|
|
|
kCDVolume = 3,
|
|
|
|
kLineVolume = 4,
|
2020-10-27 00:00:47 +01:00
|
|
|
kMasterVolume = 5,
|
|
|
|
kAgressiveMode = 6,
|
|
|
|
kPolygonDetails = 7,
|
|
|
|
kShadowSettings = 8,
|
|
|
|
kSceneryZoom = 9
|
2020-10-24 14:26:50 +02:00
|
|
|
};
|
2020-10-27 00:00:47 +01:00
|
|
|
}
|
2020-10-24 14:26:50 +02:00
|
|
|
|
2020-10-27 00:19:28 +01:00
|
|
|
#define checkMenuQuit(callMenu) if ((callMenu) == kQuitEngine) { return kQuitEngine; }
|
2020-10-27 00:00:47 +01:00
|
|
|
#define kBackground 9999
|
2020-10-26 23:43:17 +01:00
|
|
|
|
2020-10-23 12:18:28 +02:00
|
|
|
namespace _priv {
|
2020-10-14 14:20:38 +02:00
|
|
|
/** Main Menu Settings
|
|
|
|
|
|
|
|
Used to create the game main menu. */
|
2020-10-23 12:18:28 +02:00
|
|
|
static const int16 MainMenuSettings[] = {
|
2020-10-14 15:16:30 +02:00
|
|
|
0, // Current loaded button (button number)
|
|
|
|
4, // Num of buttons
|
|
|
|
200, // Buttons box height ( is used to calc the height where the first button will appear )
|
|
|
|
0, // unused
|
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kNewGame, // new game
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kContinueGame, // continue game
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kOptions, // options
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kQuit, // quit
|
2020-10-14 14:20:38 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Give Up Menu Settings
|
|
|
|
|
|
|
|
Used to create the in-game menu. */
|
2020-10-23 12:18:28 +02:00
|
|
|
static const int16 GiveUpMenuSettings[] = {
|
2020-10-14 15:16:30 +02:00
|
|
|
0, // Current loaded button (button number)
|
|
|
|
2, // Num of buttons
|
|
|
|
240, // Buttons box height ( is used to calc the height where the first button will appear )
|
|
|
|
0, // unused
|
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kContinue, // continue game
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kGiveUp, // quit game
|
2020-10-14 14:20:38 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Give Up Menu Settings
|
|
|
|
|
|
|
|
Used to create the in-game menu. This menu have one extra item to save the game */
|
2020-10-23 12:18:28 +02:00
|
|
|
static const int16 GiveUpMenuWithSaveSettings[] = {
|
2020-10-14 15:16:30 +02:00
|
|
|
0, // Current loaded button (button number)
|
|
|
|
3, // Num of buttons
|
|
|
|
240, // Buttons box height ( is used to calc the height where the first button will appear )
|
|
|
|
0, // unused
|
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kContinue, // continue game
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kCreateSaveGame, // save game
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kGiveUp, // quit game
|
2020-10-14 14:20:38 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Options Menu Settings
|
|
|
|
|
|
|
|
Used to create the options menu. */
|
2020-10-23 12:18:28 +02:00
|
|
|
static const int16 OptionsMenuSettings[] = {
|
2020-10-14 15:16:30 +02:00
|
|
|
0, // Current loaded button (button number)
|
|
|
|
4, // Num of buttons
|
|
|
|
0, // Buttons box height ( is used to calc the height where the first button will appear )
|
|
|
|
0, // unused
|
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kReturnMenu, // return to previous menu
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kVolumeSettings, // volume settings
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kSaveManage, // save game management
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kAdvanced, // advanced options
|
2020-10-14 14:20:38 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Advanced Options Menu Settings
|
|
|
|
|
|
|
|
Used to create the advanced options menu. */
|
2020-10-23 12:18:28 +02:00
|
|
|
static const int16 AdvOptionsMenuSettings[] = {
|
2020-10-14 15:16:30 +02:00
|
|
|
0, // Current loaded button (button number)
|
|
|
|
5, // Num of buttons
|
|
|
|
0, // Buttons box height ( is used to calc the height where the first button will appear )
|
|
|
|
0, // unused
|
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kReturnMenu, // return to main menu
|
|
|
|
MenuButtonTypes::kAgressiveMode,
|
|
|
|
TextId::kBehaviourAgressiveManual, // aggressive mode (manual|auto)
|
|
|
|
MenuButtonTypes::kPolygonDetails,
|
|
|
|
TextId::kDetailsPolygonsHigh, // Polygon detail (full|medium|low)
|
|
|
|
MenuButtonTypes::kShadowSettings,
|
|
|
|
TextId::kDetailsShadowHigh, // Shadows (all|character|no)
|
|
|
|
MenuButtonTypes::kSceneryZoom,
|
|
|
|
TextId::kScenaryZoomOn, // scenary zoon (on|off)
|
2020-10-14 14:20:38 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Save Game Management Menu Settings
|
|
|
|
|
|
|
|
Used to create the save game management menu. */
|
2020-10-23 12:18:28 +02:00
|
|
|
static const int16 SaveManageMenuSettings[] = {
|
2020-10-14 15:16:30 +02:00
|
|
|
0, // Current loaded button (button number)
|
|
|
|
3, // Num of buttons
|
|
|
|
0, // Buttons box height ( is used to calc the height where the first button will appear )
|
|
|
|
0, // unused
|
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kReturnMenu, // return to main menu
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kCreateSaveGame, // copy saved game
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kDeleteSaveGame, // delete saved game
|
2020-10-14 14:20:38 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Volume Menu Settings
|
|
|
|
|
|
|
|
Used to create the volume menu. */
|
2020-10-23 12:18:28 +02:00
|
|
|
static const int16 VolumeMenuSettings[] = {
|
2020-10-14 15:16:30 +02:00
|
|
|
0, // Current loaded button (button number)
|
|
|
|
7, // Num of buttons
|
|
|
|
0, // Buttons box height ( is used to calc the height where the first button will appear )
|
|
|
|
0, // unused
|
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kReturnMenu, // return to main menu
|
|
|
|
MenuButtonTypes::kMusicVolume,
|
|
|
|
TextId::kMusicVolume, // music volume
|
|
|
|
MenuButtonTypes::kSoundVolume,
|
|
|
|
TextId::kSoundVolume, // sfx volume
|
|
|
|
MenuButtonTypes::kCDVolume,
|
|
|
|
TextId::kCDVolume, // cd volume
|
|
|
|
MenuButtonTypes::kLineVolume,
|
|
|
|
TextId::kLineInVolume, // line-in volume
|
|
|
|
MenuButtonTypes::kMasterVolume,
|
|
|
|
TextId::kMasterVolume, // master volume
|
2020-10-14 15:16:30 +02:00
|
|
|
0,
|
2020-10-27 00:00:47 +01:00
|
|
|
TextId::kSaveSettings, // save parameters
|
2020-10-14 14:20:38 +02:00
|
|
|
};
|
2020-10-23 12:18:28 +02:00
|
|
|
} // namespace _priv
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-23 13:38:02 +02:00
|
|
|
static int16 *copySettings(const int16 *settings, size_t size) {
|
2020-10-23 12:18:28 +02:00
|
|
|
int16 *buf = (int16 *)malloc(size);
|
|
|
|
if (buf == nullptr) {
|
|
|
|
error("Failed to allocate menu state memory");
|
|
|
|
}
|
|
|
|
memcpy(buf, settings, size);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2020-10-25 00:55:11 +02:00
|
|
|
Menu::Menu(TwinEEngine *engine) {
|
|
|
|
_engine = engine;
|
|
|
|
|
2020-10-23 12:18:28 +02:00
|
|
|
OptionsMenuState = copySettings(_priv::OptionsMenuSettings, sizeof(_priv::OptionsMenuSettings));
|
|
|
|
GiveUpMenuWithSaveState = copySettings(_priv::GiveUpMenuWithSaveSettings, sizeof(_priv::GiveUpMenuWithSaveSettings));
|
|
|
|
VolumeMenuState = copySettings(_priv::VolumeMenuSettings, sizeof(_priv::VolumeMenuSettings));
|
|
|
|
SaveManageMenuState = copySettings(_priv::SaveManageMenuSettings, sizeof(_priv::SaveManageMenuSettings));
|
|
|
|
GiveUpMenuState = copySettings(_priv::GiveUpMenuSettings, sizeof(_priv::GiveUpMenuSettings));
|
|
|
|
MainMenuState = copySettings(_priv::MainMenuSettings, sizeof(_priv::MainMenuSettings));
|
|
|
|
AdvOptionsMenuState = copySettings(_priv::AdvOptionsMenuSettings, sizeof(_priv::AdvOptionsMenuSettings));
|
2020-10-25 01:25:28 +02:00
|
|
|
|
|
|
|
Common::fill(&behaviourAnimState[0], &behaviourAnimState[4], 0);
|
2020-10-25 05:18:52 +01:00
|
|
|
Common::fill(&itemAngle[0], &itemAngle[255], 0);
|
|
|
|
Common::fill(&currMenuTextBuffer[0], &currMenuTextBuffer[256], 0);
|
2020-10-23 12:18:28 +02:00
|
|
|
}
|
2020-10-14 15:16:30 +02:00
|
|
|
|
2020-10-23 23:19:59 +02:00
|
|
|
Menu::~Menu() {
|
|
|
|
free(plasmaEffectPtr);
|
|
|
|
free(OptionsMenuState);
|
|
|
|
free(GiveUpMenuWithSaveState);
|
|
|
|
free(VolumeMenuState);
|
|
|
|
free(SaveManageMenuState);
|
|
|
|
free(GiveUpMenuState);
|
|
|
|
free(MainMenuState);
|
|
|
|
free(AdvOptionsMenuState);
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
void Menu::plasmaEffectRenderFrame() {
|
2020-10-23 10:54:45 +02:00
|
|
|
for (int32 j = 1; j < PLASMA_HEIGHT - 1; j++) {
|
|
|
|
for (int32 i = 1; i < PLASMA_WIDTH - 1; i++) {
|
2020-10-22 16:32:52 +02:00
|
|
|
/* Here we calculate the average of all 8 neighbour pixel values */
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-23 10:54:45 +02:00
|
|
|
int16 c;
|
2020-10-14 15:16:30 +02:00
|
|
|
c = plasmaEffectPtr[(i - 1) + (j - 1) * PLASMA_WIDTH]; //top-left
|
|
|
|
c += plasmaEffectPtr[(i + 0) + (j - 1) * PLASMA_WIDTH]; //top
|
|
|
|
c += plasmaEffectPtr[(i + 1) + (j - 1) * PLASMA_WIDTH]; //top-right
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
c += plasmaEffectPtr[(i - 1) + (j + 0) * PLASMA_WIDTH]; //left
|
|
|
|
c += plasmaEffectPtr[(i + 1) + (j + 0) * PLASMA_WIDTH]; //right
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
c += plasmaEffectPtr[(i - 1) + (j + 1) * PLASMA_WIDTH]; // bottom-left
|
|
|
|
c += plasmaEffectPtr[(i + 0) + (j + 1) * PLASMA_WIDTH]; // bottom
|
|
|
|
c += plasmaEffectPtr[(i + 1) + (j + 1) * PLASMA_WIDTH]; // bottom-right
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-22 16:32:52 +02:00
|
|
|
/* And the 2 least significant bits are used as a
|
|
|
|
* randomizing parameter for statistically fading the flames */
|
|
|
|
c = (c >> 3) | ((c & 0x0003) << 13);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
if (!(c & 0x6500) &&
|
|
|
|
(j >= (PLASMA_HEIGHT - 4) || c > 0)) {
|
|
|
|
c--; /*fade this pixel*/
|
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
/* plot the pixel using the calculated color */
|
|
|
|
plasmaEffectPtr[i + (PLASMA_HEIGHT + j) * PLASMA_WIDTH] = (uint8)c;
|
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
// flip the double-buffer while scrolling the effect vertically:
|
2020-10-23 10:54:45 +02:00
|
|
|
uint8 *dest = plasmaEffectPtr;
|
2020-10-23 12:14:44 +02:00
|
|
|
const uint8 *src = plasmaEffectPtr + (PLASMA_HEIGHT + 1) * PLASMA_WIDTH;
|
2020-10-23 10:54:45 +02:00
|
|
|
for (int32 i = 0; i < PLASMA_HEIGHT * PLASMA_WIDTH; i++)
|
2020-10-14 14:20:38 +02:00
|
|
|
*(dest++) = *(src++);
|
|
|
|
}
|
|
|
|
|
2020-10-26 00:18:17 +01:00
|
|
|
void Menu::processPlasmaEffect(int32 left, int32 top, int32 color) {
|
2020-10-23 10:54:45 +02:00
|
|
|
const int32 max_value = color + 15;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
plasmaEffectRenderFrame();
|
|
|
|
|
2020-10-23 12:14:44 +02:00
|
|
|
const uint8 *in = plasmaEffectPtr + 5 * PLASMA_WIDTH;
|
2020-10-23 20:09:33 +02:00
|
|
|
uint8 *out = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top] + left;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-22 16:32:52 +02:00
|
|
|
for (int32 i = 0; i < 25; i++) {
|
|
|
|
for (int32 j = 0; j < kMainMenuButtonWidth; j++) {
|
2020-10-23 10:54:45 +02:00
|
|
|
const uint8 c = MIN(in[i * kMainMenuButtonWidth + j] / 2 + color, max_value);
|
2020-10-14 15:16:30 +02:00
|
|
|
/* 2x2 squares sharing the same pixel color: */
|
2020-10-26 00:18:17 +01:00
|
|
|
const int32 target = 2 * (i * DEFAULT_SCREEN_WIDTH + j);
|
2020-10-23 10:54:45 +02:00
|
|
|
out[target + 0] = c;
|
2020-10-14 14:20:38 +02:00
|
|
|
out[target + 1] = c;
|
2020-10-26 00:18:17 +01:00
|
|
|
out[target + DEFAULT_SCREEN_WIDTH + 0] = c;
|
|
|
|
out[target + DEFAULT_SCREEN_WIDTH + 1] = c;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
void Menu::drawBox(int32 left, int32 top, int32 right, int32 bottom) {
|
2020-10-23 11:00:46 +02:00
|
|
|
_engine->_interface->drawLine(left, top, right, top, 79); // top line
|
|
|
|
_engine->_interface->drawLine(left, top, left, bottom, 79); // left line
|
2020-10-23 10:54:45 +02:00
|
|
|
_engine->_interface->drawLine(right, top + 1, right, bottom, 73); // right line
|
|
|
|
_engine->_interface->drawLine(left + 1, bottom, right, bottom, 73); // bottom line
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-22 20:06:15 +02:00
|
|
|
void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 textId, bool hover) {
|
2020-10-23 10:54:45 +02:00
|
|
|
const int32 left = width - kMainMenuButtonSpan / 2;
|
|
|
|
const int32 right = width + kMainMenuButtonSpan / 2;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-22 16:32:52 +02:00
|
|
|
// topheight is the center Y pos of the button
|
2020-10-23 10:54:45 +02:00
|
|
|
const int32 top = topheight - 25; // this makes the button be 50 height
|
|
|
|
const int32 bottom = topheight + 25;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-23 12:45:13 +02:00
|
|
|
if (hover) {
|
2020-10-27 00:00:47 +01:00
|
|
|
if (buttonId <= MenuButtonTypes::kMasterVolume && buttonId >= MenuButtonTypes::kMusicVolume) {
|
2020-10-14 14:20:38 +02:00
|
|
|
int32 newWidth = 0;
|
2020-10-22 20:01:32 +02:00
|
|
|
switch (buttonId) {
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kMusicVolume: {
|
2020-10-23 10:54:45 +02:00
|
|
|
const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
|
2020-10-14 15:16:30 +02:00
|
|
|
newWidth = _engine->_screens->crossDot(left, right, Audio::Mixer::kMaxMixerVolume, volume);
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kSoundVolume: {
|
2020-10-23 10:54:45 +02:00
|
|
|
const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
|
2020-10-14 15:16:30 +02:00
|
|
|
newWidth = _engine->_screens->crossDot(left, right, Audio::Mixer::kMaxMixerVolume, volume);
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kCDVolume: {
|
2020-10-14 15:16:30 +02:00
|
|
|
const AudioCDManager::Status status = _engine->_system->getAudioCDManager()->getStatus();
|
|
|
|
newWidth = _engine->_screens->crossDot(left, right, Audio::Mixer::kMaxMixerVolume, status.volume);
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kLineVolume: {
|
2020-10-23 10:54:45 +02:00
|
|
|
const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
|
2020-10-14 15:16:30 +02:00
|
|
|
newWidth = _engine->_screens->crossDot(left, right, Audio::Mixer::kMaxMixerVolume, volume);
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kMasterVolume: {
|
2020-10-23 10:54:45 +02:00
|
|
|
const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
|
2020-10-14 15:16:30 +02:00
|
|
|
newWidth = _engine->_screens->crossDot(left, right, Audio::Mixer::kMaxMixerVolume, volume);
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-26 23:43:17 +01:00
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-26 00:18:17 +01:00
|
|
|
processPlasmaEffect(left, top, 80);
|
2020-10-14 15:16:30 +02:00
|
|
|
if (!(_engine->getRandomNumber() % 5)) {
|
|
|
|
plasmaEffectPtr[_engine->getRandomNumber() % 140 * 10 + 1900] = 255;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_interface->drawSplittedBox(newWidth, top, right, bottom, 68);
|
2020-10-14 14:20:38 +02:00
|
|
|
} else {
|
2020-10-26 00:18:17 +01:00
|
|
|
processPlasmaEffect(left, top, 64);
|
2020-10-14 15:16:30 +02:00
|
|
|
if (!(_engine->getRandomNumber() % 5)) {
|
|
|
|
plasmaEffectPtr[_engine->getRandomNumber() % 320 * 10 + 6400] = 255;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-10-21 14:19:00 +02:00
|
|
|
_engine->_interface->blitBox(left, top, right, bottom, (const int8 *)_engine->workVideoBuffer.getPixels(), left, top, (int8 *)_engine->frontVideoBuffer.getPixels());
|
2020-10-23 10:54:45 +02:00
|
|
|
_engine->_interface->drawTransparentBox(left, top, right, bottom, 4);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
drawBox(left, top, right, bottom);
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->setFontColor(15);
|
|
|
|
_engine->_text->setFontParameters(2, 8);
|
|
|
|
char dialText[256];
|
2020-10-22 20:01:32 +02:00
|
|
|
_engine->_text->getMenuText(textId, dialText, sizeof(dialText));
|
2020-10-14 15:16:30 +02:00
|
|
|
const int32 textSize = _engine->_text->getTextSize(dialText);
|
|
|
|
_engine->_text->drawText(width - (textSize / 2), topheight - 18, dialText);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->copyBlockPhys(left, top, right, bottom);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-23 08:48:38 +02:00
|
|
|
void Menu::drawButton(const int16 *menuSettings, bool hover) {
|
2020-10-22 20:06:15 +02:00
|
|
|
int16 buttonNumber = menuSettings[MenuSettings_CurrentLoadedButton];
|
|
|
|
const int32 maxButton = menuSettings[MenuSettings_NumberOfButtons];
|
|
|
|
int32 topHeight = menuSettings[MenuSettings_ButtonsBoxHeight];
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
if (topHeight == 0) {
|
|
|
|
topHeight = 35;
|
|
|
|
} else {
|
2020-10-23 09:00:18 +02:00
|
|
|
topHeight = topHeight - (((maxButton - 1) * 6) + (maxButton * 50)) / 2;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (maxButton <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
uint8 currentButton = 0;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-22 20:06:15 +02:00
|
|
|
const int16 *localData = menuSettings;
|
2020-10-23 09:00:18 +02:00
|
|
|
localData += MenuSettings_FirstButtonState;
|
2020-10-14 14:20:38 +02:00
|
|
|
do {
|
|
|
|
// get menu item settings
|
2020-10-14 15:16:30 +02:00
|
|
|
uint8 menuItemId = (uint8)*localData;
|
2020-10-14 14:20:38 +02:00
|
|
|
localData += 1;
|
2020-10-23 09:00:18 +02:00
|
|
|
uint16 textId = *localData;
|
2020-10-14 14:20:38 +02:00
|
|
|
localData += 1;
|
2020-10-23 08:48:38 +02:00
|
|
|
if (hover) {
|
2020-10-14 14:20:38 +02:00
|
|
|
if (currentButton == buttonNumber) {
|
2020-10-23 09:00:18 +02:00
|
|
|
drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, textId, hover);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (currentButton == buttonNumber) {
|
2020-10-23 09:00:18 +02:00
|
|
|
drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, textId, true);
|
2020-10-14 14:20:38 +02:00
|
|
|
} else {
|
2020-10-23 09:00:18 +02:00
|
|
|
drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, textId, false);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
currentButton++;
|
|
|
|
topHeight += 56; // increase button top height
|
|
|
|
} while (currentButton < maxButton);
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
int32 Menu::processMenu(int16 *menuSettings) {
|
2020-10-22 16:32:52 +02:00
|
|
|
int16 currentButton = menuSettings[MenuSettings_CurrentLoadedButton];
|
2020-10-23 13:38:02 +02:00
|
|
|
bool buttonsNeedRedraw = true;
|
2020-10-22 16:32:52 +02:00
|
|
|
const int32 numEntry = menuSettings[MenuSettings_NumberOfButtons];
|
2020-10-14 15:16:30 +02:00
|
|
|
int32 maxButton = numEntry - 1;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-25 21:55:14 +01:00
|
|
|
_engine->_input->enableKeyMap(uiKeyMapId);
|
2020-10-23 20:09:33 +02:00
|
|
|
|
|
|
|
_engine->_screens->loadMenuImage(false);
|
2020-10-14 14:20:38 +02:00
|
|
|
do {
|
2020-10-23 13:38:02 +02:00
|
|
|
_engine->readKeys();
|
|
|
|
|
2020-10-23 20:09:33 +02:00
|
|
|
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIDown)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
currentButton++;
|
|
|
|
if (currentButton == numEntry) { // if current button is the last, than next button is the first
|
|
|
|
currentButton = 0;
|
2020-10-14 15:16:30 +02:00
|
|
|
}
|
2020-10-23 13:38:02 +02:00
|
|
|
buttonsNeedRedraw = true;
|
2020-10-23 20:09:33 +02:00
|
|
|
} else if (_engine->_input->toggleActionIfActive(TwinEActionType::UIUp)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
currentButton--;
|
|
|
|
if (currentButton < 0) { // if current button is the first, than previous button is the last
|
|
|
|
currentButton = maxButton;
|
|
|
|
}
|
|
|
|
buttonsNeedRedraw = true;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-26 23:57:19 +01:00
|
|
|
int16 *menuStatePtr = &menuSettings[MenuSettings_FirstButtonState] + currentButton * 2;
|
|
|
|
const int16 id = *menuStatePtr; // get button parameters from settings array
|
|
|
|
int16 *textId = menuStatePtr + 1; // to store the changed values
|
2020-10-24 14:26:50 +02:00
|
|
|
if (menuSettings == AdvOptionsMenuState) {
|
|
|
|
switch (id) {
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kAgressiveMode:
|
2020-10-24 14:26:50 +02:00
|
|
|
if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft) || _engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
|
2020-10-26 23:57:19 +01:00
|
|
|
if (_engine->_actor->autoAgressive) {
|
|
|
|
_engine->_actor->autoAgressive = false;
|
2020-10-27 00:00:47 +01:00
|
|
|
*textId = TextId::kBehaviourAgressiveManual;
|
2020-10-26 23:57:19 +01:00
|
|
|
} else {
|
|
|
|
_engine->_actor->autoAgressive = true;
|
2020-10-27 00:00:47 +01:00
|
|
|
*textId = TextId::kBehaviourAgressiveAuto;
|
2020-10-26 23:57:19 +01:00
|
|
|
}
|
2020-10-24 14:26:50 +02:00
|
|
|
}
|
|
|
|
break;
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kPolygonDetails:
|
2020-10-26 23:57:19 +01:00
|
|
|
if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
|
|
|
|
_engine->cfgfile.PolygonDetails--;
|
|
|
|
} else if (_engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
|
|
|
|
_engine->cfgfile.PolygonDetails++;
|
|
|
|
}
|
|
|
|
_engine->cfgfile.PolygonDetails %= 3;
|
|
|
|
if (_engine->cfgfile.PolygonDetails == 0) {
|
2020-10-27 00:00:47 +01:00
|
|
|
*textId = TextId::kDetailsPolygonsLow;
|
2020-10-26 23:57:19 +01:00
|
|
|
} else if (_engine->cfgfile.PolygonDetails == 1) {
|
2020-10-27 00:00:47 +01:00
|
|
|
*textId = TextId::kDetailsPolygonsMiddle;
|
2020-10-26 23:57:19 +01:00
|
|
|
} else {
|
2020-10-27 00:00:47 +01:00
|
|
|
*textId = TextId::kDetailsPolygonsHigh;
|
2020-10-26 23:57:19 +01:00
|
|
|
}
|
2020-10-24 14:26:50 +02:00
|
|
|
break;
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kShadowSettings:
|
2020-10-24 14:26:50 +02:00
|
|
|
if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
|
|
|
|
_engine->cfgfile.ShadowMode--;
|
|
|
|
} else if (_engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
|
|
|
|
_engine->cfgfile.ShadowMode++;
|
|
|
|
}
|
|
|
|
_engine->cfgfile.ShadowMode %= 3;
|
2020-10-26 23:57:19 +01:00
|
|
|
if (_engine->cfgfile.ShadowMode == 0) {
|
2020-10-27 00:00:47 +01:00
|
|
|
*textId = TextId::kShadowsDisabled;
|
2020-10-26 23:57:19 +01:00
|
|
|
} else if (_engine->cfgfile.ShadowMode == 1) {
|
2020-10-27 00:00:47 +01:00
|
|
|
*textId = TextId::kShadowsFigures;
|
2020-10-26 23:57:19 +01:00
|
|
|
} else {
|
2020-10-27 00:00:47 +01:00
|
|
|
*textId = TextId::kDetailsShadowHigh;
|
2020-10-26 23:57:19 +01:00
|
|
|
}
|
2020-10-24 14:26:50 +02:00
|
|
|
break;
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kSceneryZoom:
|
2020-10-24 14:26:50 +02:00
|
|
|
if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft) || _engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
|
2020-10-26 23:57:19 +01:00
|
|
|
if (_engine->cfgfile.SceZoom) {
|
|
|
|
_engine->cfgfile.SceZoom = false;
|
2020-10-27 00:00:47 +01:00
|
|
|
*textId = TextId::kNoScenaryZoom;
|
2020-10-26 23:57:19 +01:00
|
|
|
} else {
|
|
|
|
_engine->cfgfile.SceZoom = true;
|
2020-10-27 00:00:47 +01:00
|
|
|
*textId = TextId::kScenaryZoomOn;
|
2020-10-26 23:57:19 +01:00
|
|
|
}
|
2020-10-24 14:26:50 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (menuSettings == VolumeMenuState) {
|
2020-10-23 13:38:02 +02:00
|
|
|
Audio::Mixer *mixer = _engine->_system->getMixer();
|
|
|
|
switch (id) {
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kMusicVolume: {
|
2020-10-23 13:38:02 +02:00
|
|
|
int volume = mixer->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
|
2020-10-23 20:09:33 +02:00
|
|
|
if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
volume -= 4;
|
2020-10-24 14:26:50 +02:00
|
|
|
} else if (_engine->_input->isActionActive(TwinEActionType::UIRight)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
volume += 4;
|
|
|
|
}
|
|
|
|
_engine->_music->musicVolume(volume);
|
|
|
|
break;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kSoundVolume: {
|
2020-10-23 13:38:02 +02:00
|
|
|
int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
|
2020-10-24 14:26:50 +02:00
|
|
|
if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
volume -= 4;
|
2020-10-24 14:26:50 +02:00
|
|
|
} else if (_engine->_input->isActionActive(TwinEActionType::UIRight)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
volume += 4;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-23 13:38:02 +02:00
|
|
|
mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
|
|
|
|
break;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kCDVolume: {
|
2020-10-23 13:38:02 +02:00
|
|
|
AudioCDManager::Status status = _engine->_system->getAudioCDManager()->getStatus();
|
2020-10-24 14:26:50 +02:00
|
|
|
if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
status.volume -= 4;
|
2020-10-24 14:26:50 +02:00
|
|
|
} else if (_engine->_input->isActionActive(TwinEActionType::UIRight)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
status.volume += 4;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-23 13:38:02 +02:00
|
|
|
_engine->_system->getAudioCDManager()->setVolume(status.volume);
|
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kLineVolume: {
|
2020-10-23 13:38:02 +02:00
|
|
|
int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
|
2020-10-24 14:26:50 +02:00
|
|
|
if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
volume -= 4;
|
2020-10-24 14:26:50 +02:00
|
|
|
} else if (_engine->_input->isActionActive(TwinEActionType::UIRight)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
volume += 4;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-23 13:38:02 +02:00
|
|
|
mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
|
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case MenuButtonTypes::kMasterVolume: {
|
2020-10-23 13:38:02 +02:00
|
|
|
int volume = mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
|
2020-10-24 14:26:50 +02:00
|
|
|
if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
volume -= 4;
|
2020-10-24 14:26:50 +02:00
|
|
|
} else if (_engine->_input->isActionActive(TwinEActionType::UIRight)) {
|
2020-10-23 13:38:02 +02:00
|
|
|
volume += 4;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-23 13:38:02 +02:00
|
|
|
mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-23 13:38:02 +02:00
|
|
|
if (buttonsNeedRedraw) {
|
2020-10-22 16:32:52 +02:00
|
|
|
menuSettings[MenuSettings_CurrentLoadedButton] = currentButton;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-23 12:45:43 +02:00
|
|
|
// draw all buttons
|
|
|
|
drawButton(menuSettings, false);
|
2020-10-23 13:38:02 +02:00
|
|
|
buttonsNeedRedraw = false;
|
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-23 13:38:02 +02:00
|
|
|
// draw plasma effect for the current selected button
|
|
|
|
drawButton(menuSettings, true);
|
2020-10-26 22:49:18 +01:00
|
|
|
if (_engine->shouldQuit()) {
|
2020-10-26 23:43:17 +01:00
|
|
|
return kQuitEngine;
|
2020-10-26 22:49:18 +01:00
|
|
|
}
|
2020-10-24 14:26:50 +02:00
|
|
|
// TODO: update volume settings
|
2020-10-26 00:13:54 +01:00
|
|
|
_engine->_system->delayMillis(10);
|
2020-10-23 20:09:33 +02:00
|
|
|
} while (!_engine->_input->toggleActionIfActive(TwinEActionType::UIEnter));
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-27 00:00:47 +01:00
|
|
|
const int buttonTextId = *(menuSettings + MenuSettings_FirstButton + currentButton * 2); // get current browsed button
|
|
|
|
return buttonTextId;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
int32 Menu::advoptionsMenu() {
|
|
|
|
_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
|
2020-10-23 13:38:02 +02:00
|
|
|
_engine->flip();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-27 00:00:47 +01:00
|
|
|
for (;;) {
|
2020-10-23 12:18:28 +02:00
|
|
|
switch (processMenu(AdvOptionsMenuState)) {
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kReturnMenu: {
|
|
|
|
return 0;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-26 23:43:17 +01:00
|
|
|
case kQuitEngine:
|
|
|
|
return kQuitEngine;
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kBehaviourAgressiveManual:
|
|
|
|
case TextId::kDetailsPolygonsHigh:
|
|
|
|
case TextId::kDetailsShadowHigh:
|
|
|
|
case TextId::kScenaryZoomOn:
|
2020-10-14 14:20:38 +02:00
|
|
|
default:
|
2020-10-27 00:00:47 +01:00
|
|
|
warning("Unknown menu button handled");
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
int32 Menu::savemanageMenu() {
|
|
|
|
_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
|
2020-10-23 13:38:02 +02:00
|
|
|
_engine->flip();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-27 00:00:47 +01:00
|
|
|
for (;;) {
|
2020-10-23 12:18:28 +02:00
|
|
|
switch (processMenu(SaveManageMenuState)) {
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kReturnMenu:
|
|
|
|
return 0;
|
|
|
|
case TextId::kCreateSaveGame:
|
|
|
|
// TODO: implement save game handling and slot rendering
|
|
|
|
break;
|
|
|
|
case TextId::kDeleteSaveGame:
|
|
|
|
// TODO: implement save game deletion and slot rendering
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
2020-10-26 23:43:17 +01:00
|
|
|
case kQuitEngine:
|
|
|
|
return kQuitEngine;
|
2020-10-14 14:20:38 +02:00
|
|
|
default:
|
2020-10-27 00:00:47 +01:00
|
|
|
warning("Unknown menu button handled");
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
int32 Menu::volumeMenu() {
|
|
|
|
_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
|
2020-10-23 13:38:02 +02:00
|
|
|
_engine->flip();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-27 00:00:47 +01:00
|
|
|
for (;;) {
|
2020-10-23 12:18:28 +02:00
|
|
|
switch (processMenu(VolumeMenuState)) {
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kReturnMenu:
|
|
|
|
return 0;
|
|
|
|
case TextId::kSaveSettings:
|
|
|
|
// TODO: implement setting persisting
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
2020-10-26 23:43:17 +01:00
|
|
|
case kQuitEngine:
|
|
|
|
return kQuitEngine;
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kMusicVolume:
|
|
|
|
case TextId::kSoundVolume:
|
|
|
|
case TextId::kCDVolume:
|
|
|
|
case TextId::kLineInVolume:
|
|
|
|
case TextId::kMasterVolume:
|
2020-10-14 14:20:38 +02:00
|
|
|
default:
|
2020-10-27 00:00:47 +01:00
|
|
|
warning("Unknown menu button handled");
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
int32 Menu::optionsMenu() {
|
|
|
|
_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
|
2020-10-23 13:38:02 +02:00
|
|
|
_engine->flip();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_sound->stopSamples();
|
|
|
|
//_engine->_music->playCDtrack(9);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-27 00:00:47 +01:00
|
|
|
for (;;) {
|
2020-10-23 12:18:28 +02:00
|
|
|
switch (processMenu(OptionsMenuState)) {
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kReturnGame:
|
|
|
|
case TextId::kReturnMenu: {
|
|
|
|
return 0;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kVolumeSettings: {
|
2020-10-27 00:19:28 +01:00
|
|
|
checkMenuQuit(volumeMenu())
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kSaveManage: {
|
2020-10-27 00:19:28 +01:00
|
|
|
checkMenuQuit(savemanageMenu())
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kAdvanced: {
|
2020-10-27 00:19:28 +01:00
|
|
|
checkMenuQuit(advoptionsMenu())
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case kQuitEngine:
|
|
|
|
return kQuitEngine;
|
2020-10-14 14:20:38 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-22 16:32:52 +02:00
|
|
|
bool Menu::init() {
|
2020-10-14 14:20:38 +02:00
|
|
|
// load menu effect file only once
|
|
|
|
plasmaEffectPtr = (uint8 *)malloc(kPlasmaEffectFilesize);
|
|
|
|
memset(plasmaEffectPtr, 0, kPlasmaEffectFilesize);
|
2020-10-22 16:32:52 +02:00
|
|
|
return _engine->_hqrdepack->hqrGetEntry(plasmaEffectPtr, Resources::HQR_RESS_FILE, RESSHQR_PLASMAEFFECT) > 0;
|
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-22 16:32:52 +02:00
|
|
|
void Menu::run() {
|
|
|
|
_engine->_text->initTextBank(0);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-22 16:32:52 +02:00
|
|
|
_engine->_music->playTrackMusic(9); // LBA's Theme
|
|
|
|
_engine->_sound->stopSamples();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-23 12:18:28 +02:00
|
|
|
switch (processMenu(MainMenuState)) {
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kNewGame: {
|
2020-10-22 16:32:52 +02:00
|
|
|
_engine->_menuOptions->newGameMenu();
|
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kContinueGame: {
|
2020-10-22 16:32:52 +02:00
|
|
|
_engine->_menuOptions->continueGameMenu();
|
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kOptions: {
|
2020-10-22 16:32:52 +02:00
|
|
|
optionsMenu();
|
|
|
|
break;
|
|
|
|
}
|
2020-10-27 00:00:47 +01:00
|
|
|
case TextId::kQuit: {
|
2020-10-22 16:32:52 +02:00
|
|
|
Common::Event event;
|
|
|
|
event.type = Common::EVENT_QUIT;
|
|
|
|
_engine->_system->getEventManager()->pushEvent(event);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case kBackground: {
|
|
|
|
_engine->_screens->loadMenuImage();
|
2020-10-22 19:02:43 +02:00
|
|
|
break;
|
2020-10-22 16:32:52 +02:00
|
|
|
}
|
2020-10-26 23:43:17 +01:00
|
|
|
case kQuitEngine:
|
|
|
|
return;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-22 16:32:52 +02:00
|
|
|
_engine->_system->delayMillis(1000 / _engine->cfgfile.Fps);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
int32 Menu::giveupMenu() {
|
|
|
|
_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
|
|
|
|
_engine->_sound->pauseSamples();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-23 12:15:24 +02:00
|
|
|
int16 *localMenu;
|
|
|
|
if (_engine->cfgfile.UseAutoSaving == 1) {
|
2020-10-23 12:18:28 +02:00
|
|
|
localMenu = GiveUpMenuState;
|
2020-10-23 12:15:24 +02:00
|
|
|
} else {
|
2020-10-23 12:18:28 +02:00
|
|
|
localMenu = GiveUpMenuWithSaveState;
|
2020-10-23 12:15:24 +02:00
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-23 12:15:24 +02:00
|
|
|
int32 menuId;
|
2020-10-14 14:20:38 +02:00
|
|
|
do {
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->initTextBank(0);
|
2020-10-14 14:20:38 +02:00
|
|
|
menuId = processMenu(localMenu);
|
2020-10-27 00:00:47 +01:00
|
|
|
switch (menuId) {
|
|
|
|
case TextId::kContinue:
|
|
|
|
_engine->_sound->resumeSamples();
|
|
|
|
break;
|
|
|
|
case TextId::kGiveUp:
|
|
|
|
_engine->_sound->stopSamples();
|
|
|
|
return 1;
|
|
|
|
case TextId::kCreateSaveGame:
|
|
|
|
// TODO: handle save game creation
|
|
|
|
break;
|
|
|
|
case kQuitEngine:
|
2020-10-26 23:43:17 +01:00
|
|
|
return kQuitEngine;
|
2020-10-27 00:00:47 +01:00
|
|
|
default:
|
|
|
|
warning("Unknown menu button handled: %i", menuId);
|
2020-10-26 23:43:17 +01:00
|
|
|
}
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
|
|
|
|
_engine->_system->delayMillis(1000 / _engine->cfgfile.Fps);
|
2020-10-27 00:00:47 +01:00
|
|
|
} while (menuId != TextId::kGiveUp && menuId != TextId::kContinue);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
void Menu::drawInfoMenu(int16 left, int16 top) {
|
2020-10-14 14:20:38 +02:00
|
|
|
int32 boxLeft, boxTop, boxRight, boxBottom;
|
|
|
|
int32 newBoxLeft, newBoxLeft2, i;
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_interface->resetClip();
|
2020-10-14 14:20:38 +02:00
|
|
|
drawBox(left, top, left + 450, top + 80);
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_interface->drawSplittedBox(left + 1, top + 1, left + 449, top + 79, 0);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
newBoxLeft2 = left + 9;
|
|
|
|
|
2020-10-26 22:10:44 +01:00
|
|
|
_engine->_grid->drawSprite(0, newBoxLeft2, top + 13, _engine->_resources->spriteTable[SPRITEHQR_LIFEPOINTS]);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
boxRight = left + 325;
|
|
|
|
newBoxLeft = left + 25;
|
2020-10-14 15:16:30 +02:00
|
|
|
boxLeft = _engine->_screens->crossDot(newBoxLeft, boxRight, 50, _engine->_scene->sceneHero->life);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
boxTop = top + 10;
|
|
|
|
boxBottom = top + 25;
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_interface->drawSplittedBox(newBoxLeft, boxTop, boxLeft, boxBottom, 91);
|
2020-10-14 14:20:38 +02:00
|
|
|
drawBox(left + 25, top + 10, left + 324, top + 10 + 14);
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
if (!_engine->_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED] && _engine->_gameState->gameFlags[InventoryItems::kiTunic]) {
|
2020-10-26 22:10:44 +01:00
|
|
|
_engine->_grid->drawSprite(0, newBoxLeft2, top + 36, _engine->_resources->spriteTable[SPRITEHQR_MAGICPOINTS]);
|
2020-10-14 15:16:30 +02:00
|
|
|
if (_engine->_gameState->magicLevelIdx > 0) {
|
|
|
|
_engine->_interface->drawSplittedBox(newBoxLeft, top + 35, _engine->_screens->crossDot(newBoxLeft, boxRight, 80, _engine->_gameState->inventoryMagicPoints), top + 50, 75);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-14 15:16:30 +02:00
|
|
|
drawBox(left + 25, top + 35, left + _engine->_gameState->magicLevelIdx * 80 + 20, top + 35 + 15);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
boxLeft = left + 340;
|
|
|
|
|
|
|
|
/** draw coin sprite */
|
2020-10-26 22:10:44 +01:00
|
|
|
_engine->_grid->drawSprite(0, boxLeft, top + 15, _engine->_resources->spriteTable[SPRITEHQR_KASHES]);
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->setFontColor(155);
|
|
|
|
Common::String inventoryNumKashes = Common::String::format("%d", _engine->_gameState->inventoryNumKashes);
|
|
|
|
_engine->_text->drawText(left + 370, top + 5, inventoryNumKashes.c_str());
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
/** draw key sprite */
|
2020-10-26 22:10:44 +01:00
|
|
|
_engine->_grid->drawSprite(0, boxLeft, top + 55, _engine->_resources->spriteTable[SPRITEHQR_KEY]);
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->setFontColor(155);
|
|
|
|
Common::String inventoryNumKeys = Common::String::format("%d", _engine->_gameState->inventoryNumKeys);
|
|
|
|
_engine->_text->drawText(left + 370, top + 40, inventoryNumKeys.c_str());
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
// prevent
|
2020-10-14 15:16:30 +02:00
|
|
|
if (_engine->_gameState->inventoryNumLeafs > _engine->_gameState->inventoryNumLeafsBox) {
|
|
|
|
_engine->_gameState->inventoryNumLeafs = _engine->_gameState->inventoryNumLeafsBox;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Clover leaf boxes
|
2020-10-14 15:16:30 +02:00
|
|
|
for (i = 0; i < _engine->_gameState->inventoryNumLeafsBox; i++) {
|
2020-10-26 22:10:44 +01:00
|
|
|
_engine->_grid->drawSprite(0, _engine->_screens->crossDot(left + 25, left + 325, 10, i), top + 58, _engine->_resources->spriteTable[SPRITEHQR_CLOVERLEAFBOX]);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Clover leafs
|
2020-10-14 15:16:30 +02:00
|
|
|
for (i = 0; i < _engine->_gameState->inventoryNumLeafs; i++) {
|
2020-10-26 22:10:44 +01:00
|
|
|
_engine->_grid->drawSprite(0, _engine->_screens->crossDot(left + 25, left + 325, 10, i) + 2, top + 60, _engine->_resources->spriteTable[SPRITEHQR_CLOVERLEAF]);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->copyBlockPhys(left, top, left + 450, top + 135);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-24 12:32:00 +02:00
|
|
|
// TODO: convert cantDrawBox to bool
|
2020-10-14 15:16:30 +02:00
|
|
|
void Menu::drawBehaviour(HeroBehaviourType behaviour, int32 angle, int16 cantDrawBox) {
|
|
|
|
int32 boxLeft = behaviour * 110 + 110;
|
|
|
|
int32 boxRight = boxLeft + 99;
|
|
|
|
int32 boxTop = 110;
|
|
|
|
int32 boxBottom = 229;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-26 22:21:31 +01:00
|
|
|
uint8 *currentAnim = _engine->_resources->animTable[_engine->_actor->heroAnimIdx[behaviour]];
|
2020-10-14 15:16:30 +02:00
|
|
|
int32 currentAnimState = behaviourAnimState[behaviour];
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
if (_engine->_animations->setModelAnimation(currentAnimState, currentAnim, behaviourEntity, &behaviourAnimData[behaviour])) {
|
2020-10-14 14:20:38 +02:00
|
|
|
currentAnimState++; // keyframe
|
2020-10-14 15:16:30 +02:00
|
|
|
if (currentAnimState >= _engine->_animations->getNumKeyframes(currentAnim)) {
|
|
|
|
currentAnimState = _engine->_animations->getStartKeyframe(currentAnim);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
behaviourAnimState[behaviour] = currentAnimState;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cantDrawBox == 0) {
|
|
|
|
drawBox(boxLeft - 1, boxTop - 1, boxRight + 1, boxBottom + 1);
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_interface->saveClip();
|
|
|
|
_engine->_interface->resetClip();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
if (behaviour != _engine->_actor->heroBehaviour) { // unselected
|
|
|
|
_engine->_interface->drawSplittedBox(boxLeft, boxTop, boxRight, boxBottom, 0);
|
2020-10-14 14:20:38 +02:00
|
|
|
} else { // selected
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_interface->drawSplittedBox(boxLeft, boxTop, boxRight, boxBottom, 69);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
// behaviour menu title
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_interface->drawSplittedBox(110, 239, 540, 279, 0);
|
2020-10-14 14:20:38 +02:00
|
|
|
drawBox(110, 239, 540, 279);
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->setFontColor(15);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
char dialText[256];
|
2020-10-24 18:32:22 +02:00
|
|
|
if (_engine->_actor->heroBehaviour == kAggressive && _engine->_actor->autoAgressive) {
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->getMenuText(4, dialText, sizeof(dialText));
|
2020-10-14 14:20:38 +02:00
|
|
|
} else {
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->getMenuText(_engine->_actor->heroBehaviour, dialText, sizeof(dialText));
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->drawText((650 - _engine->_text->getTextSize(dialText)) / 2, 240, dialText);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_renderer->renderBehaviourModel(boxLeft, boxTop, boxRight, boxBottom, -600, angle, behaviourEntity);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->copyBlockPhys(boxLeft, boxTop, boxRight, boxBottom);
|
|
|
|
_engine->copyBlockPhys(110, 239, 540, 279);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_interface->loadClip();
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
void Menu::drawBehaviourMenu(int32 angle) {
|
2020-10-14 14:20:38 +02:00
|
|
|
drawBox(100, 100, 550, 290);
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_interface->drawTransparentBox(101, 101, 549, 289, 2);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-26 22:21:31 +01:00
|
|
|
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[kNormal], _engine->_resources->animTable[_engine->_actor->heroAnimIdx[kNormal]], behaviourEntity, &behaviourAnimData[kNormal]);
|
2020-10-14 14:20:38 +02:00
|
|
|
drawBehaviour(kNormal, angle, 0);
|
|
|
|
|
2020-10-26 22:21:31 +01:00
|
|
|
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[kAthletic], _engine->_resources->animTable[_engine->_actor->heroAnimIdx[kAthletic]], behaviourEntity, &behaviourAnimData[kAthletic]);
|
2020-10-14 14:20:38 +02:00
|
|
|
drawBehaviour(kAthletic, angle, 0);
|
|
|
|
|
2020-10-26 22:21:31 +01:00
|
|
|
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[kAggressive], _engine->_resources->animTable[_engine->_actor->heroAnimIdx[kAggressive]], behaviourEntity, &behaviourAnimData[kAggressive]);
|
2020-10-14 14:20:38 +02:00
|
|
|
drawBehaviour(kAggressive, angle, 0);
|
|
|
|
|
2020-10-26 22:21:31 +01:00
|
|
|
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[kDiscrete], _engine->_resources->animTable[_engine->_actor->heroAnimIdx[kDiscrete]], behaviourEntity, &behaviourAnimData[kDiscrete]);
|
2020-10-14 14:20:38 +02:00
|
|
|
drawBehaviour(kDiscrete, angle, 0);
|
|
|
|
|
|
|
|
drawInfoMenu(100, 300);
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->copyBlockPhys(100, 100, 550, 290);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
void Menu::processBehaviourMenu() {
|
|
|
|
if (_engine->_actor->heroBehaviour == kProtoPack) {
|
|
|
|
_engine->_sound->stopSamples();
|
|
|
|
_engine->_actor->setBehaviour(kNormal);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
behaviourEntity = _engine->_actor->bodyTable[_engine->_scene->sceneHero->entity];
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_actor->heroAnimIdx[kNormal] = _engine->_actor->heroAnimIdxNORMAL;
|
|
|
|
_engine->_actor->heroAnimIdx[kAthletic] = _engine->_actor->heroAnimIdxATHLETIC;
|
|
|
|
_engine->_actor->heroAnimIdx[kAggressive] = _engine->_actor->heroAnimIdxAGGRESSIVE;
|
|
|
|
_engine->_actor->heroAnimIdx[kDiscrete] = _engine->_actor->heroAnimIdxDISCRETE;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_movements->setActorAngleSafe(_engine->_scene->sceneHero->angle, _engine->_scene->sceneHero->angle - 256, 50, &moveMenu);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-22 13:21:32 +02:00
|
|
|
int32 tmpTextBank = _engine->_text->currentTextBank;
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->currentTextBank = -1;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->initTextBank(0);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
drawBehaviourMenu(_engine->_scene->sceneHero->angle);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
HeroBehaviourType tmpHeroBehaviour = _engine->_actor->heroBehaviour;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-26 22:21:31 +01:00
|
|
|
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[_engine->_actor->heroBehaviour], _engine->_resources->animTable[_engine->_actor->heroAnimIdx[_engine->_actor->heroBehaviour]], behaviourEntity, &behaviourAnimData[_engine->_actor->heroBehaviour]);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-22 13:21:32 +02:00
|
|
|
int32 tmpTime = _engine->lbaTime;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-23 20:09:33 +02:00
|
|
|
while (_engine->_input->isActionActive(TwinEActionType::BehaviourMenu) || _engine->_input->isQuickBehaviourActionActive()) {
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->readKeys();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
int heroBehaviour = (int)_engine->_actor->heroBehaviour;
|
2020-10-24 12:32:00 +02:00
|
|
|
if (_engine->_input->toggleActionIfActive(TwinEActionType::TurnLeft)) {
|
2020-10-14 14:20:38 +02:00
|
|
|
heroBehaviour--;
|
2020-10-24 13:16:41 +02:00
|
|
|
} else if (_engine->_input->toggleActionIfActive(TwinEActionType::TurnRight)) {
|
|
|
|
heroBehaviour++;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
if (heroBehaviour < kNormal) {
|
|
|
|
heroBehaviour = kDiscrete;
|
2020-10-24 12:32:00 +02:00
|
|
|
} else if (heroBehaviour >= kProtoPack) {
|
2020-10-14 15:16:30 +02:00
|
|
|
heroBehaviour = kNormal;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_actor->heroBehaviour = (HeroBehaviourType)heroBehaviour;
|
|
|
|
|
|
|
|
if (tmpHeroBehaviour != _engine->_actor->heroBehaviour) {
|
|
|
|
drawBehaviour(tmpHeroBehaviour, _engine->_scene->sceneHero->angle, 1);
|
|
|
|
tmpHeroBehaviour = _engine->_actor->heroBehaviour;
|
|
|
|
_engine->_movements->setActorAngleSafe(_engine->_scene->sceneHero->angle, _engine->_scene->sceneHero->angle - 256, 50, &moveMenu);
|
2020-10-26 22:21:31 +01:00
|
|
|
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[_engine->_actor->heroBehaviour], _engine->_resources->animTable[_engine->_actor->heroAnimIdx[_engine->_actor->heroBehaviour]], behaviourEntity, &behaviourAnimData[_engine->_actor->heroBehaviour]);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
drawBehaviour(_engine->_actor->heroBehaviour, -1, 1);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_system->delayMillis(1000 / 50);
|
|
|
|
_engine->lbaTime++;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->lbaTime = tmpTime;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_actor->setBehaviour(_engine->_actor->heroBehaviour);
|
|
|
|
_engine->_gameState->initEngineProjections();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->currentTextBank = tmpTextBank;
|
|
|
|
_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
void Menu::drawMagicItemsBox(int32 left, int32 top, int32 right, int32 bottom, int32 color) { // Rect
|
|
|
|
_engine->_interface->drawLine(left, top, right, top, color); // top line
|
|
|
|
_engine->_interface->drawLine(left, top, left, bottom, color); // left line
|
|
|
|
_engine->_interface->drawLine(right, ++top, right, bottom, color); // right line
|
|
|
|
_engine->_interface->drawLine(++left, bottom, right, bottom, color); // bottom line
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
void Menu::drawItem(int32 item) {
|
2020-10-25 21:43:09 +01:00
|
|
|
const int32 itemX = (item / 4) * 85 + 64;
|
|
|
|
const int32 itemY = (item & 3) * 75 + 52;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-25 21:43:09 +01:00
|
|
|
const int32 left = itemX - 37;
|
|
|
|
const int32 right = itemX + 37;
|
|
|
|
const int32 top = itemY - 32;
|
|
|
|
const int32 bottom = itemY + 32;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_interface->drawSplittedBox(left, top, right, bottom,
|
|
|
|
inventorySelectedItem == item ? inventorySelectedColor : 0);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
if (_engine->_gameState->gameFlags[item] && !_engine->_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED] && item < NUM_INVENTORY_ITEMS) {
|
|
|
|
_engine->_renderer->prepareIsoModel(_engine->_resources->inventoryTable[item]);
|
2020-10-14 14:20:38 +02:00
|
|
|
itemAngle[item] += 8;
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_renderer->renderInventoryItem(itemX, itemY, _engine->_resources->inventoryTable[item], itemAngle[item], 15000);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-25 21:43:09 +01:00
|
|
|
if (item == InventoryItems::kGasItem) { // has GAS
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->setFontColor(15);
|
|
|
|
Common::String inventoryNumGas = Common::String::format("%d", _engine->_gameState->inventoryNumGas);
|
|
|
|
_engine->_text->drawText(left + 3, top + 32, inventoryNumGas.c_str());
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
drawBox(left, top, right, bottom);
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->copyBlockPhys(left, top, right, bottom);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
void Menu::drawInventoryItems() {
|
|
|
|
_engine->_interface->drawTransparentBox(17, 10, 622, 320, 4);
|
2020-10-14 14:20:38 +02:00
|
|
|
drawBox(17, 10, 622, 320);
|
|
|
|
drawMagicItemsBox(110, 18, 188, 311, 75);
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->copyBlockPhys(17, 10, 622, 320);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-23 20:09:33 +02:00
|
|
|
for (int32 item = 0; item < NUM_INVENTORY_ITEMS; item++) {
|
2020-10-14 14:20:38 +02:00
|
|
|
drawItem(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
void Menu::processInventoryMenu() {
|
2020-10-22 13:21:32 +02:00
|
|
|
int32 tmpAlphaLight = _engine->_scene->alphaLight;
|
|
|
|
int32 tmpBetaLight = _engine->_scene->betaLight;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_screens->copyScreen(_engine->frontVideoBuffer, _engine->workVideoBuffer);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_renderer->setLightVector(896, 950, 0);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
|
|
|
inventorySelectedColor = 68;
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
if (_engine->_gameState->inventoryNumLeafs > 0) {
|
|
|
|
_engine->_gameState->gameFlags[InventoryItems::kiCloverLeaf] = 1;
|
2020-10-25 21:26:04 +01:00
|
|
|
// TODO: shouldn't this get reset? } else {
|
|
|
|
// _engine->_gameState->gameFlags[InventoryItems::kiCloverLeaf] = 0;
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
drawInventoryItems();
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->initTextBank(2);
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-22 13:21:32 +02:00
|
|
|
int32 bx = 3;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->setFontCrossColor(4);
|
|
|
|
_engine->_text->initDialogueBox();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-25 22:16:21 +01:00
|
|
|
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
|
|
|
keymapper->getKeymap(uiKeyMapId)->setEnabled(true);
|
|
|
|
|
2020-10-23 20:09:33 +02:00
|
|
|
while (_engine->_input->isActionActive(TwinEActionType::InventoryMenu)) {
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->readKeys();
|
2020-10-22 13:21:32 +02:00
|
|
|
int32 prevSelectedItem = inventorySelectedItem;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-25 22:03:04 +01:00
|
|
|
if (_engine->_input->toggleAbortAction()) {
|
2020-10-14 14:20:38 +02:00
|
|
|
break;
|
2020-10-24 13:31:56 +02:00
|
|
|
}
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-25 22:03:04 +01:00
|
|
|
const bool cursorDown = _engine->_input->toggleActionIfActive(TwinEActionType::UIDown);
|
|
|
|
const bool cursorUp = _engine->_input->toggleActionIfActive(TwinEActionType::UIUp);
|
|
|
|
const bool cursorLeft = _engine->_input->toggleActionIfActive(TwinEActionType::UILeft);
|
|
|
|
const bool cursorRight = _engine->_input->toggleActionIfActive(TwinEActionType::UIRight);
|
|
|
|
if (cursorDown) {
|
2020-10-14 14:20:38 +02:00
|
|
|
inventorySelectedItem++;
|
|
|
|
if (inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
|
|
|
|
inventorySelectedItem = 0;
|
|
|
|
}
|
|
|
|
drawItem(prevSelectedItem);
|
|
|
|
bx = 3;
|
2020-10-25 22:03:04 +01:00
|
|
|
} else if (cursorUp) {
|
2020-10-14 14:20:38 +02:00
|
|
|
inventorySelectedItem--;
|
|
|
|
if (inventorySelectedItem < 0) {
|
|
|
|
inventorySelectedItem = NUM_INVENTORY_ITEMS - 1;
|
|
|
|
}
|
|
|
|
drawItem(prevSelectedItem);
|
|
|
|
bx = 3;
|
|
|
|
}
|
|
|
|
|
2020-10-25 22:03:04 +01:00
|
|
|
if (cursorLeft) {
|
2020-10-14 14:20:38 +02:00
|
|
|
inventorySelectedItem -= 4;
|
|
|
|
if (inventorySelectedItem < 0) {
|
|
|
|
inventorySelectedItem += NUM_INVENTORY_ITEMS;
|
|
|
|
}
|
|
|
|
drawItem(prevSelectedItem);
|
|
|
|
bx = 3;
|
2020-10-25 22:03:04 +01:00
|
|
|
} else if (cursorRight) {
|
2020-10-14 14:20:38 +02:00
|
|
|
inventorySelectedItem += 4;
|
|
|
|
if (inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
|
|
|
|
inventorySelectedItem -= NUM_INVENTORY_ITEMS;
|
|
|
|
}
|
|
|
|
drawItem(prevSelectedItem);
|
|
|
|
bx = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bx == 3) {
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->initInventoryDialogueBox();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
if (_engine->_gameState->gameFlags[inventorySelectedItem] == 1 && !_engine->_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED] && inventorySelectedItem < NUM_INVENTORY_ITEMS) {
|
|
|
|
_engine->_text->initText(inventorySelectedItem + 100);
|
2020-10-14 14:20:38 +02:00
|
|
|
} else {
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->initText(128);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
bx = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bx != 2) {
|
2020-10-14 15:16:30 +02:00
|
|
|
bx = _engine->_text->printText10();
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// TRICKY: 3D model rotation delay - only apply when no text is drawing
|
|
|
|
if (bx == 0 || bx == 2) {
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_system->delayMillis(15);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-25 22:03:04 +01:00
|
|
|
if (_engine->_input->toggleActionIfActive(TwinEActionType::UINextPage)) {
|
2020-10-14 14:20:38 +02:00
|
|
|
if (bx == 2) {
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->initInventoryDialogueBox();
|
2020-10-14 14:20:38 +02:00
|
|
|
bx = 0;
|
|
|
|
} else {
|
2020-10-14 15:16:30 +02:00
|
|
|
if (_engine->_gameState->gameFlags[inventorySelectedItem] == 1 && !_engine->_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED] && inventorySelectedItem < NUM_INVENTORY_ITEMS) {
|
|
|
|
_engine->_text->initInventoryDialogueBox();
|
|
|
|
_engine->_text->initText(inventorySelectedItem + 100);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
drawItem(inventorySelectedItem);
|
|
|
|
|
2020-10-25 22:03:04 +01:00
|
|
|
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIEnter) && _engine->_gameState->gameFlags[inventorySelectedItem] == 1 && !_engine->_gameState->gameFlags[GAMEFLAG_INVENTORY_DISABLED] && inventorySelectedItem < NUM_INVENTORY_ITEMS) {
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->loopInventoryItem = inventorySelectedItem;
|
2020-10-14 14:20:38 +02:00
|
|
|
inventorySelectedColor = 91;
|
|
|
|
drawItem(inventorySelectedItem);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-25 22:16:21 +01:00
|
|
|
keymapper->getKeymap(uiKeyMapId)->setEnabled(false);
|
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->printTextVar13 = 0;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_scene->alphaLight = tmpAlphaLight;
|
|
|
|
_engine->_scene->betaLight = tmpBetaLight;
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_gameState->initEngineProjections();
|
2020-10-14 14:20:38 +02:00
|
|
|
|
2020-10-14 15:16:30 +02:00
|
|
|
_engine->_text->initTextBank(_engine->_text->currentTextBank + 3);
|
2020-10-14 14:20:38 +02:00
|
|
|
}
|
2020-10-14 15:16:30 +02:00
|
|
|
|
|
|
|
} // namespace TwinE
|