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_common.h"
29 #include "engines/icb/debug.h"
30 #include "engines/icb/p4_generic.h"
31 #include "engines/icb/p4_generic.h"
32 #include "engines/icb/common/px_common.h"
33 #include "engines/icb/common/px_scriptengine.h"
34 #include "engines/icb/common/px_game_object.h"
35 #include "engines/icb/common/ptr_util.h"
36 #include "engines/icb/mission.h"
37 #include "engines/icb/session.h"
38 #include "engines/icb/global_objects.h"
39 #include "engines/icb/object_structs.h"
40 #include "engines/icb/res_man.h"
41 #include "engines/icb/light.h"
42 
43 namespace ICB {
44 
fn_get_weapon(int32 & result,int32 * params)45 mcodeFunctionReturnCodes fn_get_weapon(int32 &result, int32 *params) { return (MS->fn_get_weapon(result, params)); }
46 
fn_pass_flag_to_engine(int32 & result,int32 * params)47 mcodeFunctionReturnCodes fn_pass_flag_to_engine(int32 &result, int32 *params) { return (MS->fn_pass_flag_to_engine(result, params)); }
48 
fn_restart_object(int32 & result,int32 * params)49 mcodeFunctionReturnCodes fn_restart_object(int32 &result, int32 *params) { return (MS->fn_restart_object(result, params)); }
50 
fn_get_persons_weapon(int32 & result,int32 * params)51 mcodeFunctionReturnCodes fn_get_persons_weapon(int32 &result, int32 *params) { return (MS->fn_get_persons_weapon(result, params)); }
52 
fn_kill_me(int32 & result,int32 * params)53 mcodeFunctionReturnCodes fn_kill_me(int32 &result, int32 *params) { return (MS->fn_kill_me(result, params)); }
54 
fn_kill_object(int32 & result,int32 * params)55 mcodeFunctionReturnCodes fn_kill_object(int32 &result, int32 *params) { return (MS->fn_kill_object(result, params)); }
56 
fn_new_script(int32 & result,int32 * params)57 mcodeFunctionReturnCodes fn_new_script(int32 &result, int32 *params) { return (MS->fn_new_script(result, params)); }
58 
fn_gosub(int32 & result,int32 * params)59 mcodeFunctionReturnCodes fn_gosub(int32 &result, int32 *params) { return (MS->fn_gosub(result, params)); }
60 
fn_set_to_exlusive_coords(int32 & result,int32 * params)61 mcodeFunctionReturnCodes fn_set_to_exlusive_coords(int32 &result, int32 *params) { return (MS->fn_set_to_exlusive_coords(result, params)); }
62 
fn_object_rerun_logic_context(int32 & result,int32 * params)63 mcodeFunctionReturnCodes fn_object_rerun_logic_context(int32 &result, int32 *params) { return (MS->fn_object_rerun_logic_context(result, params)); }
64 
fn_set_strike_overide(int32 & result,int32 * params)65 mcodeFunctionReturnCodes fn_set_strike_overide(int32 &result, int32 *params) { return (MS->fn_set_strike_overide(result, params)); }
66 
fn_set_shoot_overide(int32 & result,int32 * params)67 mcodeFunctionReturnCodes fn_set_shoot_overide(int32 &result, int32 *params) { return (MS->fn_set_shoot_overide(result, params)); }
68 
fn_is_player_running(int32 & result,int32 * params)69 mcodeFunctionReturnCodes fn_is_player_running(int32 &result, int32 *params) { return (MS->fn_is_player_running(result, params)); }
70 
fn_is_player_walking(int32 & result,int32 * params)71 mcodeFunctionReturnCodes fn_is_player_walking(int32 &result, int32 *params) { return (MS->fn_is_player_walking(result, params)); }
72 
fn_set_dynamic_light(int32 & result,int32 * params)73 mcodeFunctionReturnCodes fn_set_dynamic_light(int32 &result, int32 *params) { return (MS->fn_set_dynamic_light(result, params)); }
74 
speak_set_dynamic_light(int32 & result,int32 * params)75 mcodeFunctionReturnCodes speak_set_dynamic_light(int32 &result, int32 *params) { return (MS->speak_set_dynamic_light(result, params)); }
76 
fn_activate_sparkle(int32 & result,int32 * params)77 mcodeFunctionReturnCodes fn_activate_sparkle(int32 &result, int32 *params) { return (MS->fn_activate_sparkle(result, params)); }
78 
fn_deactivate_sparkle(int32 & result,int32 * params)79 mcodeFunctionReturnCodes fn_deactivate_sparkle(int32 &result, int32 *params) { return (MS->fn_deactivate_sparkle(result, params)); }
80 
81 // fn_activate_sparkle(x,y,z);
fn_activate_sparkle(int32 &,int32 * params)82 mcodeFunctionReturnCodes _game_session::fn_activate_sparkle(int32 &, int32 *params) {
83 	PXreal rx, ry, rz;
84 
85 	L->GetPosition(rx, ry, rz);
86 
87 	int32 x, y, z;
88 	x = (int32)rx;
89 	y = (int32)ry;
90 	z = (int32)rz;
91 
92 	L->sparkleX = (int16)(params[0] - x);
93 	L->sparkleY = (int16)(params[1] - y);
94 	L->sparkleZ = (int16)(params[2] - z);
95 
96 	L->sparkleOn = TRUE8;
97 
98 	return IR_CONT;
99 }
100 
101 // fn_deactivate_sparkle(x,y,z);
fn_deactivate_sparkle(int32 &,int32 *)102 mcodeFunctionReturnCodes _game_session::fn_deactivate_sparkle(int32 &, int32 *) {
103 	L->sparkleOn = FALSE8;
104 
105 	return IR_CONT;
106 }
107 
108 // these are the con and des-tructors for the game object objects
109 // they are homeless and so stay here
___init(const char * name)110 void _logic::___init(const char *name) {
111 	int32 j;
112 
113 	// set objects name
114 	Set_string(name, ob_name);
115 
116 	// This object is active
117 	ob_status = OB_STATUS_NOT_HELD;
118 
119 	// give full run rights
120 	big_mode = __SCRIPT;
121 
122 	// clear the pointer to the voxel object specific structure
123 	// if these are NULL then the object is non mega
124 	voxel_info = NULL;
125 	mega = NULL; // clear mega info
126 
127 	// defaults to a prop
128 	image_type = PROP;
129 
130 	// defaults to no-type-set
131 	object_type = __NO_TYPE_SET;
132 
133 	// defaults to responding to events, LOS etc.
134 	do_not_disturb = FALSE8;
135 
136 	// set crude switch to off
137 	context_request = FALSE8;
138 
139 	// this is important - reset the looping flag
140 	looping = 0;
141 	pause = 0;
142 
143 	// an object must register itself for interaction
144 	player_can_interact = FALSE8;
145 
146 	// reset pan adjust value
147 	pan_adjust = ZERO_TURN;
148 
149 	// reset auto pan stuff
150 	auto_display_pan = ZERO_TURN;
151 	auto_panning = FALSE8;
152 
153 	// clear the logic tree
154 	for (j = 0; j < TREE_SIZE; j++) {
155 		logic[j] = 0;
156 		logic_ref[j] = 0;
157 	}
158 
159 	// set owner rect to something safe - for fn_on_screen calls by props
160 	owner_floor_rect = 0;
161 
162 	cur_anim_type = __NO_ANIM;
163 
164 	// reset the custom script list to 0 items
165 	total_list = 0;
166 
167 	// defualt to tight pan interact type
168 	three_sixty_interact = FALSE8;
169 
170 	// defaul to no prop coords set
171 	prop_coords_set = FALSE8;
172 
173 	// not in a conversation
174 	conversation_uid = NO_SPEECH_REQUEST;
175 
176 	// height is straight ahead...
177 	look_height = -1;
178 
179 	// logic culling
180 	hold_mode = none;
181 	camera_held = FALSE8;
182 
183 	// all sound effects to default
184 	sfxVars[0] = sfxVars[1] = sfxVars[2] = 0;
185 
186 	// sparkle off by default
187 	sparkleOn = FALSE8;
188 }
189 
___init()190 void _mega::___init() {
191 	// need to reset target_pan in the same way as we need to reset looping in _logic()
192 	auto_target_pan = ZERO_TURN; // auto target
193 
194 	target_pan = ZERO_TURN; // reset turn-on-spot-to pan
195 	cur_parent = NULL;
196 	cur_slice = 0;
197 	number_of_barriers = 0;  // number of local barriers associated with mega position
198 	number_of_nudge = 0;     // number of local barriers associated with mega position
199 	number_of_animating = 0; // animating barriers
200 	target_id = 0;
201 	interacting = FALSE8;
202 
203 	// set some chr$ defaults
204 	weapon = __NOT_SET;
205 	motion = __MOTION_WALK;
206 	custom = FALSE8;
207 	has_exclusive_coords = FALSE8; // cord and chi may overide this
208 	is_evil = FALSE8;
209 	make_remora_beep = FALSE8;
210 	m_phase = 0;
211 
212 	m_main_route.total_points = 0; // final route size
213 	m_main_route.diag_bars = 0;
214 	m_main_route.number_of_diag_bars = 0;
215 
216 	use_strike_script = 0;
217 	use_fire_script = 0;
218 	on_players_floor = FALSE8;
219 	anim_speed = 1;
220 	pushed = 0; // coords not pushed
221 	reverse_route = 0;
222 
223 	// Set a default speech colour for megas.
224 	speech_red = 0;
225 	speech_green = 230;
226 	speech_blue = 230;
227 
228 	next_anim_type = __NO_ANIM;
229 
230 	// initialise the dynamic light...
231 	InitDynamicLight();
232 
233 	// Not currently shooting
234 	is_shooting = FALSE8;
235 	drawShadow = TRUE8; // shadows on
236 
237 	// async
238 	asyncing = 0;       // not loading file
239 	async_list_pos = 0; // start of list
240 	async_weapon = __NOT_SET;
241 
242 	// generic stair info for shadow correction
243 	on_stairs = TRUE8;
244 
245 	inShadePercentage = DEFAULT_INSHADE_PERCENTAGE; // default shade value
246 
247 	// footstep stuff
248 	footstep_status = 0;       // current foot left/right status...
249 	footstep_weight = 100;     // weight of footstep (100 is Cord) 255 maximum...
250 	footstep_special = FALSE8; // whether special or not...
251 
252 	// default router extrapolation size
253 	extrap_size = 25;
254 
255 	// set to draw
256 	display_me = TRUE8;
257 
258 	dead = FALSE8; // still alive!
259 
260 	// camera control
261 	y_locked = FALSE8;
262 
263 	// breath off as default
264 	breath.on = 0;
265 }
266 
fn_set_to_exlusive_coords(int32 &,int32 *)267 mcodeFunctionReturnCodes _game_session::fn_set_to_exlusive_coords(int32 &, int32 *) {
268 	if (!logic_structs[cur_id]->mega)
269 		Fatal_error("terminal misuse of fn_set_to_exclusive_coords");
270 
271 	logic_structs[cur_id]->mega->has_exclusive_coords = TRUE8;
272 
273 	return IR_CONT;
274 }
275 
fn_get_persons_weapon(int32 & result,int32 * params)276 mcodeFunctionReturnCodes _game_session::fn_get_persons_weapon(int32 &result, int32 *params) {
277 	// return the weapon type to the script
278 
279 	// params        0   name of mega
280 
281 	uint32 id;
282 
283 	const char *mega_name = (const char *)MemoryUtil::resolvePtr(params[0]);
284 
285 	id = objects->Fetch_item_number_by_name(mega_name);
286 	if (id == 0xffffffff)
287 		Fatal_error("fn_get_persons_weapon: object [%s] does not exist", mega_name);
288 
289 	if (!logic_structs[id]->mega)
290 		Fatal_error("fn_get_persons_weapon: object [%s] not a mega", mega_name);
291 
292 	result = logic_structs[id]->mega->Fetch_armed_status();
293 
294 	return (IR_CONT);
295 }
296 
fn_get_weapon(int32 & result,int32 *)297 mcodeFunctionReturnCodes _game_session::fn_get_weapon(int32 &result, int32 *) {
298 	// return the weapon type to the script
299 	// no params
300 
301 	result = Fetch_cur_megas_armed_status();
302 
303 	return (IR_CONT);
304 }
305 
fn_is_player_running(int32 & result,int32 *)306 mcodeFunctionReturnCodes _game_session::fn_is_player_running(int32 &result, int32 *) {
307 	if (player.player_status == RUNNING)
308 		result = 1;
309 	else
310 		result = 0;
311 
312 	return IR_CONT;
313 }
314 
fn_is_player_walking(int32 & result,int32 *)315 mcodeFunctionReturnCodes _game_session::fn_is_player_walking(int32 &result, int32 *) {
316 	if (player.player_status == WALKING)
317 		result = 1;
318 	else
319 		result = 0;
320 
321 	return IR_CONT;
322 }
323 
Fetch_cur_megas_armed_status()324 bool8 _game_session::Fetch_cur_megas_armed_status() {
325 	// return a megas armed status
326 
327 	if (!M)
328 		Fatal_error("%d not a mega but called Fetch_megas_weapon_type", cur_id);
329 
330 	return (M->Fetch_armed_status());
331 }
332 
Fetch_cur_megas_pose()333 __weapon _game_session::Fetch_cur_megas_pose() {
334 	// return a megas weapon type - can be called from outside of _game_session
335 
336 	if (!M)
337 		Fatal_error("%d not a mega but called Fetch_megas_weapon_type", cur_id);
338 
339 	return (M->Fetch_pose());
340 }
341 
Fetch_cur_megas_custom_text()342 const char *_game_session::Fetch_cur_megas_custom_text() {
343 	// return pointer to megas custom ascii - mine, object, etc
344 
345 	if (!M)
346 		Fatal_error("%d not a mega but called Fetch_megas_weapon_type", cur_id);
347 
348 	return (M->custom_set);
349 }
350 
Fetch_custom()351 bool8 _game_session::Fetch_custom() {
352 	// return a megas weapon type - can be called from outside of _game_session
353 
354 	if (!M)
355 		Fatal_error("%d not a mega but called Fetch_cur_megas_custom_type", cur_id);
356 
357 	return (M->Fetch_custom());
358 }
359 
Fetch_custom(void)360 bool8 _mega::Fetch_custom(void) {
361 	// return custom anim type from _mega struct
362 
363 	return (custom);
364 }
365 
Reset_cur_megas_custom_type()366 void _game_session::Reset_cur_megas_custom_type() {
367 	// resets to __NONE the current custom type
368 	// this is probably desireable and will save scripters doing it - or not and forgetting
369 
370 	if (!M)
371 		Fatal_error("%d not a mega but called Reset_cur_megas_custom_type", cur_id);
372 
373 	M->custom = FALSE8; //__NONE;
374 }
375 
Fetch_armed_status()376 bool8 _mega::Fetch_armed_status() {
377 	// return weapon type from _mega struct
378 	// see also _game_session::Fetch_cur_megas_weapon_type
379 
380 	return (armed_state_table[weapon]);
381 }
382 
Is_crouched(void)383 bool8 _mega::Is_crouched(void) {
384 	// is the mega croucing - called by LOS
385 
386 	return (crouch_state_table[weapon]);
387 }
388 
Fetch_pose(void)389 __weapon _mega::Fetch_pose(void) {
390 	// fetch custume subset - i.e crouch, crouch_gun, unarmed, etc.
391 
392 	return (weapon);
393 }
394 
Set_script(const char * script_name)395 void _game_session::Set_script(const char *script_name) {
396 	// set the script on the current level
397 	char *ad;
398 
399 	ad = (char *)scripts->Fetch_item_by_name(script_name);
400 
401 	L->logic[L->logic_level] = ad;
402 
403 	// write reference for change script checks later - i.e. FN_context_chosen_script
404 	L->logic_ref[L->logic_level] = ad;
405 }
406 
Context_check(uint32 script_name)407 void _game_session::Context_check(uint32 script_name) {
408 	// we have been passed a script name - we need to check if this script is the same or
409 	// different from the one currently running on logic level 1. If the same then we do
410 	// nothing. If different then we set the level 1 logic to this new script
411 
412 	char *ad;
413 
414 	Zdebug("context check");
415 
416 	ad = (char *)scripts->Try_fetch_item_by_hash(script_name);
417 
418 	Zdebug("context_check ad=%d ref=%d", ad, L->logic_ref[1]);
419 
420 	if (L->logic_ref[1] != ad) {
421 		// write actual offset
422 		L->logic[1] = ad;
423 
424 		// write reference for change script checks later - i.e. FN_context_chosen_script
425 		L->logic_ref[1] = ad;
426 
427 		L->logic_level = 1; // reset to level 1
428 
429 		L->looping = 0; // reset the logic state flag
430 
431 		if (L->mega)
432 			M->custom = FALSE8; // reset
433 
434 		L->pause = 0;
435 	}
436 }
437 
fn_context_chosen_logic(int32 & result,int32 * params)438 mcodeFunctionReturnCodes fn_context_chosen_logic(int32 &result, int32 *params) {
439 	// the logic context script has chosen a logic to set up but we do nothing if the script is running already
440 	// this function is used for an immediate logic change - i.e. it wont wait for animations to finish first
441 
442 	//	params[0]    ascii name of new script
443 
444 	return (MS->fn_context_chosen_logic(result, params));
445 }
446 
fn_context_chosen_logic(int32 &,int32 * params)447 mcodeFunctionReturnCodes _game_session::fn_context_chosen_logic(int32 &, int32 *params) {
448 	// pass the (hashed) name
449 	Context_check(params[0]); // now # number
450 
451 	return (IR_TERMINATE); // get us back
452 }
453 
Shut_down_object()454 void _game_session::Shut_down_object() {
455 	// lock out an object
456 
457 	// Tell the event manager to stop handling events for this object.  [PS 09/12/98]
458 	g_oEventManager->ShutDownEventProcessingForObject(cur_id);
459 
460 	logic_structs[cur_id]->ob_status = OB_STATUS_HELD; // lock out
461 
462 	prop_state_table[cur_id] = 0; // set to state 0 - in case killed because of illegal frame
463 
464 	Tdebug("objects_that_died.txt", "**OBJECT '%s' [id=%d] has been shut down**", object->GetName(), cur_id);
465 }
466 
fn_kill_me(int32 &,int32 *)467 mcodeFunctionReturnCodes _game_session::fn_kill_me(int32 &, int32 *) {
468 	// kill this object
469 
470 	Shut_down_object("fn_kill_me");
471 
472 	return (IR_STOP);
473 }
474 
fn_kill_object(int32 &,int32 * params)475 mcodeFunctionReturnCodes _game_session::fn_kill_object(int32 &, int32 *params) {
476 	// kill this object
477 	const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
478 
479 	uint32 id = objects->Fetch_item_number_by_name(object_name);
480 
481 	if (id == 0xffffffff)
482 		Fatal_error("fn_kill_object finds [%s] does not exist", object_name);
483 
484 	if (id == cur_id)
485 		Fatal_error("fn_kill_object - dont use this function to shut self down [%s]", object_name);
486 
487 	// Tell the event manager to stop handling events for this object.
488 	g_oEventManager->ShutDownEventProcessingForObject(id);
489 
490 	prop_state_table[id] = 0; // set to state 0 - in case killed because of illegal frame
491 
492 	logic_structs[id]->ob_status = OB_STATUS_HELD; // lock out
493 
494 	Tdebug("objects_that_died.txt", "**OBJECT '%s' shut down by fn_kill_object", object_name);
495 
496 	return (IR_CONT);
497 }
498 
Shut_down_object(const char * ascii)499 void _game_session::Shut_down_object(const char *ascii) {
500 	// lock out an object
501 
502 	// Tell the event manager to stop handling events for this object.
503 	g_oEventManager->ShutDownEventProcessingForObject(cur_id);
504 
505 	logic_structs[cur_id]->ob_status = OB_STATUS_HELD; // lock out
506 
507 	prop_state_table[cur_id] = 0; // set to state 0 - in case killed because of illegal frame
508 
509 	Tdebug("objects_that_died.txt", "**OBJECT '%s' [id=%d] has been shut down** %s", object->GetName(), cur_id, ascii);
510 }
511 
Console_shut_down_object(const char * name)512 bool8 _game_session::Console_shut_down_object(const char *name) {
513 	// we have name of object
514 
515 	uint32 id = objects->Fetch_item_number_by_name(name);
516 	if (id == 0xffffffff)
517 		return (FALSE8);
518 
519 	// Tell the event manager to stop handling events for this object.
520 	g_oEventManager->ShutDownEventProcessingForObject(id);
521 
522 	prop_state_table[id] = 0; // set to state 0 - in case killed because of illegal frame
523 
524 	logic_structs[id]->ob_status = OB_STATUS_HELD; // lock out
525 
526 	Tdebug("objects_that_died.txt", "**OBJECT '%s' [id=%d] has been shut down** %s", name, id, "Console_shut_down_object");
527 
528 	return (TRUE8);
529 }
530 
Free_object(const char * name)531 bool8 _game_session::Free_object(const char *name) {
532 	// we have name of object
533 	uint32 id = objects->Fetch_item_number_by_name(name);
534 
535 	if (id == 0xffffffff)
536 		return (FALSE8);
537 
538 	logic_structs[id]->ob_status = OB_STATUS_NOT_HELD; // lock out
539 
540 	Tdebug("objects_that_died.txt", "**OBJECT '%s' [id=%d] has been free'd by user ** %s", name, id, "Free_object");
541 
542 	return (TRUE8);
543 }
544 
Console_shut_down_all_mega_objects()545 void _game_session::Console_shut_down_all_mega_objects() {
546 	// how many objs in the mission
547 	uint32 tot_obs = Fetch_number_of_objects();
548 
549 	if (tot_obs) {
550 		Tdebug("objects_that_died.txt", "\n\nuser shutting down all mega objects");
551 
552 		for (uint32 j = 0; j < tot_obs; j++)
553 			if (logic_structs[j]->mega)
554 				Shut_down_id(j);
555 	}
556 
557 	Tdebug("objects_that_died.txt", "\n\n");
558 }
559 
Console_shut_down_all_objects()560 void _game_session::Console_shut_down_all_objects() {
561 	// how many objs in the mission
562 	uint32 tot_obs = Fetch_number_of_objects();
563 
564 	if (tot_obs) {
565 		Tdebug("objects_that_died.txt", "\n\nuser shutting down all objects");
566 
567 		for (uint32 j = 0; j < tot_obs; j++)
568 			Shut_down_id(j);
569 	}
570 
571 	Tdebug("objects_that_died.txt", "\n\n");
572 }
573 
Shut_down_id(uint32 id)574 void _game_session::Shut_down_id(uint32 id) {
575 	// we have id of object
576 
577 	// must be legal id
578 	assert(id < MS->Fetch_number_of_objects());
579 
580 	logic_structs[id]->ob_status = OB_STATUS_HELD; // lock out
581 
582 	Tdebug("objects_that_died.txt", "**OBJECT %s [id=%d] has been shut down** %s", (const char *)logic_structs[id]->GetName(), id, "Shut_down_id");
583 }
584 
fn_shut_down_object(int32 & result,int32 * params)585 mcodeFunctionReturnCodes fn_shut_down_object(int32 &result, int32 *params) {
586 	// shut down current object - wont be logic processed any int32er
587 	return (MS->fn_shut_down_object(result, params));
588 }
589 
fn_shut_down_object(int32 &,int32 *)590 mcodeFunctionReturnCodes _game_session::fn_shut_down_object(int32 & /*result*/, int32 * /*params*/) {
591 	//	params   none
592 
593 	Shut_down_object();
594 
595 	return (IR_STOP);
596 }
597 
fn_pause(int32 & result,int32 * params)598 mcodeFunctionReturnCodes fn_pause(int32 &result, int32 *params) {
599 	// shut down current object - wont be logic processed any int32er
600 	return (MS->fn_pause(result, params));
601 }
602 
fn_pause(int32 &,int32 * params)603 mcodeFunctionReturnCodes _game_session::fn_pause(int32 &, int32 *params) {
604 	//	params   1 = pause value
605 	// params:  0 pointer to object's logic structure
606 	//          1 number of game-cycles to pause
607 
608 	// NB. Pause-value of 0 causes script to continue, 1 causes a 1-cycle quit, 2 gives 2 cycles, etc.
609 
610 	if (!L->looping) { // start the pause
611 		L->looping = 1;
612 		L->pause = params[0]; // no. of game cycles
613 	}
614 
615 	if (L->pause) {             // if non-zero
616 		L->pause--;         // decrement the pause count
617 		return (IR_REPEAT); // drop out of script, but call this again next cycle
618 	} else {                    // pause count is zerp
619 		L->looping = 0;
620 		return (IR_CONT); // continue script
621 	}
622 }
623 
fn_missing_routine(int32 &,int32 *)624 mcodeFunctionReturnCodes fn_missing_routine(int32 &, int32 *) {
625 	// shut down current object - wont be logic processed any int32er
626 	Message_box("fn_missing_routine shutting down [%s]", MS->Fetch_object_name(MS->Fetch_cur_id()));
627 
628 	MS->Shut_down_object(" - fn_missing_routine");
629 
630 	return (IR_STOP);
631 }
632 
fn_pass_flag_to_engine(int32 &,int32 * params)633 mcodeFunctionReturnCodes _game_session::fn_pass_flag_to_engine(int32 & /*result*/, int32 *params) {
634 	// script passed a value to the engine
635 
636 	// NOTE this is an fn_function which may be used in either normal scripts or engine called socket style scrips - that is why it is
637 	// fn- not socket_
638 
639 	Fatal_error("never use fn_pass_flag_to_engine");
640 
641 	script_var_value = params[0];
642 
643 	return (IR_CONT);
644 }
645 
fn_object_rerun_logic_context(int32 &,int32 * params)646 mcodeFunctionReturnCodes _game_session::fn_object_rerun_logic_context(int32 &, int32 *params) {
647 	// reset the named object so it reruns its logic context
648 
649 	// params    0   name of object
650 
651 	const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
652 
653 	uint32 id = objects->Fetch_item_number_by_name(object_name);
654 	if (id == 0xffffffff)
655 		Fatal_error("fn_object_rerun_logic_context cant find object [%s]", object_name);
656 
657 	logic_structs[id]->context_request = TRUE8;
658 
659 	return IR_CONT;
660 }
661 
fn_restart_object(int32 &,int32 *)662 mcodeFunctionReturnCodes _game_session::fn_restart_object(int32 &, int32 *) {
663 	// force an object to return to its logic context
664 
665 	Zdebug("fn_restart_object");
666 
667 	L->logic_level = 0; // force back down
668 
669 	return (IR_TERMINATE); // script to go around
670 }
671 
Reset_all_objects()672 void _game_session::Reset_all_objects() {
673 	// force all game objects back to level 0 where they will rerun logic contexts
674 	// if they are held this will have no effect
675 
676 	uint32 tot_obs = Fetch_number_of_objects();
677 
678 	for (uint32 j = 0; j < tot_obs; j++) {
679 		logic_structs[j]->logic_level = 0;
680 		logic_structs[j]->logic_ref[1] = 0;
681 	}
682 }
683 
fn_new_script(int32 &,int32 * params)684 mcodeFunctionReturnCodes _game_session::fn_new_script(int32 &, int32 *params) {
685 	// change to a new **local** script
686 
687 	// params    0   name of new script
688 	uint32 k;
689 	char *ad;
690 	uint32 script_hash;
691 	const char *script_name = (const char *)MemoryUtil::resolvePtr(params[0]);
692 
693 	script_hash = HashString(script_name);
694 
695 	// try and find a script with the passed extention i.e. ???::looping
696 	for (k = 0; k < object->GetNoScripts(); k++) {
697 		if (script_hash == object->GetScriptNamePartHash(k)) {
698 			// script k is the one to run
699 			// get the address of the script we want to run
700 			ad = (char *)scripts->Try_fetch_item_by_hash(object->GetScriptNameFullHash(k));
701 
702 			// write actual offset
703 			L->logic[1] = ad;
704 
705 			// write reference for change script checks later - i.e. FN_context_chosen_script
706 			L->logic_ref[1] = ad;
707 
708 			L->logic_level = 1; //
709 
710 			L->looping = 0; // reset to 0 for new logics
711 
712 			if (L->mega)
713 				M->custom = FALSE8; // reset
714 
715 			// script interpretter shouldnt write a pc back
716 			return (IR_TERMINATE);
717 		}
718 	}
719 
720 	Fatal_error("fn_new_script - cant find script [%s] in object [%s]", script_name, object->GetName());
721 	return IR_CONT; // keep daft compiler happy
722 }
723 
fn_gosub(int32 &,int32 * params)724 mcodeFunctionReturnCodes _game_session::fn_gosub(int32 &, int32 *params) {
725 	// gosub to a new **local** script
726 
727 	// params    0   name of new script
728 	uint32 k;
729 	char *ad;
730 	uint32 script_hash;
731 	const char *script_name = (const char *)MemoryUtil::resolvePtr(params[0]);
732 
733 	script_hash = HashString(script_name);
734 
735 	if (L->logic_level != 1)
736 		Fatal_error("object [%s] has performed an illegal gosub", object->GetName());
737 
738 	// try and find a script with the passed extention i.e. ???::looping
739 	for (k = 0; k < object->GetNoScripts(); k++) {
740 		// now check for actual script name
741 		if (script_hash == object->GetScriptNamePartHash(k)) {
742 			// script k is the one to run
743 			// get the address of the script we want to run
744 
745 			ad = (char *)scripts->Try_fetch_item_by_hash(object->GetScriptNameFullHash(k));
746 
747 			// write actual offset
748 			L->logic[2] = ad;
749 
750 			L->logic_level = 2; //
751 
752 			L->looping = 0; // reset to 0 for new logics
753 
754 			if (L->mega)
755 				M->custom = FALSE8; // reset
756 
757 			L->old_looping = 0; // gets popped on dropoff
758 
759 			// script interpretter shouldnt write a pc back
760 			return (IR_GOSUB);
761 		}
762 	}
763 
764 	Fatal_error("fn_gosub - cant find script [%s] in object [%s]", script_name, object->GetName());
765 	return IR_CONT; // keep daft compiler happy
766 }
767 
fn_set_strike_overide(int32 &,int32 * params)768 mcodeFunctionReturnCodes _game_session::fn_set_strike_overide(int32 &, int32 *params) {
769 	// set a mega to strike overide - i.e. run a script instead of hitting them
770 
771 	// params    0   name of mega
772 	//			1  0 off 1 on
773 	const char *mega_name = (const char *)MemoryUtil::resolvePtr(params[0]);
774 	uint32 tar = MS->objects->Fetch_item_number_by_name(mega_name);
775 	if (tar == 0xffffffff)
776 		Fatal_error("fn_set_strike_overide finds object [%s] does not exist", mega_name);
777 
778 	if (logic_structs[tar]->image_type == PROP)
779 		Fatal_error("fn_set_strike_overide called on non mega");
780 
781 	logic_structs[tar]->mega->use_strike_script = (uint8)params[1];
782 
783 	return IR_CONT;
784 }
785 
fn_set_shoot_overide(int32 &,int32 * params)786 mcodeFunctionReturnCodes _game_session::fn_set_shoot_overide(int32 &, int32 *params) {
787 	// set a mega to strike overide - i.e. run a script instead of hitting them
788 
789 	// params    0   name of mega
790 	//			1  0 off 1 on
791 
792 	const char *mega_name = (const char *)MemoryUtil::resolvePtr(params[0]);
793 
794 	uint32 tar = MS->objects->Fetch_item_number_by_name(mega_name);
795 	if (tar == 0xffffffff)
796 		Fatal_error("fn_set_shoot_overide finds object [%s] does not exist", mega_name);
797 
798 	if (logic_structs[tar]->image_type == PROP)
799 		Fatal_error("fn_set_shoot_overide called on non mega");
800 
801 	logic_structs[tar]->mega->use_fire_script = (uint8)params[1];
802 
803 	return IR_CONT;
804 }
805 
InitDynamicLight(void)806 void _mega::InitDynamicLight(void) {
807 	dynLight.nStates = 1;       // one state
808 	dynLight.w = 0;             // zero width
809 	dynLight.b = 0;             // zero bounce
810 	dynLight.anu = 0;           // don't use it
811 	dynLight.type = OMNI_LIGHT; // OMNI
812 	dynLight.ba = 0;            // means nothing for an OMNI
813 	dynLight.bs = 0;            // means nothing for an OMNI
814 
815 	dynLight.states[0].ans2 = 0; // dont think these things are used...
816 	dynLight.states[0].ane2 = (100 * 1) * (100 * 1);
817 
818 	dynLight.states[0].m = 128; // no shade...
819 
820 	// direction don't matter it's an OMNI light
821 	dynLight.states[0].vx = 4096; // ignored for an OMNI light
822 	dynLight.states[0].vy = 0;    // ignored for an OMNI light
823 	dynLight.states[0].vz = 0;    // ignored for an OMNI light    }
824 }
825 
826 // fn_set_dynamic_light(cycles,r,g,b,x,y,z,falloff);
fn_set_dynamic_light(int32 &,int32 * params)827 mcodeFunctionReturnCodes _game_session::fn_set_dynamic_light(int32 &, int32 *params) {
828 	M->SetDynamicLight(params[0],                       // cycles
829 	                   params[1], params[2], params[3], // rgb
830 	                   params[4], params[5], params[6], // xyz
831 	                   params[7]);                      // falloff
832 
833 	return IR_CONT;
834 }
835 
836 // speak_set_dynamic_light("object",cycles,r,g,b,x,y,z,falloff);
speak_set_dynamic_light(int32 &,int32 * params)837 mcodeFunctionReturnCodes _game_session::speak_set_dynamic_light(int32 &, int32 *params) {
838 	const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
839 
840 	int32 obj_id = objects->Fetch_item_number_by_name(object_name);
841 
842 	logic_structs[obj_id]->mega->SetDynamicLight(params[1],                       // cycles
843 	                                             params[2], params[3], params[4], // rgb
844 	                                             params[5], params[6], params[7], // xyz
845 	                                             params[8]);                      // falloff
846 
847 	return IR_CONT;
848 }
849 
850 // SetDynamicLight(cycles,r,g,b,x,y,z);
851 // where cycles is number of cycles to stay on (-1 for constant, 0 for off)
SetDynamicLight(int32 in_cycles,int32 in_r,int32 in_g,int32 in_b,int32 in_x,int32 in_y,int32 in_z,int32 falloff)852 void _mega::SetDynamicLight(int32 in_cycles, int32 in_r, int32 in_g, int32 in_b, int32 in_x, int32 in_y, int32 in_z, int32 falloff) {
853 	// set cycles (on)
854 	if (in_cycles != 0)
855 		dynLightOn = in_cycles + 1; // +1 cycles for first update (before drawing...)
856 	else
857 		dynLightOn = 0; // 0 cycles
858 
859 	// check colours are 0-255
860 	if ((in_r > 255) || (in_r < 0) || (in_g > 255) || (in_g < 0) || (in_b > 255) || (in_b < 0))
861 		Fatal_error("Dynamic light rgb %d,%d,%d out of range (0-255)", in_r, in_g, in_b);
862 
863 	// set colours (scale 0-255 to 0-4095)
864 	dynLight.states[0].c.r = (int16)((in_r * 4096) / 256);
865 	dynLight.states[0].c.g = (int16)((in_g * 4096) / 256);
866 	dynLight.states[0].c.b = (int16)((in_b * 4096) / 256);
867 
868 	// set the v field of colour to be the maximum of r,g,b
869 
870 	dynLight.states[0].c.v = dynLight.states[0].c.r;         // start at red
871 	if (dynLight.states[0].c.g > dynLight.states[0].c.v)     // if green bigger
872 		dynLight.states[0].c.v = dynLight.states[0].c.g; // set to green
873 	if (dynLight.states[0].c.b > dynLight.states[0].c.v)     // if blue bigger
874 		dynLight.states[0].c.v = dynLight.states[0].c.b; // set to blue
875 
876 	// setup positions
877 	dynLightX = (int16)in_x;
878 	dynLightY = (int16)in_y;
879 	dynLightZ = (int16)in_z;
880 
881 	// falloff
882 	if (falloff == 0) {
883 		dynLight.afu = 0; // don't use it
884 	} else {
885 		dynLight.states[0].afs2 = (falloff * falloff) / 100; // (d/10)^2     = (d*d)/100
886 		dynLight.states[0].afe2 = falloff * falloff;         // d^2          = (d*d)
887 
888 		dynLight.afu = 1; // use it
889 	}
890 }
891 
AddDynamicLight(PSXLampList & lamplist,_logic * log)892 void AddDynamicLight(PSXLampList &lamplist, _logic *log) {
893 	_mega *mega = log->mega;
894 
895 	if (mega->dynLightOn == 0)
896 		return;
897 
898 	int32 xx, yy, zz;
899 
900 	xx = mega->dynLightX;
901 	yy = mega->dynLightY;
902 	zz = mega->dynLightZ;
903 
904 	// rotate around character...
905 
906 	PXfloat ss, cc;
907 	PXfloat angle = -log->pan * TWO_PI;
908 
909 	ss = (PXfloat)PXsin(angle);
910 	cc = (PXfloat)PXcos(angle);
911 
912 // rotate xx and zz around act.trueRot.vy       ONE
913 	mega->dynLight.states[0].pos.vx = (int32)(xx * cc - zz * ss);
914 	mega->dynLight.states[0].pos.vz = (int32)(xx * ss + zz * cc);
915 	mega->dynLight.states[0].pos.vy = (int32)yy; // no rotation
916 
917 	// and add the players position
918 
919 	mega->dynLight.states[0].pos.vx += (int32)mega->actor_xyz.x;
920 	mega->dynLight.states[0].pos.vy += (int32)mega->actor_xyz.y;
921 	mega->dynLight.states[0].pos.vz += (int32)mega->actor_xyz.z;
922 
923 	// for each lamp to add
924 	lamplist.lamps[lamplist.n] = &(mega->dynLight);
925 	lamplist.states[lamplist.n] = 0;
926 	lamplist.n++;
927 }
928 
UpdateMegaFX()929 void _game_session::UpdateMegaFX() {
930 	// first do things which are done for all megas
931 	// next do things that are only done for visable ones...
932 
933 	// do the check
934 	if (!Object_visible_to_camera(cur_id))
935 		return;
936 
937 	// now do on screen only things
938 
939 	// dynamic light
940 	// if >0 then reduce it (only stay on for certain number of cycles... (THIS NEDS MOVING TO SOME MEGA UPDATE BIT)
941 	if (M->dynLightOn > 0)
942 		M->dynLightOn--;
943 
944 	// breathing
945 	M->breath.Update();
946 
947 	// bullet
948 	UpdateCartridgeCase();
949 
950 	// if talking then update talking
951 	if ((cur_id == (uint)speech_info[CONV_ID].current_talker) && // we are the one talking
952 	    (speech_info[CONV_ID].total_subscribers > 1) &&          // not talking to myself
953 	    (speech_info[CONV_ID].state == __SAYING)                 // are definately saying, not just getting ready to...
954 	    ) {
955 		// get rap
956 		rap_API *pose = (rap_API *)rs_anims->Res_open(I->get_pose_name(), I->pose_hash, I->base_path, I->base_path_hash);
957 
958 		// use it
959 		UpdateTalking(L, pose); // update jaw and neck bone
960 	} else {
961 		I->neckBone.Target0(); // update towards <0,0,0>
962 		I->jawBone.Target0();  // same
963 	}
964 
965 	I->jawBone.Update();
966 	I->neckBone.Update();
967 	I->lookBone.Update();
968 
969 	// next do ones that are only for player
970 
971 	// return here...
972 	if (cur_id != player.Fetch_player_id())
973 		return;
974 
975 	// now do player only things
976 
977 	// shot deformation
978 	player.shotDeformation.Update();
979 
980 	// if counter is full then jerk body back
981 	if (player.being_shot == 3)
982 		SetPlayerShotBone(player.shot_by_id); // set to maximum push now...
983 
984 	// reduce counter (when it's zero we can shoot again)
985 	if (player.being_shot)
986 		player.being_shot--;
987 
988 	UpdatePlayerLook();
989 }
990 
991 } // End of namespace ICB
992