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