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/common/px_scriptengine.h"
32 #include "engines/icb/common/px_game_object.h"
33 #include "engines/icb/icb.h"
34 #include "engines/icb/common/ptr_util.h"
35 #include "engines/icb/floors.h"
36 #include "engines/icb/mission.h"
37 #include "engines/icb/global_objects.h"
38 #include "engines/icb/object_structs.h"
39 #include "engines/icb/sound.h"
40 #include "engines/icb/res_man.h"
41
42 namespace ICB {
43
fn_apply_bullet(int32 & result,int32 * params)44 mcodeFunctionReturnCodes fn_apply_bullet(int32 &result, int32 *params) { return (g_mission->session->fn_apply_bullet(result, params)); }
45
fn_set_to_last_frame_generic_anim(int32 & result,int32 * params)46 mcodeFunctionReturnCodes fn_set_to_last_frame_generic_anim(int32 &result, int32 *params) { return (MS->fn_set_to_last_frame_generic_anim(result, params)); }
47
fn_play_custom_anim(int32 & result,int32 * params)48 mcodeFunctionReturnCodes fn_play_custom_anim(int32 &result, int32 *params) { return (MS->fn_play_custom_anim(result, params)); }
49
fn_easy_play_generic_anim(int32 & result,int32 * params)50 mcodeFunctionReturnCodes fn_easy_play_generic_anim(int32 &result, int32 *params) { return (MS->fn_easy_play_generic_anim(result, params)); }
51
fn_easy_play_custom_anim(int32 & result,int32 * params)52 mcodeFunctionReturnCodes fn_easy_play_custom_anim(int32 &result, int32 *params) { return (MS->fn_easy_play_custom_anim(result, params)); }
53
fn_snap_face_object(int32 & result,int32 * params)54 mcodeFunctionReturnCodes fn_snap_face_object(int32 &result, int32 *params) { return (MS->fn_snap_face_object(result, params)); }
55
fn_face_coord(int32 & result,int32 * params)56 mcodeFunctionReturnCodes fn_face_coord(int32 &result, int32 *params) { return (MS->fn_face_coord(result, params)); }
57
fn_face_object(int32 & result,int32 * params)58 mcodeFunctionReturnCodes fn_face_object(int32 &result, int32 *params) { return (MS->fn_face_object(result, params)); }
59
fn_set_to_first_frame_custom_anim(int32 & result,int32 * params)60 mcodeFunctionReturnCodes fn_set_to_first_frame_custom_anim(int32 &result, int32 *params) { return (MS->fn_set_to_first_frame_custom_anim(result, params)); }
61
fn_set_to_last_frame_custom_anim(int32 & result,int32 * params)62 mcodeFunctionReturnCodes fn_set_to_last_frame_custom_anim(int32 &result, int32 *params) { return (MS->fn_set_to_last_frame_custom_anim(result, params)); }
63
fn_new_apply_bullet(int32 & result,int32 * params)64 mcodeFunctionReturnCodes fn_new_apply_bullet(int32 &result, int32 *params) { return (MS->fn_new_apply_bullet(result, params)); }
65
fn_play_generic_anim(int32 & result,int32 * params)66 mcodeFunctionReturnCodes fn_play_generic_anim(int32 &result, int32 *params) { return (MS->fn_play_generic_anim(result, params)); }
67
fn_reverse_generic_anim(int32 & result,int32 * params)68 mcodeFunctionReturnCodes fn_reverse_generic_anim(int32 &result, int32 *params) { return (MS->fn_reverse_generic_anim(result, params)); }
69
fn_apply_anim_y(int32 & result,int32 * params)70 mcodeFunctionReturnCodes fn_apply_anim_y(int32 &result, int32 *params) { return (MS->fn_apply_anim_y(result, params)); }
71
fn_set_to_first_frame_generic_anim(int32 & result,int32 * params)72 mcodeFunctionReturnCodes fn_set_to_first_frame_generic_anim(int32 &result, int32 *params) { return (MS->fn_set_to_first_frame_generic_anim(result, params)); }
73
fn_easy_play_generic_anim_with_pan(int32 & result,int32 * params)74 mcodeFunctionReturnCodes fn_easy_play_generic_anim_with_pan(int32 &result, int32 *params) { return (MS->fn_easy_play_generic_anim_with_pan(result, params)); }
75
fn_fast_face_object(int32 & result,int32 * params)76 mcodeFunctionReturnCodes fn_fast_face_object(int32 &result, int32 *params) { return (MS->fn_fast_face_object(result, params)); }
77
fn_face_nicos_pan(int32 & result,int32 * params)78 mcodeFunctionReturnCodes fn_face_nicos_pan(int32 &result, int32 *params) { return (MS->fn_face_nicos_pan(result, params)); }
79
fn_add_y(int32 & result,int32 * params)80 mcodeFunctionReturnCodes fn_add_y(int32 &result, int32 *params) { return (MS->fn_add_y(result, params)); }
81
fn_reverse_custom_anim(int32 & result,int32 * params)82 mcodeFunctionReturnCodes fn_reverse_custom_anim(int32 &result, int32 *params) { return (MS->fn_reverse_custom_anim(result, params)); }
83
fn_fast_face_coord(int32 & result,int32 * params)84 mcodeFunctionReturnCodes fn_fast_face_coord(int32 &result, int32 *params) { return (MS->fn_fast_face_coord(result, params)); }
85
fn_easy_play_custom_anim_with_pan(int32 & result,int32 * params)86 mcodeFunctionReturnCodes fn_easy_play_custom_anim_with_pan(int32 &result, int32 *params) { return (MS->fn_easy_play_custom_anim_with_pan(result, params)); }
87
fn_prime_custom_anim(int32 & result,int32 * params)88 mcodeFunctionReturnCodes fn_prime_custom_anim(int32 &result, int32 *params) { return (MS->fn_prime_custom_anim(result, params)); }
89
fn_sync_with_mega(int32 & result,int32 * params)90 mcodeFunctionReturnCodes fn_sync_with_mega(int32 &result, int32 *params) { return (MS->fn_sync_with_mega(result, params)); }
91
fn_set_feet_to_pan(int32 & result,int32 * params)92 mcodeFunctionReturnCodes fn_set_feet_to_pan(int32 &result, int32 *params) { return (MS->fn_set_feet_to_pan(result, params)); }
93
fn_hard_load_generic_anim(int32 & result,int32 * params)94 mcodeFunctionReturnCodes fn_hard_load_generic_anim(int32 &result, int32 *params) { return (MS->fn_hard_load_generic_anim(result, params)); }
95
fn_hard_load_custom_anim(int32 & result,int32 * params)96 mcodeFunctionReturnCodes fn_hard_load_custom_anim(int32 &result, int32 *params) { return (MS->fn_hard_load_custom_anim(result, params)); }
97
fn_face_camera(int32 & result,int32 * params)98 mcodeFunctionReturnCodes fn_face_camera(int32 &result, int32 *params) { return (MS->fn_face_camera(result, params)); }
99
fn_face_camera(int32 &,int32 * params)100 mcodeFunctionReturnCodes _game_session::fn_face_camera(int32 &, int32 *params) {
101 // params 0 face away from camera
102 // 1 face toward camera
103
104 PXfloat new_pan, diff;
105 PXcamera currentCamera;
106
107 if (!L->looping) {
108 currentCamera = GetCamera();
109 new_pan = (PXfloat)currentCamera.pan;
110
111 // reverse 180deg?
112 if (params[1])
113 new_pan += HALF_TURN;
114
115 if (new_pan > HALF_TURN)
116 new_pan -= FULL_TURN;
117
118 else if (new_pan < -HALF_TURN)
119 new_pan += FULL_TURN;
120
121 // get difference between the two
122 diff = new_pan - L->pan;
123
124 if (PXfabs(diff) > (FULL_TURN / 10)) { // 0.1f
125 // work out which way to turn
126 if (diff > HALF_TURN)
127 diff -= FULL_TURN;
128
129 else if (diff < -HALF_TURN)
130 diff += FULL_TURN;
131
132 // diff is now the distance to turn by and its sign denotes direction
133
134 if (diff < FLOAT_ZERO) {
135 M->turn_dir = 0; // right
136 } else {
137 M->turn_dir = 1; // left
138 }
139
140 M->target_pan = (PXfloat)PXfabs(diff); // save positive pan distance
141
142 M->actual_target_pan = new_pan; // actual target which we may clip to
143
144 L->anim_pc = 0; // legal pc for first frame in turn anim - this needs thought
145
146 L->looping = TRUE8;
147 } else {
148 // shallow angle so snap and continue as normal
149 L->pan = new_pan;
150 return IR_CONT;
151 }
152 }
153
154 // still got some to go
155 if (M->target_pan) {
156 Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, 1);
157 return (IR_REPEAT);
158 }
159
160 // we're done
161 L->looping = FALSE8;
162
163 // set to stand
164 L->cur_anim_type = __STAND;
165 L->anim_pc = 0;
166
167 return (IR_CONT);
168 }
169
170 // fn_set_feet_to_pan()
171 // ensures actual pan is what we are looking at
fn_set_feet_to_pan(int32 &,int32 *)172 mcodeFunctionReturnCodes _game_session::fn_set_feet_to_pan(int32 &, int32 *) {
173 // we face straight ahead
174 I->lookBone.boneTarget.vz = (int16)(0);
175
176 // and our pan is set to the looking_pan
177 L->pan = M->looking_pan;
178
179 return IR_CONT;
180 }
181
fn_face_coord(int32 &,int32 * params)182 mcodeFunctionReturnCodes _game_session::fn_face_coord(int32 &, int32 *params) {
183 // params 0 target x
184 // 1 target z
185
186 // return IR_CONT or
187 // IR_REPEAT
188
189 if (!L->looping) {
190 // setup
191
192 if (Calc_target_pan((PXreal)params[0], (PXreal)params[1], L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
193 // turn required
194
195 L->looping = TRUE8;
196 } else
197 return (IR_CONT); // will have possibly made a tiny snap
198 }
199
200 // still got some to go
201 if (M->target_pan) {
202 Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, 1);
203 return (IR_REPEAT);
204 }
205
206 // we're done
207 L->looping = FALSE8;
208
209 // set to stand
210 L->cur_anim_type = __STAND;
211 L->anim_pc = 0;
212
213 return (IR_CONT);
214 }
215
fn_face_nicos_pan(int32 &,int32 * params)216 mcodeFunctionReturnCodes _game_session::fn_face_nicos_pan(int32 &, int32 *params) {
217 // params 0 target nico
218 // 1 reserved for future use
219
220 // return IR_CONT or
221 // IR_REPEAT
222
223 _feature_info *start_pos;
224 PXfloat new_pan, diff;
225
226 const char *nico_name = (const char *)MemoryUtil::resolvePtr(params[0]);
227
228 if (!L->looping) {
229 // setup
230 start_pos = (_feature_info *)features->Try_fetch_item_by_name(nico_name);
231 if (!start_pos)
232 Fatal_error("no NICO marker (fn_face_nico) ob %s, nico %s", object->GetName(), nico_name);
233
234 new_pan = start_pos->direction;
235
236 // get difference between the two
237 diff = new_pan - L->pan;
238
239 if (PXfabs(diff) > (FULL_TURN / 10)) { // 0.1f
240 // work out which way to turn
241 if (diff > HALF_TURN)
242 diff -= FULL_TURN;
243 else if (diff < -HALF_TURN)
244 diff += FULL_TURN;
245
246 // diff is now the distance to turn by and its sign denotes direction
247
248 if (diff < FLOAT_ZERO) {
249 M->turn_dir = 0; // right
250 } else {
251 M->turn_dir = 1; // left
252 }
253
254 M->target_pan = (PXfloat)PXfabs(diff); // save positive pan distance
255
256 M->actual_target_pan = new_pan; // actual target which we may clip to
257
258 L->anim_pc = 0; // legal pc for first frame in turn anim - this needs thought
259
260 L->looping = TRUE8;
261 } else {
262 // shallow angle so snap and continue as normal
263 L->pan = new_pan;
264 return IR_CONT;
265 }
266 }
267
268 // still got some to go
269 if (M->target_pan) {
270 Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, 1);
271 return (IR_REPEAT);
272 }
273
274 // we're done
275 L->looping = FALSE8;
276
277 // set to stand
278 L->cur_anim_type = __STAND;
279 L->anim_pc = 0;
280
281 return (IR_CONT);
282 }
283
fn_face_object(int32 &,int32 * params)284 mcodeFunctionReturnCodes _game_session::fn_face_object(int32 &, int32 *params) {
285 // params target object
286
287 // return IR_CONT or
288 // IR_REPEAT
289
290 const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
291
292 if (!L->looping) {
293 // setup
294 _logic *log;
295
296 uint32 id = objects->Fetch_item_number_by_name(object_name);
297
298 log = Fetch_object_struct(id);
299
300 if (log->image_type == PROP) {
301 if (Calc_target_pan(log->prop_xyz.x, log->prop_xyz.z, M->actor_xyz.x, M->actor_xyz.z)) {
302 // turn required
303 L->looping = TRUE8;
304 } else
305 return (IR_CONT); // will have possibly made a tiny snap
306
307 } else {
308 if (Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
309 // turn required
310 L->looping = TRUE8;
311 } else
312 return (IR_CONT); // will have possibly made a tiny snap
313 }
314 }
315
316 // still got some to go
317 if (M->target_pan) {
318 Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, 1);
319 return (IR_REPEAT);
320 }
321
322 // we're done
323 L->looping = FALSE8;
324
325 // set to stand
326 L->cur_anim_type = __STAND;
327 L->anim_pc = 0;
328
329 return (IR_CONT);
330 }
331
fn_fast_face_object(int32 &,int32 * params)332 mcodeFunctionReturnCodes _game_session::fn_fast_face_object(int32 &, int32 *params) {
333 // params 0 target object
334 // 1 speed up
335
336 // return IR_CONT or
337 // IR_REPEAT
338
339 const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
340
341 if (!L->looping) {
342 // setup
343 _logic *log;
344
345 uint32 id = objects->Fetch_item_number_by_name(object_name);
346
347 log = Fetch_object_struct(id);
348
349 if (log->image_type == PROP) {
350 if (Calc_target_pan(log->prop_xyz.x, log->prop_xyz.z, M->actor_xyz.x, M->actor_xyz.z)) {
351 // turn required
352 L->looping = TRUE8;
353 } else
354 return (IR_CONT); // will have possibly made a tiny snap
355 } else {
356 if (Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
357 // turn required
358 L->looping = TRUE8;
359 } else
360 return (IR_CONT); // will have possibly made a tiny snap
361 }
362 }
363
364 // still got some to go
365 if (M->target_pan) {
366 Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, params[1]);
367 return (IR_REPEAT);
368 }
369
370 // we're done
371 L->looping = FALSE8;
372
373 // set to stand
374 L->cur_anim_type = __STAND;
375 L->anim_pc = 0;
376
377 return (IR_CONT);
378 }
379
fn_fast_face_coord(int32 &,int32 * params)380 mcodeFunctionReturnCodes _game_session::fn_fast_face_coord(int32 &, int32 *params) {
381 // params 0 x
382 // 1 z
383 // 2 speed up
384
385 // return IR_CONT or
386 // IR_REPEAT
387
388 if (!L->looping) {
389 if (Calc_target_pan((PXreal)params[0], (PXreal)params[1], L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
390 // turn required
391 L->looping = TRUE8;
392 } else
393 return (IR_CONT); // will have possibly made a tiny snap
394 }
395
396 // still got some to go
397 if (M->target_pan) {
398 Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, params[2]);
399 return (IR_REPEAT);
400 }
401
402 // we're done
403 L->looping = FALSE8;
404
405 // set to stand
406 L->cur_anim_type = __STAND;
407 L->anim_pc = 0;
408
409 return (IR_CONT);
410 }
411
Need_to_turn_to_face_object(uint32 id)412 bool8 _game_session::Need_to_turn_to_face_object(uint32 id) {
413 // is a turn required to face an object
414 // used by chi
415
416 _logic *log;
417
418 log = Fetch_object_struct(id);
419
420 if (log->image_type == PROP)
421 Fatal_error("fast_face_object = target must be mega");
422
423 if (Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
424 // turn required
425 return TRUE8;
426 }
427
428 return (FALSE8); // may even have made a tiny snap
429 }
430
fast_face_object(uint32 id,uint32 speed)431 bool8 _game_session::fast_face_object(uint32 id, uint32 speed) {
432 // called in engine
433 // for example from chi logic
434
435 if (!L->looping) {
436 // setup
437 _logic *log;
438
439 log = Fetch_object_struct(id);
440
441 if (log->image_type == PROP)
442 Fatal_error("fast_face_object = target must be mega");
443
444 if (Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
445 // turn required
446 L->looping = TRUE8;
447 } else
448 return (TRUE8); // will have possibly made a tiny snap
449 }
450
451 // still got some to go
452 if (M->target_pan) {
453 Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, speed);
454 return (FALSE8);
455 }
456
457 // we're done
458 L->looping = FALSE8;
459
460 // set to stand
461 L->cur_anim_type = __STAND;
462 L->anim_pc = 0;
463
464 return (TRUE8);
465 }
466
fast_face_rnd(uint32 speed)467 bool8 _game_session::fast_face_rnd(uint32 speed) {
468 PXfloat new_pan, diff;
469
470 if (!L->looping) {
471 // pick a random pan
472 new_pan = (FULL_TURN * (g_icb->getRandomSource()->getRandomNumber(359 - 1))) / 360;
473
474 // get difference between the two
475 diff = new_pan - L->pan;
476
477 if (PXfabs(diff) > (FULL_TURN / 10)) { // 0.1f
478 // work out which way to turn
479 if (diff > HALF_TURN)
480 diff -= FULL_TURN;
481
482 else if (diff < -HALF_TURN)
483 diff += FULL_TURN;
484
485 // diff is now the distance to turn by and its sign denotes direction
486 if (diff < FLOAT_ZERO) {
487 M->turn_dir = 0; // right
488 } else {
489 M->turn_dir = 1; // left
490 }
491
492 M->target_pan = (PXfloat)PXfabs(diff); // save positive pan distance
493
494 M->actual_target_pan = new_pan; // actual target which we may clip to
495
496 L->anim_pc = 0; // legal pc for first frame in turn anim - this needs thought
497
498 L->looping = TRUE8;
499
500 } else
501 return TRUE8; // random was too tiny to bother
502 }
503
504 // still got some to go
505 if (M->target_pan) {
506 Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, speed);
507 return (FALSE8);
508 }
509
510 // we're done
511 L->looping = FALSE8;
512
513 // set to stand
514 L->cur_anim_type = __STAND;
515 L->anim_pc = 0;
516
517 return (TRUE8);
518 }
519
fn_snap_face_object(int32 &,int32 * params)520 mcodeFunctionReturnCodes _game_session::fn_snap_face_object(int32 &, int32 *params) {
521 // force pan - no animation
522
523 // params 0 target object
524 // return IR_CONT
525
526 _logic *log;
527
528 const char *object_name = (const char *)MemoryUtil::resolvePtr(params[0]);
529
530 Zdebug("fn_snap_face_object [%s]", object_name);
531
532 uint32 id = objects->Fetch_item_number_by_name(object_name);
533
534 if (id == 0xffffffff)
535 Fatal_error("fn_snap_face_object cant find target object %s", object_name);
536
537 log = Fetch_object_struct(id);
538
539 if (log->image_type == PROP) {
540 if (Calc_target_pan(log->prop_xyz.x, log->prop_xyz.z, M->actor_xyz.x, M->actor_xyz.z)) {
541 L->pan = M->actual_target_pan;
542 M->actual_target_pan = REAL_ZERO;
543 }
544 } else {
545 if (Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z)) {
546 L->pan = M->actual_target_pan;
547 M->actual_target_pan = REAL_ZERO;
548 }
549 }
550
551 return (IR_CONT);
552 }
553
speech_face_object(uint32 tar_id)554 bool8 _game_session::speech_face_object(uint32 tar_id) {
555 // custom system for speech
556
557 // return TRUE8 - more to do
558 // FALSE - done
559 bool8 res;
560
561 if (!L->looping) {
562 // setup
563 _logic *log;
564
565 log = Fetch_object_struct(tar_id);
566
567 if (log->image_type == VOXEL)
568 res = Calc_target_pan(log->mega->actor_xyz.x, log->mega->actor_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z);
569
570 else
571 res = Calc_target_pan(log->prop_xyz.x, log->prop_xyz.z, L->mega->actor_xyz.x, L->mega->actor_xyz.z);
572
573 if (res) {
574 // turn required
575 L->looping = TRUE8;
576 } else { // will have possibly made a tiny snap
577 // set to stand
578 L->cur_anim_type = __STAND;
579 L->anim_pc = 0;
580
581 return (FALSE8); // done!
582 }
583 }
584
585 // still got some to go
586 if (M->target_pan) {
587 Animate_turn_to_pan(__TURN_ON_THE_SPOT_CLOCKWISE, 1);
588 return (TRUE8); // more to do
589 }
590
591 // we're done
592 L->looping = FALSE8;
593
594 // set to stand
595 L->cur_anim_type = __STAND;
596 L->anim_pc = 0;
597
598 Zdebug(" finished");
599
600 return (FALSE8); // done
601 }
602
fn_reverse_generic_anim(int32 &,int32 * params)603 mcodeFunctionReturnCodes _game_session::fn_reverse_generic_anim(int32 &, int32 *params) {
604 // params 0 ascii name of anim
605
606 // return IR_CONT or
607 // IR_REPEAT
608
609 bool8 ret;
610
611 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
612
613 if (!L->looping) {
614 // setup
615 M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
616 L->looping = 100;
617 ANIM_CHECK(M->next_anim_type);
618 L->list[0] = HashString(anim_name);
619 }
620
621 if (L->looping == 100) {
622 // setup
623 // psx async loading check - is file in memory
624 if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
625 return IR_REPEAT;
626
627 if ((Object_visible_to_camera(cur_id)) &&
628 (!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
629 return IR_REPEAT;
630
631 L->cur_anim_type = M->next_anim_type; // anim now in memory
632
633 L->looping = TRUE8;
634
635 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
636
637 // set last frame
638 L->anim_pc = anim->frame_qty - 2;
639
640 return (IR_REPEAT);
641 }
642
643 // ok, we are simply animating through the frames
644 // last frame is currently displayed?
645 if (!L->anim_pc) {
646 L->looping = FALSE8;
647 return (IR_CONT);
648 }
649
650 // shift character and frame forward by the amount appropriate
651 ret = MS->Reverse_frame_and_motion(L->cur_anim_type, 0, M->anim_speed);
652 if (!ret) { // could not move forward?
653 L->looping = FALSE8;
654 return (IR_CONT);
655 }
656
657 return (IR_REPEAT);
658 }
659
fn_play_generic_anim(int32 &,int32 * params)660 mcodeFunctionReturnCodes _game_session::fn_play_generic_anim(int32 &, int32 *params) {
661 // params 0 ascii name of anim
662
663 // return IR_CONT or
664 // IR_REPEAT
665
666 bool8 ret;
667
668 const char *anim_name = NULL;
669 if (params && params[0]) {
670 anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
671 }
672
673 if (!L->looping) {
674 // setup
675 M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
676 L->looping = 100;
677 ANIM_CHECK(M->next_anim_type);
678 L->list[0] = HashString(anim_name);
679 }
680
681 if (L->looping == 100) {
682 // psx async loading check - is file in memory
683 if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
684 return IR_REPEAT;
685
686 if ((Object_visible_to_camera(cur_id)) &&
687 (!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
688 return IR_REPEAT;
689
690 // anim found and started ok
691 L->looping = TRUE8;
692
693 L->cur_anim_type = M->next_anim_type; // anim now in memory
694
695 // get animation
696 ANIM_CHECK(L->cur_anim_type);
697
698 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
699
700 // advance the frame
701 L->anim_pc = anim->frame_qty - 2;
702 Advance_frame_and_motion(L->cur_anim_type, 0, 1);
703 L->anim_pc = 0;
704
705 return (IR_REPEAT);
706 }
707
708 // ok, we are simply animating through the frames
709
710 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
711
712 // last frame is currently displayed?
713 if ((int32)(L->anim_pc + M->anim_speed) >= (anim->frame_qty - 1)) {
714 L->looping = FALSE8;
715 return (IR_CONT);
716 }
717
718 // shift character and frame forward by the amount appropriate
719 ret = Advance_frame_and_motion(L->cur_anim_type, 0, M->anim_speed);
720
721 if (!ret) { // could not move forward?
722 L->looping = FALSE8;
723 return (IR_CONT);
724 }
725
726 // more to do - come back again next cycle
727 return (IR_REPEAT);
728 }
729
fn_easy_play_generic_anim(int32 &,int32 * params)730 mcodeFunctionReturnCodes _game_session::fn_easy_play_generic_anim(int32 &, int32 *params) {
731 // barriers are ignored!
732
733 // params 0 ascii name of anim
734
735 // return IR_CONT or
736 // IR_REPEAT
737
738 const char *anim_name = NULL;
739 if (params && params[0]) {
740 anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
741 }
742
743 if (!L->looping) {
744 // setup
745 M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
746 L->looping = 100;
747 ANIM_CHECK(M->next_anim_type);
748 L->list[0] = HashString(anim_name);
749 }
750
751 if (L->looping == 100) {
752 // setup
753 // psx async loading check - is file in memory
754 if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
755 return IR_REPEAT;
756
757 if ((Object_visible_to_camera(cur_id)) &&
758 (!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
759 return IR_REPEAT;
760
761 L->cur_anim_type = M->next_anim_type; // anim now in memory
762 L->looping = TRUE8;
763
764 // advance the frame
765 // get animation
766 ANIM_CHECK(L->cur_anim_type);
767
768 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
769
770 L->anim_pc = anim->frame_qty - 2;
771 Easy_frame_and_motion(L->cur_anim_type, 0, 1);
772 L->anim_pc = 0;
773
774 return (IR_REPEAT);
775 }
776
777 // ok, we are simply animating through the frames
778
779 // get animation
780 ANIM_CHECK(L->cur_anim_type);
781
782 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash);
783
784 // last frame is currently displayed?
785 if ((int32)(L->anim_pc + M->anim_speed) >= (anim->frame_qty - 1)) {
786 L->looping = FALSE8;
787 return (IR_CONT);
788 }
789
790 // shift character and frame forward by the amount appropriate
791 MS->Easy_frame_and_motion(L->cur_anim_type, 0, M->anim_speed);
792
793 // more to do - come back again next cycle
794 return (IR_REPEAT);
795 }
796
fn_easy_play_generic_anim_with_pan(int32 &,int32 * params)797 mcodeFunctionReturnCodes _game_session::fn_easy_play_generic_anim_with_pan(int32 &, int32 *params) {
798 // barriers are ignored!
799
800 // params 0 ascii name of anim
801
802 // return IR_CONT or
803 // IR_REPEAT
804
805 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
806
807 if (!L->looping) {
808 // setup
809 M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
810 L->looping = 100;
811 ANIM_CHECK(M->next_anim_type);
812 L->list[0] = HashString(anim_name);
813 }
814
815 if (L->looping == 100) {
816 // setup
817
818 // psx async loading check - is file in memory
819 if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
820 return IR_REPEAT;
821
822 if ((Object_visible_to_camera(cur_id)) &&
823 (!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
824 return IR_REPEAT;
825
826 L->cur_anim_type = M->next_anim_type; // anim now in memory
827
828 L->looping = TRUE8;
829
830 // advance the frame
831 // get animation
832 ANIM_CHECK(L->cur_anim_type);
833
834 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
835
836 L->anim_pc = anim->frame_qty - 2;
837 Easy_frame_motion_and_pan(L->cur_anim_type, 0);
838 L->anim_pc = 0;
839
840 return (IR_REPEAT);
841 }
842
843 // ok, we are simply animating through the frames
844
845 // get animation
846 ANIM_CHECK(L->cur_anim_type);
847
848 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
849
850 // last frame is currently displayed?
851 if ((int32)(L->anim_pc + 1) == (anim->frame_qty - 1)) {
852 L->looping = FALSE8;
853 return (IR_CONT);
854 }
855
856 // shift character and frame forward by the amount appropriate
857 MS->Easy_frame_motion_and_pan(L->cur_anim_type, 0);
858
859 // more to do - come back again next cycle
860 return (IR_REPEAT);
861 }
862
fn_easy_play_custom_anim_with_pan(int32 &,int32 * params)863 mcodeFunctionReturnCodes _game_session::fn_easy_play_custom_anim_with_pan(int32 &, int32 *params) {
864 // barriers are ignored!
865 // pan is updated
866
867 // params 0 ascii name of anim
868
869 // return IR_CONT or
870 // IR_REPEAT
871
872 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
873
874 Zdebug("fn_easy_play_custom_anim_with_pan %s %s", object->GetName(), anim_name);
875
876 if (!L->looping) {
877 // set anim up
878 I->Init_custom_animation(anim_name);
879 Reset_cur_megas_custom_type();
880 L->looping = 100; // have to distinguish between first time in and first cycle with anim in memory
881 ANIM_CHECK(__NON_GENERIC);
882 L->list[0] = HashString(anim_name);
883 }
884
885 // anim is in memory so do first frame then pass on to normal logic path
886 if (L->looping == 100) {
887 // psx async loading check - is file in memory
888 if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
889 return IR_REPEAT;
890
891 if ((Object_visible_to_camera(cur_id)) &&
892 (!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
893 return IR_REPEAT;
894
895 I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
896 L->cur_anim_type = __PROMOTED_NON_GENERIC;
897
898 L->anim_pc = 0;
899 L->looping = TRUE8;
900
901 return (IR_REPEAT);
902 }
903
904 // ok, we are simply animating through the frames
905
906 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
907
908 // last frame is currently displayed?
909 if ((int32)(L->anim_pc + 1) == (anim->frame_qty - 1)) {
910 L->looping = FALSE8;
911
912 return (IR_CONT);
913 }
914
915 // shift character and frame forward by the amount appropriate
916 MS->Easy_frame_motion_and_pan(L->cur_anim_type, 0);
917
918 // more to do - come back again next cycle
919 return (IR_REPEAT);
920 }
921
fn_set_to_last_frame_generic_anim(int32 &,int32 * params)922 mcodeFunctionReturnCodes _game_session::fn_set_to_last_frame_generic_anim(int32 &, int32 *params) {
923 // params 0 ascii name of anim
924
925 // return IR_CONT or IR_STOP if error
926
927 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
928
929 if (!L->looping) {
930 M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
931 L->looping = 100;
932 ANIM_CHECK(M->next_anim_type);
933 L->list[0] = HashString(anim_name);
934 }
935
936 // psx async loading check - is file in memory
937 if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
938 return IR_REPEAT;
939
940 if ((Object_visible_to_camera(cur_id)) &&
941 (!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
942 return IR_REPEAT;
943
944 L->cur_anim_type = M->next_anim_type; // anim now in memory
945
946 // ok, set to last frame
947 // get animation
948 ANIM_CHECK(L->cur_anim_type);
949
950 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash); //
951
952 // set to last frame
953 L->anim_pc = anim->frame_qty - 2; // if 10 frames then 10+1 (looper) == 11 meaning 9 is last displayable frame number
954 L->looping = 0;
955
956 return IR_CONT;
957 }
958
fn_set_to_first_frame_generic_anim(int32 &,int32 * params)959 mcodeFunctionReturnCodes _game_session::fn_set_to_first_frame_generic_anim(int32 &, int32 *params) {
960 // params 0 ascii name of anim
961
962 // return IR_CONT or IR_STOP if error
963
964 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
965
966 if (!L->looping) {
967 M->next_anim_type = Fetch_generic_anim_from_ascii(anim_name);
968 L->looping = 100;
969 ANIM_CHECK(M->next_anim_type);
970 }
971
972 // psx async loading check - is file in memory
973 if (!rs_anims->Res_open(I->get_info_name(M->next_anim_type), I->info_name_hash[M->next_anim_type], I->base_path, I->base_path_hash))
974 return IR_REPEAT;
975
976 if ((Object_visible_to_camera(cur_id)) &&
977 (!rs_anims->Res_open(I->get_anim_name(M->next_anim_type), I->anim_name_hash[M->next_anim_type], I->base_path, I->base_path_hash)))
978 return IR_REPEAT;
979
980 L->cur_anim_type = M->next_anim_type; // anim now in memory
981
982 // set to last frame
983 L->anim_pc = 0; // first
984 L->looping = 0;
985
986 return (IR_CONT);
987 }
988
fn_set_to_first_frame_custom_anim(int32 &,int32 * params)989 mcodeFunctionReturnCodes _game_session::fn_set_to_first_frame_custom_anim(int32 &, int32 *params) {
990 // set to first frame of a custom animation
991 // must use fn-set-custom before this
992
993 // params 0 name of anim
994
995 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
996
997 if (!L->looping) { // once
998 I->Init_custom_animation(anim_name);
999 L->looping = 1;
1000 ANIM_CHECK(__NON_GENERIC);
1001 }
1002
1003 // psx async loading check - is file in memory
1004 if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
1005 return IR_REPEAT;
1006
1007 if ((Object_visible_to_camera(cur_id)) && (!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
1008 return IR_REPEAT;
1009
1010 I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
1011 L->cur_anim_type = __PROMOTED_NON_GENERIC;
1012
1013 L->anim_pc = 0;
1014 L->looping = 0;
1015
1016 return (IR_CONT);
1017 }
1018
fn_set_to_last_frame_custom_anim(int32 &,int32 * params)1019 mcodeFunctionReturnCodes _game_session::fn_set_to_last_frame_custom_anim(int32 &, int32 *params) {
1020 // set to last frame of a custom animation
1021 // must use fn-set-custom before this
1022
1023 // params 0 name of anim
1024
1025 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
1026
1027 if (!L->looping) { // once
1028 I->Init_custom_animation(anim_name);
1029 L->looping = 1;
1030 ANIM_CHECK(__NON_GENERIC);
1031 }
1032
1033 // psx async loading check - is file in memory
1034 if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
1035 return IR_REPEAT;
1036
1037 if ((Object_visible_to_camera(cur_id)) && (!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
1038 return IR_REPEAT;
1039
1040 I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
1041 L->cur_anim_type = __PROMOTED_NON_GENERIC;
1042
1043 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(L->cur_anim_type), I->info_name_hash[L->cur_anim_type], I->base_path, I->base_path_hash);
1044
1045 // set to last frame
1046 L->anim_pc = anim->frame_qty - 2; // if 10 frames then 10+1 (looper) == 11 meaning 9 is last displayable frame number
1047
1048 L->looping = 0;
1049
1050 return IR_CONT;
1051 }
1052
fn_hard_load_generic_anim(int32 &,int32 * params)1053 mcodeFunctionReturnCodes _game_session::fn_hard_load_generic_anim(int32 &, int32 *params) {
1054 // get generic anim into memory NOW
1055
1056 // params 0 name of anim
1057 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
1058
1059 __mega_set_names load;
1060
1061 load = Fetch_generic_anim_from_ascii(anim_name);
1062 ANIM_CHECK(load);
1063 rs_anims->Res_open(I->get_info_name(load), I->info_name_hash[load], I->base_path, I->base_path_hash);
1064
1065 if (Object_visible_to_camera(cur_id))
1066 rs_anims->Res_open(I->get_anim_name(load), I->anim_name_hash[load], I->base_path, I->base_path_hash);
1067
1068 return IR_CONT;
1069 }
1070
fn_hard_load_custom_anim(int32 &,int32 * params)1071 mcodeFunctionReturnCodes _game_session::fn_hard_load_custom_anim(int32 &, int32 *params) {
1072 // get custom anim into memory NOW
1073
1074 // params 0 name of anim
1075
1076 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
1077
1078 I->Init_custom_animation(anim_name);
1079 Reset_cur_megas_custom_type();
1080
1081 ANIM_CHECK(__NON_GENERIC);
1082 rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash); //
1083
1084 if (Object_visible_to_camera(cur_id))
1085 rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash);
1086
1087 return IR_CONT;
1088 }
1089
fn_prime_custom_anim(int32 &,int32 * params)1090 mcodeFunctionReturnCodes _game_session::fn_prime_custom_anim(int32 &, int32 *params) {
1091 // get custom anim into memory
1092
1093 // params 0 name of anim
1094
1095 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
1096
1097 if (!L->looping) {
1098 I->Init_custom_animation(anim_name);
1099 Reset_cur_megas_custom_type();
1100
1101 L->looping = 100;
1102
1103 ANIM_CHECK(__NON_GENERIC);
1104 }
1105
1106 // anim is in memory so do first frame then pass on to normal logic path
1107 if (L->looping == 100) {
1108 // psx async loading check - is file in memory
1109 if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
1110 return IR_REPEAT;
1111
1112 if ((Object_visible_to_camera(cur_id)) &&
1113 (!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
1114 return IR_REPEAT;
1115 }
1116
1117 // anim is now in memory
1118 L->looping = 0;
1119 return IR_CONT;
1120 }
1121
fn_play_custom_anim(int32 & result,int32 * params)1122 mcodeFunctionReturnCodes _game_session::fn_play_custom_anim(int32 &result, int32 *params) {
1123 // a mega character plays an anim
1124 // the anim IS NOT part of the generic set
1125 // barriers are checked
1126
1127 // params 0 name of anim
1128
1129 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
1130
1131 if (!L->looping) {
1132 I->Init_custom_animation(anim_name);
1133 Reset_cur_megas_custom_type();
1134 L->looping = 100;
1135 ANIM_CHECK(__NON_GENERIC);
1136 L->list[0] = HashString(anim_name);
1137 }
1138
1139 // anim is in memory so do first frame then pass on to normal logic path
1140 if (L->looping == 100) {
1141 // psx async loading check - is file in memory
1142 if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
1143 return IR_REPEAT;
1144
1145 if ((Object_visible_to_camera(cur_id)) &&
1146 (!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
1147 return IR_REPEAT;
1148
1149 I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
1150 L->cur_anim_type = __PROMOTED_NON_GENERIC;
1151
1152 L->anim_pc = 0;
1153 L->looping = TRUE8;
1154
1155 return IR_REPEAT;
1156 }
1157
1158 return (fn_play_generic_anim(result, 0));
1159 }
1160
fn_reverse_custom_anim(int32 &,int32 * params)1161 mcodeFunctionReturnCodes _game_session::fn_reverse_custom_anim(int32 &, int32 *params) {
1162 // a mega character plays an anim backward
1163 // the anim IS NOT part of the generic set
1164 // barriers are checked
1165
1166 // params 0 name of anim
1167
1168 bool8 ret;
1169
1170 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
1171
1172 if (!L->looping) {
1173 I->Init_custom_animation(anim_name);
1174 Reset_cur_megas_custom_type();
1175 L->looping = 100;
1176 ANIM_CHECK(__NON_GENERIC);
1177 L->list[0] = HashString(anim_name);
1178 }
1179
1180 // anim is in memory so do first frame then pass on to normal logic path
1181 if (L->looping == 100) {
1182 // psx async loading check - is file in memory
1183 if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
1184 return IR_REPEAT;
1185
1186 if ((Object_visible_to_camera(cur_id)) &&
1187 (!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
1188 return IR_REPEAT;
1189
1190 I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
1191 L->cur_anim_type = __PROMOTED_NON_GENERIC;
1192
1193 PXanim *anim = (PXanim *)rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash); //
1194 L->anim_pc = anim->frame_qty - 2;
1195 L->looping = TRUE8;
1196
1197 return IR_REPEAT;
1198 }
1199
1200 // last frame is currently displayed?
1201 if (!L->anim_pc) {
1202 L->looping = FALSE8;
1203 return IR_CONT;
1204 }
1205
1206 // shift character and frame forward by the amount appropriate
1207 ret = MS->Reverse_frame_and_motion(L->cur_anim_type, 0, M->anim_speed);
1208 if (!ret) { // could not move forward?
1209 L->looping = FALSE8;
1210 return IR_CONT;
1211 }
1212
1213 // more to do - come back again next cycle
1214 return IR_REPEAT;
1215 }
1216
fn_easy_play_custom_anim(int32 & result,int32 * params)1217 mcodeFunctionReturnCodes _game_session::fn_easy_play_custom_anim(int32 &result, int32 *params) {
1218 // a mega character plays an anim
1219 // the anim IS NOT part of the generic set
1220 // barriers are ignored
1221
1222 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
1223
1224 if (!L->looping) {
1225 I->Init_custom_animation(anim_name);
1226 Reset_cur_megas_custom_type();
1227 L->looping = 100; // have to distinguish between first time in and first cycle with anim in memory
1228 ANIM_CHECK(__NON_GENERIC);
1229 L->list[0] = HashString(anim_name);
1230 }
1231
1232 // anim is in memory so do first frame then pass on to normal logic path
1233 if (L->looping == 100) {
1234 // psx async loading check - is file in memory
1235 if (!rs_anims->Res_open(I->get_info_name(__NON_GENERIC), I->info_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash))
1236 return IR_REPEAT;
1237
1238 if ((Object_visible_to_camera(cur_id)) &&
1239 (!rs_anims->Res_open(I->get_anim_name(__NON_GENERIC), I->anim_name_hash[__NON_GENERIC], I->base_path, I->base_path_hash)))
1240 return IR_REPEAT;
1241
1242 I->Promote_non_generic(); // swap out the _NON_GENERIC to safe place
1243 L->cur_anim_type = __PROMOTED_NON_GENERIC;
1244
1245 L->anim_pc = 0;
1246 L->looping = TRUE8;
1247 return (IR_REPEAT);
1248 }
1249
1250 return (fn_easy_play_generic_anim(result, 0));
1251 }
1252
fn_apply_bullet(int32 &,int32 *)1253 mcodeFunctionReturnCodes _game_session::fn_apply_bullet(int32 &, int32 *) {
1254 // a bullet is to hit an object
1255 // we simply call its gun_shot socket
1256 // this system circumvents the logic context switch
1257 // this should be used when guards shoot the player... and when chi shoots guards
1258
1259 // params 0 name of target
1260
1261 M->SetDynamicLight(1, 255, 255, 255, 0, 150, 100, 200); // 2 metres
1262
1263 // Hey we are shooting someone (muzzle flash on / cartridge case on (we my want to split this!)
1264 M->is_shooting = TRUE8;
1265
1266 return (IR_CONT);
1267 }
1268
fn_sync_with_mega(int32 &,int32 * params)1269 mcodeFunctionReturnCodes _game_session::fn_sync_with_mega(int32 &, int32 *params) {
1270 // params 0 name of target mega
1271 // 1 nowt
1272
1273 const char *mega_name = (const char *)MemoryUtil::resolvePtr(params[0]);
1274
1275 if (!L->looping) {
1276 L->list[0] = objects->Fetch_item_number_by_name(mega_name);
1277 L->list[1] = 42; // we are here
1278 L->looping = TRUE8; // dont do this again
1279 }
1280
1281 if (logic_structs[L->list[0]]->list[1] == 42) {
1282 // we are going first
1283 L->list[1] = 43;
1284 L->looping = 0;
1285 return IR_CONT; // byeee
1286 } else if (logic_structs[L->list[0]]->list[1] == 43) {
1287 // its gone first
1288 logic_structs[L->list[0]]->list[1] = 0; // clean it up
1289 L->list[1] = 0; // clean us up
1290 L->looping = 0;
1291 return IR_CONT;
1292 }
1293
1294 return IR_REPEAT;
1295 }
1296
fn_new_apply_bullet(int32 &,int32 * params)1297 mcodeFunctionReturnCodes _game_session::fn_new_apply_bullet(int32 &, int32 *params) {
1298 // a bullet is to hit an object with a percentage chance of hitting
1299 // on a hit simply call its gun_shot socket
1300 // this system circumvents the logic context switch
1301 // this should be used when guards shoot the player... and when chi shoots guards
1302
1303 // params 0 name of target
1304 // 1 percentage chance
1305
1306 uint32 tid;
1307 int32 retval;
1308 int32 rnd;
1309 PXreal sub1, sub2, len;
1310 bool8 crouched = FALSE8;
1311
1312 const char *target_name = (const char *)MemoryUtil::resolvePtr(params[0]);
1313
1314 // gun sound
1315 if (logic_structs[cur_id]->sfxVars[GUNSHOT_SFX_VAR] != 0)
1316 RegisterSound(cur_id, NULL, logic_structs[cur_id]->sfxVars[GUNSHOT_SFX_VAR], gunDesc, (int8)127); // have to use full version so we can give hash instead of string
1317 else
1318 RegisterSound(cur_id, defaultGunSfx, gunDesc); // use small version as we have string not hash
1319
1320 // shot types
1321 // 0 - nothing on screen
1322 // 1 - normal light/muzzleflash/cartridge case
1323 // default is 1
1324 int32 shotType = object->GetIntegerValueOrDefault("gun_effects", 1);
1325
1326 // if mega then do dynamic light (only if shotType isnt 0
1327 if ((logic_structs[cur_id]->image_type == VOXEL) && (shotType == 1)) {
1328 // dynamic light
1329 M->SetDynamicLight(1, 255, 255, 255, 0, 150, 100, 200); // 2 metres
1330 // Hey we are shooting someone (muzzle flash on / cartridge case on (we my want to split this!)
1331 M->is_shooting = TRUE8;
1332 }
1333
1334 // get id
1335 tid = objects->Fetch_item_number_by_name(target_name);
1336
1337 // how near
1338 if (L->image_type == PROP) { // we are prop
1339 sub1 = (PXreal)L->prop_xyz.x - logic_structs[tid]->mega->actor_xyz.x;
1340 sub2 = (PXreal)L->prop_xyz.z - logic_structs[tid]->mega->actor_xyz.z;
1341 } else {
1342 crouched = M->Is_crouched();
1343 sub1 = (PXreal)M->actor_xyz.x - logic_structs[tid]->mega->actor_xyz.x;
1344 sub2 = (PXreal)M->actor_xyz.z - logic_structs[tid]->mega->actor_xyz.z;
1345 }
1346
1347 // dist
1348 len = (PXreal)((sub1 * sub1) + (sub2 * sub2));
1349
1350 // hit chance
1351 rnd = g_icb->getRandomSource()->getRandomNumber(100 - 1);
1352
1353 // we didn't miss
1354 int32 missed = 0;
1355
1356 // user hit chance of 0 means always miss
1357 if (params[1]) {
1358 // age chance true, or within distance, or crouching
1359 if ((rnd < params[1]) || (len < (PXreal)(ALWAYS_HIT_DIST * ALWAYS_HIT_DIST)) || (crouched)) { // hit
1360
1361 // if prop is firing then target must be on A floor
1362 // ELSE
1363 // if mega firing then both y coords must be the same
1364 if (((L->image_type == PROP) && (floor_def->On_a_floor(logic_structs[tid]->mega))) ||
1365 ((L->image_type == VOXEL) && (M->actor_xyz.y == logic_structs[tid]->mega->actor_xyz.y))) {
1366
1367 // kick kinematic for the player if we are shooting the player
1368 if (tid == player.Fetch_player_id()) {
1369 MS->player.being_shot = 3; // cant shoot for 3 cycles (engine anim over three frames)
1370 MS->player.shot_by_id = (int8)cur_id; // shot by us...!
1371
1372 c_game_object *ob = (c_game_object *)objects->Fetch_item_by_number(player.Fetch_player_id());
1373 int32 ret = ob->GetVariable("hits");
1374 uint32 hits = ob->GetIntegerVariable(ret);
1375
1376 PXreal subp1, subp2;
1377 if (L->image_type == PROP) { // we are prop
1378 subp1 = logic_structs[tid]->mega->actor_xyz.x - L->prop_xyz.x;
1379 subp2 = logic_structs[tid]->mega->actor_xyz.z - L->prop_xyz.z;
1380 } else {
1381 subp1 = logic_structs[tid]->mega->actor_xyz.x - M->actor_xyz.x;
1382 subp2 = logic_structs[tid]->mega->actor_xyz.z - M->actor_xyz.z;
1383 }
1384 PXreal dist = ((subp1 * subp1) + (subp2 * subp2));
1385
1386 if (dist < PXreal(200 * 200)) {
1387 if (hits >= 4)
1388 hits -= 4;
1389 else
1390 hits = 0;
1391 } else if (dist < PXreal(500 * 500)) {
1392 if (hits >= 2)
1393 hits -= 2;
1394 else
1395 hits = 0;
1396 } else if (hits)
1397 hits--;
1398
1399 ob->SetIntegerVariable(ret, hits);
1400 }
1401
1402 MS->Call_socket(tid, "gun_shot", &retval); // the hit takes
1403
1404 // cancel any speech
1405 Exit_speech(tid);
1406 }
1407 } else {
1408 // ricochet sound
1409 missed = 1;
1410 }
1411 } else { // missed
1412 missed = 1;
1413 }
1414
1415 if (missed) {
1416 // gun sound
1417 if (logic_structs[cur_id]->sfxVars[RICOCHET_SFX_VAR] != 0)
1418 RegisterSound(cur_id, NULL, logic_structs[cur_id]->sfxVars[RICOCHET_SFX_VAR], ricochetDesc,
1419 (int8)127); // have to use full version so we can give hash instead of string
1420 else
1421 RegisterSound(cur_id, defaultRicochetSfx, ricochetDesc); // use small version as we have string not hash
1422 }
1423
1424 // if a guard, adjust the bullet/clip figures
1425 if (logic_structs[cur_id]->image_type == VOXEL)
1426 if (M->is_evil) {
1427 // take chi and player out of the equation
1428
1429 int32 ret = object->GetVariable("cur_bullets");
1430 if (ret != -1) {
1431 int32 result = object->GetIntegerVariable(ret);
1432
1433 if (!result) { // no bullets
1434 int32 clipret = object->GetVariable("number_of_clips");
1435 int32 no_clips = object->GetIntegerVariable(clipret);
1436 if (no_clips == -1)
1437 Fatal_error("object has no 'number_of_clips' variable");
1438
1439 if (no_clips) { // has clips left
1440 no_clips--; // 1 less
1441 object->SetIntegerVariable(clipret, no_clips);
1442
1443 int32 bull_per_clip = MS->player.GetBulletsPerClip();
1444
1445 object->SetIntegerVariable(ret, bull_per_clip); // reload the gun
1446 }
1447 } else { // has bullets, fire one
1448 result--;
1449 object->SetIntegerVariable(ret, result); // reload
1450 }
1451 }
1452 }
1453
1454 return (IR_CONT);
1455 }
1456
fn_apply_anim_y(int32 &,int32 * params)1457 mcodeFunctionReturnCodes _game_session::fn_apply_anim_y(int32 &, int32 *params) {
1458 // add the y offset from frame 0 to end frame
1459 // used for climbing ladders and stairs and so on where the height gets moved
1460
1461 // params 0 generic anim name
1462
1463 uint32 k;
1464 PXreal y_next;
1465
1466 const char *anim_name = (const char *)MemoryUtil::resolvePtr(params[0]);
1467
1468 // search for the named generic anim - cant use __ANIM_NAME from script unfortunately
1469 for (k = 0; k < __TOTAL_ANIMS; k++) {
1470 // we must search the table
1471 if (!strcmp(anim_name, master_anim_name_table[k].name)) {
1472 // found!
1473 ANIM_CHECK(k);
1474
1475 PXanim *pAnim = (PXanim *)rs_anims->Res_open(I->get_info_name(k), I->info_name_hash[k], I->base_path, I->base_path_hash); //
1476 PXreal x, z;
1477 PXreal yend;
1478 PXreal ystart;
1479
1480 PXFrameEnOfAnim(pAnim->frame_qty - 1, pAnim)->markers[ORG_POS].GetXYZ(&x, ¥d, &z);
1481
1482 PXFrameEnOfAnim(0, pAnim)->markers[ORG_POS].GetXYZ(&x, &ystart, &z);
1483
1484 y_next = yend - ystart;
1485
1486 Tdebug("y_apply.txt", "%s offset - %3.1f", (const char *)I->get_info_name(k), y_next);
1487
1488 M->actor_xyz.y += y_next;
1489 return IR_CONT;
1490 }
1491 }
1492
1493 Fatal_error("fn_apply_anim_y [%s] cant find generic anim [%s]", object->GetName(), anim_name);
1494
1495 return IR_CONT;
1496 }
1497
fn_add_y(int32 &,int32 * params)1498 mcodeFunctionReturnCodes _game_session::fn_add_y(int32 &, int32 *params) {
1499 // add y value to a mega
1500
1501 // params 0 value
1502
1503 if (L->image_type == PROP)
1504 Fatal_error("fn_add_y cant be used on a prop - %s", object->GetName());
1505
1506 M->actor_xyz.y += params[0];
1507
1508 Tdebug("fn_add_y.txt", "%s +%d to %3.1f", object->GetName(), params[0], M->actor_xyz.y);
1509
1510 return IR_CONT;
1511 }
1512
1513 } // End of namespace ICB
1514