mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 13:50:13 +00:00
397 lines
13 KiB
C++
397 lines
13 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* Additional copyright for this file:
|
|
* Copyright (C) 1999-2000 Revolution Software Ltd.
|
|
* This code is based on source code created by Revolution Software,
|
|
* used with permission.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "engines/icb/icb.h"
|
|
#include "engines/icb/icon_menu.h"
|
|
#include "engines/icb/global_objects.h"
|
|
#include "engines/icb/sound.h"
|
|
#include "engines/icb/res_man.h"
|
|
#include "engines/icb/remora.h"
|
|
#include "engines/icb/mission.h"
|
|
|
|
namespace ICB {
|
|
|
|
// Use globals as it reduces rdata storage on PSX
|
|
const char *global_nothing_selected = "NOTHING_SELECTED";
|
|
|
|
_icon_menu::_icon_menu() {
|
|
m_eIconMenuGameState = INACTIVE;
|
|
m_bValidSelection = FALSE8;
|
|
m_nKeyLock = FALSE8;
|
|
m_nHighlightCounter = 0;
|
|
m_bHighlightVisible = FALSE8;
|
|
m_bAllowEscape = TRUE8;
|
|
m_bWiderThanScreen = FALSE8;
|
|
m_nAddedMedipacks = 0;
|
|
m_nAddedClips = 0;
|
|
m_nAddedSymbol = 0;
|
|
m_nAddedFlashCount = 0;
|
|
|
|
Common::strcpy_s(m_pcGlobalClusterFile, GLOBAL_CLUSTER_PATH);
|
|
Common::strcpy_s(m_pcIconCluster, ICON_CLUSTER_PATH);
|
|
|
|
m_nGlobalClusterHash = NULL_HASH;
|
|
m_nIconClusterHash = NULL_HASH;
|
|
m_nSelectedIconHash = NULL_HASH;
|
|
m_pcSelectedIconName = global_nothing_selected;
|
|
}
|
|
|
|
bool8 _icon_menu::CycleIconMenu(const _input &sKeyboardState) {
|
|
bool8 nRetVal = TRUE8;
|
|
|
|
static int32 lastInventoryPress = 0;
|
|
int32 inventoryPress;
|
|
|
|
// Cycle the transparency for the highlight, to pulse the icon on screen
|
|
++m_nHighlightCounter;
|
|
|
|
if (m_nHighlightCounter == ICON_MENU_HIGHLIGHT_SPEED) {
|
|
m_nHighlightCounter = 0;
|
|
m_bHighlightVisible = (bool8)!m_bHighlightVisible;
|
|
}
|
|
|
|
inventoryPress = sKeyboardState.IsButtonSet(__INVENTORY);
|
|
|
|
// FIND GOBACK if there is one
|
|
// found is -1 means none found
|
|
int32 found = -1;
|
|
int32 i;
|
|
|
|
// loop through all the icons or until we find a goback
|
|
i = 0;
|
|
while ((i < m_pIconList->GetIconCount()) && (found == -1)) {
|
|
// get the icon
|
|
const uint32 hash = m_pIconList->GetIconHash(i);
|
|
|
|
// look for goback or return
|
|
if ((hash == HashString("return")) || (hash == HashString("goback")))
|
|
found = i;
|
|
|
|
i++;
|
|
}
|
|
|
|
// if there is a goback option and we are gholding down inventory key and we are not ucrrently on goback then scroll round until we
|
|
// get there...
|
|
// also only if we are not scrolling
|
|
if ((found != -1) && (inventoryPress) && (m_nSelectedIcon != (uint)found) && (m_nScrollDirection == ICON_MENU_SCROLL_NONE)) {
|
|
m_nSelectedIcon = found;
|
|
m_pcSelectedIconName = const_cast<char *>(m_pIconList->GetIcon(m_nSelectedIcon));
|
|
m_nSelectedIconHash = m_pIconList->GetIconHash(m_nSelectedIcon);
|
|
}
|
|
|
|
// See what keys are being pressed.
|
|
|
|
// INVENTORY QUIT: we must not be in the remora, m_bAllowEscape must be true
|
|
// key not locked, we are pressing inventory and we wern't last time...
|
|
if (((g_icb->getGameType() == GType_ICB && !g_oRemora->IsActive()) ||
|
|
(g_icb->getGameType() != GType_ICB)) && (m_bAllowEscape) && (!m_nKeyLock) && (inventoryPress) && (!lastInventoryPress)) {
|
|
CloseDownIconMenu();
|
|
|
|
// Return the player's state to what it was before the menu was activated.
|
|
MS->player.Pop_control_mode();
|
|
MS->player.Set_player_status(STOOD);
|
|
|
|
// Lock the keypress so it can't be repeated.
|
|
m_nKeyLock = TRUE8;
|
|
|
|
// Tell the calling function this function doesn't need calling any more.
|
|
nRetVal = FALSE8;
|
|
|
|
}
|
|
// REMORA QUIT: remora is active we just let go of inventory button, key not locked we have a return...
|
|
else if (((g_icb->getGameType() == GType_ICB && g_oRemora->IsActive()) ||
|
|
(g_icb->getGameType() != GType_ICB)) && (!m_nKeyLock) && (!inventoryPress) && (lastInventoryPress) && (found != -1)) {
|
|
m_nLastSelection = found;
|
|
m_bValidSelection = TRUE8;
|
|
|
|
// Close down the menu.
|
|
CloseDownIconMenu();
|
|
|
|
// Lock the keypress so it can't be repeated.
|
|
m_nKeyLock = TRUE8;
|
|
|
|
// Tell the calling function this function doesn't need calling any more.
|
|
nRetVal = FALSE8;
|
|
|
|
lastInventoryPress = 0;
|
|
}
|
|
// CONVERSATION QUIT: remora is not active m_bAllowEscape is probably true
|
|
// no key lock, inventory was pressed and has now been released...
|
|
// and we have a quit!
|
|
else if (((g_icb->getGameType() == GType_ICB && !g_oRemora->IsActive()) ||
|
|
(g_icb->getGameType() != GType_ICB)) && (!m_bAllowEscape) && (!m_nKeyLock) && (!inventoryPress) && (lastInventoryPress) && (found != -1)) {
|
|
m_nLastSelection = found;
|
|
m_bValidSelection = TRUE8;
|
|
|
|
// Close down the menu.
|
|
CloseDownIconMenu();
|
|
|
|
// Lock the keypress so it can't be repeated.
|
|
m_nKeyLock = TRUE8;
|
|
|
|
// Tell the calling function this function doesn't need calling any more.
|
|
nRetVal = FALSE8;
|
|
|
|
lastInventoryPress = 0;
|
|
} else if (!m_nKeyLock && sKeyboardState.IsButtonSet(__INTERACT)) {
|
|
// Player is selecting the current icon. Don't select it if it is the 'empty' icon
|
|
if (m_pIconList->GetIconHash(m_nSelectedIcon) != HashString(ICON_LIST_EMPTY_ICON)) {
|
|
m_nLastSelection = m_nSelectedIcon;
|
|
m_bValidSelection = TRUE8;
|
|
}
|
|
if (g_icb->getGameType() == GType_ICB && !g_oRemora->IsActive()) {
|
|
// Return the player's state to what it was before the menu was activated.
|
|
MS->player.Pop_control_mode();
|
|
MS->player.Set_player_status(STOOD);
|
|
}
|
|
// Close down the menu.
|
|
CloseDownIconMenu();
|
|
|
|
// Lock the keypress so it can't be repeated.
|
|
m_nKeyLock = TRUE8;
|
|
|
|
// Tell the calling function this function doesn't need calling any more.
|
|
nRetVal = FALSE8;
|
|
} else if (!m_nKeyLock && !sKeyboardState.IsButtonSet(__SIDESTEP) && (sKeyboardState.turn == __LEFT)) {
|
|
// Move current selection left : if we are not scrolling & more than item in the list
|
|
if ((m_nScrollDirection == ICON_MENU_SCROLL_NONE) && (m_pIconList->GetIconCount() > 1)) {
|
|
|
|
if (m_nSelectedIcon == 0)
|
|
m_nSelectedIcon = m_pIconList->GetIconCount() - 1;
|
|
else
|
|
--m_nSelectedIcon;
|
|
|
|
// Set the name & hash value of the currently selected icon.
|
|
// Set_string( m_pIconList->GetIcon( m_nSelectedIcon ), m_pcSelectedIconName, MAXLEN_ICON_NAME );
|
|
m_pcSelectedIconName = const_cast<char *>(m_pIconList->GetIcon(m_nSelectedIcon));
|
|
m_nSelectedIconHash = m_pIconList->GetIconHash(m_nSelectedIcon);
|
|
|
|
// Lock the keypress so it can't be repeated.
|
|
m_nKeyLock = TRUE8;
|
|
|
|
// Tell the calling function this function does need calling again next cycle.
|
|
nRetVal = TRUE8;
|
|
|
|
// Hey hey we are scrolling to the right even though pressed LEFT
|
|
m_nScrollDirection = ICON_MENU_SCROLL_RIGHT;
|
|
}
|
|
} else if (!m_nKeyLock && !sKeyboardState.IsButtonSet(__SIDESTEP) && sKeyboardState.turn == __RIGHT) {
|
|
// Move current selection right : if we are not scrolling & more than item in the list
|
|
if ((m_nScrollDirection == ICON_MENU_SCROLL_NONE) && (m_pIconList->GetIconCount() > 1)) {
|
|
if (m_nSelectedIcon == (uint32)(m_pIconList->GetIconCount() - 1))
|
|
m_nSelectedIcon = 0;
|
|
else
|
|
++m_nSelectedIcon;
|
|
|
|
// Set the name & hash value of the currently selected icon.
|
|
// Set_string( m_pIconList->GetIcon( m_nSelectedIcon ), m_pcSelectedIconName, MAXLEN_ICON_NAME );
|
|
m_pcSelectedIconName = const_cast<char *>(m_pIconList->GetIcon(m_nSelectedIcon));
|
|
m_nSelectedIconHash = m_pIconList->GetIconHash(m_nSelectedIcon);
|
|
|
|
// Lock the keypress so it can't be repeated.
|
|
m_nKeyLock = TRUE8;
|
|
|
|
// Tell the calling function this function does need calling again next cycle.
|
|
nRetVal = TRUE8;
|
|
|
|
// Hey hey we are scrolling to the left even though pressed RIGHT
|
|
m_nScrollDirection = ICON_MENU_SCROLL_LEFT;
|
|
}
|
|
}
|
|
|
|
// Release the keylock if it is on and none of the keys that caused it to be set are still being pressed.
|
|
if (m_nKeyLock && !sKeyboardState.IsButtonSet(__INVENTORY) && !sKeyboardState.IsButtonSet(__INTERACT)) {
|
|
m_nKeyLock = FALSE8;
|
|
}
|
|
|
|
// update last press
|
|
// only update if we are coming back, so as not to do the
|
|
// muck up first time you do remora after inventory
|
|
if (nRetVal) {
|
|
lastInventoryPress = inventoryPress;
|
|
}
|
|
|
|
// Return a value to indicate if this function should be called again next cycle.
|
|
return (nRetVal);
|
|
}
|
|
|
|
void _icon_menu::CycleHoldingLogic() {
|
|
// Check if there is a current interact object.
|
|
if (!MS->player.Fetch_player_interact_status()) {
|
|
// No interact object, so drop whatever we're holding.
|
|
ClearSelection();
|
|
}
|
|
}
|
|
|
|
void _icon_menu::CycleAddingLogic() {
|
|
// Increment the flash counter. If not a state toggle point, simply return.
|
|
if (m_nAddedFlashCount++ < ICON_MENU_ADDED_FLASHRATE)
|
|
return;
|
|
|
|
// Right, we are toggling the state of the flashing icons. First reset the counter.
|
|
m_nAddedFlashCount = 0;
|
|
|
|
// Behaviour now depends on whether the icon is currently being displayed ot not.
|
|
if (m_nAddedSymbol == 0) {
|
|
// Symbol is currently off so we are turning it on. We need to know whether to
|
|
// flash a medipack symbol or an ammo clip symbol.
|
|
if (m_nAddedMedipacks > 0) {
|
|
// Turning on a medipack symbol.
|
|
m_nAddedSymbol = 1;
|
|
|
|
// Play a sound to go with it.
|
|
RegisterSoundSpecial(defaultAddingMediSfx, addingMediDesc, 127, 0);
|
|
} else if (m_nAddedClips > 0) {
|
|
// Turning on a clips symbol.
|
|
m_nAddedSymbol = 2;
|
|
|
|
// Play a sound to go with it.
|
|
RegisterSoundSpecial(defaultAddingClipSfx, addingClipDesc, 127, 0);
|
|
} else if (m_bEmailArrived) {
|
|
// Turning on an email-arrived symbol.
|
|
m_nAddedSymbol = 3;
|
|
|
|
// Play a sound to go with it.
|
|
RegisterSoundSpecial(defaultEmailSfx, emailDesc, 127, 0);
|
|
}
|
|
} else {
|
|
// See which symbol is active.
|
|
switch (m_nAddedSymbol) {
|
|
case 1:
|
|
// Medipack symbol is currently being displayed. Turn it off.
|
|
--m_nAddedMedipacks;
|
|
m_nAddedSymbol = 0;
|
|
break;
|
|
|
|
case 2:
|
|
// Clips symbol is currently being displayed. Turn it off.
|
|
--m_nAddedClips;
|
|
m_nAddedSymbol = 0;
|
|
break;
|
|
|
|
default:
|
|
// This is a funny one. First time in here will be because the symbol is 3, which
|
|
// means an email-waiting symbol is being displayed. To turn it off, we don't set
|
|
// it to zero, however; instead we increment it, and then we keep incrementing it
|
|
// until we hit the count that controls how long the symbol should be off before it
|
|
// is flashed again.
|
|
if (++m_nAddedSymbol == ICON_MENU_EMAIL_FLASHRATE)
|
|
m_nAddedSymbol = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _icon_menu::PreloadIcon(const char *pcIconPath, const char *pcIconName) {
|
|
uint32 nFullIconNameHash;
|
|
|
|
// Make the full URL for the icon.
|
|
char pcFullIconName[MAXLEN_URL];
|
|
Common::sprintf_s(pcFullIconName, "%s%s.%s", pcIconPath, pcIconName, PX_BITMAP_EXT);
|
|
|
|
// Open the icon resource.
|
|
nFullIconNameHash = NULL_HASH;
|
|
rs_icons->Res_open(pcFullIconName, nFullIconNameHash, m_pcIconCluster, m_nIconClusterHash);
|
|
}
|
|
|
|
const char *_icon_menu::GetLastSelection() {
|
|
// Only return a selection if one has been made.
|
|
if (m_bValidSelection) {
|
|
if (m_pIconList->GetIconCount() > 0)
|
|
return (m_pIconList->GetIcon(m_nLastSelection));
|
|
else
|
|
return (nullptr);
|
|
} else {
|
|
return (nullptr);
|
|
}
|
|
}
|
|
|
|
uint32 _icon_menu::GetLastSelectionHash() const {
|
|
// Only return a selection if one has been made.
|
|
if (m_bValidSelection) {
|
|
if (m_pIconList->GetIconCount() > 0)
|
|
return (m_pIconList->GetIconHash(m_nLastSelection));
|
|
else
|
|
return (NULL_HASH);
|
|
} else {
|
|
return (NULL_HASH);
|
|
}
|
|
}
|
|
|
|
void _icon_menu::CloseDownIconMenu() {
|
|
// The Remora has to call this function when it quits, to make sure the icon menu disappears with it, but
|
|
// it is up to the script writer to make sure that the Remora has an icon menu displayed; therefore, there is
|
|
// the possibility that the Remora will quit and try to call this function when no icon menu is being
|
|
// displayed. We have to check for this here.
|
|
if (m_eIconMenuGameState == INACTIVE)
|
|
return;
|
|
|
|
// Menu is active, so close it down.
|
|
CloseDownIconMenuDisplay();
|
|
m_eIconMenuGameState = INACTIVE;
|
|
}
|
|
|
|
bool8 _icon_menu::IsAdding() const {
|
|
if ((m_nAddedMedipacks > 0) || (m_nAddedClips > 0) || m_bEmailArrived)
|
|
return (TRUE8);
|
|
else
|
|
return (FALSE8);
|
|
}
|
|
|
|
#define ICON_MENU_SCROLLCYCLES_INCREMENT (ICON_X_SIZE / 4)
|
|
#define ICON_MENU_SCROLLCYCLES_MAX ICON_X_SIZE
|
|
|
|
// Scroll the icons smoothly left or right
|
|
// This returns the x-position to start drawing the icons from (nX)
|
|
// it also sets the first icon to start drawing (nIconIndex)
|
|
int32 _icon_menu::GetScrollingPosition(const int32 nInputX, uint32 &nIconIndex) {
|
|
int32 nX = nInputX;
|
|
|
|
// OK are we scrolling
|
|
if (m_nScrollDirection != ICON_MENU_SCROLL_NONE) {
|
|
if (m_nScrollCycles >= ICON_MENU_SCROLLCYCLES_MAX) {
|
|
m_nScrollCycles = 0;
|
|
m_nScrollDirection = ICON_MENU_SCROLL_NONE;
|
|
m_nLastIconIndex = (uint8)nIconIndex;
|
|
} else {
|
|
if (m_nScrollDirection == ICON_MENU_SCROLL_RIGHT) {
|
|
// scroll right
|
|
nX += m_nScrollCycles;
|
|
nX -= ICON_X_SIZE;
|
|
} else {
|
|
// scroll left : keep old icon index
|
|
nX -= m_nScrollCycles;
|
|
nIconIndex = m_nLastIconIndex;
|
|
}
|
|
|
|
m_nScrollCycles += ICON_MENU_SCROLLCYCLES_INCREMENT;
|
|
}
|
|
}
|
|
|
|
return nX;
|
|
}
|
|
|
|
} // End of namespace ICB
|