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