mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-05 00:36:57 +00:00
1113 lines
35 KiB
C++
1113 lines
35 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/common/px_linkeddatafile.h"
|
|
#include "engines/icb/remora.h"
|
|
#include "engines/icb/line_of_sight.h"
|
|
#include "engines/icb/sound.h"
|
|
#include "engines/icb/global_switches.h"
|
|
#include "engines/icb/custom_logics.h"
|
|
#include "engines/icb/mission.h"
|
|
|
|
#include "common/stream.h"
|
|
|
|
namespace ICB {
|
|
|
|
_remora::_remora() {
|
|
m_eGameState = INACTIVE;
|
|
m_eCurrentMode = MOTION_SCAN;
|
|
m_eLastMode = MOTION_SCAN;
|
|
m_bModeChanged = FALSE8;
|
|
m_eModeOverride = NO_OVERRIDE;
|
|
m_nNextAvailableRow = 0;
|
|
m_nFirstLineToDraw = REMORA_FIRST_SCROLLING_LINE;
|
|
m_bScrollingRequired = FALSE8;
|
|
m_bTextPictureLoaded = FALSE8;
|
|
m_bScrolling = FALSE8;
|
|
m_nStartYPixelOffset = 0;
|
|
m_nCharacterHeight = 0;
|
|
m_bFlashingTextVisible = FALSE8;
|
|
m_nFlashCounter = 0;
|
|
m_bMainHeadingSet = FALSE8;
|
|
m_nCurrentPalette = 0;
|
|
m_pDisplayBuffer = nullptr;
|
|
|
|
// Set initial zoom range and an initial zoom.
|
|
m_nMinZoom = REMORA_SCAN_ZOOM_HARD_LOWER;
|
|
m_nMaxZoom = REMORA_SCAN_ZOOM_HARD_UPPER;
|
|
m_nCurrentZoom = REMORA_SCAN_START_ZOOM;
|
|
|
|
// Name of the cluster which holds remora graphics.
|
|
Common::strcpy_s(m_pcRemoraCluster, REMORA_CLUSTER_PATH);
|
|
m_nScanPan = 0;
|
|
|
|
// Make the hash name of the remora graphics cluster.
|
|
m_nRemoraClusterHash = EngineHashString(m_pcRemoraCluster);
|
|
|
|
// No progress bar.
|
|
m_nProgressBarValue = -1;
|
|
}
|
|
|
|
void _remora::InitialiseRemora() {
|
|
// Initialise the mode control variables.
|
|
m_eGameState = INACTIVE;
|
|
m_eCurrentMode = MOTION_SCAN;
|
|
m_eLastMode = MOTION_SCAN;
|
|
m_eModeOverride = NO_OVERRIDE;
|
|
m_bModeChanged = FALSE8;
|
|
|
|
// Clear any mega speech (there shouldn't be any though).
|
|
m_pcSpeechText = nullptr;
|
|
m_nSpeechTimer = 0;
|
|
|
|
// Initially, the zoom is set at 1X and cannot be moved. This might well change.
|
|
m_nMinZoom = REMORA_SCAN_ZOOM_HARD_LOWER;
|
|
m_nMaxZoom = REMORA_SCAN_ZOOM_HARD_UPPER;
|
|
m_nCurrentZoom = REMORA_SCAN_START_ZOOM;
|
|
|
|
// Make sure there is no outstanding email.
|
|
memset(m_pcEmailID, 0, (REMORA_MAXLEN_EMAIL_ID_STRING + 1) * sizeof(char));
|
|
|
|
// Text system initialisation.
|
|
m_nNextAvailableRow = 0;
|
|
m_nFirstLineToDraw = REMORA_FIRST_SCROLLING_LINE;
|
|
m_bScrollingRequired = FALSE8;
|
|
m_bTextPictureLoaded = FALSE8;
|
|
m_nScreenFlashCount = 0;
|
|
m_bScrolling = FALSE8;
|
|
m_nStartYPixelOffset = 0;
|
|
m_nCharacterHeight = 0;
|
|
m_bFlashingTextVisible = FALSE8;
|
|
m_nFlashCounter = 0;
|
|
m_bMainHeadingSet = FALSE8;
|
|
|
|
// Reset any floor ranges that may have been set.
|
|
m_nNumFloorRangesSet = 0;
|
|
m_nNumCurrentFloorRanges = 0;
|
|
|
|
// No progress bar.
|
|
m_nProgressBarValue = -1;
|
|
|
|
// Now do any platform-specific initialisation.
|
|
DoPlatformSpecificInitialisation();
|
|
}
|
|
|
|
void _remora::DeactivateRemora(bool8 bForceShutdown) {
|
|
// In order to stop Remora scripts dropping out during pauses and speech, we enforce
|
|
// the rule here that the Remora will not quit unless it is at a point where it is
|
|
// waiting for user-input - i.e. the icon menu is active.
|
|
if (bForceShutdown || g_oIconMenu->IsActive()) {
|
|
// Play the Remora-deactivate sound.
|
|
RegisterSoundSpecial(deactivateRemoraSfx, deactivateRemoraDesc, 127, 0);
|
|
|
|
m_eGameState = SWITCHING_OFF;
|
|
ReleaseTextFormattingMemory();
|
|
}
|
|
}
|
|
|
|
void _remora::SetMode(RemoraMode eMode) {
|
|
// Ignore the function call if the Remora is not active.
|
|
if (m_eGameState == INACTIVE)
|
|
return;
|
|
|
|
// If we are setting a new mode, we need to flag the fact to make sure the current bit gets
|
|
// closed down properly.
|
|
if (m_eCurrentMode != eMode)
|
|
m_bModeChanged = TRUE8;
|
|
|
|
// Clear text in case script writers are jumping into a non-text mode like the scan.
|
|
ClearAllText();
|
|
|
|
// And set the new mode.
|
|
m_eLastMode = m_eCurrentMode;
|
|
m_eCurrentMode = eMode;
|
|
}
|
|
|
|
void _remora::SetDefaultOrOverrideMode() {
|
|
// Check if the override is set.
|
|
if (m_eModeOverride != NO_OVERRIDE) {
|
|
// There is an override set, so use it.
|
|
SetMode(m_eModeOverride);
|
|
m_eModeOverride = NO_OVERRIDE;
|
|
} else {
|
|
// No, there isn't one set, so just use the default.
|
|
SetMode(REMORA_DEFAULT_MODE);
|
|
}
|
|
}
|
|
|
|
void _remora::DisplayCharacterSpeech(uint32 nHash) {
|
|
// No character speech is displayed unless sub_titles are turned on
|
|
if (g_px->on_screen_text == TRUE8) {
|
|
const char *pcText;
|
|
|
|
// Find the text in the resources.
|
|
pcText = g_oRemora->LocateTextFromReference(nHash);
|
|
|
|
// Check we have a valid pointer.
|
|
if (!pcText)
|
|
Fatal_error("_remora::DisplayCharacterSpeech() failed to find text for hash %x", nHash);
|
|
|
|
// Text must begin with an asterisk, which we don't display.
|
|
if (pcText[0] != TS_SPOKEN_LINE)
|
|
Fatal_error("Text [%s] not marked for actors in _remora::DisplayCharacterSpeech()", pcText);
|
|
|
|
// Put the text in the buffer.
|
|
m_pcSpeechText = &pcText[1];
|
|
} else {
|
|
m_pcSpeechText = nullptr;
|
|
}
|
|
|
|
// Initialise the counter for how int32 it will be displayed.
|
|
m_nSpeechTimer = SayLineOfSpeech(nHash);
|
|
}
|
|
|
|
void _remora::SetCurrentZoom(uint32 nZoom) {
|
|
// The zoom gets clipped at the current limits.
|
|
if (nZoom > m_nMaxZoom)
|
|
m_nCurrentZoom = m_nMaxZoom;
|
|
else if (nZoom < m_nMinZoom)
|
|
m_nCurrentZoom = m_nMinZoom;
|
|
else
|
|
m_nCurrentZoom = nZoom;
|
|
}
|
|
|
|
bool8 _remora::IsThisEmailWaiting(const char *pcEmailID) const {
|
|
if ((pcEmailID == nullptr) || (strlen(m_pcEmailID) == 0))
|
|
return (FALSE8);
|
|
|
|
if (strcmp(pcEmailID, m_pcEmailID))
|
|
return (FALSE8);
|
|
else
|
|
return (TRUE8);
|
|
}
|
|
|
|
bool8 _remora::EMPEffect() {
|
|
if (m_nScreenFlashCount == 0) {
|
|
m_nScreenFlashCount = REMORA_FLASH_EFFECT_LENGTH;
|
|
return (TRUE8);
|
|
} else {
|
|
--m_nScreenFlashCount;
|
|
|
|
if (m_nScreenFlashCount == 0)
|
|
return (FALSE8);
|
|
else
|
|
return (TRUE8);
|
|
}
|
|
}
|
|
|
|
void _remora::CycleRemoraLogic(const _input &sKeyboardState) {
|
|
_logic *pPlayerObject;
|
|
uint32 nRemoraID;
|
|
|
|
// Count down the speech-display counter.
|
|
m_nSpeechTimer = (m_nSpeechTimer > 0) ? m_nSpeechTimer - 1 : 0;
|
|
|
|
// Work the counter that controls the flashing of email waiting symbols.
|
|
++m_nFlashCounter;
|
|
|
|
if (m_nFlashCounter == REMORA_TEXT_FLASH_RATE) {
|
|
// Reset the counter and toggle the visibility state of the text.
|
|
m_nFlashCounter = 0;
|
|
m_bFlashingTextVisible = (bool8)!m_bFlashingTextVisible;
|
|
}
|
|
|
|
// If text is scrolling, process the scroll.
|
|
if (m_bScrolling) {
|
|
int32 scrollAmount = (256 * m_nCharacterHeight) / REMORA_SCROLL_CYCLES;
|
|
|
|
// See which way we're scrolling.
|
|
if (m_eTextScroll == SCROLL_UP) {
|
|
m_nStartYPixelOffset -= scrollAmount;
|
|
|
|
if (m_nStartYPixelOffset <= -256 * m_nCharacterHeight) {
|
|
m_nStartYPixelOffset += 256 * m_nCharacterHeight;
|
|
m_bScrolling = FALSE8;
|
|
m_eTextScroll = SCROLL_NONE;
|
|
++m_nFirstLineToDraw;
|
|
}
|
|
} else {
|
|
m_nStartYPixelOffset += scrollAmount;
|
|
|
|
if (m_nStartYPixelOffset >= 256 * m_nCharacterHeight) {
|
|
m_nStartYPixelOffset -= 256 * m_nCharacterHeight;
|
|
m_bScrolling = FALSE8;
|
|
m_eTextScroll = SCROLL_NONE;
|
|
--m_nFirstLineToDraw;
|
|
}
|
|
}
|
|
}
|
|
|
|
// This function works a bit like a Windows message handler in that is has to be reentrant. That's why it has
|
|
// initialisation, normal operation, and close-down sections.
|
|
switch (m_eGameState) {
|
|
case SWITCHING_ON:
|
|
// This creates sprites etc., ready to be blitted to the working buffer.
|
|
SetUpRemora();
|
|
|
|
// This initialises the Remora's menu control variables.
|
|
InitialiseMenuControlVariables();
|
|
|
|
// Now run any initialisation code for each of the modes.
|
|
switch (m_eCurrentMode) {
|
|
case MOTION_SCAN:
|
|
SetUpWideScan();
|
|
break;
|
|
|
|
case INFRA_RED_LINK:
|
|
break;
|
|
|
|
case DATABASE:
|
|
break;
|
|
|
|
case COMMUNICATIONS:
|
|
break;
|
|
|
|
case M08_LOCK_CONTROL:
|
|
SetUpM08LockControl();
|
|
break;
|
|
|
|
default:
|
|
// This should never happen.
|
|
Fatal_error("Invalid Remora mode %d while initialising", m_eCurrentMode);
|
|
|
|
} // end switch
|
|
|
|
// Remora is now active.
|
|
m_eGameState = ACTIVE;
|
|
|
|
break;
|
|
|
|
case ACTIVE:
|
|
// If there has been a mode change, we need to close down the old mode and start up the new one.
|
|
if (m_bModeChanged) {
|
|
// We're handling the mode change, so clear the trigger nFlag.
|
|
m_bModeChanged = FALSE8;
|
|
|
|
// Do the close down for the old mode.
|
|
switch (m_eLastMode) {
|
|
case MOTION_SCAN:
|
|
break;
|
|
|
|
case INFRA_RED_LINK:
|
|
break;
|
|
|
|
case DATABASE:
|
|
break;
|
|
|
|
case COMMUNICATIONS:
|
|
break;
|
|
|
|
case MAP:
|
|
break;
|
|
|
|
case M08_LOCK_CONTROL:
|
|
break;
|
|
|
|
default:
|
|
// This should never happen.
|
|
Fatal_error("Invalid Remora mode %d switching Remora modes", m_eCurrentMode);
|
|
}
|
|
|
|
// Do the set-up for the new mode.
|
|
switch (m_eCurrentMode) {
|
|
case MOTION_SCAN:
|
|
SetUpWideScan();
|
|
break;
|
|
|
|
case INFRA_RED_LINK:
|
|
break;
|
|
|
|
case DATABASE:
|
|
break;
|
|
|
|
case COMMUNICATIONS:
|
|
break;
|
|
|
|
case M08_LOCK_CONTROL:
|
|
SetUpM08LockControl();
|
|
break;
|
|
|
|
default:
|
|
// This should never happen.
|
|
Fatal_error("Invalid Remora mode %d switching to new Remora mode.", m_eCurrentMode);
|
|
}
|
|
} else {
|
|
// There was no mode change, so just run any logic associated with the current mode.
|
|
switch (m_eCurrentMode) {
|
|
case MOTION_SCAN:
|
|
|
|
// Update player position (x and z only).
|
|
pPlayerObject = MS->logic_structs[MS->player.Fetch_player_id()];
|
|
m_nPlayerX = (int32)pPlayerObject->mega->actor_xyz.x;
|
|
m_nPlayerZ = (int32)pPlayerObject->mega->actor_xyz.z;
|
|
|
|
// Check if the local pan has been updated, which means the Remora is being 'swung'
|
|
// from side to side.
|
|
if (sKeyboardState.IsButtonSet(__SIDESTEP)) {
|
|
if (sKeyboardState.turn == __LEFT)
|
|
m_fPlayerPan = remainder(m_fPlayerPan - REMORA_SCAN_PAN_STEP, FULL_TURN, HALF_TURN);
|
|
else if (sKeyboardState.turn == __RIGHT)
|
|
m_fPlayerPan = remainder(m_fPlayerPan + REMORA_SCAN_PAN_STEP, FULL_TURN, HALF_TURN);
|
|
} else {
|
|
ProcessUpDownZoomKeys(sKeyboardState);
|
|
}
|
|
|
|
// Check for the palette-change key.
|
|
if (sKeyboardState.IsButtonSet(__ATTACK))
|
|
m_nCurrentPalette = (uint8)(((int32)m_nCurrentPalette + 1) % REMORA_NUM_COLOUR_SCHEMES);
|
|
|
|
// Update the beam position.
|
|
m_nScanPan = (m_nScanPan + REMORA_SCAN_SPEED) % 360;
|
|
|
|
break;
|
|
|
|
case INFRA_RED_LINK:
|
|
ProcessUpDownTextKeys(sKeyboardState);
|
|
break;
|
|
|
|
case DATABASE:
|
|
ProcessUpDownTextKeys(sKeyboardState);
|
|
break;
|
|
|
|
case COMMUNICATIONS:
|
|
break;
|
|
|
|
case M08_LOCK_CONTROL:
|
|
break;
|
|
|
|
default:
|
|
// This should never happen.
|
|
Fatal_error("Invalid Remora mode %d while Remora active", m_eCurrentMode);
|
|
|
|
} // end switch
|
|
|
|
} // end if
|
|
|
|
// Fire button quits the speech timer.
|
|
if (sKeyboardState.IsButtonSet(__ATTACK))
|
|
m_nSpeechTimer = 0;
|
|
|
|
break;
|
|
|
|
case SWITCHING_OFF:
|
|
// Remora is closing down. First close down according to which mode it is in.
|
|
switch (m_eCurrentMode) {
|
|
case MOTION_SCAN:
|
|
break;
|
|
|
|
case INFRA_RED_LINK:
|
|
break;
|
|
|
|
case DATABASE:
|
|
break;
|
|
|
|
case COMMUNICATIONS:
|
|
break;
|
|
|
|
case MAP:
|
|
break;
|
|
|
|
case M08_LOCK_CONTROL:
|
|
break;
|
|
|
|
default:
|
|
// This should never happen.
|
|
Fatal_error("Invalid Remora mode %d switching Remora off", m_eCurrentMode);
|
|
|
|
} // end switch
|
|
|
|
// Close down the icon menu.
|
|
g_oIconMenu->CloseDownIconMenu();
|
|
|
|
// Now close down the base graphic.
|
|
CloseDownRemora();
|
|
|
|
// Remora is now inactive.
|
|
m_eGameState = INACTIVE;
|
|
|
|
nRemoraID = LinkedDataObject::Fetch_item_number_by_name(MS->objects, REMORA_NAME);
|
|
|
|
if (nRemoraID == PX_LINKED_DATA_FILE_ERROR)
|
|
Fatal_error("No logic object for Remora in _remora::CycleRemoraLogic()");
|
|
|
|
g_oEventManager->PostNamedEventToObject(EVENT_LOGIC_RERUN, nRemoraID, nRemoraID);
|
|
|
|
break;
|
|
|
|
default:
|
|
// This should never happen.
|
|
Fatal_error("Invalid Remora state");
|
|
}
|
|
}
|
|
|
|
void _remora::SetText(const char *pcText, uint8 nAttribute, uint8 nIndent, _pin_position ePosition) {
|
|
uint32 i;
|
|
_TSparams *psTextParameters;
|
|
const char *pcParsePos;
|
|
uint32 nNumRemoraFormattedLines;
|
|
uint32 nLineLength;
|
|
bool8 bMainHeading;
|
|
uint32 nEffectiveWidth;
|
|
|
|
// Ignore the function call if the Remora is not active.
|
|
if (m_eGameState == INACTIVE)
|
|
return;
|
|
|
|
// If this is a blank line, deal with it now.
|
|
if (nAttribute == 0) {
|
|
// Check we haven't run out of lines.
|
|
if (m_nNextAvailableRow == REMORA_TEXT_BUFFER_ROWS)
|
|
Fatal_error("Run out of adding blank line in Remora text - limit %d", REMORA_TEXT_BUFFER_ROWS);
|
|
|
|
// Insert single blank line.
|
|
m_pDisplayBuffer[m_nNextAvailableRow++].s_nAttribute = 0;
|
|
|
|
// Nothing more to do with blank lines.
|
|
return;
|
|
}
|
|
|
|
// We have sub-headings and main headings, which share a text colour (and as a bad left-over from the old code,
|
|
// also share a text attribute value). Main headings are centred though, so we can easily differentiate them.
|
|
if (((nAttribute & REMORA_TEXT_HEADING) != 0) && (ePosition == PIN_AT_CENTRE))
|
|
bMainHeading = TRUE8;
|
|
else
|
|
bMainHeading = FALSE8;
|
|
|
|
// Work out the effective print width accounting for tabs.The X-coordinate we pin the text to depends on whether or not the text is centred or not.
|
|
if (ePosition == PIN_AT_CENTRE) {
|
|
nEffectiveWidth = REMORA_DISPLAY_WIDTH;
|
|
} else {
|
|
// Left-justification must also handle tabs.
|
|
nEffectiveWidth = REMORA_DISPLAY_WIDTH - nIndent * (REMORA_TEXT_TAB_ONE);
|
|
|
|
// Check we haven't tabbed down to a too-small column of text.
|
|
if (nEffectiveWidth < 50)
|
|
Fatal_error("Too many tabs in [%s] in _remora::SetText()", pcText);
|
|
}
|
|
|
|
// First we need to ask the text sprite drawer what the text will format like, so we can work out if it will fit.
|
|
MS->Format_remora_text(pcText, REMORA_ROW_SPACING, REMORA_CHARACTER_SPACING, nEffectiveWidth);
|
|
nNumRemoraFormattedLines = MS->text_bloc->GetLineInfo()->noOfLines;
|
|
|
|
// The Format_remora_text() function sets up the parameter block for the text sprite. Since this block
|
|
// has to be set up to get the height of a character and since a heading has to be set before anything
|
|
// else, this is a convenient place for the Remora to initialise its character-height variable.
|
|
if (m_nCharacterHeight == 0) {
|
|
psTextParameters = MS->text_bloc->GetParams();
|
|
m_nCharacterHeight = (uint8)MS->text_bloc->CharHeight(psTextParameters->fontResource, psTextParameters->fontResource_hash);
|
|
|
|
// To have ceiling based rounding
|
|
m_nPictureHeightCorrection = (uint8)(m_nCharacterHeight - 1);
|
|
}
|
|
|
|
// Check if we are setting the main heading for the screen.
|
|
if (bMainHeading) {
|
|
// This is a heading, so we are starting the display afresh.
|
|
m_nNextAvailableRow = 0;
|
|
|
|
// First scrolling line to draw is one past the heading.
|
|
m_nFirstLineToDraw = REMORA_FIRST_SCROLLING_LINE;
|
|
|
|
// We now have a heading.
|
|
m_bMainHeadingSet = TRUE8;
|
|
} else {
|
|
// Must have set a heading for the screen before any paragraph text can be set.
|
|
if (m_nNextAvailableRow == 0)
|
|
Fatal_error("You cannot set text on the Remora screen until a heading has been set for the screen.");
|
|
}
|
|
|
|
// Copy the text into the buffer.
|
|
pcParsePos = pcText;
|
|
|
|
for (i = 0; i < nNumRemoraFormattedLines; ++i) {
|
|
// Get length of line.
|
|
nLineLength = MS->text_bloc->GetLineInfo()->line[i].length;
|
|
|
|
// Copy one line.
|
|
strncpy(m_pDisplayBuffer[m_nNextAvailableRow].s_pcText, const_cast<char *>(pcParsePos), nLineLength);
|
|
|
|
// Make sure we haven't lost the terminator (but I'm sure he'll be back, if we have).
|
|
m_pDisplayBuffer[m_nNextAvailableRow].s_pcText[nLineLength] = '\0';
|
|
|
|
// Fill in the attributes for the line.
|
|
m_pDisplayBuffer[m_nNextAvailableRow].s_uPos.s_ePinPosition = ePosition;
|
|
m_pDisplayBuffer[m_nNextAvailableRow].s_nAttribute = nAttribute;
|
|
m_pDisplayBuffer[m_nNextAvailableRow].s_uXY.s_nIndent = nIndent;
|
|
|
|
// Move the line count on 1.
|
|
++m_nNextAvailableRow;
|
|
|
|
// And move the parse pointer past the line we have just dealt with.
|
|
pcParsePos += nLineLength;
|
|
|
|
// And skip any spaces.
|
|
while (*pcParsePos == ' ')
|
|
++pcParsePos;
|
|
}
|
|
|
|
// Check if the scroll controls need activating.
|
|
if (m_nNextAvailableRow > REMORA_DISPLAYED_TEXT_ROWS)
|
|
m_bScrollingRequired = TRUE8;
|
|
}
|
|
|
|
void _remora::SetupPicture(uint32 nXPixelOffset, const char *pcPictureName) {
|
|
uint32 i;
|
|
uint32 nPictureHeight, nPictureWidth;
|
|
uint32 nNumPictureRows;
|
|
|
|
const char *pcFullPictureNameAndPath;
|
|
|
|
// Ignore the function call if the Remora is not active.
|
|
if (m_eGameState == INACTIVE)
|
|
return;
|
|
|
|
// Check there is not a picture loaded already.
|
|
if (m_bTextPictureLoaded)
|
|
return;
|
|
|
|
// Flag the fact that there is now a picture loaded.
|
|
m_bTextPictureLoaded = TRUE8;
|
|
|
|
// Must have set a heading for the screen before anything else can be set.
|
|
if (m_nNextAvailableRow == 0)
|
|
Fatal_error("You cannot put a picture in the Remora until a heading has been set for the screen.");
|
|
|
|
// Load the picture.
|
|
pcFullPictureNameAndPath = MakeRemoraGraphicsPath(pcPictureName);
|
|
m_oTextPicture.InitialiseFromBitmapName(pcFullPictureNameAndPath, m_pcRemoraCluster, m_nRemoraClusterHash);
|
|
|
|
// Get the size of the image.
|
|
nPictureHeight = m_oTextPicture.GetHeight();
|
|
nPictureWidth = m_oTextPicture.GetWidth();
|
|
|
|
// Check it isn't too big.
|
|
if ((nPictureWidth > REMORA_MAX_PICTURE_WIDTH) || (nPictureHeight > REMORA_MAX_PICTURE_HEIGHT))
|
|
Fatal_error("Picture [%s] is %d wide X %d high (maximum is %d X %d)", pcPictureName, nPictureWidth, nPictureHeight, REMORA_MAX_PICTURE_WIDTH,
|
|
REMORA_MAX_PICTURE_HEIGHT);
|
|
|
|
// Need to know how many rows it occupies, so we can leave a gap in the text.
|
|
nNumPictureRows = (nPictureHeight + m_nPictureHeightCorrection) / m_nCharacterHeight;
|
|
|
|
// Check it fits in the virtual screen buffer.
|
|
if (m_nNextAvailableRow + nNumPictureRows >= REMORA_TEXT_BUFFER_ROWS)
|
|
Fatal_error("Picture [%s] at row %d will go over the end of the Remora's buffer", pcPictureName, m_nNextAvailableRow);
|
|
|
|
for (i = 0; i < nNumPictureRows; ++i) {
|
|
// Fill in the attributes for the line.
|
|
m_pDisplayBuffer[m_nNextAvailableRow].s_uPos.s_nXOffset = nXPixelOffset;
|
|
m_pDisplayBuffer[m_nNextAvailableRow].s_nAttribute = REMORA_TEXT_PICTURE;
|
|
|
|
// This is a count maintained in the rows occupied by the picture of how far into the
|
|
// picture we currently are. Makes working out a Y-draw-height easy later.
|
|
m_pDisplayBuffer[m_nNextAvailableRow].s_uXY.s_nPictureRow = (uint8)i;
|
|
|
|
// Move the line count on 1.
|
|
++m_nNextAvailableRow;
|
|
}
|
|
|
|
// Check if the scroll controls need activating.
|
|
if (m_nNextAvailableRow > REMORA_DISPLAYED_TEXT_ROWS)
|
|
m_bScrollingRequired = TRUE8;
|
|
}
|
|
|
|
void _remora::AddFloorRange(uint32 nLower, uint32 nUpper) {
|
|
LinkedDataFile *pSlices;
|
|
|
|
// Check that top value is within the available slices (bottom one must be because it is unsigned). First,
|
|
// get the pointer to the slices (this will already have been loaded by the line-of-sight engine).
|
|
pSlices = g_oLineOfSight->GetSlicesPointer();
|
|
|
|
if (nUpper >= LinkedDataObject::Fetch_number_of_items(pSlices))
|
|
nUpper = LinkedDataObject::Fetch_number_of_items(pSlices) - 1;
|
|
|
|
// Upper must be greater than lower, or it isn't a range.
|
|
if (nUpper <= nLower)
|
|
return;
|
|
|
|
// And there is a fixed maximum range that can be accommodated.
|
|
if (((nUpper - nLower) + 1) > REMORA_MAX_INCLUDED_SLICES)
|
|
Fatal_error("Range (%d-%d) greater than maximum %d in _remora::AddFloorRange()", nLower, nUpper, REMORA_MAX_INCLUDED_SLICES);
|
|
|
|
// Okay, it's a valid range now, so let's add it.
|
|
m_pFloorRanges[m_nNumFloorRangesSet].s_nLower = (uint8)nLower;
|
|
m_pFloorRanges[m_nNumFloorRangesSet].s_nUpper = (uint8)nUpper;
|
|
|
|
// Update count of how many we have.
|
|
++m_nNumFloorRangesSet;
|
|
}
|
|
|
|
void _remora::Save(Common::WriteStream *stream) const {
|
|
// Save any outstanding email. Just write the whole string since it is small and there's only one.
|
|
stream->write(m_pcEmailID, sizeof(char) * (REMORA_MAXLEN_EMAIL_ID_STRING + 1));
|
|
}
|
|
|
|
void _remora::Restore(Common::SeekableReadStream *stream) {
|
|
// Save any outstanding email. Just write the whole string since it is small and there's only one.
|
|
if (stream->read(m_pcEmailID, sizeof(char) * (REMORA_MAXLEN_EMAIL_ID_STRING + 1)) != sizeof(char) * (REMORA_MAXLEN_EMAIL_ID_STRING + 1))
|
|
Fatal_error("Error restoring email ID string in _remora::Restore()");
|
|
|
|
// Inform the icon menu whether or not there is an email waiting now we have restored.
|
|
if (strlen(m_pcEmailID) > 0)
|
|
g_oIconMenu->SetEmailArrived();
|
|
else
|
|
g_oIconMenu->ClearEmailArrived();
|
|
}
|
|
|
|
void _remora::ProcessUpDownTextKeys(const _input &sKeyboardState) {
|
|
// If the text does not extend over the edge of the screen then there is nothing to do.
|
|
if (!m_bScrollingRequired)
|
|
return;
|
|
|
|
// Also do nothing if text is already in process of scrolling.
|
|
if (m_bScrolling)
|
|
return;
|
|
|
|
// Check for up and down keys.
|
|
if (sKeyboardState.momentum == __STILL) {
|
|
return;
|
|
} else if (sKeyboardState.momentum == __BACKWARD_1) {
|
|
// Moving down through the text, so text will scroll upwards on the screen. Check that
|
|
// we can still scroll in this direction.
|
|
if ((m_nFirstLineToDraw + REMORA_DISPLAYED_TEXT_ROWS) < m_nNextAvailableRow) {
|
|
m_nStartYPixelOffset = 0;
|
|
m_eTextScroll = SCROLL_UP;
|
|
m_bScrolling = TRUE8;
|
|
} else {
|
|
m_eTextScroll = SCROLL_NONE;
|
|
m_bScrolling = FALSE8;
|
|
}
|
|
} else {
|
|
// Moving up through the text, so text will scroll down on the screen. Check that we
|
|
// can still scroll in this direction.
|
|
if (m_nFirstLineToDraw > REMORA_FIRST_SCROLLING_LINE) {
|
|
m_nStartYPixelOffset = 0;
|
|
m_eTextScroll = SCROLL_DOWN;
|
|
m_bScrolling = TRUE8;
|
|
} else {
|
|
m_eTextScroll = SCROLL_NONE;
|
|
m_bScrolling = FALSE8;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _remora::ProcessUpDownZoomKeys(const _input &sKeyboardState) {
|
|
int32 nNewZoom;
|
|
|
|
// Check for up and down keys.
|
|
if (sKeyboardState.momentum == __STILL) {
|
|
return;
|
|
} else if (sKeyboardState.momentum == __BACKWARD_1) {
|
|
// Zooming out.
|
|
nNewZoom = m_nCurrentZoom - REMORA_SCAN_ZOOM_STEP;
|
|
} else {
|
|
// Zooming in.
|
|
nNewZoom = m_nCurrentZoom + REMORA_SCAN_ZOOM_STEP;
|
|
}
|
|
|
|
// Apply the new zoom value (this function keeps it range-capped to the current limits).
|
|
SetCurrentZoom(nNewZoom);
|
|
}
|
|
|
|
const char *_remora::LocateTextFromReference(uint32 nHashRef) {
|
|
const char *pcTextLine;
|
|
|
|
// Look for the reference.
|
|
pcTextLine = (const char *)LinkedDataObject::Try_fetch_item_by_hash(MS->text, nHashRef);
|
|
|
|
// If we found it, return it.
|
|
if (pcTextLine)
|
|
return (pcTextLine);
|
|
|
|
// Look in the global text file.
|
|
pcTextLine = (const char *)LinkedDataObject::Try_fetch_item_by_hash(global_text, nHashRef);
|
|
|
|
// Return the pointer regardless.
|
|
return (pcTextLine);
|
|
}
|
|
|
|
void _remora::DrawScreenText() {
|
|
int32 nStartXPixel, nStartYPixel;
|
|
int32 nVirtualRow, nScreenRow;
|
|
uint8 nRed, nGreen, nBlue;
|
|
uint32 nEffectiveWidth, nTabWidth;
|
|
_rs_params sParams;
|
|
uint32 nBaseY;
|
|
int32 nDisplayedTextRows;
|
|
|
|
// We always start drawing at row 0 on the screen.
|
|
nScreenRow = 0;
|
|
|
|
// The place we start taking stuff to draw depends on how far down the virtual buffer we are. If
|
|
// we are scrolling down then we start drawing one line early to make it look smooth.
|
|
switch (m_eTextScroll) {
|
|
case SCROLL_DOWN:
|
|
nVirtualRow = m_nFirstLineToDraw - 1;
|
|
nBaseY = REMORA_TEXT_TOP_MARGIN - m_nCharacterHeight;
|
|
nDisplayedTextRows = REMORA_DISPLAYED_TEXT_ROWS + 2;
|
|
break;
|
|
|
|
case SCROLL_UP:
|
|
nVirtualRow = m_nFirstLineToDraw;
|
|
nBaseY = REMORA_TEXT_TOP_MARGIN;
|
|
nDisplayedTextRows = REMORA_DISPLAYED_TEXT_ROWS + 2;
|
|
break;
|
|
|
|
default:
|
|
nVirtualRow = m_nFirstLineToDraw;
|
|
nBaseY = REMORA_TEXT_TOP_MARGIN;
|
|
nDisplayedTextRows = REMORA_DISPLAYED_TEXT_ROWS;
|
|
break;
|
|
}
|
|
|
|
// Loop for each line in view.
|
|
while ((nScreenRow < nDisplayedTextRows) && (nVirtualRow < m_nNextAvailableRow)) {
|
|
// Work out how far down the screen to start drawing this line
|
|
nStartYPixel = nBaseY + (nScreenRow * m_nCharacterHeight);
|
|
nStartYPixel += (m_nStartYPixelOffset / 256); // scaled down
|
|
|
|
// Check to see if it is a picture or text.
|
|
if (m_pDisplayBuffer[nVirtualRow].s_nAttribute & REMORA_TEXT_PICTURE) {
|
|
// We have a picture to display. If the picture goes off the top of the screen then we
|
|
// need to move the top edge of the picture to make it look like we are displaying the
|
|
// picture from part-way down.
|
|
nStartYPixel -= (m_nCharacterHeight * m_pDisplayBuffer[nVirtualRow].s_uXY.s_nPictureRow);
|
|
|
|
// Draw it.
|
|
sParams.bCentre = FALSE8;
|
|
sParams.bUpdate = FALSE8;
|
|
sParams.nW = 0;
|
|
sParams.nH = 0;
|
|
sParams.bAllFrames = TRUE8;
|
|
nStartXPixel = REMORA_TEXT_LEFT_MARGIN + m_pDisplayBuffer[nVirtualRow].s_uPos.s_nXOffset;
|
|
|
|
m_oTextPicture.DrawXYSprite(nStartXPixel + REMORA_SCREEN_ORIGIN_X, nStartYPixel + REMORA_SCREEN_ORIGIN_Y, &sParams);
|
|
|
|
// Picture gets drawn in one go, so we can simply skip forward past the whole thing now.
|
|
while (m_pDisplayBuffer[nVirtualRow].s_nAttribute & REMORA_TEXT_PICTURE) {
|
|
++nVirtualRow;
|
|
++nScreenRow;
|
|
}
|
|
} else {
|
|
// Displaying a line of text, not a picture. Check if it's just a blank line.
|
|
if (m_pDisplayBuffer[nVirtualRow].s_nAttribute == 0) {
|
|
++nVirtualRow;
|
|
++nScreenRow;
|
|
continue;
|
|
}
|
|
|
|
// Set the colour to draw this text in.
|
|
ColourToRGB(m_pDisplayBuffer[nVirtualRow].s_nAttribute, nRed, nGreen, nBlue);
|
|
SetTextColour(nRed, nGreen, nBlue);
|
|
|
|
// The X-coordinate we pin the text to depends on whether or not the text is centred or not.
|
|
if (m_pDisplayBuffer[nVirtualRow].s_uPos.s_ePinPosition == PIN_AT_CENTRE) {
|
|
nStartXPixel = REMORA_TEXT_CENTRE;
|
|
nEffectiveWidth = REMORA_DISPLAY_WIDTH;
|
|
} else {
|
|
// Left-justification must also handle tabs.
|
|
nTabWidth = m_pDisplayBuffer[nVirtualRow].s_uXY.s_nIndent * REMORA_TEXT_TAB_ONE;
|
|
nStartXPixel = REMORA_TEXT_LEFT_MARGIN + nTabWidth;
|
|
nEffectiveWidth = REMORA_DISPLAY_WIDTH - nTabWidth;
|
|
}
|
|
|
|
// Draw the line of text.
|
|
MS->Create_remora_text(nStartXPixel, nStartYPixel, m_pDisplayBuffer[nVirtualRow].s_pcText, 0, m_pDisplayBuffer[nVirtualRow].s_uPos.s_ePinPosition,
|
|
REMORA_ROW_SPACING, REMORA_CHARACTER_SPACING, nEffectiveWidth);
|
|
MS->Render_speech(MS->text_bloc);
|
|
MS->Kill_remora_text();
|
|
|
|
// Moved on on the screen and in the virtual buffer.
|
|
++nVirtualRow;
|
|
++nScreenRow;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _remora::DrawEmailWaiting() {
|
|
uint32 nHashRef;
|
|
const char *pcEmailWaitingText;
|
|
|
|
// Check if there is a message waiting and the flash counter is currently on.
|
|
if ((strlen(m_pcEmailID) > 0) && m_bFlashingTextVisible) {
|
|
// Find the text message to display.
|
|
nHashRef = HashString("email_waiting");
|
|
pcEmailWaitingText = LocateTextFromReference(nHashRef);
|
|
|
|
MS->Create_remora_text(REMORA_EMAIL_WAITING_X, REMORA_EMAIL_WAITING_Y, pcEmailWaitingText, 0, PIN_AT_TOP_LEFT, 0, 0, REMORA_DISPLAY_WIDTH);
|
|
MS->Render_speech(MS->text_bloc);
|
|
MS->Kill_remora_text();
|
|
}
|
|
}
|
|
|
|
void _remora::ClearAllText() {
|
|
// Ignore the function call if the Remora is not active.
|
|
if (m_eGameState == INACTIVE)
|
|
return;
|
|
|
|
// Reset the text control variables.
|
|
m_nNextAvailableRow = 0;
|
|
m_nFirstLineToDraw = 0;
|
|
|
|
m_bScrollingRequired = FALSE8;
|
|
m_bScrolling = FALSE8; // these three need resetting so when we go to a new page we don't try scrolling off screen
|
|
m_nStartYPixelOffset = 0;
|
|
m_eTextScroll = SCROLL_NONE;
|
|
|
|
m_bTextPictureLoaded = FALSE8;
|
|
m_bMainHeadingSet = FALSE8;
|
|
|
|
// These control the spoken text display.
|
|
m_pcSpeechText = nullptr;
|
|
m_nSpeechTimer = 0;
|
|
}
|
|
|
|
void _remora::DrawVoiceOverText() const {
|
|
// Here we draw the text that characters may say inside the Remora.
|
|
if (g_px->on_screen_text && (m_nSpeechTimer > 0) && (strlen(m_pcSpeechText) > 0)) {
|
|
// Yes we need to display speech text.
|
|
MS->Create_remora_text(REMORA_SPEECH_X_POSITION, REMORA_SPEECH_Y_POSITION, m_pcSpeechText, 0, PIN_AT_CENTRE, 0, 0, REMORA_DISPLAY_WIDTH);
|
|
|
|
MS->Render_speech(MS->text_bloc);
|
|
MS->Kill_remora_text();
|
|
}
|
|
}
|
|
|
|
void _remora::SetCommonActivateInfo(RemoraMode eMode) {
|
|
uint32 i, j;
|
|
_logic *pPlayerObject;
|
|
LinkedDataFile *pSlices;
|
|
BarrierSlice *pSlice;
|
|
int32 nSlice;
|
|
uint32 nNumSlices;
|
|
bool8 bInFloorRange;
|
|
|
|
// Set the mode flags.
|
|
m_eGameState = SWITCHING_ON;
|
|
m_eCurrentMode = eMode;
|
|
m_bModeChanged = FALSE8;
|
|
|
|
// Cancel the flash counter if it was left running last time.
|
|
m_nScreenFlashCount = 0;
|
|
|
|
// Get position of player. The scanner modes need this information.
|
|
pPlayerObject = MS->logic_structs[MS->player.Fetch_player_id()];
|
|
m_nPlayerY = (int32)pPlayerObject->mega->actor_xyz.y;
|
|
m_nPlayerX = (int32)pPlayerObject->mega->actor_xyz.x;
|
|
m_nPlayerZ = (int32)pPlayerObject->mega->actor_xyz.z;
|
|
|
|
// If we are in the special one-off M08 interface or the map mode, the pan is fixed, otherwise we
|
|
// get it from the player.
|
|
if ((m_eCurrentMode == M08_LOCK_CONTROL) || (m_eCurrentMode == MAP))
|
|
m_fPlayerPan = REAL_ZERO;
|
|
else
|
|
m_fPlayerPan = pPlayerObject->pan;
|
|
|
|
// Just knowing the y height of the player is now not enough for the scan modes because they may need to
|
|
// include floors and objects from different heights. Here we work out the slices and range of heights
|
|
// that need including in scan displays.
|
|
pSlices = g_oLineOfSight->GetSlicesPointer();
|
|
|
|
// Find out which slice we're in.
|
|
nNumSlices = LinkedDataObject::Fetch_number_of_items(pSlices);
|
|
nSlice = 0;
|
|
|
|
for (i = 0; i < nNumSlices; ++i) {
|
|
// Get the slice.
|
|
pSlice = (BarrierSlice *)LinkedDataObject::Fetch_item_by_number(pSlices, i);
|
|
|
|
// See if the player's feet are in this slice.
|
|
if ((m_nPlayerY >= pSlice->bottom) && (m_nPlayerY < pSlice->top))
|
|
nSlice = i;
|
|
}
|
|
|
|
// Right, we know which slice the player is in. Check to see if this is in one of the ranges.
|
|
bInFloorRange = FALSE8;
|
|
m_nNumCurrentFloorRanges = 0;
|
|
i = 0;
|
|
while (!bInFloorRange && (i < m_nNumFloorRangesSet)) {
|
|
if ((nSlice >= m_pFloorRanges[i].s_nLower) && (nSlice <= m_pFloorRanges[i].s_nUpper)) {
|
|
// Yes, the slice is contained in a range, so when we do a scan, we need to include everything
|
|
// in the range.
|
|
bInFloorRange = TRUE8;
|
|
|
|
for (j = m_pFloorRanges[i].s_nLower; j <= m_pFloorRanges[i].s_nUpper; ++j) {
|
|
m_pSlices[m_nNumCurrentFloorRanges] = (BarrierSlice *)LinkedDataObject::Fetch_item_by_number(pSlices, j);
|
|
m_pnSlices[m_nNumCurrentFloorRanges] = j;
|
|
++m_nNumCurrentFloorRanges;
|
|
}
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
// If we didn't set a floor range then we must set a single floor slice.
|
|
if (!bInFloorRange) {
|
|
// Only one slice required to be displayed.
|
|
m_pSlices[0] = (BarrierSlice *)LinkedDataObject::Fetch_item_by_number(pSlices, nSlice);
|
|
m_pnSlices[0] = nSlice;
|
|
m_nNumCurrentFloorRanges = 1;
|
|
}
|
|
|
|
// Set an absolute floor and ceiling.
|
|
m_nIncludedFloor = (int32)m_pSlices[0]->bottom;
|
|
m_nIncludedCeiling = (int32)m_pSlices[m_nNumCurrentFloorRanges - 1]->top;
|
|
|
|
// Clear the text buffer.
|
|
ClearAllText();
|
|
}
|
|
|
|
void _remora::AccessMenuLevelVariables(int32 *pnParams, MenuVariableAccessMode eRetrieve) {
|
|
uint32 i, j;
|
|
CGame *pGameObject;
|
|
char pcVarName[] = REMORA_MENU_LEVEL_NAME;
|
|
uint32 nDigitPos;
|
|
|
|
// Get the Remora's game object.
|
|
pGameObject = (CGame *)LinkedDataObject::Fetch_item_by_name(MS->objects, REMORA_NAME);
|
|
|
|
// Get the position where we need to add the digit to the menu variable name.
|
|
nDigitPos = strlen(pcVarName) - 1;
|
|
|
|
// System currently supports 5 menu levels. We must set these variables.
|
|
for (i = 0; i < REMORA_MENU_DEPTH; ++i) {
|
|
// Make the name of the variable.
|
|
pcVarName[nDigitPos] = (char)(i + '1');
|
|
|
|
// Find the variable in the Remora's game object.
|
|
j = 0;
|
|
while ((j < CGameObject::GetNoLvars(pGameObject)) && strcmp(pcVarName, CGameObject::GetScriptVariableName(pGameObject, j)))
|
|
++j;
|
|
|
|
// If we ran out of variables, this is an error because we haven't found the one we're looking for.
|
|
if (j == CGameObject::GetNoLvars(pGameObject))
|
|
Fatal_error("Failed to find menu variable %s in _remora::AccessMenuLevelVariables()", pcVarName);
|
|
|
|
// Found it, so get or set it.
|
|
if (eRetrieve == GET)
|
|
pnParams[i] = CGameObject::GetIntegerVariable(pGameObject, j);
|
|
else
|
|
CGameObject::SetIntegerVariable(pGameObject, j, pnParams[i]);
|
|
}
|
|
}
|
|
|
|
_remora::ScreenSymbol _remora::GetSymbolToDrawObject(_logic *pObject, uint32 nID) const {
|
|
__object_type eObjectType;
|
|
CGame *pGameObject;
|
|
uint32 nScriptVar, nVarVal;
|
|
|
|
// If it's player, always return same symbol.
|
|
if (nID == MS->player.Fetch_player_id())
|
|
return (SS_REMORA);
|
|
|
|
// Get the type field stored in the object.
|
|
eObjectType = pObject->object_type;
|
|
|
|
// Decide what colour it should be.
|
|
switch (eObjectType) {
|
|
case (__BUTTON_OPERATED_DOOR):
|
|
// In the case of doors, we must work out whether or not they are closed.
|
|
if (pObject->list[BOD_STATE_INDEX])
|
|
return (DOOR_CLOSED);
|
|
else
|
|
return (DOOR_OPEN);
|
|
break;
|
|
|
|
case (__ORGANIC_MEGA):
|
|
// Need to find out if the human is alive or dead.
|
|
pGameObject = (CGame *)LinkedDataObject::Fetch_item_by_number(MS->objects, nID);
|
|
nScriptVar = CGameObject::GetVariable(pGameObject, "state");
|
|
nVarVal = CGameObject::GetIntegerVariable(pGameObject, nScriptVar);
|
|
if (nVarVal == 1)
|
|
return (DEAD_HUMAN);
|
|
else
|
|
return (ALIVE_HUMAN);
|
|
|
|
break;
|
|
|
|
case (__NON_ORGANIC_MEGA):
|
|
// Need to find out if the robot is alive or dead.
|
|
pGameObject = (CGame *)LinkedDataObject::Fetch_item_by_number(MS->objects, nID);
|
|
nScriptVar = CGameObject::GetVariable(pGameObject, "state");
|
|
nVarVal = CGameObject::GetIntegerVariable(pGameObject, nScriptVar);
|
|
if (nVarVal == 1)
|
|
return (DEAD_ROBOT);
|
|
else
|
|
return (ALIVE_ROBOT);
|
|
|
|
break;
|
|
|
|
case (__REMORA_CARRIER):
|
|
// This is an object carrying a Remora, but only the player gets a special symbol now.
|
|
pGameObject = (CGame *)LinkedDataObject::Fetch_item_by_number(MS->objects, nID);
|
|
nScriptVar = CGameObject::GetVariable(pGameObject, "state");
|
|
nVarVal = CGameObject::GetIntegerVariable(pGameObject, nScriptVar);
|
|
if (nVarVal == 1)
|
|
return (DEAD_HUMAN);
|
|
else
|
|
return (ALIVE_HUMAN);
|
|
break;
|
|
|
|
case (__RECHARGE_POINT):
|
|
pGameObject = (CGame *)LinkedDataObject::Fetch_item_by_number(MS->objects, nID);
|
|
nScriptVar = CGameObject::GetVariable(pGameObject, "set_mine");
|
|
nVarVal = CGameObject::GetIntegerVariable(pGameObject, nScriptVar);
|
|
if (nVarVal == 1)
|
|
return (RECHARGE_ARMED);
|
|
else
|
|
return (RECHARGE_UNARMED);
|
|
break;
|
|
|
|
case (__AUTO_DOOR):
|
|
// In the case of doors, we must work out whether or not they are closed.
|
|
if (pObject->list[CAD_STATE_INDEX])
|
|
return (DOOR_CLOSED);
|
|
else
|
|
return (DOOR_OPEN);
|
|
break;
|
|
|
|
default:
|
|
// If the object has no type set then don't display it.
|
|
return (DO_NOT_DISPLAY);
|
|
}
|
|
}
|
|
|
|
void _remora::BuildM08DoorList() {
|
|
m_pnDoorIDs[0] = MS->Fetch_named_objects_id("door_corridor1_to_interorgation");
|
|
m_pnDoorIDs[1] = MS->Fetch_named_objects_id("cell_door");
|
|
m_pnDoorIDs[2] = MS->Fetch_named_objects_id("door_corridor1_to_liftstart");
|
|
m_pnDoorIDs[3] = MS->Fetch_named_objects_id("door_corridor1_to_security");
|
|
m_pnDoorIDs[4] = MS->Fetch_named_objects_id("door_cell_to_lukyan");
|
|
m_pnDoorIDs[5] = MS->Fetch_named_objects_id("door_security_to_lukyan");
|
|
m_pnDoorIDs[6] = MS->Fetch_named_objects_id("door_corridor2_to_security");
|
|
m_pnDoorIDs[7] = MS->Fetch_named_objects_id("door_security_to_exitlift");
|
|
m_pnDoorIDs[8] = MS->Fetch_named_objects_id("door_security_to_doorcontrol");
|
|
m_pnDoorIDs[9] = MS->Fetch_named_objects_id("door_corridor2_to_doorcontrol");
|
|
m_pnDoorIDs[10] = MS->Fetch_named_objects_id("door_exitlift_to_mainlift_sec");
|
|
m_pnDoorIDs[11] = MS->Fetch_named_objects_id("door_robot");
|
|
}
|
|
|
|
} // End of namespace ICB
|