1 /***************************************************************************
2 Collision & Crash Code.
3
4 There are two types of collision: Scenery & Traffic.
5
6 1/ Traffic: The Ferrari will spin after a collision.
7 2/ Scenery: There are three types of scenery collision:
8 - Low speed bump. Car rises slightly in the air and stalls.
9 - Mid speed spin. Car spins and slides after collision.
10 - High speed flip. If slightly slower, car rolls into screen.
11 Otherwise, grows towards screen and vanishes
12
13 Known Issues With Original Code:
14 - Passenger sprites flicker if they land moving in the water on Stage 1
15
16 The Ferrari sprite is used differently by the crash code.
17 As there's only one of them, I've rolled the additional variables into
18 this class.
19
20 Copyright Chris White.
21 See license.txt for more details.
22 ***************************************************************************/
23
24 #include "engine/oferrari.hpp"
25 #include "engine/oinputs.hpp"
26 #include "engine/olevelobjs.hpp"
27 #include "engine/outils.hpp"
28 #include "engine/ocrash.hpp"
29
30 OCrash ocrash;
31
OCrash(void)32 OCrash::OCrash(void)
33 {
34 }
35
36
~OCrash(void)37 OCrash::~OCrash(void)
38 {
39 }
40
init(oentry * f,oentry * s,oentry * p1,oentry * p1s,oentry * p2,oentry * p2s)41 void OCrash::init(oentry* f, oentry* s, oentry* p1, oentry* p1s, oentry* p2, oentry* p2s)
42 {
43 spr_ferrari = f;
44 spr_shadow = s;
45 spr_pass1 = p1;
46 spr_pass1s = p1s;
47 spr_pass2 = p2;
48 spr_pass2s = p2s;
49
50 // Setup function pointers for passenger sprites
51 function_pass1 = &OCrash::do_crash_passengers;
52 function_pass2 = &OCrash::do_crash_passengers;
53 }
54
is_flip()55 bool OCrash::is_flip()
56 {
57 return crash_counter && crash_type == CRASH_FLIP;
58 }
59
enable()60 void OCrash::enable()
61 {
62 // This is called multiple times, so need this check in place
63 if (spr_ferrari->control & OSprites::ENABLE)
64 return;
65
66 spr_ferrari->control |= OSprites::ENABLE;
67
68 // Reset all corresponding variables
69 spinflipcount1 = 0;
70 spinflipcount2 = 0;
71 slide = 0;
72 frame = 0;
73 addr = 0;
74 camera_x_target = 0;
75 camera_xinc = 0;
76 lookup_index = 0;
77 frame_restore = 0;
78 shift = 0;
79 crash_speed = 0;
80 crash_zinc = 0;
81 crash_side = 0;
82
83 spr_ferrari->counter = 0;
84
85 outrun.ttrial.crashes++;
86 }
87
88 // Source: 0x1128
clear_crash_state()89 void OCrash::clear_crash_state()
90 {
91 spin_control1 = 0;
92 coll_count1 = 0;
93 coll_count2 = 0;
94 olevelobjs.collision_sprite = 0;
95 crash_counter = 0;
96 crash_state = 0;
97 crash_z = 0;
98 spin_pass_frame = 0;
99 crash_spin_count = 0;
100 crash_delay = 0;
101 crash_type = 0;
102 skid_counter = 0;
103 }
104
tick()105 void OCrash::tick()
106 {
107 if (!outrun.tick_frame &&
108 oroad.get_view_mode() == ORoad::VIEW_INCAR &&
109 crash_type != CRASH_FLIP)
110 return;
111
112 // Do Ferrari
113 if (spr_ferrari->control & OSprites::ENABLE)
114 if (outrun.tick_frame) do_crash();
115 else osprites.do_spr_order_shadows(spr_ferrari);
116
117 // Do Car Shadow
118 if (spr_shadow->control & OSprites::ENABLE)
119 if (outrun.tick_frame) do_shadow(spr_ferrari, spr_shadow);
120 else osprites.do_spr_order_shadows(spr_shadow);
121
122 // Do Passenger 1
123 if (spr_pass1->control & OSprites::ENABLE)
124 if (outrun.tick_frame) ((ocrash).*(function_pass1))(spr_pass1);
125 else osprites.do_spr_order_shadows(spr_pass1);
126
127 // Do Passenger 1 Shadow
128 if (spr_pass1s->control & OSprites::ENABLE)
129 if (outrun.tick_frame) do_shadow(spr_pass1, spr_pass1s);
130 else osprites.do_spr_order_shadows(spr_pass1s);
131
132 // Do Passenger 2
133 if (spr_pass2->control & OSprites::ENABLE)
134 if (outrun.tick_frame) ((ocrash).*(function_pass2))(spr_pass2);
135 else osprites.do_spr_order_shadows(spr_pass2);
136
137 // Do Passenger 2 Shadow
138 if (spr_pass2s->control & OSprites::ENABLE)
139 if (outrun.tick_frame) do_shadow(spr_pass2, spr_pass2s);
140 else osprites.do_spr_order_shadows(spr_pass2s);
141 }
142
143 // Source: 0x1162
do_crash()144 void OCrash::do_crash()
145 {
146 switch (outrun.game_state)
147 {
148 case GS_INIT_MUSIC:
149 case GS_MUSIC:
150 end_collision();
151 return;
152
153 // Fall through to continue code below
154 case GS_ATTRACT:
155 case GS_INGAME:
156 case GS_BONUS:
157 break;
158
159 default:
160 // In other modes render crashing ferrari if crash counter is set
161 if (crash_counter)
162 {
163 if (oroad.get_view_mode() != ORoad::VIEW_INCAR || crash_type == CRASH_FLIP)
164 osprites.do_spr_order_shadows(spr_ferrari);
165 }
166 // Set Distance Into Screen from crash counter
167 spr_ferrari->road_priority = spr_ferrari->counter;
168 return;
169 }
170
171 // ------------------------------------------------------------------------
172 // cont1: Adjust steering
173 // ------------------------------------------------------------------------
174 int16_t steering_adjust = oinputs.steering_adjust;
175 oinputs.steering_adjust = 0;
176
177 if (!oferrari.car_ctrl_active)
178 {
179 if (spin_control1 == 0)
180 {
181 uint16_t inc = ((oinitengine.car_increment >> 16) * 31) >> 5;
182 oinitengine.car_increment = (oinitengine.car_increment & 0xFFFF) | (inc << 16);
183 oferrari.car_inc_old = inc;
184 }
185 else
186 {
187 oinputs.steering_adjust = steering_adjust >> 1;
188 }
189 }
190
191 // ------------------------------------------------------------------------
192 // Determine whether to init spin or crash code
193 // ------------------------------------------------------------------------
194 int16_t spin2_copy = spin_control2;
195
196 // dec_spin2:
197 if (spin2_copy != 0)
198 {
199 spin2_copy -= 2;
200 if (spin2_copy < 0)
201 spin_control2 = 0;
202 else
203 spin_switch(spin2_copy);
204 }
205
206 // dec_spin1:
207 int16_t spin1_copy = spin_control1;
208
209 if (spin1_copy != 0)
210 {
211 spin1_copy -= 2;
212 if (spin1_copy < 0)
213 spin_control1 = 0;
214 else
215 spin_switch(spin1_copy);
216 }
217 // Not spinning, init crash code
218 else
219 crash_switch();
220 }
221
222 // Source: 0x1224
spin_switch(const uint16_t ctrl)223 void OCrash::spin_switch(const uint16_t ctrl)
224 {
225 crash_counter++;
226 crash_z = 0;
227
228 switch (ctrl & 3)
229 {
230 // No Spin - Need to init crash/spin routines
231 case 0:
232 init_collision();
233 break;
234 // Init Spin
235 case 1:
236 do_collision();
237 break;
238 // Spin In Progress - End Collision Routine
239 case 2:
240 case 3:
241 end_collision();
242 break;
243 }
244 }
245
246 // Init Crash.
247 //
248 // Source: 0x1252
crash_switch()249 void OCrash::crash_switch()
250 {
251 crash_counter++;
252 crash_z = 0;
253
254 switch (crash_state & 7)
255 {
256 // No Crash. Need to setup crash routines.
257 case 0:
258 init_collision();
259 break;
260 // Initial Collision
261 case 1:
262 if ((crash_type & 3) == 0) do_bump();
263 else do_collision();
264 break;
265 // Flip Car
266 case 2:
267 do_car_flip();
268 break;
269 // Horizontally Flip Car, Trigger Smoke Cloud
270 case 3:
271 case 4:
272 trigger_smoke();
273 break;
274 // Do Girl Pointing Finger Animation/Delay Before Pan
275 case 5:
276 post_flip_anim();
277 break;
278 // Pan Camera To Track Centre
279 case 6:
280 pan_camera();
281 break;
282 // Camera Repositioned. Prepare For Restart.
283 case 7:
284 end_collision();
285 break;
286 }
287 }
288
289 // Init Collision. Used For Spin & Flip
290 //
291 // Source: 0x1962
init_collision()292 void OCrash::init_collision()
293 {
294 oferrari.car_state = OFerrari::CAR_ANIM_SEQ; // Denote car animation sequence
295
296 // Enable crash sprites
297 spr_shadow->control |= OSprites::ENABLE;
298 spr_pass1->control |= OSprites::ENABLE;
299 spr_pass2->control |= OSprites::ENABLE;
300
301 // Disable normal sprites
302 oferrari.spr_ferrari->control &= ~OSprites::ENABLE;
303 oferrari.spr_shadow->control &= ~OSprites::ENABLE;
304 oferrari.spr_pass1->control &= ~OSprites::ENABLE;
305 oferrari.spr_pass2->control &= ~OSprites::ENABLE;
306
307 spr_ferrari->x = oferrari.spr_ferrari->x;
308 spr_ferrari->y = 221;
309 spr_ferrari->counter = 0x1FC;
310 spr_ferrari->draw_props = oentry::BOTTOM;
311
312 // Collided with another vechicle
313 if (spin_control2)
314 init_spin2();
315 else if (spin_control1)
316 init_spin1();
317 // Crash into scenery
318 else
319 {
320 skid_counter = 0;
321 uint16_t car_inc = oinitengine.car_increment >> 16;
322 if (car_inc < 0x64)
323 collide_slow();
324 else if (car_inc < 0xC8)
325 collide_med();
326 else
327 collide_fast();
328 }
329 }
330
331 // This code also triggers a flip, if the crash_type is set correctly.
332 // Source: 0x138C
do_collision()333 void OCrash::do_collision()
334 {
335 if (olevelobjs.collision_sprite)
336 {
337 olevelobjs.collision_sprite = 0;
338 if (spin_control1 || spin_control2)
339 {
340 spin_control2 = 0;
341 spin_control1 = 0;
342 init_collision(); // Init collision with another sprite
343 return;
344 }
345
346 // Road generator 1
347 if (oinitengine.car_x_pos - (oroad.road_width >> 16) >= 0)
348 {
349 if (slide < 0)
350 {
351 slide = -slide;
352 oinitengine.car_x_pos -= slide;
353 osoundint.queue_sound(sound::CRASH2);
354 }
355 }
356 // Road generator 2
357 else
358 {
359 if (slide >= 0)
360 {
361 slide = -slide;
362 oinitengine.car_x_pos -= slide;
363 osoundint.queue_sound(sound::CRASH2);
364 }
365 }
366 }
367 // 0x13F8
368 uint32_t property_table = addr + (frame << 3);
369 crash_z = spr_ferrari->counter;
370 spr_ferrari->zoom = 0x80;
371 spr_ferrari->priority = 0x1FD;
372 oinitengine.car_x_pos -= slide;
373 spr_ferrari->addr = roms.rom0p->read32(property_table);
374
375 if (roms.rom0p->read8(4 + property_table))
376 spr_ferrari->control |= OSprites::HFLIP;
377 else
378 spr_ferrari->control &= ~OSprites::HFLIP;
379
380 //spr_ferrari->pal_src = roms.rom0p->read8(5 + property_table);
381 spr_ferrari->pal_src = oferrari.ferrari_pal;
382 spin_pass_frame = (int8_t) roms.rom0p->read8(6 + property_table);
383
384 if (--spinflipcount2 > 0)
385 {
386 done(spr_ferrari);
387 return;
388 }
389
390 spinflipcount2 = crash_spin_count; // Expired: spinflipcount
391
392 if (spinflipcount1)
393 {
394 frame++;
395
396 // 0x1470
397 // Initialize Car Flip
398 if (!spin_control1 && !spin_control2 && frame == 2 && crash_type != CRASH_SPIN)
399 {
400 crash_state = 2; // flip
401 addr = outrun.adr.sprite_crash_flip;
402 spinflipcount1 = 3; // 3 flips remaining
403 spinflipcount2 = crash_spin_count;
404 frame = 0;
405
406 // Enable passenger shadows
407 spr_pass1s->control |= OSprites::ENABLE;
408 spr_pass2s->control |= OSprites::ENABLE;
409 done(spr_ferrari);
410 return;
411 }
412 // Do Spin
413 else
414 {
415 if (slide > 0)
416 slide -= 2;
417 else if (slide < -2)
418 slide += 2;
419
420 // End of frame sequence
421 if (!roms.rom0p->read8(7 + property_table))
422 {
423 done(spr_ferrari);
424 return;
425 }
426 }
427 }
428 // 0x14F4
429 frame = 0;
430
431 // Last spin
432 if (--spinflipcount1 <= 0)
433 {
434 osoundint.queue_sound(sound::STOP_SLIP);
435 if (spin_control2)
436 {
437 spin_control2++;
438 }
439 else if (spin_control1)
440 {
441 spin_control1++;
442 }
443 // Init smoke
444 else
445 {
446 crash_state = 4; // trigger smoke
447 crash_spin_count = 1;
448 spr_ferrari->x += slide; // inc ferrari x based on slide value
449 }
450 }
451 else
452 crash_spin_count++;
453
454 done(spr_ferrari);
455 }
456
457 // Source: 0x1D0C
end_collision()458 void OCrash::end_collision()
459 {
460 // Enable 'normal' Ferrari object
461 oferrari.spr_ferrari->control |= OSprites::ENABLE;
462 oferrari.spr_shadow->control |= OSprites::ENABLE;
463 oferrari.spr_pass1->control |= OSprites::ENABLE;
464 oferrari.spr_pass2->control |= OSprites::ENABLE;
465
466 coll_count2 = coll_count1;
467 if (!coll_count2)
468 coll_count2 = coll_count1 = 1;
469
470 crash_counter = 0;
471 crash_state = 0;
472 olevelobjs.collision_sprite = 0;
473
474 oferrari.spr_ferrari->x = 0;
475 oferrari.spr_ferrari->y = 221;
476 oferrari.car_ctrl_active = true;
477 oferrari.car_state = OFerrari::CAR_NORMAL;
478 olevelobjs.spray_counter = 0;
479 crash_z = 0;
480
481 if (spin_control1)
482 oferrari.car_inc_old = oinitengine.car_increment >> 16;
483 else
484 oferrari.reset_car();
485
486 spin_control2 = 0;
487 spin_control1 = 0;
488
489 spr_ferrari->control &= ~OSprites::ENABLE;
490 spr_shadow->control &= ~OSprites::ENABLE;
491 spr_pass1->control &= ~OSprites::ENABLE;
492 spr_pass1s->control &= ~OSprites::ENABLE;
493 spr_pass2->control &= ~OSprites::ENABLE;
494 spr_pass2s->control &= ~OSprites::ENABLE;
495
496 function_pass1 = &OCrash::do_crash_passengers;
497 function_pass2 = &OCrash::do_crash_passengers;
498 oinputs.crash_input = 0x10; // Set delay in processing steering
499 }
500
501 // Low Speed Bump - Car Rises in air and sinks
502 // Source: 0x12BE
do_bump()503 void OCrash::do_bump()
504 {
505 oferrari.car_ctrl_active = false; // Disable user control of car
506 spr_ferrari->zoom = 0x80; // Set Entry Number For Zoom Lookup Table
507 spr_ferrari->priority = 0x1FD;
508
509 int16_t new_position = (int8_t) roms.rom0.read8(DATA_MOVEMENT + (lookup_index << 3));
510
511 if (new_position)
512 crash_z = spr_ferrari->counter;
513
514 spr_ferrari->y = 221 - (new_position >> shift);
515
516 uint32_t frames = addr + (frame << 3);
517 spr_ferrari->addr = roms.rom0p->read32(frames);
518
519 if (roms.rom0p->read8(frames + 4))
520 spr_ferrari->control |= OSprites::HFLIP;
521 else
522 spr_ferrari->control &= ~OSprites::HFLIP;
523
524 //spr_ferrari->pal_src = roms.rom0p->read8(frames + 5);
525 spr_ferrari->pal_src = oferrari.ferrari_pal;
526 spin_pass_frame = (int8_t) roms.rom0p->read8(frames + 6);
527
528 if (++lookup_index >= 0x10)
529 {
530 addr += (frame_restore << 3);
531 spr_ferrari->addr = roms.rom0p->read32(addr);
532 spin_pass_frame = (int8_t) roms.rom0p->read8(addr + 6);
533 crash_state = 4; // Trigger smoke cloud
534 crash_spin_count = 1; // Denote Crash
535 }
536
537 done(spr_ferrari);
538 }
539
540 // Source: 0x1562
do_car_flip()541 void OCrash::do_car_flip()
542 {
543 // Do this if during the flip, the car has recollided with a new sprite + slow crash (similar to spin_collide)
544 if (olevelobjs.collision_sprite && crash_speed == 1)
545 {
546 uint16_t car_inc16 = oinitengine.car_increment >> 16;
547
548 // Road generator 1
549 if (oinitengine.car_x_pos - (oroad.road_width >> 16) >= 0)
550 {
551 // swap_slide_dir2
552 if (slide < 0)
553 {
554 slide = -slide;
555 oinitengine.car_increment = ((car_inc16 >> 1) << 16) | (oinitengine.car_increment & 0xFFFF);
556 osoundint.queue_sound(sound::CRASH2);
557 if (oinitengine.car_increment >> 16 > 0x14)
558 {
559 int16_t z = spr_ferrari->counter > 0x1FD ? 0x1FD : spr_ferrari->counter; // d3
560 int16_t x_adjust = (0x50 * z) >> 9; // d1
561 if (slide < 0) x_adjust = -x_adjust;
562 oinitengine.car_x_pos -= x_adjust;
563 }
564 }
565 // 0x15F6
566 else
567 slide += (slide >> 3);
568 }
569 // Road generator 2
570 else
571 {
572 // swap_slide_dir2:
573 if (slide >= 0)
574 {
575 slide = -slide;
576 oinitengine.car_increment = ((car_inc16 >> 1) << 16) | (oinitengine.car_increment & 0xFFFF);
577 osoundint.queue_sound(sound::CRASH2);
578 if (oinitengine.car_increment >> 16 > 0x14)
579 {
580 int16_t z = spr_ferrari->counter > 0x1FD ? 0x1FD : spr_ferrari->counter; // d3
581 int16_t x_adjust = (0x50 * z) >> 9; // d1
582 if (slide < 0) x_adjust = -x_adjust;
583 oinitengine.car_x_pos -= x_adjust;
584 }
585 }
586 // 0x15F6
587 else
588 slide += (slide >> 3);
589 }
590 }
591
592 // flip_cont
593 olevelobjs.collision_sprite = 0; // Moved this for clarity
594 uint32_t frames = addr + (frame << 3);
595 spr_ferrari->addr = roms.rom0p->read32(frames);
596
597 // ------------------------------------------------------------------------
598 // Fast Crash: Car Heads towards camera in sky, before vanishing (0x161E)
599 // ------------------------------------------------------------------------
600 if (crash_speed == 0)
601 {
602 spr_shadow->control &= ~OSprites::ENABLE; // Disable Shadow
603 spr_ferrari->counter += crash_zinc; // Increment Crash Z
604 if (spr_ferrari->counter > 0x3FF)
605 {
606 spr_ferrari->zoom = 0;
607 spr_ferrari->counter = 0;
608 init_finger(frames);
609 done(spr_ferrari);
610 return;
611 }
612 else
613 crash_zinc++;
614 }
615 // ------------------------------------------------------------------------
616 // Slow Crash (0x1648 flip_slower)
617 // ------------------------------------------------------------------------
618 else
619 {
620 spr_ferrari->counter -= crash_zinc; // Decrement Crash Z
621 if (crash_zinc > 2)
622 crash_zinc--;
623 }
624
625 // set_crash_z_inc
626 // Note that we've set crash_zinc previously now for clarity
627
628 // use ferrari_crash_z to set priority
629 spr_ferrari->priority = spr_ferrari->counter > 0x1FD ? 0x1FD : spr_ferrari->counter;
630
631 int16_t x_diff = (slide * spr_ferrari->priority) >> 9;
632 oinitengine.car_x_pos -= x_diff;
633
634 int16_t passenger_frame = (int8_t) roms.rom0p->read8(6 + frames);
635
636 // Start of sequence
637 if (passenger_frame == 0)
638 {
639 slide >>= 1;
640 osoundint.queue_sound(sound::CRASH2);
641 }
642
643 // Set Z during lower frames
644 if (passenger_frame <= 0x10 && spr_ferrari->counter <= 0x1FE)
645 crash_z = spr_ferrari->counter;
646
647 // 0x16CC
648 passenger_frame = (passenger_frame * spr_ferrari->priority) >> 9;
649
650 // Set Ferrari Y
651 int16_t y = -(oroad.road_y[oroad.road_p0 + spr_ferrari->priority] >> 4) + 223;
652 y -= passenger_frame;
653 spr_ferrari->y = y;
654
655 // Set Ferrari Zoom from Z
656 spr_ferrari->zoom = (spr_ferrari->counter >> 2);
657 if (spr_ferrari->zoom < 0x40) spr_ferrari->zoom = 0x40;
658
659 // Set Ferrari H-Flip
660 if (crash_side)
661 spr_ferrari->control |= OSprites::HFLIP;
662 else
663 spr_ferrari->control &= ~OSprites::HFLIP;
664
665 // Palette Hack for recoloured cars. Original version was simply: spr_ferrari->pal_src = roms.rom0p->read8(4 + frames);
666 if (frame >= 7)
667 spr_ferrari->pal_src = oferrari.ferrari_pal;
668 else
669 spr_ferrari->pal_src = oferrari.ferrari_pal == OFerrari::PAL_RED ? roms.rom0p->read8(4 + frames) : oferrari.ferrari_pal + 4;
670
671 if (--spinflipcount2 > 0)
672 {
673 done(spr_ferrari);
674 return;
675 }
676
677 spinflipcount2 = crash_spin_count;
678
679 // 0x1736
680 // Advance to next frame in sequence
681 if (spinflipcount1)
682 {
683 frame++;
684 // End of frame sequence
685 if ((roms.rom0p->read8(7 + frames) & BIT_7) == 0)
686 {
687 done(spr_ferrari);
688 return;
689 }
690 }
691
692 frame = 0;
693
694 if (--spinflipcount1 > 0)
695 {
696 crash_spin_count++;
697 }
698 else
699 {
700 init_finger(frames);
701 }
702 done(spr_ferrari);
703 }
704
705 // Init Delay/Girl Pointing Finger
706 // Source: 0x175C
init_finger(uint32_t frames)707 void OCrash::init_finger(uint32_t frames)
708 {
709 crash_spin_count = 1; // Denote Crash has taken place
710
711 // Do Delay whilst girl points finger
712 if (crash_type == CRASH_FLIP)
713 {
714 oferrari.wheel_state = OFerrari::WHEELS_ON;
715 oferrari.car_state = OFerrari::CAR_NORMAL;
716 slide = 0;
717 addr += frames;
718 crash_delay = 30;
719 crash_state = 5;
720 }
721 // Slide Car and Trigger Smoke Cloud
722 else
723 {
724 crash_state = 3;
725 frame = 0;
726 addr = outrun.adr.sprite_crash_man1;
727 crash_spin_count = 4; // Denote third flip
728 spinflipcount2 = 4;
729 }
730 }
731
732 // Post Crash: Slide Car Slightly, then trigger smoke
733 // Source: 0x17D2
trigger_smoke()734 void OCrash::trigger_smoke()
735 {
736 crash_z = spr_ferrari->counter;
737 int16_t slide_copy = slide;
738
739 if (slide < 0)
740 slide++;
741 else if (slide > 0)
742 slide--;
743
744 // Slide Car
745 oinitengine.car_x_pos -= slide_copy;
746
747 spr_ferrari->addr = roms.rom0p->read32(addr);
748
749 // Set Ferrari H-Flip
750 if (roms.rom0p->read8(4 + addr))
751 spr_ferrari->control |= OSprites::HFLIP;
752 else
753 spr_ferrari->control &= ~OSprites::HFLIP;
754
755 //spr_ferrari->pal_src = roms.rom0p->read8(5 + addr);
756 spr_ferrari->pal_src = oferrari.ferrari_pal;
757 spin_pass_frame = (int8_t) roms.rom0p->read8(6 + addr);
758
759 // Slow Car
760 oinitengine.car_increment =
761 (oinitengine.car_increment - ((oinitengine.car_increment >> 2) & 0xFFFF0000))
762 | (oinitengine.car_increment & 0xFFFF);
763
764 // Car stationary
765 if (oinitengine.car_increment >> 16 <= 0)
766 {
767 oinitengine.car_increment = 0;
768 oferrari.wheel_state = OFerrari::WHEELS_ON;
769 oferrari.car_state = OFerrari::CAR_NORMAL;
770 slide = 0;
771 crash_delay = 30;
772 crash_state = 5; // post crash animation delay state
773 }
774
775 done(spr_ferrari);
776 }
777
778 // Source: 0x1870
post_flip_anim()779 void OCrash::post_flip_anim()
780 {
781 oferrari.car_ctrl_active = false; // Car and road updates disabled
782 if (--crash_delay > 0)
783 {
784 done(spr_ferrari);
785 return;
786 }
787
788 oferrari.car_ctrl_active = true;
789 crash_state = 6; // Denote pan camera to track centre
790
791 int16_t road_width = oroad.road_width >> 16;
792 int16_t car_x_pos = oinitengine.car_x_pos;
793 camera_xinc = 8;
794
795 // Double Road
796 if (road_width >= 0xD7)
797 {
798 if (car_x_pos < 0)
799 road_width = -road_width;
800 }
801 else
802 {
803 road_width = 0;
804 }
805
806 camera_x_target = road_width;
807
808 // 1/ Car on road generator 1 (1 road enabled)
809 // 2/ Car on road generator 1 (2 roads enabled)
810 if (road_width < car_x_pos)
811 {
812 camera_xinc += (car_x_pos - road_width) >> 6;
813 camera_xinc = -camera_xinc;
814 }
815 else
816 {
817 camera_xinc += (road_width - car_x_pos) >> 6;
818 }
819
820 done(spr_ferrari);
821 }
822
823 // Pan Camera Back To Centre After Flip
824 // Source: 0x18EC
pan_camera()825 void OCrash::pan_camera()
826 {
827 oferrari.car_ctrl_active = true;
828
829 oinitengine.car_x_pos += camera_xinc;
830
831 int16_t x_diff = (oferrari.car_x_diff * spr_ferrari->counter) >> 9;
832 spr_ferrari->x += x_diff;
833
834 // Pan Right
835 if (camera_xinc >= 0)
836 {
837 if (camera_x_target <= oinitengine.car_x_pos)
838 crash_state = 7; // Denote camera position and ready for restart
839 }
840 // Pan Left
841 else
842 {
843 if (camera_x_target >= oinitengine.car_x_pos)
844 crash_state = 7;
845 }
846
847 done(spr_ferrari);
848 }
849
850 // Source: 0x1C7E
init_spin1()851 void OCrash::init_spin1()
852 {
853 osoundint.queue_sound(sound::INIT_SLIP);
854 uint16_t car_inc = oinitengine.car_increment >> 16;
855 uint16_t spins = 1;
856 if (car_inc > 0xB4)
857 spins += outils::random() & 1;
858
859 spinflipcount1 = spins;
860 crash_spin_count = 2;
861 spinflipcount2 = 2;
862
863 slide = ((spins + 1) << 2) + (car_inc > 0xFF) ? 0xFF >> 3 : car_inc >> 3;
864
865 if (skid_counter_bak < 0)
866 addr = outrun.adr.sprite_crash_spin1;
867 else
868 {
869 addr = outrun.adr.sprite_crash_spin1;
870 slide = -slide;
871 }
872
873 spin_control1++;
874 frame = 0;
875 skid_counter = 0;
876 spr_ferrari->road_priority = spr_ferrari->counter;
877 }
878
879 // Source: 0x1C10
init_spin2()880 void OCrash::init_spin2()
881 {
882 osoundint.queue_sound(sound::INIT_SLIP);
883 uint16_t car_inc = oinitengine.car_increment >> 16;
884 spinflipcount1 = 1;
885 crash_spin_count = 2;
886 spinflipcount2 = 8;
887
888 slide = (car_inc > 0xFF) ? 0xFF >> 3 : car_inc >> 3;
889
890 if (oinitengine.road_type != OInitEngine::ROAD_RIGHT)
891 {
892 addr = outrun.adr.sprite_crash_spin1;
893 }
894 else
895 {
896 addr = outrun.adr.sprite_crash_spin1;
897 slide = -slide;
898 }
899
900 spin_control2++;
901 frame = 0;
902 skid_counter = 0;
903 spr_ferrari->road_priority = spr_ferrari->counter;
904 }
905
906 // Collision: Slow
907 // Rebound and bounce car in air
908 // Source: 0x19EE
collide_slow()909 void OCrash::collide_slow()
910 {
911 osoundint.queue_sound(sound::REBOUND);
912
913 // Setup shift value for car bump, based on current speed, which ultimately determines how much car rises in air
914 uint16_t car_inc = oinitengine.car_increment >> 16;
915
916 if (car_inc <= 0x28)
917 shift = 6;
918 else if (car_inc <= 0x46)
919 shift = 5;
920 else
921 shift = 4;
922
923 lookup_index = 0;
924
925 // Calculate change in road y, so we can determine incline frame for ferrari
926 int16_t y = oroad.road_y[oroad.road_p0 + (0x3E0 / 2)] - oroad.road_y[oroad.road_p0 + (0x3F0 / 2)];
927 frame_restore = 0;
928 if (y >= 0x12) frame_restore++;
929 if (y >= 0x13) frame_restore++;
930
931 // Right Hand Side: Increment Frame Entry By 3
932 if (oinitengine.car_x_pos < 0)
933 addr = outrun.adr.sprite_bump_data2;
934 else
935 addr = outrun.adr.sprite_bump_data1;
936
937 crash_type = CRASH_BUMP; // low speed bump
938 oinitengine.car_increment &= 0xFFFF;
939
940 // set_collision:
941 frame = 0;
942 crash_state = 1; // collision with object
943 spr_ferrari->road_priority = spr_ferrari->counter;
944 }
945
946 // Collision: Medium
947 // Spin car
948 // Source: 0x1A98
collide_med()949 void OCrash::collide_med()
950 {
951 osoundint.queue_sound(sound::INIT_SLIP);
952
953 // Set number of spins based on car speed
954 uint16_t car_inc = oinitengine.car_increment >> 16;
955 spinflipcount1 = car_inc <= 0x96 ? 1 : 2;
956 spinflipcount2 = crash_spin_count = 2;
957 slide = ((spinflipcount1 + 1) << 2) + ((car_inc > 0xFF ? 0xFF : car_inc) >> 3);
958
959 // Right Hand Side: Increment Frame Entry By 3
960 if (oinitengine.car_x_pos < 0)
961 {
962 addr = outrun.adr.sprite_crash_spin1;
963 slide = -slide;
964 }
965 else
966 addr = outrun.adr.sprite_crash_spin1;
967
968 crash_type = CRASH_SPIN;
969
970 // set_collision:
971 frame = 0;
972 crash_state = 1; // collision with object
973 spr_ferrari->road_priority = spr_ferrari->counter;
974 }
975
976 // Collision: Fast
977 // Spin, Then Flip Car
978 //
979 // Source: 0x1B12
collide_fast()980 void OCrash::collide_fast()
981 {
982 osoundint.queue_sound(sound::CRASH1);
983
984 uint16_t car_inc = oinitengine.car_increment >> 16;
985 if (car_inc > 0xFA)
986 {
987 crash_zinc = 1;
988 crash_speed = 0;
989 }
990 else
991 {
992 crash_zinc = 0x10;
993 crash_speed = 1;
994 }
995
996 spinflipcount1 = 1;
997 spinflipcount2 = crash_spin_count = 2;
998
999 slide = (car_inc > 0xFF ? 0xFF : car_inc) >> 2;
1000 slide += (slide >> 1);
1001
1002 if (oinitengine.road_type != OInitEngine::ROAD_STRAIGHT)
1003 {
1004 int16_t d2 = (0x78 - (oinitengine.road_curve <= 0x78 ? oinitengine.road_curve : 0x78)) >> 1;
1005
1006 // collide_fast_curve:
1007 slide += d2;
1008 if (oinitengine.road_type == OInitEngine::ROAD_RIGHT)
1009 slide = -slide;
1010 }
1011 else
1012 {
1013 if (oinitengine.car_x_pos < 0) slide = -slide; // rhs
1014 }
1015
1016 // set_fast_slide:
1017 if (slide > 0x78)
1018 slide = 0x78;
1019
1020 if (oinitengine.car_x_pos < 0)
1021 {
1022 addr = outrun.adr.sprite_crash_spin2;
1023 crash_side = 0; // RHS
1024 }
1025 else
1026 {
1027 addr = outrun.adr.sprite_crash_spin1;
1028 crash_side = 1; // LHS
1029 }
1030
1031 crash_type = CRASH_FLIP; // Flip
1032
1033 // set_collision:
1034 frame = 0;
1035 crash_state = 1; // collision with object
1036 spr_ferrari->road_priority = spr_ferrari->counter;
1037 }
1038
1039 // Source: 0x1556
done(oentry * sprite)1040 void OCrash::done(oentry* sprite)
1041 {
1042 osprites.map_palette(sprite);
1043
1044 if (oroad.get_view_mode() != ORoad::VIEW_INCAR || crash_type == CRASH_FLIP)
1045 osprites.do_spr_order_shadows(sprite);
1046
1047 sprite->road_priority = sprite->counter;
1048 }
1049
1050 // ------------------------------------------------------------------------------------------------
1051 // SHADOW CRASH ROUTINES
1052 // ------------------------------------------------------------------------------------------------
1053
1054 // Render Shadow
1055 //
1056 // Disabled during fast car flip, when car rapidly heading towards screen
1057 //
1058 // Source: 0x1DF2
do_shadow(oentry * src_sprite,oentry * dst_sprite)1059 void OCrash::do_shadow(oentry* src_sprite, oentry* dst_sprite)
1060 {
1061 uint8_t shadow_shift;
1062
1063 // Ferrari Shadow
1064 if (src_sprite == spr_ferrari)
1065 {
1066 dst_sprite->draw_props = oentry::BOTTOM;
1067 shadow_shift = 1;
1068 }
1069 else
1070 {
1071 shadow_shift = 3;
1072 }
1073
1074 dst_sprite->x = src_sprite->x;
1075 dst_sprite->road_priority = src_sprite->road_priority;
1076
1077 // Get Z from source sprite (stored in counter)
1078 uint16_t counter = (src_sprite->counter) >> shadow_shift;
1079 counter = counter - (counter >> 2);
1080 dst_sprite->zoom = (uint8_t) counter;
1081
1082 // Set shadow y
1083 uint16_t offset = src_sprite->counter > 0x1FF ? 0x1FF : src_sprite->counter;
1084 dst_sprite->y = -(oroad.road_y[oroad.road_p0 + offset] >> 4) + 223;
1085
1086 if (oroad.get_view_mode() != ORoad::VIEW_INCAR || crash_type == CRASH_FLIP)
1087 osprites.do_spr_order_shadows(dst_sprite);
1088 }
1089
1090 // ------------------------------------------------------------------------------------------------
1091 // PASSENGER CRASH ROUTINES
1092 // ------------------------------------------------------------------------------------------------
1093
1094 // Flips & Spins Only
1095 //
1096 // Process passengers during crash scenario.
1097 //
1098 // Source: 0x1E66
do_crash_passengers(oentry * sprite)1099 void OCrash::do_crash_passengers(oentry* sprite)
1100 {
1101 // --------------------------------------------------------------------------------------------
1102 // Flip car
1103 // --------------------------------------------------------------------------------------------
1104 if (crash_state == 2)
1105 {
1106 // Update pointer to functions
1107 if (sprite == spr_pass1)
1108 function_pass1 = &OCrash::flip_start;
1109 else if (sprite == spr_pass2)
1110 function_pass2 = &OCrash::flip_start;
1111
1112 // Crash Passenger Flip
1113 crash_pass_flip(sprite);
1114 return;
1115 }
1116
1117 // --------------------------------------------------------------------------------------------
1118 // Non-Flip
1119 // --------------------------------------------------------------------------------------------
1120 if (crash_state < 5)
1121 crash_pass1(sprite);
1122 else
1123 crash_pass2(sprite);
1124
1125 if (oroad.get_view_mode() != ORoad::VIEW_INCAR || crash_type == CRASH_FLIP)
1126 {
1127 osprites.map_palette(sprite);
1128 osprites.do_spr_order_shadows(sprite);
1129 }
1130 }
1131
1132 // Position Passenger Sprites During Crash (But Not Flip)
1133 //
1134 // - Process passenger sprites in crash scenario
1135 // - Called separately for man and girl
1136 //
1137 // Source: 0x1EA6
crash_pass1(oentry * sprite)1138 void OCrash::crash_pass1(oentry* sprite)
1139 {
1140 uint32_t frames = (sprite == spr_pass1 ? outrun.adr.sprite_crash_man1 : outrun.adr.sprite_crash_girl1) + (spin_pass_frame << 3);
1141
1142 sprite->addr = roms.rom0p->read32(frames);
1143 uint8_t props = roms.rom0p->read8(4 + frames);
1144 sprite->pal_src = roms.rom0p->read8(5 + frames);
1145 sprite->x = spr_ferrari->x + (int8_t) roms.rom0p->read8(6 + frames);
1146 sprite->y = spr_ferrari->y + (int8_t) roms.rom0p->read8(7 + frames);
1147
1148 // Check H-Flip
1149 if (props & BIT_7)
1150 sprite->control |= OSprites::HFLIP;
1151 else
1152 sprite->control &= ~OSprites::HFLIP;
1153
1154 // Test whether we should set priority higher (unused on passenger sprites I think)
1155 if (props & BIT_0)
1156 sprite->priority = sprite->road_priority = 0x1FE;
1157 else
1158 sprite->priority = sprite->road_priority = 0x1FD;
1159
1160 sprite->zoom = 0x7E;
1161 }
1162
1163 // Passenger animations following the crash sequence i.e. when car is stationary
1164 //
1165 // 3 = hands battering,
1166 // 2 = man scratches head, girl taps car
1167 // 1 = man scratch head & girl points
1168 // 0 = man subdued & girl points
1169 //
1170 // - Process passenger sprites in crash scenario
1171 // - Called separately for man and girl
1172 // - Selects which passenger animation to play
1173 //
1174 // Source: 0x1F26
crash_pass2(oentry * sprite)1175 void OCrash::crash_pass2(oentry* sprite)
1176 {
1177 uint32_t frames = (sprite == spr_pass1 ? outrun.adr.sprite_crash_man2 : outrun.adr.sprite_crash_girl2);
1178
1179 // Use coll_count2 to select one of the three animations that can be played
1180 // Use crash_delay to toggle between two distinct frames
1181 frames += ((coll_count2 & 3) << 4) + (crash_delay & 8);
1182
1183 sprite->addr = roms.rom0p->read32(frames);
1184 uint8_t props = roms.rom0p->read8(4 + frames);
1185 sprite->pal_src = roms.rom0p->read8(5 + frames);
1186 sprite->x = spr_ferrari->x + (int8_t) roms.rom0p->read8(6 + frames);
1187 sprite->y = spr_ferrari->y + (int8_t) roms.rom0p->read8(7 + frames);
1188
1189 // Check H-Flip
1190 if (props & BIT_7)
1191 sprite->control |= OSprites::HFLIP;
1192 else
1193 sprite->control &= ~OSprites::HFLIP;
1194
1195 // Test whether we should set priority higher (unused on passenger sprites I think)
1196 if (props & BIT_0)
1197 sprite->priority = sprite->road_priority = 0x1FF;
1198 else
1199 sprite->priority = sprite->road_priority = 0x1FE;
1200
1201 sprite->zoom = 0x7E;
1202
1203 // Man
1204 if (sprite == spr_pass1)
1205 {
1206 const int8_t XY_OFF[] =
1207 {
1208 -0xC, -0x1E,
1209 0x2, -0x1B,
1210 0x4, -0x1A,
1211 0x5, -0x1E,
1212 0x11, -0x1B,
1213 0x0, -0x1A,
1214 -0x1, -0x1B,
1215 -0xC, -0x1C,
1216 -0xE, -0x1B,
1217 -0xE, -0x1C,
1218 -0xE, -0x1D,
1219 -0xC, -0x1B,
1220 -0xC, -0x1C,
1221 -0xC, -0x1D,
1222 };
1223
1224 sprite->x += XY_OFF[spin_pass_frame << 1];
1225 sprite->y += XY_OFF[(spin_pass_frame << 1) + 1];
1226 }
1227 // Woman
1228 else
1229 {
1230 const int8_t XY_OFF[] =
1231 {
1232 0xA, -0x1A,
1233 0x0, -0x1B,
1234 -0xF, -0x1B,
1235 -0x15, -0x1B,
1236 -0x2, -0x1E,
1237 0x7, -0x1A,
1238 0x13, -0x1D,
1239 0x9, -0x1B,
1240 0x3, -0x1B,
1241 0x3, -0x1C,
1242 0x3, -0x1D,
1243 0x7, -0x1B,
1244 0x7, -0x1C,
1245 0x7, -0x1D,
1246 };
1247
1248 sprite->x += XY_OFF[spin_pass_frame << 1];
1249 sprite->y += XY_OFF[(spin_pass_frame << 1) + 1];
1250 }
1251 }
1252
1253 // Handle passenger animation sequence during car flip
1254 //
1255 // 3 main stages:
1256 // 1/ Flip passengers out of car
1257 // 2/ Passengers sit up on road after crash
1258 // 3/ Passengers turn head and look at car (only if camera pan)
1259 //
1260 // Source: 0x1FDE
1261
crash_pass_flip(oentry * sprite)1262 void OCrash::crash_pass_flip(oentry* sprite)
1263 {
1264 // Some of these variable names really need refactoring
1265 sprite->reload = 0; // clear passenger flip control
1266 sprite->xw1 = 0;
1267 sprite->x = spr_ferrari->x;
1268 sprite->traffic_speed = crash_spin_count;
1269 sprite->counter = 0x1FE; // sprite zoom
1270
1271 // Set address of animation sequence based on whether male/female
1272 sprite->z = sprite == spr_pass1 ? outrun.adr.sprite_crash_flip_m1 : outrun.adr.sprite_crash_flip_g1;
1273
1274 flip_start(sprite);
1275 }
1276
1277 // Source: 0x201A
flip_start(oentry * sprite)1278 void OCrash::flip_start(oentry* sprite)
1279 {
1280 if (outrun.game_state != GS_ATTRACT && outrun.game_state != GS_INGAME)
1281 {
1282 osprites.do_spr_order_shadows(sprite);
1283 done(sprite);
1284 return;
1285 }
1286
1287 switch (sprite->reload & 3) // check passenger flip control
1288 {
1289 // Flip passengers out of car
1290 case 0:
1291 pass_flip(sprite);
1292 break;
1293
1294 // Passengers sit up on road after crash
1295 case 1:
1296 pass_situp(sprite);
1297 break;
1298
1299 // Passengers turn head and look at car (only if camera pan)
1300 case 2:
1301 case 3:
1302 pass_turnhead(sprite);
1303 break;
1304 }
1305 }
1306
1307 // Flip passengers out of car
1308 // Source: 0x2066
pass_flip(oentry * sprite)1309 void OCrash::pass_flip(oentry* sprite)
1310 {
1311 // Fast crash
1312 if (crash_speed == 0)
1313 {
1314 sprite->counter += (crash_zinc << 2);
1315
1316 if (sprite->counter > 0x3FF)
1317 {
1318 sprite->reload = 1; // // Passenger Control: Passengers sit up on road after crash
1319
1320 // Disable sprite and shadow
1321 sprite->control &= ~OSprites::ENABLE;
1322 if (sprite == spr_pass1)
1323 spr_pass1s->control &= ~OSprites::ENABLE;
1324 else
1325 spr_pass2s->control &= ~OSprites::ENABLE;
1326 return;
1327 }
1328 }
1329 // Slow crash
1330 else
1331 {
1332 int16_t zinc = crash_zinc >> 2;
1333
1334 // Adjust the z position of the female more than the man
1335 if (sprite == spr_pass2)
1336 {
1337 zinc += (zinc >> 1);
1338 }
1339
1340 sprite->counter -= zinc;
1341 }
1342
1343 // set_z_lookup
1344 int16_t zoom = sprite->counter >> 2;
1345 if (zoom < 0x40) zoom = 0x40;
1346 sprite->zoom = (uint8_t) zoom;
1347
1348 uint32_t frames = sprite->z + (sprite->xw1 << 3);
1349 sprite->addr = roms.rom0p->read32(frames);
1350
1351 uint16_t offset = sprite->counter > 0x1FF ? 0x1FF : sprite->counter;
1352 int16_t y_change = (((int8_t) roms.rom0p->read8(6 + frames)) * offset) >> 9; // d1
1353
1354 sprite->y = -(oroad.road_y[oroad.road_p0 + offset] >> 4) + 223;
1355 sprite->y -= y_change;
1356
1357 // 2138
1358
1359 sprite->priority = offset;
1360 if (crash_side)
1361 sprite->control |= OSprites::HFLIP;
1362 else
1363 sprite->control &= ~OSprites::HFLIP;
1364
1365 sprite->pal_src = roms.rom0p->read8(4 + frames);
1366
1367 // Decrement spin count
1368 // Increment frame of passengers for first spins
1369 if (--sprite->traffic_speed <= 0)
1370 {
1371 sprite->traffic_speed = crash_spin_count;
1372 sprite->xw1++; // Increase passenger frame
1373
1374 // End of animation sequence. Progress to next sequnce of animations.
1375 if (roms.rom0p->read8(7 + frames) & BIT_7)
1376 {
1377 sprite->reload = 1; // Passenger Control: Passengers sit up on road after crash
1378 sprite->xw1 = 0; // Reset passenger frame
1379
1380 // Update address of animation sequence to be used
1381 sprite->z = sprite == spr_pass1 ? outrun.adr.sprite_crash_flip_m2 : outrun.adr.sprite_crash_flip_g2;
1382 frames = sprite->z;
1383
1384 // Set Frame Delay for this animation sequence from lower bytes
1385 sprite->traffic_speed = roms.rom0p->read8(7 + frames) & 0x7F;
1386
1387 done(sprite);
1388 return;
1389 }
1390 }
1391
1392 // set_passenger_x
1393 sprite->x = spr_ferrari->x;
1394 sprite->x += ((int8_t) roms.rom0p->read8(5 + frames));
1395 done(sprite);
1396 }
1397
1398 // Passengers sit up on road after crash
1399 // Source: 0x205A
pass_situp(oentry * sprite)1400 void OCrash::pass_situp(oentry* sprite)
1401 {
1402 // Update passenger x position
1403 int16_t x_diff = (oferrari.car_x_diff * sprite->counter) >> 9;
1404 sprite->x += x_diff;
1405
1406 uint32_t frames = sprite->z + (sprite->xw1 << 3);
1407 sprite->addr = roms.rom0p->read32(frames);
1408 sprite->pal_src = roms.rom0p->read8(4 + frames);
1409
1410 // Decrement frame delay counter
1411 if (--sprite->traffic_speed <= 0)
1412 {
1413 sprite->traffic_speed = roms.rom0p->read8(0xF + frames) & 0x7F;
1414
1415 // End of animation sequence. Progress to next sequnce of animations.
1416 if (roms.rom0p->read8(7 + frames) & BIT_7)
1417 {
1418 sprite->reload = 2; // Passenger Control: Passengers turn head and look at car
1419 }
1420 else
1421 {
1422 sprite->xw1++; // Increase passenger frame
1423
1424 // If camera pan: Make passengers turn heads!
1425 if (crash_state == 6)
1426 sprite->reload = 2;
1427 }
1428 }
1429 done(sprite);
1430 }
1431
1432 // Passengers turn head and look at car (only if camera pan)
1433 // Source: 0x222C
pass_turnhead(oentry * sprite)1434 void OCrash::pass_turnhead(oentry* sprite)
1435 {
1436 // Update passenger x position
1437 int16_t x_diff = (oferrari.car_x_diff * sprite->counter) >> 9;
1438 sprite->x += x_diff;
1439
1440 uint32_t frames = sprite->z + (sprite->xw1 << 3);
1441 sprite->addr = roms.rom0p->read32(frames);
1442 sprite->pal_src = roms.rom0p->read8(4 + frames);
1443
1444 // End of animation sequence.
1445 if (roms.rom0p->read8(7 + frames) & BIT_7)
1446 {
1447 done(sprite);
1448 return;
1449 }
1450
1451 // Decrement frame delay counter
1452 if (--sprite->traffic_speed <= 0)
1453 {
1454 sprite->traffic_speed = roms.rom0p->read8(0xF + frames) & 0x7F;
1455 sprite->xw1++; // Increase passenger frame
1456 }
1457
1458 done(sprite);
1459 }