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/p4.h"
29 #include "engines/icb/common/px_anims.h"
30 #include "engines/icb/session.h"
31 #include "engines/icb/animation_mega_set.h"
32 #include "engines/icb/global_objects.h"
33 #include "engines/icb/debug.h"
34 #include "engines/icb/player.h"
35 #include "engines/icb/res_man.h"
36
37 namespace ICB {
38
Easy_frame_motion_and_pan(__mega_set_names anim_type,bool8)39 bool8 _game_session::Easy_frame_motion_and_pan(__mega_set_names anim_type, bool8 /*player*/) {
40 // advances frame and motion AND PAN but does not check for barrier collisions
41 PXreal xnext, znext;
42 PXreal x, z;
43
44 ANIM_CHECK(anim_type);
45
46 PXanim *pAnim = (PXanim *)rs_anims->Res_open(I->get_info_name(anim_type), I->info_name_hash[anim_type], I->base_path, I->base_path_hash);
47
48 if (L->anim_pc + 1 >= pAnim->frame_qty)
49 Fatal_error("Easy_frame_and_motion finds [%s] has illegal frame in anim [%s] %d %d", (const char *)L->GetName(), (const char *)I->get_info_name(anim_type),
50 L->anim_pc, pAnim->frame_qty);
51
52 // add the change in pan from the last frame to the current frame of the anim to the logic objects pan
53 PXreal pan1, pan2;
54
55 // Get next frame from the anim
56 PXframe *nextFrame = PXFrameEnOfAnim(L->anim_pc + 1, pAnim);
57
58 // Get current frame from the anim
59 PXframe *currentFrame = PXFrameEnOfAnim(L->anim_pc, pAnim);
60
61 nextFrame->markers[ORG_POS].GetPan(&pan1);
62 currentFrame->markers[ORG_POS].GetPan(&pan2);
63
64 L->pan += (pan1 - pan2); // update by difference
65
66 // get motion displacement from currently displayed frame to next one
67 // note that we always read frame+1 for motion of next frame even though the voxel frame itself will be looped back to 0
68 PXreal x1, x2, z1, z2, unused;
69
70 nextFrame->markers[ORG_POS].GetXYZ(&x2, &unused, &z2);
71 currentFrame->markers[ORG_POS].GetXYZ(&x1, &unused, &z1);
72
73 xnext = x2 - x1;
74 znext = z2 - z1;
75
76 // advance the frame
77 L->anim_pc = (L->anim_pc + 1) % (pAnim->frame_qty - 1);
78
79 // get the pan unwind value of the frame to be printed
80 PXreal pan;
81
82 // Get the new current frame, using a new reference !
83 // as GCC got it all wrong if the same reference was re-used
84 currentFrame = PXFrameEnOfAnim(L->anim_pc, pAnim);
85
86 currentFrame->markers[ORG_POS].GetPan(&pan);
87
88 L->pan_adjust = pan; // this value will be unwound from the orientation of the frame at render time in stage draw
89
90 // calculate the new x and z coordinate from this frames motion offset
91 // do the z and x together
92 PXfloat ang = (L->pan - L->pan_adjust) * TWO_PI;
93 PXfloat cang = (PXfloat)PXcos(ang);
94 PXfloat sang = (PXfloat)PXsin(ang);
95
96 x = M->actor_xyz.x + PXfloat2PXreal(xnext * cang + znext * sang);
97 z = M->actor_xyz.z + PXfloat2PXreal(znext * cang - xnext * sang);
98
99 // x and z are the new coordinates
100
101 // record the new true actor position
102 M->actor_xyz.x = x;
103 M->actor_xyz.z = z;
104
105 // check for new parent box and if so bring barriers
106 if (L->pan >= HALF_TURN)
107 L->pan -= FULL_TURN;
108 else if (L->pan <= -HALF_TURN)
109 L->pan += FULL_TURN;
110
111 return (TRUE8);
112 }
113
Easy_frame_and_motion(__mega_set_names anim_type,bool8,uint8 nFrames)114 bool8 _game_session::Easy_frame_and_motion(__mega_set_names anim_type, bool8 /*player*/, uint8 nFrames) {
115 // advances frame and motion but does not check for barrier collisions
116 PXreal xnext, znext;
117 PXreal x, z;
118
119 ANIM_CHECK(anim_type);
120
121 PXanim *pAnim = (PXanim *)rs_anims->Res_open(I->get_info_name(anim_type), I->info_name_hash[anim_type], I->base_path, I->base_path_hash);
122
123 if ((L->anim_pc + nFrames) >= pAnim->frame_qty)
124 Fatal_error("Easy_frame_and_motion finds [%s] has illegal frame in anim [%s] %d %d", (const char *)L->GetName(), (const char *)I->get_info_name(anim_type),
125 L->anim_pc, pAnim->frame_qty);
126
127 // get motion displacement from currently displayed frame to next one
128 // note that we always read frame+1 for motion of next frame even though the voxel frame itself will be looped back to 0
129 PXreal x1, x2, z1, z2, unused;
130
131 // Get next frame from the anim
132 PXframe *nextFrame = PXFrameEnOfAnim(L->anim_pc + nFrames, pAnim);
133 // Get current frame from the anim
134 PXframe *currentFrame = PXFrameEnOfAnim(L->anim_pc, pAnim);
135
136 nextFrame->markers[ORG_POS].GetXYZ(&x2, &unused, &z2);
137 currentFrame->markers[ORG_POS].GetXYZ(&x1, &unused, &z1);
138
139 xnext = x2 - x1;
140 znext = z2 - z1;
141
142 // calculate the new x and z coordinate from this frames motion offset
143 // do the z and x together
144 PXfloat ang = L->pan * TWO_PI;
145 PXfloat cang = (PXfloat)PXcos(ang);
146 PXfloat sang = (PXfloat)PXsin(ang);
147
148 x = M->actor_xyz.x + PXfloat2PXreal(xnext * cang + znext * sang);
149 z = M->actor_xyz.z + PXfloat2PXreal(znext * cang - xnext * sang);
150 // x and z are the new coordinates
151
152 // advance the frame
153 L->anim_pc = (L->anim_pc + nFrames);
154
155 // record the new true actor position
156 M->actor_xyz.x = x;
157 M->actor_xyz.z = z;
158
159 return (TRUE8);
160 }
161
Advance_frame_and_motion(__mega_set_names anim_type,bool8 pl,uint8 nFrames)162 bool8 _game_session::Advance_frame_and_motion(__mega_set_names anim_type, bool8 pl, uint8 nFrames) {
163 // attempts to move the frame forward and move the character
164 // returns fail and frame is not changed if the way forward is blocked by a barrier
165 // the frame counter will be looped
166 // handles shallow barrier bump correction!
167
168 __barrier_result ret;
169 uint32 initial_pc = L->anim_pc;
170
171 ANIM_CHECK(anim_type);
172
173 ret = Core_advance(anim_type, pl, nFrames);
174
175 if (ret == __BLOCKED)
176 return (FALSE8);
177
178 if ((ret == __OK) || (ret == __NUDGED))
179 return (TRUE8);
180
181 // pan was corrected - go around again
182
183 L->anim_pc = initial_pc;
184 ret = Core_advance(anim_type, pl, nFrames);
185
186 if (ret == __BLOCKED) // v odd indeed
187 return (FALSE8);
188
189 if ((ret == __OK) || (ret == __NUDGED))
190 return (TRUE8); // good
191
192 // corrected again - this is strange
193
194 return (FALSE8);
195 }
196
Core_advance(__mega_set_names anim_type,bool8 pl,uint8 nFrames)197 __barrier_result _game_session::Core_advance(__mega_set_names anim_type, bool8 pl, uint8 nFrames) {
198 PXreal xnext, znext;
199 PXreal x, z;
200 __barrier_result ret;
201
202 PXanim *pAnim = (PXanim *)rs_anims->Res_open(I->get_info_name(anim_type), I->info_name_hash[anim_type], I->base_path, I->base_path_hash);
203
204 if ((L->anim_pc + nFrames) >= pAnim->frame_qty)
205 Fatal_error("Core_advance finds [%s] has illegal frame in anim [%s] %d %d", (const char *)L->GetName(), (const char *)I->get_info_name(anim_type), L->anim_pc,
206 pAnim->frame_qty);
207
208 // get motion displacement from currently displayed frame to next one
209 // note that we always read frame+1 for motion of next frame even though the voxel frame itself will be looped back to 0
210 PXreal x1, x2, z1, z2, unused;
211
212 // Get next frame from the anim
213 PXframe *nextFrame = PXFrameEnOfAnim(L->anim_pc + nFrames, pAnim);
214 // Get current frame from the anim
215 PXframe *currentFrame = PXFrameEnOfAnim(L->anim_pc, pAnim);
216
217 nextFrame->markers[ORG_POS].GetXYZ(&x2, &unused, &z2);
218 currentFrame->markers[ORG_POS].GetXYZ(&x1, &unused, &z1);
219
220 xnext = x2 - x1;
221 znext = z2 - z1;
222
223 // calculate the new x and z coordinate from this frames motion offset
224 // do the z and x together
225 PXfloat ang = L->pan * TWO_PI;
226 PXfloat cang = (PXfloat)PXcos(ang);
227 PXfloat sang = (PXfloat)PXsin(ang);
228
229 x = M->actor_xyz.x + PXfloat2PXreal(xnext * cang + znext * sang);
230 z = M->actor_xyz.z + PXfloat2PXreal(znext * cang - xnext * sang);
231 // x and z are the new coordinates
232
233 // but, are we walking into a barrier?
234 ret = Check_barrier_bump_and_bounce(x, M->actor_xyz.y, z, // new position
235 M->actor_xyz.x, M->actor_xyz.y, M->actor_xyz.z, // old position
236 pl);
237
238 L->anim_pc = (L->anim_pc + nFrames);
239
240 // did we move forward without a problem?
241 if (ret == __OK) {
242 // advance the frame
243
244 // record the new true actor position
245 M->actor_xyz.x = x;
246 M->actor_xyz.z = z;
247
248 // check for new parent box and if so bring barriers
249 Prepare_megas_route_barriers(pl);
250 }
251
252 return (ret);
253 }
254
Normalise_anim_pc()255 void _game_session::Normalise_anim_pc() {
256 // routines that make raw calls to advance_frame_and_motion need to call this to reset anim pc
257 // this is because of changes required by the multi-speed capabilities
258
259 PXanim *pAnim = (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); //
260 L->anim_pc = (L->anim_pc) % (pAnim->frame_qty - 1);
261 }
262
Reverse_frame_and_motion(__mega_set_names anim_type,bool8 pl,uint8 nFrames)263 bool8 _game_session::Reverse_frame_and_motion(__mega_set_names anim_type, bool8 pl, uint8 nFrames) {
264 // as Advance_frame_and_motion but frames work backward
265 // the frame counter will be looped
266 // handles shallow barrier bump correction!
267
268 __barrier_result ret;
269
270 ANIM_CHECK(anim_type);
271
272 ret = Core_reverse(anim_type, pl, nFrames);
273
274 if (ret == __BLOCKED)
275 return (FALSE8);
276
277 if ((ret == __OK) || (ret == __NUDGED))
278 return (TRUE8);
279
280 // pan was corrected - go around again
281 ret = Core_reverse(anim_type, pl, nFrames);
282
283 if (ret == __BLOCKED) // v odd indeed
284 return (FALSE8);
285
286 if ((ret == __OK) || (ret == __NUDGED))
287 return (TRUE8); // good
288
289 // corrected again - this is strange
290
291 return (FALSE8);
292 }
293
Core_reverse(__mega_set_names anim_type,bool8 pl,uint8 nFrames)294 __barrier_result _game_session::Core_reverse(__mega_set_names anim_type, bool8 pl, uint8 nFrames) {
295 // as Advance_frame_and_motion but frames work backward
296 // the frame counter will be looped
297 // handles shallow barrier bump correction!
298
299 PXreal xnext, znext;
300 PXreal x, z;
301 __barrier_result ret;
302 uint32 next_pc;
303
304 ANIM_CHECK(anim_type);
305
306 PXanim *pAnim = (PXanim *)rs_anims->Res_open(I->get_info_name(anim_type), I->info_name_hash[anim_type], I->base_path, I->base_path_hash);
307
308 // if we are on frame 0 then shift up to pretend we're coming in off the dummy frame
309 if (!L->anim_pc) {
310 next_pc = pAnim->frame_qty - 2;
311 L->anim_pc = pAnim->frame_qty - 1;
312 } else if (L->anim_pc < nFrames)
313 next_pc = 0;
314 else
315 next_pc = L->anim_pc - nFrames;
316
317 if ((next_pc >= pAnim->frame_qty) || (L->anim_pc >= pAnim->frame_qty))
318 Fatal_error("Core_reverse finds [%s] has illegal frame in anim [%s] %d %d %d", (const char *)L->GetName(), (const char *)I->get_info_name(anim_type), next_pc,
319 L->anim_pc, pAnim->frame_qty);
320
321 // get motion displacement from currently displayed frame to next one
322 // note that we always read frame+1 for motion of next frame even though the voxel frame itself will be looped back to 0
323 PXreal x1, x2, z1, z2, unused;
324
325 // Get next frame from the anim
326 PXframe *nextFrame = PXFrameEnOfAnim(next_pc, pAnim);
327 // Get current frame from the anim
328 PXframe *currentFrame = PXFrameEnOfAnim(L->anim_pc, pAnim);
329
330 nextFrame->markers[ORG_POS].GetXYZ(&x2, &unused, &z2);
331 currentFrame->markers[ORG_POS].GetXYZ(&x1, &unused, &z1);
332
333 xnext = x2 - x1;
334 znext = z2 - z1;
335
336 // calculate the new x and z coordinate from this frames motion offset
337 // do the z and x together
338 PXfloat ang = L->pan * TWO_PI;
339 PXfloat cang = (PXfloat)PXcos(ang);
340 PXfloat sang = (PXfloat)PXsin(ang);
341
342 x = M->actor_xyz.x + PXfloat2PXreal(xnext * cang + znext * sang);
343 z = M->actor_xyz.z + PXfloat2PXreal(znext * cang - xnext * sang);
344 // x and z are the new coordinates
345
346 // but, are we walking into a barrier?
347 ret = Check_barrier_bump_and_bounce(x, M->actor_xyz.y, z, // new position
348 M->actor_xyz.x, M->actor_xyz.y, M->actor_xyz.z, // old position
349 pl);
350
351 L->anim_pc = next_pc;
352
353 // did we move forward without a problem?
354 if (ret == __OK) {
355 // record the new true actor position
356 M->actor_xyz.x = x;
357 M->actor_xyz.z = z;
358
359 // check for new parent box and if so bring barriers
360 Prepare_megas_route_barriers(pl);
361 }
362
363 return (ret);
364 }
365
Animate_turn_to_pan(__mega_set_names anim_type,uint32 speedup)366 void _game_session::Animate_turn_to_pan(__mega_set_names anim_type, uint32 speedup) {
367 // route manager turns character on the spot until facing route->target_pan
368 // final pan may need to be snapped to avoid overrun
369 // once done, x,z are restored to pre-turn animations - this is essential if character is to follow route correctly
370 // there is no barrier check!
371
372 // do a frames turn anim
373 // have we finished
374 // snap pan
375 // restore x,z
376
377 uint32 next_pc, info_pc;
378 PXfloat this_pan_change;
379
380 // set type
381 L->cur_anim_type = anim_type;
382
383 ANIM_CHECK(anim_type);
384
385 // get anim set
386 PXanim *pAnim = (PXanim *)rs_anims->Res_open(L->voxel_info->get_info_name(anim_type), L->voxel_info->info_name_hash[anim_type], L->voxel_info->base_path,
387 L->voxel_info->base_path_hash); //
388
389 // anim pc may be illegal so neutralise it
390 L->anim_pc = (L->anim_pc) % (pAnim->frame_qty - 1);
391
392 // adjust the frame PC in the direction we're going to turn
393 if (!M->turn_dir) {
394 // turning right (clockwise)
395 // anims are clockwise to run naturally through frames
396 next_pc = (L->anim_pc + 1) % (pAnim->frame_qty - 1); // next frame to display
397 info_pc = L->anim_pc + 1; // from to take movement info from
398 } else { // pos
399 // turning left
400 // reverse the anim
401
402 if (!L->anim_pc) { // pc==0
403 info_pc = next_pc = pAnim->frame_qty - 2; // take movement info from dummy marker frame
404 L->anim_pc = pAnim->frame_qty - 1; // display last legal frame - have to force this for math to work
405 } else { // pc is non zero
406 info_pc = next_pc = L->anim_pc - 1; // display and movement info from next frame down
407 }
408 }
409
410 if ((info_pc >= pAnim->frame_qty) || (next_pc >= pAnim->frame_qty))
411 Fatal_error("Animate_turn_to_pan [%s] using illegal frame", object->GetName());
412
413 // update engine pan with the difference between pan of previous frame and next frame
414 PXreal pan1, pan2;
415
416 // Get info_pc frame from the anim
417 PXframe *infoFrame = PXFrameEnOfAnim(info_pc, pAnim);
418 // Get current frame from the anim
419 PXframe *currentFrame = PXFrameEnOfAnim(L->anim_pc, pAnim);
420
421 infoFrame->markers[ORG_POS].GetPan(&pan1);
422 currentFrame->markers[ORG_POS].GetPan(&pan2);
423
424 this_pan_change = (pan1 - pan2); // update by difference
425
426 // times the speedup for fast turn functions - normally 0
427 this_pan_change *= speedup;
428
429 if (this_pan_change >= HALF_TURN) {
430 this_pan_change -= FULL_TURN;
431 } else if (this_pan_change <= -HALF_TURN) {
432 this_pan_change += FULL_TURN; // stop the wrap
433 }
434
435 if (PXfabs(this_pan_change) > M->target_pan) {
436 // we are going to turn too much this go so clip
437
438 L->pan = M->actual_target_pan; // clip to actual left
439
440 M->target_pan = ZERO_TURN; // we're done
441
442 } else {
443 // still further to go
444
445 L->pan += this_pan_change;
446
447 M->target_pan = M->target_pan - (PXfloat)PXfabs(this_pan_change);
448 }
449
450 // get motion displacement from currently displayed frame to next one
451 // note that we always read frame+1 for motion of next frame even though the voxel frame itself will be looped back to 0
452 PXreal x1, x2, z1, z2, unused;
453
454 // Get the next frame from the anim
455 PXframe *nextFrame = PXFrameEnOfAnim(next_pc, pAnim);
456
457 nextFrame->markers[ORG_POS].GetXYZ(&x2, &unused, &z2);
458
459 // Note, assumes current frame hasn't changed i.e L->info_pc is same
460 currentFrame->markers[ORG_POS].GetXYZ(&x1, &unused, &z1);
461
462 // FIXME: xnext and znext are not used currently...
463 //PXreal xnext = x2 - x1;
464 //PXreal znext = z2 - z1;
465
466 // update pc
467 L->anim_pc = next_pc; // allready computed
468
469 // get the pan unwind value of the frame to be printed
470 PXreal pan;
471
472 // Note, L->anim_pc = next_pc
473 nextFrame->markers[ORG_POS].GetPan(&pan);
474
475 L->pan_adjust = pan;
476
477 // FIXME: ang, cang and sang are not used currently...
478 // calculate the new x and z coordinate from this frames motion offset
479 // do the z and x together
480 // PXfloat ang = (L->pan - L->pan_adjust) * TWO_PI;
481 //PXfloat cang = (PXfloat)PXcos(ang);
482 //PXfloat sang = (PXfloat)PXsin(ang);
483
484 // FIXME: x and z are not used currently...
485 //PXreal x = M->actor_xyz.x + PXfloat2PXreal(xnext * cang + znext * sang);
486 //PXreal z = M->actor_xyz.z + PXfloat2PXreal(znext * cang - xnext * sang);
487 // x and z are the new coordinates
488
489 if (L->pan >= HALF_TURN)
490 L->pan -= FULL_TURN;
491 else if (L->pan <= -HALF_TURN)
492 L->pan += FULL_TURN; // stop the wrap
493 }
494
Calc_target_pan(PXreal x,PXreal z,PXreal x2,PXreal z2)495 bool8 _game_session::Calc_target_pan(PXreal x, PXreal z, PXreal x2, PXreal z2) {
496 // will LOOK TOWARDS a shallow angle or set M->target_pan
497 // not to be used by routing routines!
498
499 // x,z are source coordinate
500 // x2,z2 are target coordinate
501
502 // returns FALSE no turn required
503 // TRUE turn required
504
505 PXfloat new_pan, diff;
506
507 new_pan = PXAngleOfVector(z - z2, x - x2); // work out vector
508
509 M->looking_pan = new_pan;
510
511 // get difference between the two
512 diff = new_pan - L->pan;
513
514 if (PXfabs(diff) > (FULL_TURN / 10)) { // 0.1f
515 // work out which way to turn
516 if (diff > HALF_TURN)
517 diff -= FULL_TURN;
518
519 else if (diff < -HALF_TURN)
520 diff += FULL_TURN;
521
522 // diff is now the distance to turn by and its sign denotes direction
523
524 if (diff < FLOAT_ZERO) {
525 M->turn_dir = 0; // right
526 } else {
527 M->turn_dir = 1; // left
528 }
529
530 M->target_pan = (PXfloat)PXfabs(diff); // save positive pan distance
531
532 M->actual_target_pan = new_pan; // actual target which we may clip to
533
534 L->anim_pc = 0; // legal pc for first frame in turn anim - this needs thought
535
536 // we face straight ahead
537 I->lookBone.boneTarget.vz = (int16)(0);
538
539 return (TRUE8);
540 } else {
541 // face towards object or whatever with upper body
542 I->lookBone.boneNumber = 1;
543 I->lookBone.boneSpeed = 128;
544 I->lookBone.boneTarget.vz = (int16)(diff * (4096 / FULL_TURN)); // on psx diff is 0-4096 (full_turn), so we want diff*1 = diff * (4096/4096)
545 // on pc diff is 0-1 (full_turn), we we want diff*4096 = diff * (4096/1)
546
547 return (FALSE8);
548 }
549 }
550
Calc_target_pan_no_bones(PXreal x,PXreal z,PXreal x2,PXreal z2)551 bool8 _game_session::Calc_target_pan_no_bones(PXreal x, PXreal z, PXreal x2, PXreal z2) {
552 // will snap a shallow angle or set M->target_pan
553
554 // x,z are source coordinate
555 // x2,z2 are target coordinate
556
557 // returns FALSE no turn required
558 // TRUE turn required
559
560 PXfloat new_pan, diff;
561
562 new_pan = PXAngleOfVector(z - z2, x - x2); // work out vector
563
564 // get difference between the two
565 diff = new_pan - L->pan;
566
567 if (PXfabs(diff) > (FULL_TURN / 10)) { // 0.1f
568 // work out which way to turn
569 if (diff > HALF_TURN)
570 diff -= FULL_TURN;
571
572 else if (diff < -HALF_TURN)
573 diff += FULL_TURN;
574
575 // diff is now the distance to turn by and its sign denotes direction
576
577 if (diff < FLOAT_ZERO) {
578 M->turn_dir = 0; // right
579 } else {
580 M->turn_dir = 1; // left
581 }
582
583 M->target_pan = (PXfloat)PXfabs(diff); // save positive pan distance
584
585 M->actual_target_pan = new_pan; // actual target which we may clip to
586
587 L->anim_pc = 0; // legal pc for first frame in turn anim - this needs thought
588
589 // we face straight ahead
590 I->lookBone.boneTarget.vz = (int16)(0);
591
592 return (TRUE8);
593 } else {
594 // shallow angle so snap and continue as normal
595 L->pan = new_pan;
596
597 return FALSE8;
598 }
599 }
600
Soft_start_with_double_link(__mega_set_names link_one,__mega_set_names link_two,__mega_set_names next_anim)601 void _game_session::Soft_start_with_double_link(__mega_set_names link_one, __mega_set_names link_two, __mega_set_names next_anim) {
602 // soft start from best os 2 link anims (if CAPS available) and push follow on animation
603
604 int32 diff = 1000000; // a big number
605
606 // is the link anim available?
607 if (I->IsAnimTable(link_one)) {
608 // push hard start follow on animation
609 M->next_anim_type = next_anim;
610
611 // will pick best
612 diff = Soften_up_anim_file(link_one, diff);
613
614 if (I->IsAnimTable(link_two)) {
615 // may pick best
616 Soften_up_anim_file(link_two, diff);
617 }
618 } else { // first link anim requested not available so skip the second and jump straight in
619 // set anim type
620 L->anim_pc = 0;
621 L->cur_anim_type = next_anim;
622 }
623 }
624
Soft_start_with_single_link(__mega_set_names link_anim,__mega_set_names next_anim)625 void _game_session::Soft_start_with_single_link(__mega_set_names link_anim, __mega_set_names next_anim) {
626 // soft start a link anim (if CAPS available) and push follow on animation
627
628 int32 diff = 1000000; // a big number
629
630 // is the link anim available?
631 if (I->IsAnimTable(link_anim)) {
632 // will pick best
633 Soften_up_anim_file(link_anim, diff);
634
635 // push hard start follow on animation
636 M->next_anim_type = next_anim;
637 } else { // link anim requested but not available
638 // set anim type
639 L->anim_pc = 0;
640 L->cur_anim_type = next_anim;
641 }
642 }
643
Soft_start_single_anim(__mega_set_names next_anim)644 void _game_session::Soft_start_single_anim(__mega_set_names next_anim) {
645 // select best leg position for specified animation
646 // there is no optional link
647 // it HAS to be ok to skip past frames in the new anim
648 // also sets cur_anim_type
649
650 int32 diff = 1000000; // a big number
651
652 // next anim not in CAPS
653 if ((!L->voxel_info->IsAnimTable(next_anim))) {
654 // cant go on without a major anim - this is not a link so cant just be skipped
655 Shut_down_object("by Soft_start_single_anim next anim dont exist");
656 return;
657 }
658
659 // will pick best
660 Soften_up_anim_file(next_anim, diff);
661
662 // set anim type
663 L->cur_anim_type = next_anim;
664
665 // nothing to move onto
666 M->next_anim_type = __NO_ANIM;
667 }
668
Hard_start_single_anim(__mega_set_names next_anim)669 void _game_session::Hard_start_single_anim(__mega_set_names next_anim) {
670 // jumps straight into new anim on frame 0
671 // sets cur_anim_type
672
673 // next anim not in CAPS
674 if ((!L->voxel_info->IsAnimTable(next_anim))) {
675 // cant go on without a major anim - this is not a link so cant just be skipped
676 Shut_down_object("by Hard_start_single_anim next anim dont exist");
677 return;
678 }
679
680 // hard start on frame 0
681 L->anim_pc = 0;
682
683 // set anim type
684 L->cur_anim_type = next_anim;
685
686 // nothing to move onto
687 M->next_anim_type = __NO_ANIM;
688 }
689
Soften_up_anim_file(__mega_set_names link,int32 diff)690 int32 _game_session::Soften_up_anim_file(__mega_set_names link, int32 diff) {
691 // pick best frame in passed anim compared to best so far passed in 'diff'
692 uint32 old_leg_pos;
693 int32 j;
694
695 // Jake check the anim exists / make its name
696 ANIM_CHECK(L->cur_anim_type);
697
698 // Do this first to make the whole res_open defrag thing work nicely
699 PXanim *pCur_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);
700
701 // find out leg position for current frame
702 old_leg_pos = PXFrameEnOfAnim(L->anim_pc, pCur_Anim)->left_foot_distance;
703
704 // Jake check the link anim exists / make its name
705 ANIM_CHECK(link);
706 PXanim *pLnk_Anim = (PXanim *)rs_anims->Res_open(I->get_info_name(link), I->info_name_hash[link], I->base_path, I->base_path_hash); //
707 // special check for only one frame
708 if (pLnk_Anim->frame_qty == 1) {
709 L->cur_anim_type = link; // set type
710 L->anim_pc = 0; // first frame
711 return (diff);
712 }
713
714 // see which has the closest leg position
715 for (j = 0; j < (pLnk_Anim->frame_qty - 1); j++) {
716 int32 foot = PXFrameEnOfAnim(j, pLnk_Anim)->left_foot_distance;
717 int32 d = twabs(foot - old_leg_pos);
718
719 if (d < diff) {
720 diff = d;
721 L->cur_anim_type = link; // set type
722 L->anim_pc = j; // this frame is best so far
723 }
724 }
725
726 // return best diff so far incase we're coming back on a multiple link anim scheme
727 return (diff);
728 }
729
Play_anim()730 bool8 _game_session::Play_anim() {
731 // plays anim until finished
732 // keeps playing anim even if motion has been stopped
733 // when current is done it will play the queued M->next_anim_type if it exists. When thats done we're done
734
735 // returns 1 when done
736 // 0 we need to come back next cycle
737
738 // get animation
739 PXanim *pAnim = (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);
740
741 // last frame currently displayed?
742 if ((int32)(L->anim_pc + 1) == (pAnim->frame_qty - 1)) {
743 // we displayed the last frame last cycle - so display first of new mode this cycle
744 // we may have been playing a link anim - so check for a new anim waiting in M->next_anim_type
745 if (M->next_anim_type == __NO_ANIM) {
746 // we're finished
747 return (TRUE8);
748 }
749
750 // reset pc ready for whatever starts next
751 // current must be link so we go into new on frame 0
752 L->anim_pc = 0;
753
754 // ok, there is a link anim
755 L->cur_anim_type = M->next_anim_type;
756 M->next_anim_type = __NO_ANIM; // must clear this or it'll play forever
757
758 // need to come back
759 return (FALSE8);
760 }
761
762 // shift character and frame forward by the amount appropriate
763 Advance_frame_and_motion(L->cur_anim_type, 0, 1);
764
765 // need to come back
766 return (FALSE8);
767 }
768
Play_reverse_anim()769 bool8 _game_session::Play_reverse_anim() {
770 // plays anim until finished
771 // keeps playing anim even if motion has been stopped
772 // when current is done it will play the queued M->next_anim_type if it exists. When thats done we're done
773
774 // returns 1 when done
775 // 0 we need to come back next cycle
776 Zdebug("Play_reverse_anim");
777
778 // last frame currently displayed?
779 if (!L->anim_pc) {
780 // we displayed the last frame last cycle - so display first of new mode this cycle
781
782 // we may have been playing a link anim - so check for a new anim waiting in M->next_anim_type
783 if (M->next_anim_type == __NO_ANIM) {
784 Zdebug("done");
785 // we're finished
786 return (TRUE8);
787 }
788
789 // reset pc ready for whatever starts next
790 // current must be link so we go into new on frame 0
791 L->anim_pc = 0;
792
793 // ok, there is a link anim
794 L->cur_anim_type = M->next_anim_type;
795 M->next_anim_type = __NO_ANIM; // must clear this or it'll play forever
796
797 // need to come back
798 return (FALSE8);
799 }
800
801 // shift character and frame forward by the amount appropriate
802 Reverse_frame_and_motion(L->cur_anim_type, 0, 1);
803
804 Zdebug("~Reverse");
805
806 // need to come back
807 return (FALSE8);
808 }
809
Play_anim_with_no_movement()810 bool8 _game_session::Play_anim_with_no_movement() {
811 // plays anim until finished
812 // keeps playing anim even if motion has been stopped
813 // when current is done it will play the queued M->next_anim_type if it exists. When thats done we're done
814
815 // returns 1 when done
816 // 0 we need to come back next cycle
817
818 // get animation
819 PXanim *pAnim = (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); //
820
821 // last frame currently displayed?
822 if ((int32)(L->anim_pc + 1) == (pAnim->frame_qty - 1)) {
823 // we displayed the last frame last cycle - so display first of new mode this cycle
824
825 // we may have been playing a link anim - so check for a new anim waiting in M->next_anim_type
826 if (M->next_anim_type == __NO_ANIM) {
827 // we're finished
828 return (TRUE8);
829 }
830
831 // reset pc ready for whatever starts next
832 // current must be link so we go into new on frame 0
833 L->anim_pc = 0;
834
835 // ok, there is a link anim
836 L->cur_anim_type = M->next_anim_type;
837 M->next_anim_type = __NO_ANIM; // must clear this or it'll play forever
838
839 // need to come back
840 return (FALSE8);
841 }
842
843 // shift character and frame forward by the amount appropriate
844
845 // ok, advance frame but not position
846 L->anim_pc = (L->anim_pc + 1) % (pAnim->frame_qty - 1);
847
848 // need to come back
849 return (FALSE8);
850 }
851
Set_motion(__motion motion)852 void _game_session::Set_motion(__motion motion) {
853 // set motion type for cur object
854 M->motion = motion;
855 }
856
Get_motion()857 __motion _game_session::Get_motion() {
858 // get motion type for cur object
859 return (M->motion);
860 }
861
Set_pose(__weapon weapon)862 void _game_session::Set_pose(__weapon weapon) {
863 // set weapon type for cur object
864 M->weapon = weapon;
865 }
866
Change_pose_in_current_anim_set()867 void _game_session::Change_pose_in_current_anim_set() {
868 // change the weapon set
869 // delete an old one
870 // we very much expect a set to already have been picked by the script
871 // its likely that this will only be called by the player arm/unarm code
872
873 // create _vox_image object
874 logic_structs[cur_id]->voxel_info->___init(M->chr_name, M->anim_set, logic_structs[cur_id]->mega->Fetch_pose()); // we pass the person, set names through
875 }
876
Fetch_last_frame(__mega_set_names anima)877 uint32 _game_session::Fetch_last_frame(__mega_set_names anima) {
878 // return final frame number in animation
879 if ((!I->IsAnimTable(anima))) {
880 Fatal_error("Fetch_last_frame cant access illegal anim [%s]", master_anim_name_table[anima].name);
881 }
882
883 PXanim *pAnim = (PXanim *)rs_anims->Res_open(I->get_info_name(anima), I->info_name_hash[anima], I->base_path, I->base_path_hash);
884
885 return (pAnim->frame_qty - 1);
886 }
887
888 } // End of namespace ICB
889