scummvm/engines/icb/fn_remora_functions.cpp
2021-12-26 21:19:38 +01:00

982 lines
33 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_rcutypes.h"
#include "engines/icb/common/ptr_util.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/remora.h"
#include "engines/icb/text_sprites.h"
#include "engines/icb/icon_list_manager.h"
#include "engines/icb/global_switches.h"
#include "engines/icb/mission.h"
namespace ICB {
// This defines the maximum number of locks in the one-off mission 01 interface.
#define MAX_LOCKS_IN_M08 12
// This variable works like the L->looping flag, but controls a handful of tri-state functions in this file.
uint32 nFunctionState;
void RemoraStandardRestart(uint32 nRemoraID);
const char *SkipLineNumber(const char *pcLine);
mcodeFunctionReturnCodes fn_remora_script_activate(int32 &result, int32 *params) { return (MS->fn_remora_script_activate(result, params)); }
mcodeFunctionReturnCodes fn_remora_script_deactivate(int32 &result, int32 *params) { return (MS->fn_remora_script_deactivate(result, params)); }
mcodeFunctionReturnCodes fn_remora_is_active(int32 &result, int32 *params) { return (MS->fn_remora_is_active(result, params)); }
mcodeFunctionReturnCodes fn_remora_get_mode(int32 &result, int32 *params) { return (MS->fn_remora_get_mode(result, params)); }
mcodeFunctionReturnCodes fn_remora_set_mode(int32 &result, int32 *params) { return (MS->fn_remora_set_mode(result, params)); }
// These handle menus within the Remora.
mcodeFunctionReturnCodes fn_remora_add_icon(int32 &result, int32 *params) { return (MS->fn_remora_add_icon(result, params)); }
mcodeFunctionReturnCodes fn_remora_remove_icon(int32 &result, int32 *params) { return (MS->fn_remora_remove_icon(result, params)); }
mcodeFunctionReturnCodes fn_remora_reset_icon_list(int32 &result, int32 *params) { return (MS->fn_remora_reset_icon_list(result, params)); }
mcodeFunctionReturnCodes fn_remora_choose(int32 &result, int32 *params) { return (MS->fn_remora_choose(result, params)); }
mcodeFunctionReturnCodes fn_remora_wait_on_icon(int32 &result, int32 *params) { return (MS->fn_remora_wait_on_icon(result, params)); }
mcodeFunctionReturnCodes fn_remora_new_menu(int32 &result, int32 *params) { return (MS->fn_remora_new_menu(result, params)); }
mcodeFunctionReturnCodes fn_remora_new_menu_on_icon(int32 &result, int32 *params) { return (MS->fn_remora_new_menu_on_icon(result, params)); }
mcodeFunctionReturnCodes fn_remora_menu_return(int32 &result, int32 *params) { return (MS->fn_remora_menu_return(result, params)); }
mcodeFunctionReturnCodes fn_remora_menu_return_on_icon(int32 &result, int32 *params) { return (MS->fn_remora_menu_return_on_icon(result, params)); }
// These handle text display within the Remora.
mcodeFunctionReturnCodes fn_remora_paragraph_text(int32 &result, int32 *params) { return (MS->fn_remora_paragraph_text(result, params)); }
mcodeFunctionReturnCodes fn_remora_main_heading(int32 &result, int32 *params) { return (MS->fn_remora_main_heading(result, params)); }
mcodeFunctionReturnCodes fn_remora_sub_heading(int32 &result, int32 *params) { return (MS->fn_remora_sub_heading(result, params)); }
mcodeFunctionReturnCodes fn_remora_option_text(int32 &result, int32 *params) { return (MS->fn_remora_option_text(result, params)); }
mcodeFunctionReturnCodes fn_remora_warning_text(int32 &result, int32 *params) { return (MS->fn_remora_warning_text(result, params)); }
mcodeFunctionReturnCodes fn_remora_blank_line(int32 &result, int32 *params) { return (MS->fn_remora_blank_line(result, params)); }
// These handle graphics within the Remora.
mcodeFunctionReturnCodes fn_remora_clear_screen(int32 &result, int32 *params) { return (MS->fn_remora_clear_screen(result, params)); }
mcodeFunctionReturnCodes fn_remora_picture(int32 &result, int32 *params) { return (MS->fn_remora_picture(result, params)); }
mcodeFunctionReturnCodes fn_remora_set_max_zoom(int32 &result, int32 *params) { return (MS->fn_remora_set_max_zoom(result, params)); }
mcodeFunctionReturnCodes fn_remora_set_min_zoom(int32 &result, int32 *params) { return (MS->fn_remora_set_min_zoom(result, params)); }
mcodeFunctionReturnCodes fn_remora_set_current_zoom(int32 &result, int32 *params) { return (MS->fn_remora_set_current_zoom(result, params)); }
mcodeFunctionReturnCodes fn_remora_emp_flash(int32 &result, int32 *params) { return (MS->fn_remora_emp_flash(result, params)); }
// These deal with the Remora's email system.
mcodeFunctionReturnCodes fn_remora_send_email(int32 &result, int32 *params) { return (MS->fn_remora_send_email(result, params)); }
mcodeFunctionReturnCodes fn_remora_is_email_waiting(int32 &result, int32 *params) { return (MS->fn_remora_is_email_waiting(result, params)); }
mcodeFunctionReturnCodes fn_remora_mark_email_read(int32 &result, int32 *params) { return (MS->fn_remora_mark_email_read(result, params)); }
mcodeFunctionReturnCodes fn_remora_check_email_id(int32 &result, int32 *params) { return (MS->fn_remora_check_email_id(result, params)); }
// Miscellaneous Remora functions.
mcodeFunctionReturnCodes fn_remora_fix_motion_scan_xz(int32 &result, int32 *params) { return (MS->fn_remora_fix_motion_scan_xz(result, params)); }
mcodeFunctionReturnCodes fn_remora_default_logic(int32 &result, int32 *params) { return (MS->fn_remora_default_logic(result, params)); }
mcodeFunctionReturnCodes fn_remora_mega_says(int32 &result, int32 *params) { return (MS->fn_remora_mega_says(result, params)); }
mcodeFunctionReturnCodes fn_remora_add_floor_range(int32 &result, int32 *params) { return (MS->fn_remora_add_floor_range(result, params)); }
mcodeFunctionReturnCodes fn_remora_reset_floor_ranges(int32 &result, int32 *params) { return (MS->fn_remora_reset_floor_ranges(result, params)); }
mcodeFunctionReturnCodes fn_remora_set_map_knowledge_level(int32 &result, int32 *params) { return (MS->fn_remora_set_map_knowledge_level(result, params)); }
mcodeFunctionReturnCodes fn_remora_update_player(int32 &result, int32 *params) { return (MS->fn_remora_update_player(result, params)); }
mcodeFunctionReturnCodes fn_remora_progress_bar(int32 &result, int32 *params) { return (MS->fn_remora_progress_bar(result, params)); }
mcodeFunctionReturnCodes _game_session::fn_remora_update_player(int32 &, int32 *) {
_input *state;
// If the Remora is now shut down, we need to return to player-standing mode.
if (!g_oRemora->IsActive()) {
return (IR_CONT);
}
// check keys/pads/etc. to see what the user is trying to do
player.Update_input_state();
state = player.Fetch_input_state();
// Now just run its logic. It will process the 'deactivate' message if one was posted in previous line.
g_oRemora->CycleRemoraLogic(*state);
// Cycle the inventory logic if it is active. Note though that the fact that the Remora is active does
// not mean the inventory is, because there could be a gap between menus being displayed.
if (g_oIconListManager->IsActive())
g_oIconListManager->CycleInventoryLogic(*state);
return (IR_REPEAT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_is_active(int32 &result, int32 *) {
// Call the function that does the work.
result = g_oRemora->IsActive();
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_get_mode(int32 &result, int32 *) {
// First check that the Remora is active.
if (g_oRemora->IsActive())
result = (int32)g_oRemora->GetMode();
else
result = REMORA_NOT_ACTIVE;
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_set_mode(int32 &, int32 *params) {
// Set the mode.
g_oRemora->SetMode((_remora::RemoraMode)params[0]);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_picture(int32 &, int32 *params) {
uint32 nXOffset;
const char *picture_name = (const char *)MemoryUtil::resolvePtr(params[2]);
// Write the call in the debug file.
Zdebug("fn_remora_picture( %d, %d, %s )", (int32)params[0], (int32)params[1], picture_name);
// Neither can pixel offset.
nXOffset = ((int32)params[1] < 0) ? 0 : (uint32)params[1];
// Make the call to the Remora.
g_oRemora->SetupPicture(nXOffset, picture_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_clear_screen(int32 &, int32 *) {
// Make the call to the Remora object.
g_oRemora->ClearAllText();
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_add_icon(int32 &, int32 *params) {
char pcIconPath[ENGINE_STRING_LEN];
const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Make the call to the Remora object.
g_oIconListManager->AddIconToList(ICON_LIST_REMORA, icon_name);
// Preload the icon for PSX smoothing.
sprintf(pcIconPath, ICON_PATH);
g_oIconMenu->PreloadIcon(pcIconPath, icon_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_remove_icon(int32 &, int32 *params) {
const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Make the call to the Remora object.
g_oIconListManager->RemoveIconFromList(ICON_LIST_REMORA, icon_name);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_reset_icon_list(int32 &, int32 *) {
// Make the call to the Remora object.
g_oIconListManager->ResetList(ICON_LIST_REMORA);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_choose(int32 &, int32 *) {
// This function must be used from inside the Remora.
if (!g_oRemora->IsActive())
Fatal_error("fn_remora_choose() cannot be used outside the Remora");
// Make the call to the Remora object.
g_oIconListManager->ActivateIconMenu(ICON_LIST_REMORA, TRUE8, FALSE8);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_paragraph_text(int32 &, int32 *params) {
const char *pcText;
// Find the text in the resources.
pcText = g_oRemora->LocateTextFromReference((uint32)params[1]);
if (pcText) {
// Skip line numbers.
pcText = SkipLineNumber(pcText);
// Set the text.
g_oRemora->SetText(pcText, REMORA_TEXT_PARAGRAPH, 1, PIN_AT_TOP_LEFT);
} else {
// We failed to find it.
Fatal_error("Unable to find text for reference %x in fn_remora_paragraph_text()", (uint32)params[1]);
}
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_main_heading(int32 &, int32 *params) {
const char *pcText;
// Find the text in the resources.
pcText = g_oRemora->LocateTextFromReference((uint32)params[0]);
if (pcText) {
// Skip line numbers.
pcText = SkipLineNumber(pcText);
// Set the text.
g_oRemora->SetText(pcText, REMORA_TEXT_HEADING, 0, PIN_AT_CENTRE);
} else {
// We failed to find it.
Fatal_error("Unable to find text for reference %x in fn_remora_main_heading()", (uint32)params[0]);
}
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_sub_heading(int32 &, int32 *params) {
const char *pcText;
// Find the text in the resources.
pcText = g_oRemora->LocateTextFromReference((uint32)params[1]);
if (pcText) {
// Skip line numbers.
pcText = SkipLineNumber(pcText);
// Set the text.
g_oRemora->SetText(pcText, REMORA_TEXT_HEADING, 0, PIN_AT_TOP_LEFT);
} else {
// We failed to find it.
Fatal_error("Unable to find text for reference %x in fn_remora_sub_heading()", (uint32)params[1]);
}
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_option_text(int32 &, int32 *params) {
const char *pcText;
// Find the text in the resources.
pcText = g_oRemora->LocateTextFromReference((uint32)params[1]);
if (pcText) {
// Skip line numbers.
pcText = SkipLineNumber(pcText);
// Set the text.
g_oRemora->SetText(pcText, REMORA_TEXT_OPTION, 0, PIN_AT_TOP_LEFT);
} else {
// We failed to find it.
Fatal_error("Unable to find text for reference %x in fn_remora_option_text()", (uint32)params[1]);
}
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_warning_text(int32 &, int32 *params) {
const char *pcText;
// Find the text in the resources.
pcText = g_oRemora->LocateTextFromReference((uint32)params[1]);
if (pcText) {
// Skip line numbers.
pcText = SkipLineNumber(pcText);
// Set the text.
g_oRemora->SetText(pcText, REMORA_TEXT_WARNING, 0, PIN_AT_CENTRE);
} else {
// We failed to find it.
Fatal_error("Unable to find text for reference %x in fn_remora_warning_text()", (uint32)params[1]);
}
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_blank_line(int32 &, int32 *) {
// Set the blank line.
g_oRemora->SetText(nullptr, 0, 0, PIN_AT_CENTRE);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_progress_bar(int32 &, int32 *params) {
int32 nTargetCycles;
int32 nCurrentValue;
// Get cycles to run bar over.
nTargetCycles = (int32)params[0];
// Is this a new bar?
if (!L->looping) {
// We are now doing a script loop.
L->looping = TRUE8;
// Initially none of the bar is there.
g_oRemora->SetProgressBarValue(0);
// Set target value for bar.
g_oRemora->SetProgressBarTotal(nTargetCycles);
// And here I set a tri-state function control variable, to help with control.
nFunctionState = 1;
// Come back to this function next time.
return (IR_REPEAT);
}
// Check if we are incrementing progress bar or holding it for a cycle at 100%.
if (nFunctionState == 1) {
// Still increasing it. Get current bar position.
nCurrentValue = g_oRemora->GetProgressBarValue();
// Update bar count.
++nCurrentValue;
// Set current complete.
g_oRemora->SetProgressBarValue(nCurrentValue);
// Check if done yet.
if (nCurrentValue == nTargetCycles) {
// Finished, but we want to come back and hold it for a cycle.
nFunctionState = 2;
return (IR_REPEAT);
} else {
// Return to increment the bar some more next time.
return (IR_REPEAT);
}
} else {
// Now we have really finished.
L->looping = FALSE8;
g_oRemora->SetProgressBarValue(-1);
return (IR_CONT);
}
}
mcodeFunctionReturnCodes _game_session::fn_remora_fix_motion_scan_xz(int32 &, int32 *) {
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_script_activate(int32 &, int32 *params) {
_input *psInputState;
// In case the script writer has forgotten to do it, drop any icon currently held.
g_oIconListManager->Drop();
// This tells the UI that the Remora is now active.
MS->player.Push_control_mode(ACTOR_RELATIVE);
MS->player.Set_player_status(REMORA);
// This flag is used to indicate that the Remora has been activated in a specific mode (i.e. from script,
// rather than the keyboard). It is used to stop the Remora dropping into its default menu selection upon
// activation; instead it will use the mode set here.
g_oRemora->SetModeOverride((_remora::RemoraMode)params[0]);
// This sets a flag which the Remora will pick up next cycle.
g_oRemora->ActivateRemora((_remora::RemoraMode)params[0]);
// Cycle the Remora's logic to make sure drawing code doesn't try to do a draw before the
// Remora has had a chance to set itself up.
MS->player.Update_input_state();
psInputState = MS->player.Fetch_input_state();
g_oRemora->CycleRemoraLogic(*psInputState);
// Stop key bounce.
MS->player.remora_lock = TRUE8;
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_script_deactivate(int32 &, int32 *) {
_input sInputState;
// Write the call in the debug files.
Zdebug("fn_remora_script_deactivate();");
// If the Remora is not active then there is nothing to do.
if (!g_oRemora->IsActive())
return (IR_CONT);
// The script may be set up in such a way that the icon that was selected to cause this deactivate
// to happen may not have cleared the currently-selected icon, so do it here to be safe.
g_oIconListManager->Drop();
// Deactivate the Remora.
g_oRemora->SetMode(_remora::MOTION_SCAN);
g_oRemora->DeactivateRemora(TRUE8);
sInputState.UnSetButton(__UNUSEDBUTTON);
g_oRemora->CycleRemoraLogic(sInputState);
// This tells the UI that the Remora is now gone and the player is back.
MS->player.Pop_control_mode();
logic_structs[player.Fetch_player_id()]->mega->weapon = __NOT_ARMED;
logic_structs[player.Fetch_player_id()]->voxel_info->___init(logic_structs[player.Fetch_player_id()]->mega->chr_name,
logic_structs[player.Fetch_player_id()]->mega->anim_set, __NOT_ARMED);
MS->player.Set_player_status(STOOD);
MS->Setup_prop_sleep_states(); // recompute prop sleep states once we leave remora
// Stop key bounce.
MS->player.remora_lock = TRUE8;
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_default_logic(int32 &, int32 *) {
// Check to see if we are already looping
if (!L->looping) {
// Mark the fact that we are now looping.
L->looping = 1;
// Clear any events outstanding for the Remora.
g_oEventManager->ClearAllEventsForObject(cur_id);
// Make sure there are no icons in the list for the Remora.
g_oIconListManager->ResetList(ICON_LIST_REMORA);
// Make sure the Remora's screen is clear.
g_oRemora->ClearAllText();
// Must call this function again.
return (IR_REPEAT);
} else {
// We are looping in this function call. Simply drop out if the Remora is not active.
if (!g_oRemora->IsActive()) {
// Remora not currently active.
return (IR_REPEAT);
} else {
// Remora has been activated. Either drop into the default menu mode, or do the one specified
// by script if there is one.
g_oRemora->SetDefaultOrOverrideMode();
// Make the Remora rerun its logic context.
g_oEventManager->PostNamedEventToObject(EVENT_LOGIC_RERUN, cur_id, cur_id);
// We are not looping from now on.
L->looping = 0;
// Calling script can continue now.
return (IR_CONT);
}
}
// To fix a GCC compiler warning
return (IR_REPEAT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_new_menu(int32 &, int32 *params) {
// Set the variables so we jump to the right menu when we restart.
g_oRemora->AccessMenuLevelVariables(params, _remora::SET);
// Jump.
RemoraStandardRestart(cur_id);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_new_menu_on_icon(int32 &, int32 *params) {
const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[5]);
// Check to see if we are already looping
if (!L->looping) {
// Set the variables so we jump to the right menu when we restart.
g_oRemora->AccessMenuLevelVariables(params, _remora::SET);
// Remove any icons from the icon list.
g_oIconListManager->ResetList(ICON_LIST_REMORA);
// Add the given icon to the Remora icon list.
g_oIconListManager->AddIconToList(ICON_LIST_REMORA, icon_name);
// Activate the chooser menu.
g_oIconListManager->ActivateIconMenu(ICON_LIST_REMORA, TRUE8, FALSE8);
// Mark the fact that we are now looping.
L->looping = 1;
// And here I set the tri-state function control variable, so we know which bit to run next.
nFunctionState = 1;
// Drop out but call this function again next time.
return (IR_REPEAT);
} else {
// We are looping on this function. The set-up part must already have been done. But the function has
// two subsequent states. See which one we're on.
if (nFunctionState == 1) {
// We are looping on this function. The set-up part must already have been done.
// Check for the icon being selected.
if (g_oIconListManager->ItemHeld() && g_oIconListManager->Holding(icon_name)) {
// Drop the item held.
g_oIconListManager->Drop();
// Cord speaks his instructions to the Remora.
g_oRemora->DisplayCharacterSpeech((uint32)params[6]);
// We are now moving to a new state in this function.
nFunctionState = 2;
return (IR_REPEAT);
} else {
// Icon has not been selected, so we need to come back to this function.
return (IR_REPEAT);
}
} else {
// Second stage of this function now: displaying mega speech.
if (g_oRemora->GetSpeechTimer() == 0) {
// Do the Remora script jump.
RemoraStandardRestart(cur_id);
// Allow calling script to continue.
nFunctionState = 0;
L->looping = 0;
return (IR_CONT);
} else {
// The speech hasn't been displayed long enough, so hold inside this fn_function().
return (IR_REPEAT);
}
}
}
}
mcodeFunctionReturnCodes _game_session::fn_remora_wait_on_icon(int32 &, int32 *params) {
const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[0]);
// Check to see if we are already looping
if (!L->looping) {
// Remove any icons from the icon list.
g_oIconListManager->ResetList(ICON_LIST_REMORA);
// Add the given icon to the Remora icon list.
g_oIconListManager->AddIconToList(ICON_LIST_REMORA, icon_name);
// Activate the chooser menu.
g_oIconListManager->ActivateIconMenu(ICON_LIST_REMORA, TRUE8, FALSE8);
// Mark the fact that we are now looping.
L->looping = 1;
// And here I set the tri-state function control variable, so we know which bit to run next.
nFunctionState = 1;
// Drop out but call this function again next time.
return (IR_REPEAT);
} else {
// We are looping on this function. The set-up part must already have been done. But the function has
// two subsequent states. See which one we're on.
if (nFunctionState == 1) {
if (g_oIconListManager->ItemHeld() && g_oIconListManager->Holding(icon_name)) {
// Yes, user has selected the icon to start a new mode. First drop item held.
g_oIconListManager->Drop();
// Cord speaks his instructions to the Remora.
g_oRemora->DisplayCharacterSpeech((uint32)params[2]);
// We are now moving to a new state in this function.
nFunctionState = 2;
// Drop out but call this function again next time.
return (IR_REPEAT);
} else {
// Drop out but call this function again next time.
return (IR_REPEAT);
}
} else {
// Second stage of this function now: displaying mega speech.
if (g_oRemora->GetSpeechTimer() == 0) {
// Do the Remora new mode.
g_oRemora->SetMode((_remora::RemoraMode)params[1]);
RemoraStandardRestart(cur_id);
// Allow calling script to continue.
nFunctionState = 0;
L->looping = 0;
return (IR_CONT);
} else {
// The speech hasn't been displayed long enough, so hold inside this fn_function().
return (IR_REPEAT);
}
}
}
}
mcodeFunctionReturnCodes _game_session::fn_remora_menu_return(int32 &, int32 *params) {
int32 i;
uint32 nReturned;
int32 pnMenuVariables[REMORA_MENU_DEPTH];
// Get the current state of the menu variables.
g_oRemora->AccessMenuLevelVariables(pnMenuVariables, _remora::GET);
// Find out how deep we are already in the menu tree.
i = REMORA_MENU_DEPTH - 1;
while ((i >= 0) && (pnMenuVariables[i] == 0))
--i;
// If we ran off the end then we are already at the root, but there is little value in making this an error.
if (i < 0)
return (IR_CONT);
// We are at a certain depth in the menu tree, so back up the required amount. If we run off the end,
// this means user has requested to go back more levels than we are deep, but just ignore this.
nReturned = 0;
while ((i >= 0) && (nReturned < (uint32)params[0])) {
pnMenuVariables[i] = 0;
--i;
++nReturned;
}
// Put the new values back in the script object.
g_oRemora->AccessMenuLevelVariables(pnMenuVariables, _remora::SET);
// Jump.
RemoraStandardRestart(cur_id);
// Allow calling script to continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_menu_return_on_icon(int32 &, int32 *params) {
int32 i;
uint32 nReturned;
int32 pnMenuVariables[REMORA_MENU_DEPTH];
const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[1]);
// Check to see if we are already looping
if (!L->looping) {
// First time in, so display the icon.
g_oIconListManager->ResetList(ICON_LIST_REMORA);
g_oIconListManager->AddIconToList(ICON_LIST_REMORA, icon_name);
g_oIconListManager->ActivateIconMenu(ICON_LIST_REMORA, TRUE8, FALSE8);
// Mark the fact that we are now looping.
L->looping = 1;
// And here I set the tri-state function control variable, so we know which bit to run next.
nFunctionState = 1;
// Drop out but call this function again next time.
return (IR_REPEAT);
} else {
// We are looping on this function. The set-up part must already have been done. But the function has
// two subsequent states. See which one we're on.
if (nFunctionState == 1) {
if (g_oIconListManager->ItemHeld() && g_oIconListManager->Holding(icon_name)) {
// Clear the item held.
g_oIconListManager->Drop();
// Remove any icons from the icon list.
g_oIconListManager->ResetList(ICON_LIST_REMORA);
// Icon has been selected, so we are going to do the jump back up the menu tree. Get
// current state of the menu variables.
g_oRemora->AccessMenuLevelVariables(pnMenuVariables, _remora::GET);
// Find out how deep we are already in the menu tree.
i = REMORA_MENU_DEPTH - 1;
while ((i >= 0) && (pnMenuVariables[i] == 0))
--i;
// If we ran off the end then we are already at the root, but there is no value in
// making this an error.
if (i >= 0) {
// We are at a certain depth in the menu tree, so back up the required amount. If we run off the
// end,
// this means user has requested to go back more levels than we are deep, but just ignore this.
nReturned = 0;
while ((i >= 0) && (nReturned < (uint32)params[0])) {
pnMenuVariables[i] = 0;
--i;
++nReturned;
}
}
// Put the new values back in the script object.
g_oRemora->AccessMenuLevelVariables(pnMenuVariables, _remora::SET);
// Display what Cord needs to say.
g_oRemora->DisplayCharacterSpeech((uint32)params[2]);
// We are now moving to a new state in this function.
nFunctionState = 2;
// Drop out but call this function again next time.
return (IR_REPEAT);
} else {
// Icon has not been chosen, so call this function again next time.
return (IR_REPEAT);
}
} else {
// Second stage of this function now: displaying mega speech.
if (g_oRemora->GetSpeechTimer() == 0) {
// Do the Remora script jump.
RemoraStandardRestart(cur_id);
// Allow calling script to continue.
nFunctionState = 0;
L->looping = 0;
return (IR_CONT);
} else {
// The speech hasn't been displayed long enough, so hold inside this fn_function().
return (IR_REPEAT);
}
}
}
}
mcodeFunctionReturnCodes _game_session::fn_remora_mega_says(int32 &, int32 *params) {
// Check to see if we are already looping
if (!L->looping) {
// Mark the fact that we are now looping.
L->looping = 1;
// Find the text in the resources.
g_oRemora->DisplayCharacterSpeech((uint32)params[1]);
// Drop out but call this function again next time.
return (IR_REPEAT);
} else {
// Get the speech timer. If it has run down to zero, the supplied line has been displayed long enough,
// so we can go on to the next line of script.
if (g_oRemora->GetSpeechTimer() == 0) {
// Allow calling script to continue.
L->looping = 0;
return (IR_CONT);
}
// The speech hasn't been displayed long enough, so hold inside this fn_function().
return (IR_REPEAT);
}
}
mcodeFunctionReturnCodes _game_session::fn_remora_add_floor_range(int32 &, int32 *params) {
// Simply pass the call on to the Remora.
g_oRemora->AddFloorRange((uint32)params[0], (uint32)params[1]);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_reset_floor_ranges(int32 &, int32 *) {
// Simply pass the call on to the Remora.
g_oRemora->ResetFloorRanges();
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_send_email(int32 &, int32 *params) {
const char *email_id = (const char *)MemoryUtil::resolvePtr(params[0]);
// Set the email in the Remora.
g_oRemora->NewEmail(email_id);
// Here we borrow the logic in the icon menu which flashes added medipacks etc.
g_oIconListManager->SetEmailArrived();
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_is_email_waiting(int32 &result, int32 *) {
// Make the call to the Remora.
result = (int32)g_oRemora->IsEmailWaiting();
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_check_email_id(int32 &result, int32 *params) {
const char *email_id = (const char *)MemoryUtil::resolvePtr(params[0]);
// Check with the Remora if the string matches.
result = g_oRemora->IsThisEmailWaiting(email_id);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_mark_email_read(int32 &, int32 *) {
// Turn off the email-waiting flag in the Remora.
g_oRemora->MarkEmailRead();
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_set_max_zoom(int32 &, int32 *params) {
// Call the Remora function to do it.
g_oRemora->SetMaximumZoom((uint32)params[0]);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_set_min_zoom(int32 &, int32 *params) {
// Call the Remora function to do it.
g_oRemora->SetMinimumZoom((uint32)params[0]);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_set_current_zoom(int32 &, int32 *params) {
// Call the Remora function to do it.
g_oRemora->SetCurrentZoom((uint32)params[0]);
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_emp_flash(int32 &, int32 *) {
// If the Remora is not active, just ignore this function.
if (g_oRemora->IsActive()) {
// Check to see if we are already looping
if (!L->looping) {
// Mark the fact that we are now looping.
L->looping = 1;
}
// See if the EMP effect is still running or not.
if (g_oRemora->EMPEffect()) {
// Menu still active, so we must continue cycling its logic next time through.
return (IR_REPEAT);
} else {
// A selection has been made or the menu has been cancelled. Calling script can now continue.
L->looping = 0;
return (IR_CONT);
}
}
// Calling script can continue.
return (IR_CONT);
}
mcodeFunctionReturnCodes _game_session::fn_remora_set_map_knowledge_level(int32 &, int32 * /*params*/) {
// Calling script can continue.
return (IR_CONT);
}
void RemoraStandardRestart(uint32 nRemoraID) {
// Clear the item held if any.
g_oIconListManager->Drop();
// This blockRemove any icons from the icon list.
g_oIconListManager->ResetList(ICON_LIST_REMORA);
// Clear all text.
g_oRemora->ClearAllText();
MS->logic_structs[nRemoraID]->context_request = TRUE8;
}
const char *SkipLineNumber(const char *pcLine) {
const char *pcParsePos;
// If line number display is turned on, don't do anything.
if (g_px->speechLineNumbers)
return (pcLine);
// Initialise parse pointer.
pcParsePos = pcLine;
// If the first character is one that marks the line as being spoken or not, skip it.
if ((*pcParsePos == TS_SPOKEN_LINE) || (*pcParsePos == TS_NON_SPOKEN_LINE))
++pcParsePos;
// The first character has to start the line number to be valid.
if (*pcParsePos == TS_LINENO_OPEN) {
// Okay, we appear to have a legal line number. Find the close brace for it.
while ((*pcParsePos != '\0') && (*pcParsePos != TS_LINENO_CLOSE))
++pcParsePos;
// If we didn't find one then this is an error.
if (*pcParsePos == '\0')
Fatal_error("Failed to find the end of the line number in [%s]", pcLine);
// Skip to first non-space after the line number.
++pcParsePos;
while ((*pcParsePos != '\0') && (*pcParsePos == ' '))
++pcParsePos;
// If we got to the end of the string then we have a line number with no text following it.
if (*pcParsePos == '\0')
Fatal_error("Found line number [%s] with no text in SkipLineNumber()", pcLine);
// Write the modified pointer back into the text block.
return (pcParsePos);
} else {
// No line number so nothing to chop off.
return (pcParsePos);
}
}
} // End of namespace ICB