1269 lines
30 KiB
C++
1269 lines
30 KiB
C++
|
/** @file menu.cpp
|
||
|
@brief
|
||
|
This file contains main menu create and processing routines.
|
||
|
|
||
|
TwinEngine: a Little Big Adventure engine
|
||
|
|
||
|
Copyright (C) 2013 The TwinEngine team
|
||
|
Copyright (C) 2008-2013 Prequengine team
|
||
|
Copyright (C) 2002-2007 The TwinEngine team
|
||
|
|
||
|
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
*/
|
||
|
|
||
|
#include "sys.h"
|
||
|
#include "main.h"
|
||
|
#include "menu.h"
|
||
|
#include "menuoptions.h"
|
||
|
#include "resources.h"
|
||
|
#include "music.h"
|
||
|
#include "sound.h"
|
||
|
#include "screens.h"
|
||
|
#include "sdlengine.h"
|
||
|
#include "hqrdepack.h"
|
||
|
#include "lbaengine.h"
|
||
|
#include "text.h"
|
||
|
#include "interface.h"
|
||
|
#include "redraw.h"
|
||
|
#include "keyboard.h"
|
||
|
#include "scene.h"
|
||
|
#include "animations.h"
|
||
|
#include "actor.h"
|
||
|
#include "movements.h"
|
||
|
#include "gamestate.h"
|
||
|
#include "renderer.h"
|
||
|
#include "grid.h"
|
||
|
#include "gamestate.h"
|
||
|
|
||
|
/** Main menu background image number
|
||
|
Used when returning from credit sequence to redraw the main menu background image */
|
||
|
uint32 kPlasmaEffectFilesize = 262176;
|
||
|
|
||
|
/** Menu buttons width */
|
||
|
uint16 kMainMenuButtonWidth = 320;
|
||
|
/** Used to calculate the spanning between button and screen */
|
||
|
uint16 kMainMenuButtonSpan = 550;
|
||
|
|
||
|
|
||
|
/** Main menu types */
|
||
|
enum MainMenuType {
|
||
|
kNewGame = 20,
|
||
|
kContinueGame = 21,
|
||
|
kOptions = 23,
|
||
|
kQuit = 22,
|
||
|
kBackground = 9999
|
||
|
};
|
||
|
|
||
|
/** Give up menu types */
|
||
|
enum GiveUpMenuType {
|
||
|
kContinue = 28,
|
||
|
kGiveUp = 27 // quit
|
||
|
};
|
||
|
|
||
|
/** Options menu types */
|
||
|
enum OptionsMenuType {
|
||
|
kReturnGame = 15,
|
||
|
kReturnMenu = 26,
|
||
|
kVolume = 30,
|
||
|
kSaveManage = 46,
|
||
|
kAdvanced = 47
|
||
|
};
|
||
|
|
||
|
/** Volume menu types */
|
||
|
enum VolumeMenuType {
|
||
|
kMusicVolume = 1,
|
||
|
kSoundVolume = 2,
|
||
|
kCDVolume = 3,
|
||
|
kLineVolume = 4,
|
||
|
kMasterVolume = 5
|
||
|
};
|
||
|
|
||
|
/** Main Menu Settings
|
||
|
|
||
|
Used to create the game main menu. */
|
||
|
int16 MainMenuSettings[] = {
|
||
|
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,
|
||
|
20, // new game
|
||
|
0,
|
||
|
21, // continue game
|
||
|
0,
|
||
|
23, // options
|
||
|
0,
|
||
|
22, // quit
|
||
|
};
|
||
|
|
||
|
/** Give Up Menu Settings
|
||
|
|
||
|
Used to create the in-game menu. */
|
||
|
int16 GiveUpMenuSettings[] = {
|
||
|
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,
|
||
|
28, // continue game
|
||
|
0,
|
||
|
27, // quit game
|
||
|
};
|
||
|
|
||
|
/** Give Up Menu Settings
|
||
|
|
||
|
Used to create the in-game menu. This menu have one extra item to save the game */
|
||
|
int16 GiveUpMenuSettingsWithSave[] = {
|
||
|
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,
|
||
|
28, // continue game
|
||
|
0,
|
||
|
16, // save game
|
||
|
0,
|
||
|
27, // quit game
|
||
|
};
|
||
|
|
||
|
/** Options Menu Settings
|
||
|
|
||
|
Used to create the options menu. */
|
||
|
int16 OptionsMenuSettings[] = {
|
||
|
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,
|
||
|
24, // return to previous menu
|
||
|
0,
|
||
|
30, // volume settings
|
||
|
0,
|
||
|
46, // save game management
|
||
|
0,
|
||
|
47, // advanced options
|
||
|
};
|
||
|
|
||
|
/** Advanced Options Menu Settings
|
||
|
|
||
|
Used to create the advanced options menu. */
|
||
|
int16 AdvOptionsMenuSettings[] = {
|
||
|
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,
|
||
|
26, // return to main menu
|
||
|
0,
|
||
|
4, // aggressive mode (manual|auto)
|
||
|
6,
|
||
|
31, // Polygon detail (full|medium|low)
|
||
|
7,
|
||
|
32, // Shadows (all|character|no)
|
||
|
8,
|
||
|
33, // scenary zoon (on|off)
|
||
|
};
|
||
|
|
||
|
/** Save Game Management Menu Settings
|
||
|
|
||
|
Used to create the save game management menu. */
|
||
|
int16 SaveManageMenuSettings[] = {
|
||
|
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,
|
||
|
26, // return to main menu
|
||
|
0,
|
||
|
41, // copy saved game
|
||
|
0,
|
||
|
45, // delete saved game
|
||
|
};
|
||
|
|
||
|
/** Volume Menu Settings
|
||
|
|
||
|
Used to create the volume menu. */
|
||
|
int16 VolumeMenuSettings[] = {
|
||
|
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,
|
||
|
26, // return to main menu
|
||
|
1,
|
||
|
10, // music volume
|
||
|
2,
|
||
|
11, // sfx volume
|
||
|
3,
|
||
|
12, // cd volume
|
||
|
4,
|
||
|
13, // line-in volume
|
||
|
5,
|
||
|
14, // master volume
|
||
|
0,
|
||
|
16, // save parameters
|
||
|
};
|
||
|
|
||
|
|
||
|
/** Plasma Effect pointer to file content: RESS.HQR:51 */
|
||
|
uint8 *plasmaEffectPtr;
|
||
|
|
||
|
/** Hero behaviour menu entity */
|
||
|
uint8 *behaviourEntity;
|
||
|
/** Behaviour menu anim state */
|
||
|
int16 behaviourAnimState[4]; // winTab
|
||
|
/** Behaviour menu anim data pointer */
|
||
|
AnimTimerDataStruct behaviourAnimData[4];
|
||
|
|
||
|
int32 inventorySelectedColor;
|
||
|
int32 inventorySelectedItem; // currentSelectedObjectInInventory
|
||
|
|
||
|
#define PLASMA_WIDTH 320
|
||
|
#define PLASMA_HEIGHT 50
|
||
|
#define SCREEN_W 640
|
||
|
|
||
|
void plasmaEffectRenderFrame() {
|
||
|
int16 c;
|
||
|
int32 i, j;
|
||
|
uint8 *dest;
|
||
|
uint8 *src;
|
||
|
|
||
|
for (j = 1; j < PLASMA_HEIGHT - 1; j++) {
|
||
|
for (i = 1; i < PLASMA_WIDTH - 1; i++) {
|
||
|
/*Here we calculate the average of all 8 neighbour pixel values*/
|
||
|
|
||
|
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
|
||
|
|
||
|
c += plasmaEffectPtr[(i-1) + (j+0) * PLASMA_WIDTH]; //left
|
||
|
c += plasmaEffectPtr[(i+1) + (j+0) * PLASMA_WIDTH]; //right
|
||
|
|
||
|
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
|
||
|
|
||
|
c = (c >> 3) | ((c & 0x0003) << 13); /* And the 2 least significant bits are used as a
|
||
|
randomizing parameter for statistically fading the flames */
|
||
|
|
||
|
|
||
|
if (!(c & 0x6500) &&
|
||
|
(j >= (PLASMA_HEIGHT-4) || c > 0)){
|
||
|
c--; /*fade this pixel*/
|
||
|
}
|
||
|
|
||
|
/* plot the pixel using the calculated color */
|
||
|
plasmaEffectPtr[i + (PLASMA_HEIGHT+j)*PLASMA_WIDTH] = (uint8) c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// flip the double-buffer while scrolling the effect vertically:
|
||
|
dest = plasmaEffectPtr;
|
||
|
src = plasmaEffectPtr + (PLASMA_HEIGHT+1) * PLASMA_WIDTH;
|
||
|
for (i = 0; i < PLASMA_HEIGHT * PLASMA_WIDTH; i++)
|
||
|
*(dest++) = *(src++);
|
||
|
|
||
|
}
|
||
|
|
||
|
/** Process the plasma effect
|
||
|
@param top top height where the effect will be draw in the front buffer
|
||
|
@param color plasma effect start color */
|
||
|
void processPlasmaEffect(int32 top, int32 color) {
|
||
|
uint8 *in;
|
||
|
uint8 *out;
|
||
|
int32 i, j, target;
|
||
|
uint8 c;
|
||
|
uint8 max_value = color + 15;
|
||
|
|
||
|
plasmaEffectRenderFrame();
|
||
|
|
||
|
in = plasmaEffectPtr + 5 * PLASMA_WIDTH;
|
||
|
out = frontVideoBuffer + screenLookupTable[top];
|
||
|
|
||
|
for (i = 0; i < 25; i++) {
|
||
|
for (j = 0; j < kMainMenuButtonWidth; j++) {
|
||
|
c = in[i*kMainMenuButtonWidth + j] / 2 + color;
|
||
|
if (c > max_value)
|
||
|
c = max_value;
|
||
|
|
||
|
/* 2x2 squares sharing the same pixel color: */
|
||
|
target = 2*(i*SCREEN_W + j);
|
||
|
out[target] = c;
|
||
|
out[target + 1] = c;
|
||
|
out[target + SCREEN_W] = c;
|
||
|
out[target + SCREEN_W + 1] = c;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Draw the entire button box
|
||
|
@param left start width to draw the button
|
||
|
@param top start height to draw the button
|
||
|
@param right end width to draw the button
|
||
|
@param bottom end height to draw the button */
|
||
|
void drawBox(int32 left, int32 top, int32 right, int32 bottom) {
|
||
|
drawLine(left, top, right, top, 79); // top line
|
||
|
drawLine(left, top, left, bottom, 79); // left line
|
||
|
drawLine(right, ++top, right, bottom, 73); // right line
|
||
|
drawLine(++left, bottom, right, bottom, 73); // bottom line
|
||
|
}
|
||
|
|
||
|
/** Draws main menu button
|
||
|
@param width menu button width
|
||
|
@param topheight is the height between the top of the screen and the first button
|
||
|
@param id current button identification from menu settings
|
||
|
@param value current button key pressed value
|
||
|
@param mode flag to know if should draw as a hover button or not */
|
||
|
void drawButtonGfx(int32 width, int32 topheight, int32 id, int32 value, int32 mode) {
|
||
|
int32 right;
|
||
|
int32 top;
|
||
|
int32 left;
|
||
|
int32 bottom2;
|
||
|
int32 bottom;
|
||
|
int32 textSize;
|
||
|
int8 dialText[256];
|
||
|
/*
|
||
|
* int CDvolumeRemaped; int musicVolumeRemaped; int masterVolumeRemaped; int lineVolumeRemaped;
|
||
|
* int waveVolumeRemaped;
|
||
|
*/
|
||
|
|
||
|
memset(dialText, 0, sizeof(dialText));
|
||
|
|
||
|
left = width - kMainMenuButtonSpan / 2;
|
||
|
right = width + kMainMenuButtonSpan / 2;
|
||
|
|
||
|
// topheigh is the center Y pos of the button
|
||
|
top = topheight - 25; // this makes the button be 50 height
|
||
|
bottom = bottom2 = topheight + 25; // ||
|
||
|
|
||
|
if (mode != 0) {
|
||
|
if (id <= 5 && id >= 1) {
|
||
|
int32 newWidth = 0;
|
||
|
|
||
|
switch (id) {
|
||
|
case 1: {
|
||
|
if (cfgfile.MusicVolume > 255)
|
||
|
cfgfile.MusicVolume = 255;
|
||
|
if (cfgfile.MusicVolume < 0)
|
||
|
cfgfile.MusicVolume = 0;
|
||
|
newWidth = crossDot(left, right, 255, cfgfile.MusicVolume);
|
||
|
break;
|
||
|
}
|
||
|
case 2: {
|
||
|
if (cfgfile.WaveVolume > 255)
|
||
|
cfgfile.WaveVolume = 255;
|
||
|
if (cfgfile.WaveVolume < 0)
|
||
|
cfgfile.WaveVolume = 0;
|
||
|
newWidth = crossDot(left, right, 255, cfgfile.WaveVolume);
|
||
|
break;
|
||
|
}
|
||
|
case 3: {
|
||
|
if (cfgfile.CDVolume > 255)
|
||
|
cfgfile.CDVolume = 255;
|
||
|
if (cfgfile.CDVolume < 0)
|
||
|
cfgfile.CDVolume = 0;
|
||
|
newWidth = crossDot(left, right, 255, cfgfile.CDVolume);
|
||
|
break;
|
||
|
}
|
||
|
case 4: {
|
||
|
if (cfgfile.LineVolume > 255)
|
||
|
cfgfile.LineVolume = 255;
|
||
|
if (cfgfile.LineVolume < 0)
|
||
|
cfgfile.LineVolume = 0;
|
||
|
newWidth = crossDot(left, right, 255, cfgfile.LineVolume);
|
||
|
break;
|
||
|
}
|
||
|
case 5: {
|
||
|
if (cfgfile.MasterVolume > 255)
|
||
|
cfgfile.MasterVolume = 255;
|
||
|
if (cfgfile.MasterVolume < 0)
|
||
|
cfgfile.MasterVolume = 0;
|
||
|
newWidth = crossDot(left, right, 255, cfgfile.MasterVolume);
|
||
|
break;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
processPlasmaEffect(top, 80);
|
||
|
if (!(rand() % 5)) {
|
||
|
plasmaEffectPtr[rand() % 140 * 10 + 1900] = 255;
|
||
|
}
|
||
|
drawSplittedBox(newWidth, top, right, bottom, 68);
|
||
|
} else {
|
||
|
processPlasmaEffect(top, 64);
|
||
|
if (!(rand() % 5)) {
|
||
|
plasmaEffectPtr[rand() % 320 * 10 + 6400] = 255;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (id <= 5 && id >= 1) {
|
||
|
// implement this
|
||
|
}
|
||
|
} else {
|
||
|
blitBox(left, top, right, bottom, (int8 *) workVideoBuffer, left, top, (int8 *) frontVideoBuffer);
|
||
|
drawTransparentBox(left, top, right, bottom2, 4);
|
||
|
}
|
||
|
|
||
|
drawBox(left, top, right, bottom);
|
||
|
|
||
|
setFontColor(15);
|
||
|
setFontParameters(2, 8);
|
||
|
getMenuText(value, dialText);
|
||
|
textSize = getTextSize(dialText);
|
||
|
drawText(width - (textSize / 2), topheight - 18, dialText);
|
||
|
|
||
|
// TODO: make volume buttons
|
||
|
|
||
|
copyBlockPhys(left, top, right, bottom);
|
||
|
}
|
||
|
|
||
|
/** Process the menu button draw
|
||
|
@param data menu settings array
|
||
|
@param mode flag to know if should draw as a hover button or not */
|
||
|
void drawButton(int16 *menuSettings, int32 mode) {
|
||
|
int32 buttonNumber;
|
||
|
int32 maxButton;
|
||
|
int16 *localData = menuSettings;
|
||
|
int32 topHeight;
|
||
|
uint8 menuItemId;
|
||
|
uint16 menuItemValue; // applicable for sound menus, to save the volume/sound bar
|
||
|
int8 currentButton;
|
||
|
|
||
|
buttonNumber = *localData;
|
||
|
localData += 1;
|
||
|
maxButton = *localData;
|
||
|
localData += 1;
|
||
|
topHeight = *localData;
|
||
|
localData += 2;
|
||
|
|
||
|
if (topHeight == 0) {
|
||
|
topHeight = 35;
|
||
|
} else {
|
||
|
topHeight = topHeight - (((maxButton - 1) * 6) + ((maxButton) * 50)) / 2;
|
||
|
}
|
||
|
|
||
|
if (maxButton <= 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
currentButton = 0;
|
||
|
|
||
|
do {
|
||
|
// get menu item settings
|
||
|
menuItemId = (uint8) * localData;
|
||
|
localData += 1;
|
||
|
menuItemValue = *localData;
|
||
|
localData += 1;
|
||
|
if (mode != 0) {
|
||
|
if (currentButton == buttonNumber) {
|
||
|
drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, 1);
|
||
|
}
|
||
|
} else {
|
||
|
if (currentButton == buttonNumber) {
|
||
|
drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, 1);
|
||
|
} else {
|
||
|
drawButtonGfx(kMainMenuButtonWidth, topHeight, menuItemId, menuItemValue, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
currentButton++;
|
||
|
topHeight += 56; // increase button top height
|
||
|
|
||
|
// slow down the CPU
|
||
|
sdldelay(1);
|
||
|
} while (currentButton < maxButton);
|
||
|
}
|
||
|
|
||
|
/** Where the main menu options are processed
|
||
|
@param menuSettings menu settings array with the information to build the menu options
|
||
|
@return pressed menu button identification */
|
||
|
int32 processMenu(int16 * menuSettings) {
|
||
|
int32 localTime;
|
||
|
int32 numEntry;
|
||
|
int32 buttonNeedRedraw;
|
||
|
int32 maxButton;
|
||
|
int16 *localData = menuSettings;
|
||
|
int16 currentButton;
|
||
|
int16 id;
|
||
|
int32 musicChanged;
|
||
|
int32 buttonReleased = 1;
|
||
|
|
||
|
musicChanged = 0;
|
||
|
|
||
|
buttonNeedRedraw = 1;
|
||
|
|
||
|
numEntry = localData[1];
|
||
|
currentButton = 0; // localData[0];
|
||
|
localTime = lbaTime;
|
||
|
maxButton = numEntry - 1;
|
||
|
|
||
|
readKeys();
|
||
|
|
||
|
do {
|
||
|
// if its on main menu
|
||
|
if (localData == MainMenuSettings) {
|
||
|
if (lbaTime - localTime <= 11650) {
|
||
|
if (skipIntro == 46)
|
||
|
if (skippedKey != 32)
|
||
|
return kBackground;
|
||
|
} else {
|
||
|
return kBackground;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pressedKey == 0) {
|
||
|
buttonReleased = 1;
|
||
|
}
|
||
|
|
||
|
if (buttonReleased) {
|
||
|
key = pressedKey;
|
||
|
|
||
|
if (((uint8) key & 2)) { // on arrow key down
|
||
|
currentButton++;
|
||
|
if (currentButton == numEntry) { // if current button is the last, than next button is the first
|
||
|
currentButton = 0;
|
||
|
}
|
||
|
buttonNeedRedraw = 1;
|
||
|
buttonReleased = 0;
|
||
|
}
|
||
|
|
||
|
if (((uint8) key & 1)) { // on arrow key up
|
||
|
currentButton--;
|
||
|
if (currentButton < 0) { // if current button is the first, than previous button is the last
|
||
|
currentButton = maxButton;
|
||
|
}
|
||
|
buttonNeedRedraw = 1;
|
||
|
buttonReleased = 0;
|
||
|
}
|
||
|
|
||
|
if (*(localData + 8) <= 5) { // if its a volume button
|
||
|
id = *(localData + currentButton * 2 + 4); // get button parameters from settings array
|
||
|
|
||
|
switch (id) {
|
||
|
case kMusicVolume: {
|
||
|
if (((uint8) key & 4)) { // on arrow key left
|
||
|
cfgfile.MusicVolume -= 4;
|
||
|
}
|
||
|
if (((uint8) key & 8)) { // on arrow key right
|
||
|
cfgfile.MusicVolume += 4;
|
||
|
}
|
||
|
musicVolume(cfgfile.MusicVolume);
|
||
|
break;
|
||
|
}
|
||
|
case kSoundVolume: {
|
||
|
if (((uint8) key & 4)) { // on arrow key left
|
||
|
cfgfile.WaveVolume -= 4;
|
||
|
}
|
||
|
if (((uint8) key & 8)) { // on arrow key right
|
||
|
cfgfile.WaveVolume += 4;
|
||
|
}
|
||
|
sampleVolume(-1, cfgfile.WaveVolume);
|
||
|
break;
|
||
|
}
|
||
|
case kCDVolume: {
|
||
|
if (((uint8) key & 4)) { // on arrow key left
|
||
|
cfgfile.CDVolume -= 4;
|
||
|
}
|
||
|
if (((uint8) key & 8)) { // on arrow key right
|
||
|
cfgfile.CDVolume += 4;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case kLineVolume: {
|
||
|
if (((uint8) key & 4)) { // on arrow key left
|
||
|
cfgfile.LineVolume -= 4;
|
||
|
}
|
||
|
if (((uint8) key & 8)) { // on arrow key right
|
||
|
cfgfile.LineVolume += 4;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case kMasterVolume: {
|
||
|
if (((uint8) key & 4)) { // on arrow key left
|
||
|
cfgfile.MasterVolume -= 4;
|
||
|
}
|
||
|
if (((uint8) key & 8)) { // on arrow key right
|
||
|
cfgfile.MasterVolume += 4;
|
||
|
}
|
||
|
musicVolume(cfgfile.MusicVolume);
|
||
|
sampleVolume(-1, cfgfile.WaveVolume);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (buttonNeedRedraw == 1) {
|
||
|
*localData = currentButton;
|
||
|
|
||
|
drawButton(localData, 0); // current button
|
||
|
do {
|
||
|
readKeys();
|
||
|
drawButton(localData, 1);
|
||
|
} while (pressedKey == 0 && skippedKey == 0 && skipIntro == 0);
|
||
|
buttonNeedRedraw = 0;
|
||
|
} else {
|
||
|
if (musicChanged) {
|
||
|
// TODO: update volume settings
|
||
|
|
||
|
}
|
||
|
|
||
|
buttonNeedRedraw = 0;
|
||
|
drawButton(localData, 1);
|
||
|
readKeys();
|
||
|
// WARNING: this is here to prevent a fade bug while quit the menu
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
}
|
||
|
} while (!(skippedKey & 2) && !(skippedKey & 1));
|
||
|
|
||
|
currentButton = *(localData + 5 + currentButton * 2); // get current browsed button
|
||
|
|
||
|
readKeys();
|
||
|
|
||
|
return currentButton;
|
||
|
}
|
||
|
|
||
|
/** Used to run the advanced options menu */
|
||
|
int32 advoptionsMenu() {
|
||
|
int32 ret = 0;
|
||
|
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
|
||
|
do {
|
||
|
switch (processMenu(AdvOptionsMenuSettings)) {
|
||
|
case kReturnMenu: {
|
||
|
ret = 1; // quit option menu
|
||
|
break;
|
||
|
}
|
||
|
//TODO: add other options
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
} while (ret != 1);
|
||
|
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
flip();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/** Used to run the save game management menu */
|
||
|
int32 savemanageMenu() {
|
||
|
int32 ret = 0;
|
||
|
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
|
||
|
do {
|
||
|
switch (processMenu(SaveManageMenuSettings)) {
|
||
|
case kReturnMenu: {
|
||
|
ret = 1; // quit option menu
|
||
|
break;
|
||
|
}
|
||
|
//TODO: add other options
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
} while (ret != 1);
|
||
|
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
flip();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/** Used to run the volume menu */
|
||
|
int32 volumeMenu() {
|
||
|
int32 ret = 0;
|
||
|
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
|
||
|
do {
|
||
|
switch (processMenu(VolumeMenuSettings)) {
|
||
|
case kReturnMenu: {
|
||
|
ret = 1; // quit option menu
|
||
|
break;
|
||
|
}
|
||
|
//TODO: add other options
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
} while (ret != 1);
|
||
|
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
flip();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/** Used to run the options menu */
|
||
|
int32 optionsMenu() {
|
||
|
int32 ret = 0;
|
||
|
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
|
||
|
stopSamples();
|
||
|
//playCDtrack(9);
|
||
|
|
||
|
do {
|
||
|
switch (processMenu(OptionsMenuSettings)) {
|
||
|
case kReturnGame:
|
||
|
case kReturnMenu: {
|
||
|
ret = 1; // quit option menu
|
||
|
break;
|
||
|
}
|
||
|
case kVolume: {
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
flip();
|
||
|
volumeMenu();
|
||
|
break;
|
||
|
}
|
||
|
case kSaveManage: {
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
flip();
|
||
|
savemanageMenu();
|
||
|
break;
|
||
|
}
|
||
|
case kAdvanced: {
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
flip();
|
||
|
advoptionsMenu();
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
} while (ret != 1);
|
||
|
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
flip();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/** Used to run the main menu */
|
||
|
void mainMenu() {
|
||
|
stopSamples();
|
||
|
|
||
|
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||
|
|
||
|
// load menu effect file only once
|
||
|
plasmaEffectPtr = (uint8 *)malloc(kPlasmaEffectFilesize);
|
||
|
memset(plasmaEffectPtr, 0, kPlasmaEffectFilesize);
|
||
|
hqrGetEntry(plasmaEffectPtr, HQR_RESS_FILE, RESSHQR_PLASMAEFFECT);
|
||
|
|
||
|
while (!cfgfile.Quit) {
|
||
|
initTextBank(0);
|
||
|
|
||
|
playTrackMusic(9); // LBA's Theme
|
||
|
stopSamples();
|
||
|
|
||
|
switch (processMenu(MainMenuSettings)) {
|
||
|
case kNewGame: {
|
||
|
newGameMenu();
|
||
|
break;
|
||
|
}
|
||
|
case kContinueGame: {
|
||
|
continueGameMenu();
|
||
|
break;
|
||
|
}
|
||
|
case kOptions: {
|
||
|
copyScreen(workVideoBuffer, frontVideoBuffer);
|
||
|
flip();
|
||
|
OptionsMenuSettings[5] = kReturnMenu;
|
||
|
optionsMenu();
|
||
|
break;
|
||
|
}
|
||
|
case kQuit: {
|
||
|
cfgfile.Quit = 1;
|
||
|
break;
|
||
|
}
|
||
|
case kBackground: {
|
||
|
loadMenuImage(1);
|
||
|
}
|
||
|
}
|
||
|
fpsCycles(cfgfile.Fps);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Used to process give up menu while playing game */
|
||
|
int32 giveupMenu() {
|
||
|
//int32 saveLangue=0;
|
||
|
int32 menuId;
|
||
|
int16 * localMenu;
|
||
|
|
||
|
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||
|
pauseSamples();
|
||
|
|
||
|
if (cfgfile.UseAutoSaving == 1)
|
||
|
localMenu = GiveUpMenuSettings;
|
||
|
else
|
||
|
localMenu = GiveUpMenuSettingsWithSave;
|
||
|
|
||
|
do {
|
||
|
//saveLangue = languageCD1;
|
||
|
//languageCD1 = 0;
|
||
|
initTextBank(0);
|
||
|
|
||
|
menuId = processMenu(localMenu);
|
||
|
|
||
|
//languageCD1 = saveLangue;
|
||
|
|
||
|
initTextBank(currentTextBank + 3);
|
||
|
|
||
|
fpsCycles(cfgfile.Fps);
|
||
|
} while (menuId != kGiveUp && menuId != kContinue);
|
||
|
|
||
|
if (menuId == kGiveUp)
|
||
|
{
|
||
|
stopSamples();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
resumeSamples();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void drawInfoMenu(int16 left, int16 top)
|
||
|
{
|
||
|
int32 boxLeft, boxTop, boxRight, boxBottom;
|
||
|
int32 newBoxLeft, newBoxLeft2, i;
|
||
|
|
||
|
resetClip();
|
||
|
drawBox(left, top, left + 450, top + 80);
|
||
|
drawSplittedBox(left + 1, top + 1, left + 449, top + 79, 0);
|
||
|
|
||
|
newBoxLeft2 = left + 9;
|
||
|
|
||
|
drawSprite(0, newBoxLeft2, top + 13, spriteTable[SPRITEHQR_LIFEPOINTS]);
|
||
|
|
||
|
boxRight = left + 325;
|
||
|
newBoxLeft = left + 25;
|
||
|
boxLeft = crossDot(newBoxLeft, boxRight, 50, sceneHero->life);
|
||
|
|
||
|
boxTop = top + 10;
|
||
|
boxBottom = top + 25;
|
||
|
drawSplittedBox(newBoxLeft, boxTop, boxLeft, boxBottom, 91);
|
||
|
drawBox(left + 25, top + 10, left + 324, top + 10 + 14);
|
||
|
|
||
|
if (!gameFlags[GAMEFLAG_INVENTORY_DISABLED] && gameFlags[GAMEFLAG_TUNIC]) {
|
||
|
drawSprite(0, newBoxLeft2, top + 36, spriteTable[SPRITEHQR_MAGICPOINTS]);
|
||
|
if(magicLevelIdx > 0) {
|
||
|
drawSplittedBox(newBoxLeft, top + 35, crossDot(newBoxLeft, boxRight, 80, inventoryMagicPoints),top + 50, 75);
|
||
|
}
|
||
|
drawBox(left + 25, top + 35, left + magicLevelIdx * 80 + 20, top + 35 + 15);
|
||
|
}
|
||
|
|
||
|
boxLeft = left + 340;
|
||
|
|
||
|
/** draw coin sprite */
|
||
|
drawSprite(0, boxLeft, top + 15, spriteTable[SPRITEHQR_KASHES]);
|
||
|
setFontColor(155);
|
||
|
drawText(left + 370, top + 5, ITOA(inventoryNumKashes));
|
||
|
|
||
|
/** draw key sprite */
|
||
|
drawSprite(0, boxLeft, top + 55, spriteTable[SPRITEHQR_KEY]);
|
||
|
setFontColor(155);
|
||
|
drawText(left + 370, top + 40, ITOA(inventoryNumKeys));
|
||
|
|
||
|
// prevent
|
||
|
if (inventoryNumLeafs > inventoryNumLeafsBox) {
|
||
|
inventoryNumLeafs = inventoryNumLeafsBox;
|
||
|
}
|
||
|
|
||
|
// Clover leaf boxes
|
||
|
for (i = 0; i < inventoryNumLeafsBox; i++)
|
||
|
{
|
||
|
drawSprite(0, crossDot(left + 25, left + 325, 10, i), top + 58, spriteTable[SPRITEHQR_CLOVERLEAFBOX]);
|
||
|
}
|
||
|
|
||
|
// Clover leafs
|
||
|
for (i = 0; i < inventoryNumLeafs; i++)
|
||
|
{
|
||
|
drawSprite(0, crossDot(left + 25, left + 325, 10, i) + 2, top + 60, spriteTable[SPRITEHQR_CLOVERLEAF]);
|
||
|
}
|
||
|
|
||
|
copyBlockPhys(left, top, left + 450, top + 135);
|
||
|
}
|
||
|
|
||
|
void drawBehaviour(int16 behaviour, int32 angle, int16 cantDrawBox) {
|
||
|
uint8 *currentAnim;
|
||
|
int32 boxLeft, boxTop, boxRight, boxBottom, currentAnimState;
|
||
|
int8 dialText[256];
|
||
|
|
||
|
boxLeft = behaviour * 110 + 110;
|
||
|
boxRight = boxLeft + 99;
|
||
|
boxTop = 110;
|
||
|
boxBottom = 229;
|
||
|
|
||
|
currentAnim = animTable[heroAnimIdx[behaviour]];
|
||
|
currentAnimState = behaviourAnimState[behaviour];
|
||
|
|
||
|
if (setModelAnimation(currentAnimState, currentAnim, behaviourEntity, &behaviourAnimData[behaviour])) {
|
||
|
currentAnimState++; // keyframe
|
||
|
if (currentAnimState >= getNumKeyframes(currentAnim)) {
|
||
|
currentAnimState = getStartKeyframe(currentAnim);
|
||
|
}
|
||
|
behaviourAnimState[behaviour] = currentAnimState;
|
||
|
}
|
||
|
|
||
|
if (cantDrawBox == 0) {
|
||
|
drawBox(boxLeft - 1, boxTop - 1, boxRight + 1, boxBottom + 1);
|
||
|
}
|
||
|
|
||
|
saveClip();
|
||
|
resetClip();
|
||
|
|
||
|
if (behaviour != heroBehaviour) { // unselected
|
||
|
drawSplittedBox(boxLeft, boxTop, boxRight, boxBottom, 0);
|
||
|
} else { // selected
|
||
|
drawSplittedBox(boxLeft, boxTop, boxRight, boxBottom, 69);
|
||
|
|
||
|
// behaviour menu title
|
||
|
drawSplittedBox(110, 239, 540, 279, 0);
|
||
|
drawBox(110, 239, 540, 279);
|
||
|
|
||
|
setFontColor(15);
|
||
|
|
||
|
if (heroBehaviour == 2 && autoAgressive == 1) {
|
||
|
getMenuText(4, dialText);
|
||
|
} else {
|
||
|
getMenuText(heroBehaviour, dialText);
|
||
|
}
|
||
|
|
||
|
drawText((650 - getTextSize(dialText)) / 2, 240, dialText);
|
||
|
}
|
||
|
|
||
|
renderBehaviourModel(boxLeft, boxTop, boxRight, boxBottom, -600, angle, behaviourEntity);
|
||
|
|
||
|
copyBlockPhys(boxLeft, boxTop, boxRight, boxBottom);
|
||
|
copyBlockPhys(110, 239, 540, 279);
|
||
|
|
||
|
loadClip();
|
||
|
}
|
||
|
|
||
|
void drawBehaviourMenu(int32 angle) {
|
||
|
drawBox(100, 100, 550, 290);
|
||
|
drawTransparentBox(101, 101, 549, 289, 2);
|
||
|
|
||
|
setAnimAtKeyframe(behaviourAnimState[kNormal], animTable[heroAnimIdx[kNormal]], behaviourEntity, &behaviourAnimData[kNormal]);
|
||
|
drawBehaviour(kNormal, angle, 0);
|
||
|
|
||
|
setAnimAtKeyframe(behaviourAnimState[kAthletic], animTable[heroAnimIdx[kAthletic]], behaviourEntity, &behaviourAnimData[kAthletic]);
|
||
|
drawBehaviour(kAthletic, angle, 0);
|
||
|
|
||
|
setAnimAtKeyframe(behaviourAnimState[kAggressive], animTable[heroAnimIdx[kAggressive]], behaviourEntity, &behaviourAnimData[kAggressive]);
|
||
|
drawBehaviour(kAggressive, angle, 0);
|
||
|
|
||
|
setAnimAtKeyframe(behaviourAnimState[kDiscrete], animTable[heroAnimIdx[kDiscrete]], behaviourEntity, &behaviourAnimData[kDiscrete]);
|
||
|
drawBehaviour(kDiscrete, angle, 0);
|
||
|
|
||
|
drawInfoMenu(100, 300);
|
||
|
|
||
|
copyBlockPhys(100, 100, 550, 290);
|
||
|
}
|
||
|
|
||
|
/** Process hero behaviour menu */
|
||
|
void processBehaviourMenu() {
|
||
|
int32 tmpLanguageCD;
|
||
|
int32 tmpTextBank;
|
||
|
int32 tmpHeroBehaviour;
|
||
|
int32 tmpTime;
|
||
|
|
||
|
if (heroBehaviour == kProtoPack) {
|
||
|
stopSamples();
|
||
|
setBehaviour(kNormal);
|
||
|
}
|
||
|
|
||
|
behaviourEntity = bodyTable[sceneHero->entity];
|
||
|
|
||
|
heroAnimIdx[kNormal] = heroAnimIdxNORMAL;
|
||
|
heroAnimIdx[kAthletic] = heroAnimIdxATHLETIC;
|
||
|
heroAnimIdx[kAggressive] = heroAnimIdxAGGRESSIVE;
|
||
|
heroAnimIdx[kDiscrete] = heroAnimIdxDISCRETE;
|
||
|
|
||
|
setActorAngleSafe(sceneHero->angle, sceneHero->angle - 256, 50, &moveMenu);
|
||
|
|
||
|
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||
|
|
||
|
tmpLanguageCD = cfgfile.LanguageCDId;
|
||
|
cfgfile.LanguageCDId = 0;
|
||
|
|
||
|
tmpTextBank = currentTextBank;
|
||
|
currentTextBank = -1;
|
||
|
|
||
|
initTextBank(0);
|
||
|
|
||
|
drawBehaviourMenu(sceneHero->angle);
|
||
|
|
||
|
tmpHeroBehaviour = heroBehaviour;
|
||
|
|
||
|
setAnimAtKeyframe(behaviourAnimState[heroBehaviour], animTable[heroAnimIdx[heroBehaviour]], behaviourEntity, &behaviourAnimData[heroBehaviour]);
|
||
|
|
||
|
readKeys();
|
||
|
|
||
|
tmpTime = lbaTime;
|
||
|
|
||
|
while (skippedKey & 4 || (skipIntro >= 59 && skipIntro <= 62)) {
|
||
|
readKeys();
|
||
|
key = pressedKey;
|
||
|
|
||
|
if (key & 8) {
|
||
|
heroBehaviour++;
|
||
|
}
|
||
|
|
||
|
if (key & 4) {
|
||
|
heroBehaviour--;
|
||
|
}
|
||
|
|
||
|
if (heroBehaviour < 0) {
|
||
|
heroBehaviour = 3;
|
||
|
}
|
||
|
|
||
|
if (heroBehaviour >= 4) {
|
||
|
heroBehaviour = 0;
|
||
|
}
|
||
|
|
||
|
if (tmpHeroBehaviour != heroBehaviour) {
|
||
|
drawBehaviour(tmpHeroBehaviour, sceneHero->angle, 1);
|
||
|
tmpHeroBehaviour = heroBehaviour;
|
||
|
setActorAngleSafe(sceneHero->angle, sceneHero->angle - 256, 50, &moveMenu);
|
||
|
setAnimAtKeyframe(behaviourAnimState[heroBehaviour], animTable[heroAnimIdx[heroBehaviour]], behaviourEntity, &behaviourAnimData[heroBehaviour]);
|
||
|
|
||
|
while (pressedKey) {
|
||
|
readKeys();
|
||
|
drawBehaviour(heroBehaviour, -1, 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
drawBehaviour(heroBehaviour, -1, 1);
|
||
|
|
||
|
fpsCycles(50);
|
||
|
lbaTime++;
|
||
|
}
|
||
|
|
||
|
lbaTime = tmpTime;
|
||
|
|
||
|
setBehaviour(heroBehaviour);
|
||
|
initEngineProjections();
|
||
|
|
||
|
currentTextBank = tmpTextBank;
|
||
|
initTextBank(currentTextBank + 3);
|
||
|
|
||
|
cfgfile.LanguageCDId = tmpLanguageCD;
|
||
|
}
|
||
|
|
||
|
/** Draw the entire button box
|
||
|
@param left start width to draw the button
|
||
|
@param top start height to draw the button
|
||
|
@param right end width to draw the button
|
||
|
@param bottom end height to draw the button */
|
||
|
void drawMagicItemsBox(int32 left, int32 top, int32 right, int32 bottom, int32 color) { // Rect
|
||
|
drawLine(left, top, right, top, color); // top line
|
||
|
drawLine(left, top, left, bottom, color); // left line
|
||
|
drawLine(right, ++top, right, bottom, color); // right line
|
||
|
drawLine(++left, bottom, right, bottom, color); // bottom line
|
||
|
}
|
||
|
|
||
|
void drawItem(int32 item) {
|
||
|
int32 itemX = (item / 4) * 85 + 64;
|
||
|
int32 itemY = (item & 3) * 75 + 52;
|
||
|
|
||
|
int32 left = itemX - 37;
|
||
|
int32 right = itemX + 37;
|
||
|
int32 top = itemY - 32;
|
||
|
int32 bottom = itemY + 32;
|
||
|
|
||
|
drawSplittedBox(left, top, right, bottom,
|
||
|
inventorySelectedItem == item ? inventorySelectedColor : 0);
|
||
|
|
||
|
if (gameFlags[item] && !gameFlags[GAMEFLAG_INVENTORY_DISABLED] && item < NUM_INVENTORY_ITEMS) {
|
||
|
prepareIsoModel(inventoryTable[item]);
|
||
|
itemAngle[item] += 8;
|
||
|
renderInventoryItem(itemX, itemY, inventoryTable[item], itemAngle[item], 15000);
|
||
|
|
||
|
if (item == 15) { // has GAS
|
||
|
setFontColor(15);
|
||
|
drawText(left + 3, top + 32, ITOA(inventoryNumGas));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
drawBox(left, top, right, bottom);
|
||
|
copyBlockPhys(left, top, right, bottom);
|
||
|
}
|
||
|
|
||
|
void drawInventoryItems() {
|
||
|
int32 item;
|
||
|
|
||
|
drawTransparentBox(17, 10, 622, 320, 4);
|
||
|
drawBox(17, 10, 622, 320);
|
||
|
drawMagicItemsBox(110, 18, 188, 311, 75);
|
||
|
copyBlockPhys(17, 10, 622, 320);
|
||
|
|
||
|
for (item = 0; item < NUM_INVENTORY_ITEMS; item++) {
|
||
|
drawItem(item);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Process in-game inventory menu */
|
||
|
void processInventoryMenu() {
|
||
|
int32 di = 1;
|
||
|
int32 prevSelectedItem, tmpLanguageCD, bx, tmpAlphaLight, tmpBetaLight;
|
||
|
|
||
|
tmpAlphaLight = alphaLight;
|
||
|
tmpBetaLight = betaLight;
|
||
|
|
||
|
copyScreen(frontVideoBuffer, workVideoBuffer);
|
||
|
|
||
|
setLightVector(896, 950, 0);
|
||
|
|
||
|
inventorySelectedColor = 68;
|
||
|
|
||
|
if (inventoryNumLeafs > 0) {
|
||
|
gameFlags[GAMEFLAG_HAS_CLOVER_LEAF] = 1;
|
||
|
}
|
||
|
|
||
|
drawInventoryItems();
|
||
|
|
||
|
tmpLanguageCD = cfgfile.LanguageCDId;
|
||
|
cfgfile.LanguageCDId = 0;
|
||
|
|
||
|
initTextBank(2);
|
||
|
|
||
|
bx = 3;
|
||
|
|
||
|
setFontCrossColor(4);
|
||
|
initDialogueBox();
|
||
|
|
||
|
while (skipIntro != 1) {
|
||
|
readKeys();
|
||
|
prevSelectedItem = inventorySelectedItem;
|
||
|
|
||
|
if (!di) {
|
||
|
key = pressedKey;
|
||
|
loopPressedKey = skippedKey;
|
||
|
loopCurrentKey = skipIntro;
|
||
|
|
||
|
if (key != 0 || skippedKey != 0) {
|
||
|
di = 1;
|
||
|
}
|
||
|
} else {
|
||
|
loopCurrentKey = 0;
|
||
|
key = 0;
|
||
|
loopPressedKey = 0;
|
||
|
if (!pressedKey && !skippedKey) {
|
||
|
di = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (loopCurrentKey == 1 || loopPressedKey & 0x20)
|
||
|
break;
|
||
|
|
||
|
if (key & 2) { // down
|
||
|
inventorySelectedItem++;
|
||
|
if (inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
|
||
|
inventorySelectedItem = 0;
|
||
|
}
|
||
|
drawItem(prevSelectedItem);
|
||
|
bx = 3;
|
||
|
}
|
||
|
|
||
|
if (key & 1) { // up
|
||
|
inventorySelectedItem--;
|
||
|
if (inventorySelectedItem < 0) {
|
||
|
inventorySelectedItem = NUM_INVENTORY_ITEMS - 1;
|
||
|
}
|
||
|
drawItem(prevSelectedItem);
|
||
|
bx = 3;
|
||
|
}
|
||
|
|
||
|
if (key & 4) { // left
|
||
|
inventorySelectedItem -= 4;
|
||
|
if (inventorySelectedItem < 0) {
|
||
|
inventorySelectedItem += NUM_INVENTORY_ITEMS;
|
||
|
}
|
||
|
drawItem(prevSelectedItem);
|
||
|
bx = 3;
|
||
|
}
|
||
|
|
||
|
if (key & 8) { // right
|
||
|
inventorySelectedItem += 4;
|
||
|
if (inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
|
||
|
inventorySelectedItem -= NUM_INVENTORY_ITEMS;
|
||
|
}
|
||
|
drawItem(prevSelectedItem);
|
||
|
bx = 3;
|
||
|
}
|
||
|
|
||
|
if (bx == 3) {
|
||
|
initInventoryDialogueBox();
|
||
|
|
||
|
if (gameFlags[inventorySelectedItem] == 1 && !gameFlags[GAMEFLAG_INVENTORY_DISABLED] && inventorySelectedItem < NUM_INVENTORY_ITEMS) {
|
||
|
initText(inventorySelectedItem + 100);
|
||
|
} else {
|
||
|
initText(128);
|
||
|
}
|
||
|
bx = 0;
|
||
|
}
|
||
|
|
||
|
if (bx != 2) {
|
||
|
bx = printText10();
|
||
|
}
|
||
|
|
||
|
// TRICKY: 3D model rotation delay - only apply when no text is drawing
|
||
|
if (bx == 0 || bx == 2) {
|
||
|
sdldelay(15);
|
||
|
}
|
||
|
|
||
|
if (loopPressedKey & 1) {
|
||
|
if (bx == 2) {
|
||
|
initInventoryDialogueBox();
|
||
|
bx = 0;
|
||
|
} else {
|
||
|
if (gameFlags[inventorySelectedItem] == 1 && !gameFlags[GAMEFLAG_INVENTORY_DISABLED] && inventorySelectedItem < NUM_INVENTORY_ITEMS) {
|
||
|
initInventoryDialogueBox();
|
||
|
initText(inventorySelectedItem + 100);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
drawItem(inventorySelectedItem);
|
||
|
|
||
|
if ((loopPressedKey & 2) && gameFlags[inventorySelectedItem] == 1 && !gameFlags[GAMEFLAG_INVENTORY_DISABLED] && inventorySelectedItem < NUM_INVENTORY_ITEMS) {
|
||
|
loopInventoryItem = inventorySelectedItem;
|
||
|
inventorySelectedColor = 91;
|
||
|
drawItem(inventorySelectedItem);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
printTextVar13 = 0;
|
||
|
|
||
|
alphaLight = tmpAlphaLight;
|
||
|
betaLight = tmpBetaLight;
|
||
|
|
||
|
initEngineProjections();
|
||
|
|
||
|
cfgfile.LanguageCDId = tmpLanguageCD;
|
||
|
|
||
|
initTextBank(currentTextBank + 3);
|
||
|
|
||
|
while (skipIntro != 0 && skippedKey != 0) {
|
||
|
readKeys();
|
||
|
sdldelay(1);
|
||
|
}
|
||
|
}
|