1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1999-2000 Revolution Software Ltd.
9  * This code is based on source code created by Revolution Software,
10  * used with permission.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #include "engines/icb/common/px_rcutypes.h"
29 #include "engines/icb/common/ptr_util.h"
30 #include "engines/icb/global_objects.h"
31 #include "engines/icb/remora.h"
32 #include "engines/icb/text_sprites.h"
33 #include "engines/icb/icon_list_manager.h"
34 #include "engines/icb/global_switches.h"
35 #include "engines/icb/mission.h"
36 
37 namespace ICB {
38 
39 // This defines the maximum number of locks in the one-off mission 01 interface.
40 #define MAX_LOCKS_IN_M08 12
41 
42 // This variable works like the L->looping flag, but controls a handful of tri-state functions in this file.
43 uint32 nFunctionState;
44 
45 void RemoraStandardRestart(uint32 nRemoraID);
46 const char *SkipLineNumber(const char *pcLine);
47 
fn_remora_script_activate(int32 & result,int32 * params)48 mcodeFunctionReturnCodes fn_remora_script_activate(int32 &result, int32 *params) { return (MS->fn_remora_script_activate(result, params)); }
49 
fn_remora_script_deactivate(int32 & result,int32 * params)50 mcodeFunctionReturnCodes fn_remora_script_deactivate(int32 &result, int32 *params) { return (MS->fn_remora_script_deactivate(result, params)); }
51 
fn_remora_is_active(int32 & result,int32 * params)52 mcodeFunctionReturnCodes fn_remora_is_active(int32 &result, int32 *params) { return (MS->fn_remora_is_active(result, params)); }
53 
fn_remora_get_mode(int32 & result,int32 * params)54 mcodeFunctionReturnCodes fn_remora_get_mode(int32 &result, int32 *params) { return (MS->fn_remora_get_mode(result, params)); }
55 
fn_remora_set_mode(int32 & result,int32 * params)56 mcodeFunctionReturnCodes fn_remora_set_mode(int32 &result, int32 *params) { return (MS->fn_remora_set_mode(result, params)); }
57 
58 // These handle menus within the Remora.
fn_remora_add_icon(int32 & result,int32 * params)59 mcodeFunctionReturnCodes fn_remora_add_icon(int32 &result, int32 *params) { return (MS->fn_remora_add_icon(result, params)); }
60 
fn_remora_remove_icon(int32 & result,int32 * params)61 mcodeFunctionReturnCodes fn_remora_remove_icon(int32 &result, int32 *params) { return (MS->fn_remora_remove_icon(result, params)); }
62 
fn_remora_reset_icon_list(int32 & result,int32 * params)63 mcodeFunctionReturnCodes fn_remora_reset_icon_list(int32 &result, int32 *params) { return (MS->fn_remora_reset_icon_list(result, params)); }
64 
fn_remora_choose(int32 & result,int32 * params)65 mcodeFunctionReturnCodes fn_remora_choose(int32 &result, int32 *params) { return (MS->fn_remora_choose(result, params)); }
66 
fn_remora_wait_on_icon(int32 & result,int32 * params)67 mcodeFunctionReturnCodes fn_remora_wait_on_icon(int32 &result, int32 *params) { return (MS->fn_remora_wait_on_icon(result, params)); }
68 
fn_remora_new_menu(int32 & result,int32 * params)69 mcodeFunctionReturnCodes fn_remora_new_menu(int32 &result, int32 *params) { return (MS->fn_remora_new_menu(result, params)); }
70 
fn_remora_new_menu_on_icon(int32 & result,int32 * params)71 mcodeFunctionReturnCodes fn_remora_new_menu_on_icon(int32 &result, int32 *params) { return (MS->fn_remora_new_menu_on_icon(result, params)); }
72 
fn_remora_menu_return(int32 & result,int32 * params)73 mcodeFunctionReturnCodes fn_remora_menu_return(int32 &result, int32 *params) { return (MS->fn_remora_menu_return(result, params)); }
74 
fn_remora_menu_return_on_icon(int32 & result,int32 * params)75 mcodeFunctionReturnCodes fn_remora_menu_return_on_icon(int32 &result, int32 *params) { return (MS->fn_remora_menu_return_on_icon(result, params)); }
76 
77 // These handle text display within the Remora.
fn_remora_paragraph_text(int32 & result,int32 * params)78 mcodeFunctionReturnCodes fn_remora_paragraph_text(int32 &result, int32 *params) { return (MS->fn_remora_paragraph_text(result, params)); }
79 
fn_remora_main_heading(int32 & result,int32 * params)80 mcodeFunctionReturnCodes fn_remora_main_heading(int32 &result, int32 *params) { return (MS->fn_remora_main_heading(result, params)); }
81 
fn_remora_sub_heading(int32 & result,int32 * params)82 mcodeFunctionReturnCodes fn_remora_sub_heading(int32 &result, int32 *params) { return (MS->fn_remora_sub_heading(result, params)); }
83 
fn_remora_option_text(int32 & result,int32 * params)84 mcodeFunctionReturnCodes fn_remora_option_text(int32 &result, int32 *params) { return (MS->fn_remora_option_text(result, params)); }
85 
fn_remora_warning_text(int32 & result,int32 * params)86 mcodeFunctionReturnCodes fn_remora_warning_text(int32 &result, int32 *params) { return (MS->fn_remora_warning_text(result, params)); }
87 
fn_remora_blank_line(int32 & result,int32 * params)88 mcodeFunctionReturnCodes fn_remora_blank_line(int32 &result, int32 *params) { return (MS->fn_remora_blank_line(result, params)); }
89 
90 // These handle graphics within the Remora.
fn_remora_clear_screen(int32 & result,int32 * params)91 mcodeFunctionReturnCodes fn_remora_clear_screen(int32 &result, int32 *params) { return (MS->fn_remora_clear_screen(result, params)); }
92 
fn_remora_picture(int32 & result,int32 * params)93 mcodeFunctionReturnCodes fn_remora_picture(int32 &result, int32 *params) { return (MS->fn_remora_picture(result, params)); }
94 
fn_remora_set_max_zoom(int32 & result,int32 * params)95 mcodeFunctionReturnCodes fn_remora_set_max_zoom(int32 &result, int32 *params) { return (MS->fn_remora_set_max_zoom(result, params)); }
96 
fn_remora_set_min_zoom(int32 & result,int32 * params)97 mcodeFunctionReturnCodes fn_remora_set_min_zoom(int32 &result, int32 *params) { return (MS->fn_remora_set_min_zoom(result, params)); }
98 
fn_remora_set_current_zoom(int32 & result,int32 * params)99 mcodeFunctionReturnCodes fn_remora_set_current_zoom(int32 &result, int32 *params) { return (MS->fn_remora_set_current_zoom(result, params)); }
100 
fn_remora_emp_flash(int32 & result,int32 * params)101 mcodeFunctionReturnCodes fn_remora_emp_flash(int32 &result, int32 *params) { return (MS->fn_remora_emp_flash(result, params)); }
102 
103 // These deal with the Remora's email system.
fn_remora_send_email(int32 & result,int32 * params)104 mcodeFunctionReturnCodes fn_remora_send_email(int32 &result, int32 *params) { return (MS->fn_remora_send_email(result, params)); }
105 
fn_remora_is_email_waiting(int32 & result,int32 * params)106 mcodeFunctionReturnCodes fn_remora_is_email_waiting(int32 &result, int32 *params) { return (MS->fn_remora_is_email_waiting(result, params)); }
107 
fn_remora_mark_email_read(int32 & result,int32 * params)108 mcodeFunctionReturnCodes fn_remora_mark_email_read(int32 &result, int32 *params) { return (MS->fn_remora_mark_email_read(result, params)); }
109 
fn_remora_check_email_id(int32 & result,int32 * params)110 mcodeFunctionReturnCodes fn_remora_check_email_id(int32 &result, int32 *params) { return (MS->fn_remora_check_email_id(result, params)); }
111 
112 // Miscellaneous Remora functions.
fn_remora_fix_motion_scan_xz(int32 & result,int32 * params)113 mcodeFunctionReturnCodes fn_remora_fix_motion_scan_xz(int32 &result, int32 *params) { return (MS->fn_remora_fix_motion_scan_xz(result, params)); }
114 
fn_remora_default_logic(int32 & result,int32 * params)115 mcodeFunctionReturnCodes fn_remora_default_logic(int32 &result, int32 *params) { return (MS->fn_remora_default_logic(result, params)); }
116 
fn_remora_mega_says(int32 & result,int32 * params)117 mcodeFunctionReturnCodes fn_remora_mega_says(int32 &result, int32 *params) { return (MS->fn_remora_mega_says(result, params)); }
118 
fn_remora_add_floor_range(int32 & result,int32 * params)119 mcodeFunctionReturnCodes fn_remora_add_floor_range(int32 &result, int32 *params) { return (MS->fn_remora_add_floor_range(result, params)); }
120 
fn_remora_reset_floor_ranges(int32 & result,int32 * params)121 mcodeFunctionReturnCodes fn_remora_reset_floor_ranges(int32 &result, int32 *params) { return (MS->fn_remora_reset_floor_ranges(result, params)); }
122 
fn_remora_set_map_knowledge_level(int32 & result,int32 * params)123 mcodeFunctionReturnCodes fn_remora_set_map_knowledge_level(int32 &result, int32 *params) { return (MS->fn_remora_set_map_knowledge_level(result, params)); }
124 
fn_remora_update_player(int32 & result,int32 * params)125 mcodeFunctionReturnCodes fn_remora_update_player(int32 &result, int32 *params) { return (MS->fn_remora_update_player(result, params)); }
126 
fn_remora_progress_bar(int32 & result,int32 * params)127 mcodeFunctionReturnCodes fn_remora_progress_bar(int32 &result, int32 *params) { return (MS->fn_remora_progress_bar(result, params)); }
128 
fn_remora_update_player(int32 &,int32 *)129 mcodeFunctionReturnCodes _game_session::fn_remora_update_player(int32 &, int32 *) {
130 	_input *state;
131 
132 	// If the Remora is now shut down, we need to return to player-standing mode.
133 	if (!g_oRemora->IsActive()) {
134 		return (IR_CONT);
135 	}
136 
137 	// check keys/pads/etc. to see what the user is trying to do
138 	player.Update_input_state();
139 
140 	state = player.Fetch_input_state();
141 
142 	// Now just run its logic.  It will process the 'deactivate' message if one was posted in previous line.
143 	g_oRemora->CycleRemoraLogic(*state);
144 
145 	// Cycle the inventory logic if it is active.  Note though that the fact that the Remora is active does
146 	// not mean the inventory is, because there could be a gap between menus being displayed.
147 	if (g_oIconListManager->IsActive())
148 		g_oIconListManager->CycleInventoryLogic(*state);
149 
150 	return (IR_REPEAT);
151 }
152 
fn_remora_is_active(int32 & result,int32 *)153 mcodeFunctionReturnCodes _game_session::fn_remora_is_active(int32 &result, int32 *) {
154 	// Call the function that does the work.
155 	result = g_oRemora->IsActive();
156 
157 	// Calling script can continue.
158 	return (IR_CONT);
159 }
160 
fn_remora_get_mode(int32 & result,int32 *)161 mcodeFunctionReturnCodes _game_session::fn_remora_get_mode(int32 &result, int32 *) {
162 	// First check that the Remora is active.
163 	if (g_oRemora->IsActive())
164 		result = (int32)g_oRemora->GetMode();
165 	else
166 		result = REMORA_NOT_ACTIVE;
167 
168 	// Calling script can continue.
169 	return (IR_CONT);
170 }
171 
fn_remora_set_mode(int32 &,int32 * params)172 mcodeFunctionReturnCodes _game_session::fn_remora_set_mode(int32 &, int32 *params) {
173 	// Set the mode.
174 	g_oRemora->SetMode((_remora::RemoraMode)params[0]);
175 
176 	// Calling script can continue.
177 	return (IR_CONT);
178 }
179 
fn_remora_picture(int32 &,int32 * params)180 mcodeFunctionReturnCodes _game_session::fn_remora_picture(int32 &, int32 *params) {
181 	uint32 nXOffset;
182 
183 	const char *picture_name = (const char *)MemoryUtil::resolvePtr(params[2]);
184 
185 	// Write the call in the debug file.
186 	Zdebug("fn_remora_picture( %d, %d, %s )", (int32)params[0], (int32)params[1], picture_name);
187 
188 	// Neither can pixel offset.
189 	nXOffset = ((int32)params[1] < 0) ? 0 : (uint32)params[1];
190 
191 	// Make the call to the Remora.
192 	g_oRemora->SetupPicture(nXOffset, picture_name);
193 
194 	// Calling script can continue.
195 	return (IR_CONT);
196 }
197 
fn_remora_clear_screen(int32 &,int32 *)198 mcodeFunctionReturnCodes _game_session::fn_remora_clear_screen(int32 &, int32 *) {
199 	// Make the call to the Remora object.
200 	g_oRemora->ClearAllText();
201 
202 	// Calling script can continue.
203 	return (IR_CONT);
204 }
205 
fn_remora_add_icon(int32 &,int32 * params)206 mcodeFunctionReturnCodes _game_session::fn_remora_add_icon(int32 &, int32 *params) {
207 	char pcIconPath[ENGINE_STRING_LEN];
208 
209 	const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[0]);
210 
211 	// Make the call to the Remora object.
212 	g_oIconListManager->AddIconToList(ICON_LIST_REMORA, icon_name);
213 
214 	// Preload the icon for PSX smoothing.
215 	sprintf(pcIconPath, ICON_PATH);
216 	g_oIconMenu->PreloadIcon(pcIconPath, icon_name);
217 
218 	// Calling script can continue.
219 	return (IR_CONT);
220 }
221 
fn_remora_remove_icon(int32 &,int32 * params)222 mcodeFunctionReturnCodes _game_session::fn_remora_remove_icon(int32 &, int32 *params) {
223 	const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[0]);
224 
225 	// Make the call to the Remora object.
226 	g_oIconListManager->RemoveIconFromList(ICON_LIST_REMORA, icon_name);
227 
228 	// Calling script can continue.
229 	return (IR_CONT);
230 }
231 
fn_remora_reset_icon_list(int32 &,int32 *)232 mcodeFunctionReturnCodes _game_session::fn_remora_reset_icon_list(int32 &, int32 *) {
233 	// Make the call to the Remora object.
234 	g_oIconListManager->ResetList(ICON_LIST_REMORA);
235 
236 	// Calling script can continue.
237 	return (IR_CONT);
238 }
239 
fn_remora_choose(int32 &,int32 *)240 mcodeFunctionReturnCodes _game_session::fn_remora_choose(int32 &, int32 *) {
241 	// This function must be used from inside the Remora.
242 	if (!g_oRemora->IsActive())
243 		Fatal_error("fn_remora_choose() cannot be used outside the Remora");
244 
245 	// Make the call to the Remora object.
246 	g_oIconListManager->ActivateIconMenu(ICON_LIST_REMORA, TRUE8, FALSE8);
247 
248 	// Calling script can continue.
249 	return (IR_CONT);
250 }
251 
fn_remora_paragraph_text(int32 &,int32 * params)252 mcodeFunctionReturnCodes _game_session::fn_remora_paragraph_text(int32 &, int32 *params) {
253 	const char *pcText;
254 
255 	// Find the text in the resources.
256 	pcText = g_oRemora->LocateTextFromReference((uint32)params[1]);
257 
258 	if (pcText) {
259 		// Skip line numbers.
260 		pcText = SkipLineNumber(pcText);
261 
262 		// Set the text.
263 		g_oRemora->SetText(pcText, REMORA_TEXT_PARAGRAPH, 1, PIN_AT_TOP_LEFT);
264 	} else {
265 		// We failed to find it.
266 		Fatal_error("Unable to find text for reference %x in fn_remora_paragraph_text()", (uint32)params[1]);
267 	}
268 
269 	// Calling script can continue.
270 	return (IR_CONT);
271 }
272 
fn_remora_main_heading(int32 &,int32 * params)273 mcodeFunctionReturnCodes _game_session::fn_remora_main_heading(int32 &, int32 *params) {
274 	const char *pcText;
275 
276 	// Find the text in the resources.
277 	pcText = g_oRemora->LocateTextFromReference((uint32)params[0]);
278 
279 	if (pcText) {
280 		// Skip line numbers.
281 		pcText = SkipLineNumber(pcText);
282 
283 		// Set the text.
284 		g_oRemora->SetText(pcText, REMORA_TEXT_HEADING, 0, PIN_AT_CENTRE);
285 	} else {
286 		// We failed to find it.
287 		Fatal_error("Unable to find text for reference %x in fn_remora_main_heading()", (uint32)params[0]);
288 	}
289 
290 	// Calling script can continue.
291 	return (IR_CONT);
292 }
293 
fn_remora_sub_heading(int32 &,int32 * params)294 mcodeFunctionReturnCodes _game_session::fn_remora_sub_heading(int32 &, int32 *params) {
295 	const char *pcText;
296 
297 	// Find the text in the resources.
298 	pcText = g_oRemora->LocateTextFromReference((uint32)params[1]);
299 
300 	if (pcText) {
301 		// Skip line numbers.
302 		pcText = SkipLineNumber(pcText);
303 
304 		// Set the text.
305 		g_oRemora->SetText(pcText, REMORA_TEXT_HEADING, 0, PIN_AT_TOP_LEFT);
306 	} else {
307 		// We failed to find it.
308 		Fatal_error("Unable to find text for reference %x in fn_remora_sub_heading()", (uint32)params[1]);
309 	}
310 
311 	// Calling script can continue.
312 	return (IR_CONT);
313 }
314 
fn_remora_option_text(int32 &,int32 * params)315 mcodeFunctionReturnCodes _game_session::fn_remora_option_text(int32 &, int32 *params) {
316 	const char *pcText;
317 
318 	// Find the text in the resources.
319 	pcText = g_oRemora->LocateTextFromReference((uint32)params[1]);
320 
321 	if (pcText) {
322 		// Skip line numbers.
323 		pcText = SkipLineNumber(pcText);
324 
325 		// Set the text.
326 		g_oRemora->SetText(pcText, REMORA_TEXT_OPTION, 0, PIN_AT_TOP_LEFT);
327 	} else {
328 		// We failed to find it.
329 		Fatal_error("Unable to find text for reference %x in fn_remora_option_text()", (uint32)params[1]);
330 	}
331 
332 	// Calling script can continue.
333 	return (IR_CONT);
334 }
335 
fn_remora_warning_text(int32 &,int32 * params)336 mcodeFunctionReturnCodes _game_session::fn_remora_warning_text(int32 &, int32 *params) {
337 	const char *pcText;
338 
339 	// Find the text in the resources.
340 	pcText = g_oRemora->LocateTextFromReference((uint32)params[1]);
341 
342 	if (pcText) {
343 		// Skip line numbers.
344 		pcText = SkipLineNumber(pcText);
345 
346 		// Set the text.
347 		g_oRemora->SetText(pcText, REMORA_TEXT_WARNING, 0, PIN_AT_CENTRE);
348 	} else {
349 		// We failed to find it.
350 		Fatal_error("Unable to find text for reference %x in fn_remora_warning_text()", (uint32)params[1]);
351 	}
352 
353 	// Calling script can continue.
354 	return (IR_CONT);
355 }
356 
fn_remora_blank_line(int32 &,int32 *)357 mcodeFunctionReturnCodes _game_session::fn_remora_blank_line(int32 &, int32 *) {
358 	// Set the blank line.
359 	g_oRemora->SetText(NULL, 0, 0, PIN_AT_CENTRE);
360 
361 	// Calling script can continue.
362 	return (IR_CONT);
363 }
364 
fn_remora_progress_bar(int32 &,int32 * params)365 mcodeFunctionReturnCodes _game_session::fn_remora_progress_bar(int32 &, int32 *params) {
366 	int32 nTargetCycles;
367 	int32 nCurrentValue;
368 
369 	// Get cycles to run bar over.
370 	nTargetCycles = (int32)params[0];
371 
372 	// Is this a new bar?
373 	if (!L->looping) {
374 		// We are now doing a script loop.
375 		L->looping = TRUE8;
376 
377 		// Initially none of the bar is there.
378 		g_oRemora->SetProgressBarValue(0);
379 
380 		// Set target value for bar.
381 		g_oRemora->SetProgressBarTotal(nTargetCycles);
382 
383 		// And here I set a tri-state function control variable, to help with control.
384 		nFunctionState = 1;
385 
386 		// Come back to this function next time.
387 		return (IR_REPEAT);
388 	}
389 
390 	// Check if we are incrementing progress bar or holding it for a cycle at 100%.
391 	if (nFunctionState == 1) {
392 		// Still increasing it.  Get current bar position.
393 		nCurrentValue = g_oRemora->GetProgressBarValue();
394 
395 		// Update bar count.
396 		++nCurrentValue;
397 
398 		// Set current complete.
399 		g_oRemora->SetProgressBarValue(nCurrentValue);
400 
401 		// Check if done yet.
402 		if (nCurrentValue == nTargetCycles) {
403 			// Finished, but we want to come back and hold it for a cycle.
404 			nFunctionState = 2;
405 			return (IR_REPEAT);
406 		} else {
407 			// Return to increment the bar some more next time.
408 			return (IR_REPEAT);
409 		}
410 	} else {
411 		// Now we have really finished.
412 		L->looping = FALSE8;
413 		g_oRemora->SetProgressBarValue(-1);
414 		return (IR_CONT);
415 	}
416 }
417 
fn_remora_fix_motion_scan_xz(int32 &,int32 *)418 mcodeFunctionReturnCodes _game_session::fn_remora_fix_motion_scan_xz(int32 &, int32 *) {
419 	// Calling script can continue.
420 	return (IR_CONT);
421 }
422 
fn_remora_script_activate(int32 &,int32 * params)423 mcodeFunctionReturnCodes _game_session::fn_remora_script_activate(int32 &, int32 *params) {
424 	_input *psInputState;
425 
426 	// In case the script writer has forgotten to do it, drop any icon currently held.
427 	g_oIconListManager->Drop();
428 
429 	// This tells the UI that the Remora is now active.
430 	MS->player.Push_control_mode(ACTOR_RELATIVE);
431 	MS->player.Set_player_status(REMORA);
432 
433 	// This flag is used to indicate that the Remora has been activated in a specific mode (i.e. from script,
434 	// rather than the keyboard).  It is used to stop the Remora dropping into its default menu selection upon
435 	// activation; instead it will use the mode set here.
436 	g_oRemora->SetModeOverride((_remora::RemoraMode)params[0]);
437 
438 	// This sets a flag which the Remora will pick up next cycle.
439 	g_oRemora->ActivateRemora((_remora::RemoraMode)params[0]);
440 
441 	// Cycle the Remora's logic to make sure drawing code doesn't try to do a draw before the
442 	// Remora has had a chance to set itself up.
443 	MS->player.Update_input_state();
444 	psInputState = MS->player.Fetch_input_state();
445 	g_oRemora->CycleRemoraLogic(*psInputState);
446 
447 	// Stop key bounce.
448 	MS->player.remora_lock = TRUE8;
449 
450 	// Calling script can continue.
451 	return (IR_CONT);
452 }
453 
fn_remora_script_deactivate(int32 &,int32 *)454 mcodeFunctionReturnCodes _game_session::fn_remora_script_deactivate(int32 &, int32 *) {
455 	_input sInputState;
456 
457 	// Write the call in the debug files.
458 	Zdebug("fn_remora_script_deactivate();");
459 
460 	// If the Remora is not active then there is nothing to do.
461 	if (!g_oRemora->IsActive())
462 		return (IR_CONT);
463 
464 	// The script may be set up in such a way that the icon that was selected to cause this deactivate
465 	// to happen may not have cleared the currently-selected icon, so do it here to be safe.
466 	g_oIconListManager->Drop();
467 
468 	// Deactivate the Remora.
469 	g_oRemora->SetMode(_remora::MOTION_SCAN);
470 	g_oRemora->DeactivateRemora(TRUE8);
471 	sInputState.UnSetButton(__UNUSEDBUTTON);
472 	g_oRemora->CycleRemoraLogic(sInputState);
473 
474 	// This tells the UI that the Remora is now gone and the player is back.
475 	MS->player.Pop_control_mode();
476 
477 	logic_structs[player.Fetch_player_id()]->mega->weapon = __NOT_ARMED;
478 	logic_structs[player.Fetch_player_id()]->voxel_info->___init(logic_structs[player.Fetch_player_id()]->mega->chr_name,
479 	                                                             logic_structs[player.Fetch_player_id()]->mega->anim_set, __NOT_ARMED);
480 
481 	MS->player.Set_player_status(STOOD);
482 
483 	MS->Setup_prop_sleep_states(); // recompute prop sleep states once we leave remora
484 
485 	// Stop key bounce.
486 	MS->player.remora_lock = TRUE8;
487 
488 	// Calling script can continue.
489 	return (IR_CONT);
490 }
491 
fn_remora_default_logic(int32 &,int32 *)492 mcodeFunctionReturnCodes _game_session::fn_remora_default_logic(int32 &, int32 *) {
493 	// Check to see if we are already looping
494 	if (!L->looping) {
495 		// Mark the fact that we are now looping.
496 		L->looping = 1;
497 
498 		// Clear any events outstanding for the Remora.
499 		g_oEventManager->ClearAllEventsForObject(cur_id);
500 
501 		// Make sure there are no icons in the list for the Remora.
502 		g_oIconListManager->ResetList(ICON_LIST_REMORA);
503 
504 		// Make sure the Remora's screen is clear.
505 		g_oRemora->ClearAllText();
506 
507 		// Must call this function again.
508 		return (IR_REPEAT);
509 	} else {
510 		// We are looping in this function call.  Simply drop out if the Remora is not active.
511 		if (!g_oRemora->IsActive()) {
512 			// Remora not currently active.
513 			return (IR_REPEAT);
514 		} else {
515 			// Remora has been activated.  Either drop into the default menu mode, or do the one specified
516 			// by script if there is one.
517 			g_oRemora->SetDefaultOrOverrideMode();
518 
519 			// Make the Remora rerun its logic context.
520 			g_oEventManager->PostNamedEventToObject(EVENT_LOGIC_RERUN, cur_id, cur_id);
521 
522 			// We are not looping from now on.
523 			L->looping = 0;
524 
525 			// Calling script can continue now.
526 			return (IR_CONT);
527 		}
528 	}
529 
530 	// To fix a GCC compiler warning
531 	return (IR_REPEAT);
532 }
533 
fn_remora_new_menu(int32 &,int32 * params)534 mcodeFunctionReturnCodes _game_session::fn_remora_new_menu(int32 &, int32 *params) {
535 	// Set the variables so we jump to the right menu when we restart.
536 	g_oRemora->AccessMenuLevelVariables(params, _remora::SET);
537 
538 	// Jump.
539 	RemoraStandardRestart(cur_id);
540 
541 	// Calling script can continue.
542 	return (IR_CONT);
543 }
544 
fn_remora_new_menu_on_icon(int32 &,int32 * params)545 mcodeFunctionReturnCodes _game_session::fn_remora_new_menu_on_icon(int32 &, int32 *params) {
546 	const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[5]);
547 
548 	// Check to see if we are already looping
549 	if (!L->looping) {
550 		// Set the variables so we jump to the right menu when we restart.
551 		g_oRemora->AccessMenuLevelVariables(params, _remora::SET);
552 
553 		// Remove any icons from the icon list.
554 		g_oIconListManager->ResetList(ICON_LIST_REMORA);
555 
556 		// Add the given icon to the Remora icon list.
557 		g_oIconListManager->AddIconToList(ICON_LIST_REMORA, icon_name);
558 
559 		// Activate the chooser menu.
560 		g_oIconListManager->ActivateIconMenu(ICON_LIST_REMORA, TRUE8, FALSE8);
561 
562 		// Mark the fact that we are now looping.
563 		L->looping = 1;
564 
565 		// And here I set the tri-state function control variable, so we know which bit to run next.
566 		nFunctionState = 1;
567 
568 		// Drop out but call this function again next time.
569 		return (IR_REPEAT);
570 	} else {
571 		// We are looping on this function.  The set-up part must already have been done.  But the function has
572 		// two subsequent states.  See which one we're on.
573 		if (nFunctionState == 1) {
574 			// We are looping on this function.  The set-up part must already have been done.
575 			// Check for the icon being selected.
576 			if (g_oIconListManager->ItemHeld() && g_oIconListManager->Holding(icon_name)) {
577 				// Drop the item held.
578 				g_oIconListManager->Drop();
579 
580 				// Cord speaks his instructions to the Remora.
581 				g_oRemora->DisplayCharacterSpeech((uint32)params[6]);
582 
583 				// We are now moving to a new state in this function.
584 				nFunctionState = 2;
585 				return (IR_REPEAT);
586 			} else {
587 				// Icon has not been selected, so we need to come back to this function.
588 				return (IR_REPEAT);
589 			}
590 		} else {
591 			// Second stage of this function now: displaying mega speech.
592 			if (g_oRemora->GetSpeechTimer() == 0) {
593 				// Do the Remora script jump.
594 				RemoraStandardRestart(cur_id);
595 
596 				// Allow calling script to continue.
597 				nFunctionState = 0;
598 				L->looping = 0;
599 				return (IR_CONT);
600 			} else {
601 				// The speech hasn't been displayed long enough, so hold inside this fn_function().
602 				return (IR_REPEAT);
603 			}
604 		}
605 	}
606 }
607 
fn_remora_wait_on_icon(int32 &,int32 * params)608 mcodeFunctionReturnCodes _game_session::fn_remora_wait_on_icon(int32 &, int32 *params) {
609 	const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[0]);
610 
611 	// Check to see if we are already looping
612 	if (!L->looping) {
613 		// Remove any icons from the icon list.
614 		g_oIconListManager->ResetList(ICON_LIST_REMORA);
615 
616 		// Add the given icon to the Remora icon list.
617 		g_oIconListManager->AddIconToList(ICON_LIST_REMORA, icon_name);
618 
619 		// Activate the chooser menu.
620 		g_oIconListManager->ActivateIconMenu(ICON_LIST_REMORA, TRUE8, FALSE8);
621 
622 		// Mark the fact that we are now looping.
623 		L->looping = 1;
624 
625 		// And here I set the tri-state function control variable, so we know which bit to run next.
626 		nFunctionState = 1;
627 
628 		// Drop out but call this function again next time.
629 		return (IR_REPEAT);
630 	} else {
631 		// We are looping on this function.  The set-up part must already have been done.  But the function has
632 		// two subsequent states.  See which one we're on.
633 		if (nFunctionState == 1) {
634 			if (g_oIconListManager->ItemHeld() && g_oIconListManager->Holding(icon_name)) {
635 				// Yes, user has selected the icon to start a new mode.  First drop item held.
636 				g_oIconListManager->Drop();
637 
638 				// Cord speaks his instructions to the Remora.
639 				g_oRemora->DisplayCharacterSpeech((uint32)params[2]);
640 
641 				// We are now moving to a new state in this function.
642 				nFunctionState = 2;
643 
644 				// Drop out but call this function again next time.
645 				return (IR_REPEAT);
646 			} else {
647 				// Drop out but call this function again next time.
648 				return (IR_REPEAT);
649 			}
650 		} else {
651 			// Second stage of this function now: displaying mega speech.
652 			if (g_oRemora->GetSpeechTimer() == 0) {
653 				// Do the Remora new mode.
654 				g_oRemora->SetMode((_remora::RemoraMode)params[1]);
655 				RemoraStandardRestart(cur_id);
656 
657 				// Allow calling script to continue.
658 				nFunctionState = 0;
659 				L->looping = 0;
660 				return (IR_CONT);
661 			} else {
662 				// The speech hasn't been displayed long enough, so hold inside this fn_function().
663 				return (IR_REPEAT);
664 			}
665 		}
666 	}
667 }
668 
fn_remora_menu_return(int32 &,int32 * params)669 mcodeFunctionReturnCodes _game_session::fn_remora_menu_return(int32 &, int32 *params) {
670 	int32 i;
671 	uint32 nReturned;
672 	int32 pnMenuVariables[REMORA_MENU_DEPTH];
673 
674 	// Get the current state of the menu variables.
675 	g_oRemora->AccessMenuLevelVariables(pnMenuVariables, _remora::GET);
676 
677 	// Find out how deep we are already in the menu tree.
678 	i = REMORA_MENU_DEPTH - 1;
679 	while ((i >= 0) && (pnMenuVariables[i] == 0))
680 		--i;
681 
682 	// If we ran off the end then we are already at the root, but there is little value in making this an error.
683 	if (i < 0)
684 		return (IR_CONT);
685 
686 	// We are at a certain depth in the menu tree, so back up the required amount.  If we run off the end,
687 	// this means user has requested to go back more levels than we are deep, but just ignore this.
688 	nReturned = 0;
689 	while ((i >= 0) && (nReturned < (uint32)params[0])) {
690 		pnMenuVariables[i] = 0;
691 		--i;
692 		++nReturned;
693 	}
694 
695 	// Put the new values back in the script object.
696 	g_oRemora->AccessMenuLevelVariables(pnMenuVariables, _remora::SET);
697 
698 	// Jump.
699 	RemoraStandardRestart(cur_id);
700 
701 	// Allow calling script to continue.
702 	return (IR_CONT);
703 
704 }
705 
fn_remora_menu_return_on_icon(int32 &,int32 * params)706 mcodeFunctionReturnCodes _game_session::fn_remora_menu_return_on_icon(int32 &, int32 *params) {
707 	int32 i;
708 	uint32 nReturned;
709 	int32 pnMenuVariables[REMORA_MENU_DEPTH];
710 
711 	const char *icon_name = (const char *)MemoryUtil::resolvePtr(params[1]);
712 
713 	// Check to see if we are already looping
714 	if (!L->looping) {
715 		// First time in, so display the icon.
716 		g_oIconListManager->ResetList(ICON_LIST_REMORA);
717 		g_oIconListManager->AddIconToList(ICON_LIST_REMORA, icon_name);
718 		g_oIconListManager->ActivateIconMenu(ICON_LIST_REMORA, TRUE8, FALSE8);
719 
720 		// Mark the fact that we are now looping.
721 		L->looping = 1;
722 
723 		// And here I set the tri-state function control variable, so we know which bit to run next.
724 		nFunctionState = 1;
725 
726 		// Drop out but call this function again next time.
727 		return (IR_REPEAT);
728 	} else {
729 		// We are looping on this function.  The set-up part must already have been done.  But the function has
730 		// two subsequent states.  See which one we're on.
731 		if (nFunctionState == 1) {
732 			if (g_oIconListManager->ItemHeld() && g_oIconListManager->Holding(icon_name)) {
733 				// Clear the item held.
734 				g_oIconListManager->Drop();
735 
736 				// Remove any icons from the icon list.
737 				g_oIconListManager->ResetList(ICON_LIST_REMORA);
738 
739 				// Icon has been selected, so we are going to do the jump back up the menu tree.  Get
740 				// current state of the menu variables.
741 				g_oRemora->AccessMenuLevelVariables(pnMenuVariables, _remora::GET);
742 
743 				// Find out how deep we are already in the menu tree.
744 				i = REMORA_MENU_DEPTH - 1;
745 				while ((i >= 0) && (pnMenuVariables[i] == 0))
746 					--i;
747 
748 				// If we ran off the end then we are already at the root, but there is no value in
749 				// making this an error.
750 				if (i >= 0) {
751 					// We are at a certain depth in the menu tree, so back up the required amount.  If we run off the
752 					// end,
753 					// this means user has requested to go back more levels than we are deep, but just ignore this.
754 					nReturned = 0;
755 					while ((i >= 0) && (nReturned < (uint32)params[0])) {
756 						pnMenuVariables[i] = 0;
757 						--i;
758 						++nReturned;
759 					}
760 				}
761 
762 				// Put the new values back in the script object.
763 				g_oRemora->AccessMenuLevelVariables(pnMenuVariables, _remora::SET);
764 
765 				// Display what Cord needs to say.
766 				g_oRemora->DisplayCharacterSpeech((uint32)params[2]);
767 
768 				// We are now moving to a new state in this function.
769 				nFunctionState = 2;
770 
771 				// Drop out but call this function again next time.
772 				return (IR_REPEAT);
773 			} else {
774 				// Icon has not been chosen, so call this function again next time.
775 				return (IR_REPEAT);
776 			}
777 		} else {
778 			// Second stage of this function now: displaying mega speech.
779 			if (g_oRemora->GetSpeechTimer() == 0) {
780 				// Do the Remora script jump.
781 				RemoraStandardRestart(cur_id);
782 
783 				// Allow calling script to continue.
784 				nFunctionState = 0;
785 				L->looping = 0;
786 				return (IR_CONT);
787 			} else {
788 				// The speech hasn't been displayed long enough, so hold inside this fn_function().
789 				return (IR_REPEAT);
790 			}
791 		}
792 	}
793 }
794 
fn_remora_mega_says(int32 &,int32 * params)795 mcodeFunctionReturnCodes _game_session::fn_remora_mega_says(int32 &, int32 *params) {
796 	// Check to see if we are already looping
797 	if (!L->looping) {
798 		// Mark the fact that we are now looping.
799 		L->looping = 1;
800 
801 		// Find the text in the resources.
802 		g_oRemora->DisplayCharacterSpeech((uint32)params[1]);
803 
804 		// Drop out but call this function again next time.
805 		return (IR_REPEAT);
806 	} else {
807 		// Get the speech timer.  If it has run down to zero, the supplied line has been displayed long enough,
808 		// so we can go on to the next line of script.
809 		if (g_oRemora->GetSpeechTimer() == 0) {
810 			// Allow calling script to continue.
811 			L->looping = 0;
812 			return (IR_CONT);
813 		}
814 
815 		// The speech hasn't been displayed long enough, so hold inside this fn_function().
816 		return (IR_REPEAT);
817 	}
818 }
819 
fn_remora_add_floor_range(int32 &,int32 * params)820 mcodeFunctionReturnCodes _game_session::fn_remora_add_floor_range(int32 &, int32 *params) {
821 	// Simply pass the call on to the Remora.
822 	g_oRemora->AddFloorRange((uint32)params[0], (uint32)params[1]);
823 
824 	// Calling script can continue.
825 	return (IR_CONT);
826 }
827 
fn_remora_reset_floor_ranges(int32 &,int32 *)828 mcodeFunctionReturnCodes _game_session::fn_remora_reset_floor_ranges(int32 &, int32 *) {
829 	// Simply pass the call on to the Remora.
830 	g_oRemora->ResetFloorRanges();
831 
832 	// Calling script can continue.
833 	return (IR_CONT);
834 }
835 
fn_remora_send_email(int32 &,int32 * params)836 mcodeFunctionReturnCodes _game_session::fn_remora_send_email(int32 &, int32 *params) {
837 	const char *email_id = (const char *)MemoryUtil::resolvePtr(params[0]);
838 
839 	// Set the email in the Remora.
840 	g_oRemora->NewEmail(email_id);
841 
842 	// Here we borrow the logic in the icon menu which flashes added medipacks etc.
843 	g_oIconListManager->SetEmailArrived();
844 
845 	// Calling script can continue.
846 	return (IR_CONT);
847 }
848 
fn_remora_is_email_waiting(int32 & result,int32 *)849 mcodeFunctionReturnCodes _game_session::fn_remora_is_email_waiting(int32 &result, int32 *) {
850 	// Make the call to the Remora.
851 	result = (int32)g_oRemora->IsEmailWaiting();
852 
853 	// Calling script can continue.
854 	return (IR_CONT);
855 }
856 
fn_remora_check_email_id(int32 & result,int32 * params)857 mcodeFunctionReturnCodes _game_session::fn_remora_check_email_id(int32 &result, int32 *params) {
858 	const char *email_id = (const char *)MemoryUtil::resolvePtr(params[0]);
859 
860 	// Check with the Remora if the string matches.
861 	result = g_oRemora->IsThisEmailWaiting(email_id);
862 
863 	// Calling script can continue.
864 	return (IR_CONT);
865 }
866 
fn_remora_mark_email_read(int32 &,int32 *)867 mcodeFunctionReturnCodes _game_session::fn_remora_mark_email_read(int32 &, int32 *) {
868 	// Turn off the email-waiting flag in the Remora.
869 	g_oRemora->MarkEmailRead();
870 
871 	// Calling script can continue.
872 	return (IR_CONT);
873 }
874 
fn_remora_set_max_zoom(int32 &,int32 * params)875 mcodeFunctionReturnCodes _game_session::fn_remora_set_max_zoom(int32 &, int32 *params) {
876 	// Call the Remora function to do it.
877 	g_oRemora->SetMaximumZoom((uint32)params[0]);
878 
879 	// Calling script can continue.
880 	return (IR_CONT);
881 }
882 
fn_remora_set_min_zoom(int32 &,int32 * params)883 mcodeFunctionReturnCodes _game_session::fn_remora_set_min_zoom(int32 &, int32 *params) {
884 	// Call the Remora function to do it.
885 	g_oRemora->SetMinimumZoom((uint32)params[0]);
886 
887 	// Calling script can continue.
888 	return (IR_CONT);
889 }
890 
fn_remora_set_current_zoom(int32 &,int32 * params)891 mcodeFunctionReturnCodes _game_session::fn_remora_set_current_zoom(int32 &, int32 *params) {
892 	// Call the Remora function to do it.
893 	g_oRemora->SetCurrentZoom((uint32)params[0]);
894 
895 	// Calling script can continue.
896 	return (IR_CONT);
897 }
898 
fn_remora_emp_flash(int32 &,int32 *)899 mcodeFunctionReturnCodes _game_session::fn_remora_emp_flash(int32 &, int32 *) {
900 	// If the Remora is not active, just ignore this function.
901 	if (g_oRemora->IsActive()) {
902 		// Check to see if we are already looping
903 		if (!L->looping) {
904 			// Mark the fact that we are now looping.
905 			L->looping = 1;
906 		}
907 
908 		// See if the EMP effect is still running or not.
909 		if (g_oRemora->EMPEffect()) {
910 			// Menu still active, so we must continue cycling its logic next time through.
911 			return (IR_REPEAT);
912 		} else {
913 			// A selection has been made or the menu has been cancelled.  Calling script can now continue.
914 			L->looping = 0;
915 			return (IR_CONT);
916 		}
917 	}
918 
919 	// Calling script can continue.
920 	return (IR_CONT);
921 }
922 
fn_remora_set_map_knowledge_level(int32 &,int32 *)923 mcodeFunctionReturnCodes _game_session::fn_remora_set_map_knowledge_level(int32 &, int32 * /*params*/) {
924 	// Calling script can continue.
925 	return (IR_CONT);
926 }
927 
RemoraStandardRestart(uint32 nRemoraID)928 void RemoraStandardRestart(uint32 nRemoraID) {
929 	// Clear the item held if any.
930 	g_oIconListManager->Drop();
931 
932 	// This blockRemove any icons from the icon list.
933 	g_oIconListManager->ResetList(ICON_LIST_REMORA);
934 
935 	// Clear all text.
936 	g_oRemora->ClearAllText();
937 
938 	MS->logic_structs[nRemoraID]->context_request = TRUE8;
939 }
940 
SkipLineNumber(const char * pcLine)941 const char *SkipLineNumber(const char *pcLine) {
942 	const char *pcParsePos;
943 
944 	// If line number display is turned on, don't do anything.
945 	if (g_px->speechLineNumbers)
946 		return (pcLine);
947 
948 	// Initialise parse pointer.
949 	pcParsePos = pcLine;
950 
951 	// If the first character is one that marks the line as being spoken or not, skip it.
952 	if ((*pcParsePos == TS_SPOKEN_LINE) || (*pcParsePos == TS_NON_SPOKEN_LINE))
953 		++pcParsePos;
954 
955 	// The first character has to start the line number to be valid.
956 	if (*pcParsePos == TS_LINENO_OPEN) {
957 		// Okay, we appear to have a legal line number.  Find the close brace for it.
958 		while ((*pcParsePos != '\0') && (*pcParsePos != TS_LINENO_CLOSE))
959 			++pcParsePos;
960 
961 		// If we didn't find one then this is an error.
962 		if (*pcParsePos == '\0')
963 			Fatal_error("Failed to find the end of the line number in [%s]", pcLine);
964 
965 		// Skip to first non-space after the line number.
966 		++pcParsePos;
967 		while ((*pcParsePos != '\0') && (*pcParsePos == ' '))
968 			++pcParsePos;
969 
970 		// If we got to the end of the string then we have a line number with no text following it.
971 		if (*pcParsePos == '\0')
972 			Fatal_error("Found line number [%s] with no text in SkipLineNumber()", pcLine);
973 
974 		// Write the modified pointer back into the text block.
975 		return (pcParsePos);
976 	} else {
977 		// No line number so nothing to chop off.
978 		return (pcParsePos);
979 	}
980 }
981 
982 } // End of namespace ICB
983