1 /*
2 SDLPoP, a port/conversion of the DOS game Prince of Persia.
3 Copyright (C) 2013-2021 Dávid Nagy
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18 The authors of this program may be contacted at https://forum.princed.org
19 */
20
21 #include "common.h"
22
23 #ifndef _MSC_VER // unistd.h does not exist in the Windows SDK.
24 #include <unistd.h>
25 #endif
26
27 // data:4CB4
28 short cutscene_wait_frames;
29 // data:3D14
30 short cutscene_frame_time;
31 // data:588C
32 short disable_keys;
33 // data:436A
34 short hourglass_sandflow;
35 // data:5964
36 short hourglass_state;
37 // data:4CC4
38 short which_torch;
39
40 #pragma pack(push,1)
41 typedef struct hof_type {
42 char name[25];
43 short min,tick;
44 } hof_type;
45 SDL_COMPILE_TIME_ASSERT(hof_size, sizeof(hof_type) == 29);
46 #pragma pack(pop)
47
48 #define MAX_HOF_COUNT 6
49 // data:589A
50 hof_type hof[MAX_HOF_COUNT];
51
52 #define N_STARS 6
53
54 // data:0D92
55 rect_type hof_rects[MAX_HOF_COUNT] = {
56 { 84, 72, 96, 248},
57 { 98, 72, 110, 248},
58 {112, 72, 124, 248},
59 {126, 72, 138, 248},
60 {140, 72, 152, 248},
61 {154, 72, 166, 248},
62 };
63
64 // seg001:0004
proc_cutscene_frame(int wait_frames)65 int __pascal far proc_cutscene_frame(int wait_frames) {
66 cutscene_wait_frames = wait_frames;
67 reset_timer(timer_0);
68 do {
69 set_timer_length(timer_0, cutscene_frame_time);
70 play_both_seq();
71 draw_proom_drects(); // changed order of drects and flash
72 if (flash_time) {
73 do_flash(flash_color);
74 }
75 if (flash_time) {
76 --flash_time;
77 remove_flash();
78 }
79 if (!check_sound_playing()) {
80 play_next_sound();
81 }
82 do {
83 if (!disable_keys && do_paused()) {
84 stop_sounds();
85 draw_rect(&screen_rect, 0);
86 #ifdef USE_FADE
87 if (is_global_fading) {
88 fade_palette_buffer->proc_restore_free(fade_palette_buffer);
89 is_global_fading = 0;
90 }
91 #endif
92 return 1;
93 }
94 #ifdef USE_FADE
95 if (is_global_fading) {
96 if (fade_palette_buffer->proc_fade_frame(fade_palette_buffer)) {
97 fade_palette_buffer->proc_restore_free(fade_palette_buffer);
98 is_global_fading = 0;
99 return 2;
100 }
101 } else {
102 idle();
103 delay_ticks(1);
104 }
105 #else
106 idle();
107 #endif
108 } while(!has_timer_stopped(timer_0)); // busy waiting?
109 } while(--cutscene_wait_frames);
110 return 0;
111 }
112
113 // seg001:00DD
play_both_seq()114 void __pascal far play_both_seq() {
115 play_kid_seq();
116 play_opp_seq();
117 }
118
119 // seg001:00E6
draw_proom_drects()120 void __pascal far draw_proom_drects() {
121 draw_princess_room_bg();
122 #ifdef USE_FADE
123 if (!is_global_fading) {
124 #endif
125 while (drects_count--) {
126 copy_screen_rect(&drects[drects_count]);
127 }
128 #ifdef USE_FADE
129 }
130 #endif
131 drects_count = 0;
132 if (cutscene_wait_frames & 1) {
133 draw_star(prandom(N_STARS - 1), 1);
134 }
135 }
136
137 // seg001:0128
play_kid_seq()138 void __pascal far play_kid_seq() {
139 loadkid();
140 if (Char.frame) {
141 play_seq();
142 savekid();
143 }
144 }
145
146 // seg001:013F
play_opp_seq()147 void __pascal far play_opp_seq() {
148 loadshad_and_opp();
149 if (Char.frame) {
150 play_seq();
151 saveshad();
152 }
153 }
154
155 // seg001:0156
draw_princess_room_bg()156 void __pascal far draw_princess_room_bg() {
157 memset_near(table_counts, 0, sizeof(table_counts));
158 loadkid();
159 if (Char.frame) {
160 load_frame_to_obj();
161 obj_tilepos = 30;
162 add_objtable(0);
163 }
164 loadshad();
165 if (Char.frame) {
166 load_frame_to_obj();
167 obj_tilepos = 30;
168 add_objtable(0);
169 }
170 redraw_needed_tiles();
171 add_foretable(id_chtab_8_princessroom, 2 /*pillar piece*/, 30, 0, 167, blitters_10h_transp, 0);
172 princess_room_torch();
173 draw_hourglass();
174 draw_tables();
175 }
176
177 // seg001:01E0
seqtbl_offset_shad_char(int seq_index)178 void __pascal far seqtbl_offset_shad_char(int seq_index) {
179 loadshad();
180 seqtbl_offset_char(seq_index);
181 saveshad();
182 }
183
184 // seg001:01F9
seqtbl_offset_kid_char(int seq_index)185 void __pascal far seqtbl_offset_kid_char(int seq_index) {
186 loadkid();
187 seqtbl_offset_char(seq_index);
188 savekid();
189 }
190
191 // seg001:0212
init_mouse_cu8()192 void __pascal far init_mouse_cu8() {
193 init_mouse_go();
194 Char.x = 144;
195 seqtbl_offset_char(seq_106_mouse); // mouse
196 play_seq();
197 }
198
199 // seg001:022A
init_mouse_go()200 void __pascal far init_mouse_go() {
201 Char.charid = charid_24_mouse;
202 Char.x = 199;
203 Char.y = 167;
204 Char.direction = dir_FF_left;
205 seqtbl_offset_char(seq_105_mouse_forward); // mouse go
206 play_seq();
207 }
208
209 // seg001:024D
princess_crouching()210 void __pascal far princess_crouching() {
211 init_princess();
212 Char.x = 131;
213 Char.y = 169;
214 seqtbl_offset_char(seq_110_princess_crouching_PV2); // princess crouching [PV2]
215 play_seq();
216 }
217
218 // seg001:026A
princess_stand()219 void __pascal far princess_stand() {
220 init_princess_right();
221 Char.x = 144;
222 Char.y = 169;
223 seqtbl_offset_char(seq_94_princess_stand_PV1); // princess stand [PV1]
224 play_seq();
225 }
226
227 // seg001:0287
init_princess_x156()228 void __pascal far init_princess_x156() {
229 init_princess();
230 Char.x = 156;
231 }
232
233 // seg001:0291
princess_lying()234 void __pascal far princess_lying() {
235 init_princess();
236 Char.x = 92;
237 Char.y = 162;
238 seqtbl_offset_char(seq_103_princess_lying_PV2); // princess lying [PV2]
239 play_seq();
240 }
241
242 // seg001:02AE
init_princess_right()243 void __pascal far init_princess_right() {
244 init_princess();
245 Char.direction = dir_0_right;
246 }
247
248 // seg001:02B8
init_ending_princess()249 void __pascal far init_ending_princess() {
250 init_princess();
251 Char.x = 136;
252 Char.y = 164;
253 seqtbl_offset_char(seq_109_princess_stand_PV2); // princess standing [PV2]
254 play_seq();
255 }
256
257 // seg001:02D5
init_mouse_1()258 void __pascal far init_mouse_1() {
259 init_mouse_go();
260 Char.x -= 2;
261 Char.y = 164;
262 }
263
264 // seg001:02E4
init_princess()265 void __pascal far init_princess() {
266 Char.charid = charid_5_princess;
267 Char.x = 120;
268 Char.y = 166;
269 Char.direction = dir_FF_left;
270 seqtbl_offset_char(seq_94_princess_stand_PV1); // princess stand [PV1]
271 play_seq();
272 }
273
274 // seg001:0307
init_vizier()275 void __pascal far init_vizier() {
276 Char.charid = charid_6_vizier;
277 Char.x = 198;
278 Char.y = 166;
279 Char.direction = dir_FF_left;
280 seqtbl_offset_char(seq_95_Jaffar_stand_PV1); // Jaffar stand [PV1]
281 play_seq();
282 }
283
284 // seg001:032A
init_ending_kid()285 void __pascal far init_ending_kid() {
286 Char.charid = charid_0_kid;
287 Char.x = 198;
288 Char.y = 164;
289 Char.direction = dir_FF_left;
290 seqtbl_offset_char(seq_1_start_run); // start run
291 play_seq();
292 }
293
294 // seg001:034D
cutscene_8()295 void __pascal far cutscene_8() {
296 play_sound(sound_35_cutscene_8_9); // cutscene 8, 9
297 set_hourglass_state(hourglass_frame());
298 init_mouse_cu8();
299 savekid();
300 princess_crouching();
301 saveshad();
302 if (fade_in_1()) return;
303 if (proc_cutscene_frame(20)) return;
304 seqtbl_offset_kid_char(seq_107_mouse_stand_up_and_go); // mouse stand up and go
305 if (proc_cutscene_frame(20)) return;
306 seqtbl_offset_shad_char(seq_111_princess_stand_up_PV2); // princess stand up [PV2]
307 if (proc_cutscene_frame(20)) return;
308 Kid.frame = 0;
309 fade_out_1();
310 }
311
312 // seg001:03B7
cutscene_9()313 void __pascal far cutscene_9() {
314 play_sound(sound_35_cutscene_8_9); // cutscene 8, 9
315 set_hourglass_state(hourglass_frame());
316 princess_stand();
317 saveshad();
318 if (fade_in_1()) return;
319 init_mouse_go();
320 savekid();
321 if (proc_cutscene_frame(5)) return;
322 seqtbl_offset_shad_char(seq_112_princess_crouch_down_PV2); // princess crouch down [PV2]
323 if (proc_cutscene_frame(9)) return;
324 seqtbl_offset_kid_char(seq_114_mouse_stand); // mouse stand
325 if (proc_cutscene_frame(58)) return;
326 fade_out_1();
327 }
328
329 // seg001:041C
end_sequence_anim()330 void __pascal far end_sequence_anim() {
331 disable_keys = 1;
332 if (!is_sound_on) {
333 turn_sound_on_off(0x0F);
334 }
335 copy_screen_rect(&screen_rect);
336 play_sound(sound_26_embrace); // arrived to princess
337 init_ending_princess();
338 saveshad();
339 init_ending_kid();
340 savekid();
341 if (proc_cutscene_frame(8)) return;
342 seqtbl_offset_shad_char(seq_108_princess_turn_and_hug); // princess turn and hug [PV2]
343 if (proc_cutscene_frame(5)) return;
344 seqtbl_offset_kid_char(seq_13_stop_run); // stop run
345 if (proc_cutscene_frame(2)) return;
346 Kid.frame = 0;
347 if (proc_cutscene_frame(39)) return;
348 init_mouse_1();
349 savekid();
350 if (proc_cutscene_frame(9)) return;
351 seqtbl_offset_kid_char(seq_101_mouse_stands_up); // mouse stands up
352 if (proc_cutscene_frame(41)) return;
353 fade_out_1();
354 while (check_sound_playing()) {
355 idle();
356 delay_ticks(1);
357 }
358 }
359
360 // seg001:04D3
time_expired()361 void __pascal far time_expired() {
362 disable_keys = 1;
363 set_hourglass_state(7);
364 hourglass_sandflow = -1;
365 play_sound(sound_36_out_of_time); // time over
366 if (fade_in_1()) return;
367 if (proc_cutscene_frame(2)) return;
368 if (proc_cutscene_frame(100)) return;
369 fade_out_1();
370 while (check_sound_playing()) {
371 idle();
372 do_paused();
373 delay_ticks(1);
374 }
375 }
376
377 // seg001:0525
cutscene_12()378 void __pascal far cutscene_12() {
379 short var_2;
380 var_2 = hourglass_frame();
381 if (var_2 >= 6) {
382 set_hourglass_state(var_2);
383 init_princess_x156();
384 saveshad();
385 play_sound(sound_40_cutscene_12_short_time); // cutscene 12 short time
386 if (fade_in_1()) return;
387 if (proc_cutscene_frame(2)) return;
388 seqtbl_offset_shad_char(98); // princess turn around [PV1]
389 if (proc_cutscene_frame(24)) return;
390 fade_out_1();
391 } else {
392 cutscene_2_6();
393 }
394 }
395
396 // seg001:0584
cutscene_4()397 void __pascal far cutscene_4() {
398 play_sound(sound_27_cutscene_2_4_6_12); // cutscene 2, 4, 6, 12
399 set_hourglass_state(hourglass_frame());
400 princess_lying();
401 saveshad();
402 if (fade_in_1()) return;
403 if (proc_cutscene_frame(26)) return;
404 fade_out_1();
405 }
406
407 // seg001:05B8
cutscene_2_6()408 void __pascal far cutscene_2_6() {
409 play_sound(sound_27_cutscene_2_4_6_12); // cutscene 2, 4, 6, 12
410 set_hourglass_state(hourglass_frame());
411 init_princess_right();
412 saveshad();
413 if (fade_in_1()) return;
414 if (proc_cutscene_frame(26)) return;
415 fade_out_1();
416 }
417
418 // seg001:05EC
pv_scene()419 void __pascal far pv_scene() {
420 init_princess();
421 saveshad();
422 if (fade_in_1()) return;
423 init_vizier();
424 savekid();
425 if (proc_cutscene_frame(2)) return;
426 play_sound(sound_50_story_2_princess); // story 2: princess waiting
427 do {
428 if (proc_cutscene_frame(1)) return;
429 //idle();
430 } while(check_sound_playing());
431 cutscene_frame_time = 8;
432 if (proc_cutscene_frame(5)) return;
433 play_sound(sound_4_gate_closing); // gate closing
434 do {
435 if (proc_cutscene_frame(1)) return;
436 } while(check_sound_playing());
437 play_sound(sound_51_princess_door_opening); // princess door opening
438 if (proc_cutscene_frame(3)) return;
439 seqtbl_offset_shad_char(98); // princess turn around [PV1]
440 if (proc_cutscene_frame(5)) return;
441 seqtbl_offset_kid_char(96); // Jaffar walk [PV1]
442 if (proc_cutscene_frame(6)) return;
443 play_sound(sound_53_story_3_Jaffar_comes); // story 3: Jaffar comes
444 seqtbl_offset_kid_char(97); // Jaffar stop [PV1]
445 if (proc_cutscene_frame(4)) return;
446 if (proc_cutscene_frame(18)) return;
447 seqtbl_offset_kid_char(96); // Jaffar walk [PV1]
448 if (proc_cutscene_frame(30)) return;
449 seqtbl_offset_kid_char(97); // Jaffar stop [PV1]
450 if (proc_cutscene_frame(35)) return;
451 seqtbl_offset_kid_char(102); // Jaffar conjuring [PV1]
452 cutscene_frame_time = 7;
453 if (proc_cutscene_frame(1)) return;
454 seqtbl_offset_shad_char(99); // princess step back [PV1]
455 if (proc_cutscene_frame(17)) return;
456 hourglass_state = 1;
457 flash_time = 5;
458 flash_color = 15; // white
459 do {
460 if (proc_cutscene_frame(1)) return;
461 //idle();
462 } while(check_sound_playing());
463 seqtbl_offset_kid_char(100); // Jaffar end conjuring and walk [PV1]
464 hourglass_sandflow = 0;
465 if (proc_cutscene_frame(6)) return;
466 play_sound(sound_52_story_4_Jaffar_leaves); // story 4: Jaffar leaves
467 if (proc_cutscene_frame(24)) return;
468 hourglass_state = 2;
469 if (proc_cutscene_frame(9)) return;
470 seqtbl_offset_shad_char(113); // princess look down [PV1]
471 if (proc_cutscene_frame(28)) return;
472 fade_out_1();
473 }
474
475 // seg001:07C7
set_hourglass_state(int state)476 void __pascal far set_hourglass_state(int state) {
477 hourglass_sandflow = 0;
478 hourglass_state = state;
479 }
480
481 // data:0DEC
482 short time_bound[] = {6, 17, 33, 65};
483
484 // seg001:07DA
hourglass_frame()485 int __pascal far hourglass_frame() {
486 short bound_index;
487 for (bound_index = 0; bound_index < 4; ++bound_index) {
488 if (time_bound[bound_index] > rem_min) {
489 break;
490 }
491 }
492 return 6 - bound_index;
493 }
494
495 // data:0DF4
496 short princess_torch_pos_xh[] = {11, 26};
497 // data:0DF8
498 short princess_torch_pos_xl[] = {5, 3};
499 // data:0DFC
500 short princess_torch_frame[] = {1, 6};
501
502 // seg001:0808
princess_room_torch()503 void __pascal far princess_room_torch() {
504 short which;
505 for (which = 2; which--; ) {
506 which_torch = !which_torch;
507 princess_torch_frame[which_torch] = get_torch_frame(princess_torch_frame[which_torch]);
508 add_backtable(id_chtab_1_flameswordpotion, princess_torch_frame[which_torch] + 1, princess_torch_pos_xh[which_torch], princess_torch_pos_xl[which_torch], 116, 0, 0);
509 }
510 }
511
512 // seg001:0863
draw_hourglass()513 void __pascal far draw_hourglass() {
514 if (hourglass_sandflow >= 0) {
515 hourglass_sandflow = (hourglass_sandflow + 1) % 3;
516 if (hourglass_state >= 7) return;
517 add_foretable(id_chtab_8_princessroom, hourglass_sandflow + 10, 20, 0, 164, blitters_10h_transp, 0);
518 }
519 if (hourglass_state) {
520 add_midtable(id_chtab_8_princessroom, hourglass_state + 2, 19, 0, 168, blitters_10h_transp, 1);
521 }
522 }
523
524 // seg001:08CA
reset_cutscene()525 void __pascal far reset_cutscene() {
526 Guard.frame = 0;
527 Kid.frame = 0;
528 which_torch = 0;
529 disable_keys = 0;
530 hourglass_state = 0;
531 // memset_near(byte_1ED6E, 0, 8); // not used elsewhere
532 hourglass_sandflow = -1;
533 cutscene_frame_time = 6;
534 clear_tile_wipes();
535 next_sound = -1;
536 }
537
538 // seg001:0908
do_flash(short color)539 void __pascal far do_flash(short color) {
540 // stub
541 if (color) {
542 if (graphics_mode == gmMcgaVga) {
543 reset_timer(timer_2);
544 set_timer_length(timer_2, 2);
545 set_bg_attr(0, color);
546 if (color != 0) do_simple_wait(timer_2); // give some time to show the flash
547 } else {
548 // ...
549 }
550 }
551 }
552
delay_ticks(Uint32 ticks)553 void delay_ticks(Uint32 ticks) {
554 #ifdef USE_REPLAY
555 if (replaying && skipping_replay) return;
556 #endif
557 SDL_Delay(ticks *(1000/60));
558 }
559
560 // seg001:0981
remove_flash()561 void __pascal far remove_flash() {
562 // stub
563 if (graphics_mode == gmMcgaVga) {
564 set_bg_attr(0, 0);
565 } else {
566 // ...
567 }
568 }
569
570 // seg001:09D7
end_sequence()571 void __pascal far end_sequence() {
572 peel_type* peel;
573 short bgcolor;
574 short color;
575 rect_type rect;
576 short hof_index;
577 short i;
578 color = 0;
579 bgcolor = 15;
580 load_intro(1, &end_sequence_anim, 1);
581 clear_screen_and_sounds();
582 is_ending_sequence = true; // added (fix being able to pause the game during the end sequence)
583 load_opt_sounds(sound_56_ending_music, sound_56_ending_music); // winning theme
584 play_sound_from_buffer(sound_pointers[sound_56_ending_music]); // winning theme
585 if(offscreen_surface) free_surface(offscreen_surface); // missing in original
586 offscreen_surface = make_offscreen_buffer(&screen_rect);
587 load_title_images(0);
588 current_target_surface = offscreen_surface;
589 draw_full_image(STORY_FRAME);
590 draw_full_image(STORY_HAIL);
591 fade_in_2(offscreen_surface, 0x800);
592 pop_wait(timer_0, 900);
593 start_timer(timer_0, 240);
594 draw_full_image(TITLE_MAIN);
595 transition_ltr();
596 do_wait(timer_0);
597 for (hof_index = 0; hof_index < hof_count; ++hof_index) {
598 if (hof[hof_index].min < rem_min ||
599 (hof[hof_index].min == rem_min && hof[hof_index].tick < rem_tick)
600 ) break;
601 }
602 if (hof_index < MAX_HOF_COUNT && hof_index <= hof_count) {
603 fade_out_2(0x1000);
604 for (i = 5; hof_index + 1 <= i; --i) {
605 hof[i] = hof[i - 1];
606 }
607 hof[i].name[0] = 0;
608 hof[i].min = rem_min;
609 hof[i].tick = rem_tick;
610 if (hof_count < MAX_HOF_COUNT) {
611 ++hof_count;
612 }
613 draw_full_image(STORY_FRAME);
614 draw_full_image(HOF_POP);
615 show_hof();
616 offset4_rect_add(&rect, &hof_rects[hof_index], -4, -1, -40, -1);
617 peel = read_peel_from_screen(&rect);
618 if (graphics_mode == gmMcgaVga) {
619 color = 0xBE;
620 bgcolor = 0xB7;
621 }
622 draw_rect(&rect, bgcolor);
623 fade_in_2(offscreen_surface, 0x1800);
624 current_target_surface = onscreen_surface_;
625 while(input_str(&rect, hof[hof_index].name, 24, "", 0, 4, color, bgcolor) <= 0);
626 restore_peel(peel);
627 show_hof_text(&hof_rects[hof_index], -1, 0, hof[hof_index].name);
628 hof_write();
629 pop_wait(timer_0, 120);
630 current_target_surface = offscreen_surface;
631 draw_full_image(TITLE_MAIN);
632 transition_ltr();
633 }
634 while (check_sound_playing() && !key_test_quit()) {
635 idle();
636 delay_ticks(1);
637 }
638 fade_out_2(0x1000);
639 start_level = -1;
640 is_ending_sequence = false;
641 start_game();
642 }
643
644 // seg001:0C94
expired()645 void __pascal far expired() {
646 if (!demo_mode) {
647 if(offscreen_surface) free_surface(offscreen_surface); // missing in original
648 offscreen_surface = NULL;
649 clear_screen_and_sounds();
650 offscreen_surface = make_offscreen_buffer(&screen_rect);
651 load_intro(1, &time_expired, 1);
652 }
653 start_level = -1;
654 start_game();
655 }
656
657 // seg001:0CCD
load_intro(int which_imgs,cutscene_ptr_type func,int free_sounds)658 void __pascal far load_intro(int which_imgs,cutscene_ptr_type func,int free_sounds) {
659 short current_star;
660 draw_rect(&screen_rect, 0);
661 if (free_sounds) {
662 free_optional_sounds();
663 }
664 free_all_chtabs_from(id_chtab_3_princessinstory);
665 load_chtab_from_file(id_chtab_8_princessroom, 950, "PV.DAT", 1<<13);
666 load_chtab_from_file(id_chtab_9_princessbed, 980, "PV.DAT", 1<<14);
667 current_target_surface = offscreen_surface;
668 method_6_blit_img_to_scr(get_image(id_chtab_8_princessroom, 0), 0, 0, 0);
669 method_6_blit_img_to_scr(get_image(id_chtab_9_princessbed, 0), 0, 142, blitters_2_or);
670
671 // Free the images that are not needed anymore.
672 free_all_chtabs_from(id_chtab_9_princessbed);
673 SDL_FreeSurface(get_image(id_chtab_8_princessroom, 0));
674 if (NULL != chtab_addrs[id_chtab_8_princessroom]) chtab_addrs[id_chtab_8_princessroom]->images[0] = NULL;
675
676 load_chtab_from_file(id_chtab_3_princessinstory, 800, "PV.DAT", 1<<9);
677 load_chtab_from_file(id_chtab_4_jaffarinstory_princessincutscenes,
678 50*which_imgs + 850, "PV.DAT", 1<<10);
679 for (current_star = 0; current_star < N_STARS; ++current_star) {
680 draw_star(current_star, 0);
681 }
682 current_target_surface = onscreen_surface_;
683 while (check_sound_playing()) {
684 idle();
685 do_paused();
686 delay_ticks(1);
687 }
688 need_drects = 1;
689 reset_cutscene();
690 is_cutscene = 1;
691 func();
692 is_cutscene = 0;
693 free_all_chtabs_from(3);
694 draw_rect(&screen_rect, 0);
695 }
696
697 typedef struct star_type {
698 short x,y,color;
699 } star_type;
700
701 // data:0DC2
702 star_type stars[N_STARS] = {
703 {20, 97,0},
704 {16,104,1},
705 {23,110,2},
706 {17,116,3},
707 {24,120,4},
708 {18,128,0},
709 };
710 #define N_STAR_COLORS 5
711 // data:0DE6
712 const byte star_colors[N_STAR_COLORS] = {8, 7, 15, 15, 7};
713
714 // seg001:0E1C
draw_star(int which_star,int mark_dirty)715 void __pascal far draw_star(int which_star,int mark_dirty) {
716 // The stars in the window of the princess's room.
717 rect_type rect;
718 short star_color;
719 star_color = 15;
720 rect.right = rect.left = stars[which_star].x;
721 ++rect.right;
722 rect.bottom = rect.top = stars[which_star].y;
723 ++rect.bottom;
724 if (graphics_mode != gmCga && graphics_mode != gmHgaHerc) {
725 stars[which_star].color = (stars[which_star].color + 1) % N_STAR_COLORS;
726 star_color = star_colors[stars[which_star].color];
727 }
728 draw_rect(&rect, star_color);
729 if (mark_dirty) {
730 add_drect(&rect);
731 }
732 }
733
734 // seg001:0E94
show_hof()735 void __pascal far show_hof() {
736 // Hall of Fame
737 short index;
738 char time_text[12];
739 for (index = 0; index < hof_count; ++index) {
740
741 #ifdef ALLOW_INFINITE_TIME
742 int minutes, seconds;
743 if (hof[index].min > 0) {
744 minutes = hof[index].min - 1;
745 seconds = hof[index].tick / 12;
746 } else {
747 // negative minutes means time ran 'forward' from 0:00 upwards
748 minutes = abs(hof[index].min) - 1;
749 seconds = (719 - hof[index].tick) / 12;
750 }
751 snprintf(time_text, sizeof(time_text), "%d:%02d", minutes, seconds);
752 #else
753 snprintf(time_text, sizeof(time_text), "%d:%02d", hof[index].min - 1, hof[index].tick / 12);
754 #endif
755
756 show_hof_text(&hof_rects[index], -1, 0, hof[index].name);
757 show_hof_text(&hof_rects[index], 1, 0, time_text);
758 }
759 // stub
760 }
761
762 static const char* hof_file = "PRINCE.HOF";
763
get_hof_path(char * custom_path_buffer,size_t max_len)764 const char* get_hof_path(char* custom_path_buffer, size_t max_len) {
765 if (!use_custom_levelset) {
766 return hof_file;
767 }
768 // if playing a custom levelset, try to use the mod folder
769 snprintf_check(custom_path_buffer, max_len, "%s/%s", mod_data_path, hof_file /*PRINCE.HOF*/ );
770 return custom_path_buffer;
771 }
772
773 // seg001:0F17
hof_write()774 void __pascal far hof_write() {
775 FILE* handle;
776 char custom_hof_path[POP_MAX_PATH];
777 const char* hof_path = get_hof_path(custom_hof_path, sizeof(custom_hof_path));
778 handle = fopen(hof_path, "wb");
779 if (handle == NULL ||
780 fwrite(&hof_count, 1, 2, handle) != 2 ||
781 fwrite(&hof, 1, sizeof(hof), handle) != sizeof(hof))
782 perror(hof_path);
783 if (handle != NULL)
784 fclose(handle);
785 }
786
787 // seg001:0F6C
hof_read()788 void __pascal far hof_read() {
789 FILE* handle;
790 hof_count = 0;
791 char custom_hof_path[POP_MAX_PATH];
792 const char* hof_path = get_hof_path(custom_hof_path, sizeof(custom_hof_path));
793 handle = fopen(hof_path, "rb");
794 if (handle == NULL)
795 return;
796 if (fread(&hof_count, 1, 2, handle) != 2 ||
797 fread(&hof, 1, sizeof(hof), handle) != sizeof(hof)) {
798 perror(hof_path);
799 hof_count = 0;
800 }
801 fclose(handle);
802 }
803
804 // seg001:0FC3
show_hof_text(rect_type far * rect,int x_align,int y_align,const char * text)805 void __pascal far show_hof_text(rect_type far *rect,int x_align,int y_align, const char *text) {
806 short shadow_color;
807 short text_color;
808 rect_type rect2;
809 text_color = 15;
810 shadow_color = 0;
811 if (graphics_mode == gmMcgaVga) {
812 text_color = 0xB7;
813 }
814 offset2_rect(&rect2, rect, 1, 1);
815 show_text_with_color(&rect2, x_align, y_align, text, shadow_color);
816 show_text_with_color(rect, x_align, y_align, text, text_color);
817 }
818
819 // seg001:1029
fade_in_1()820 int __pascal far fade_in_1() {
821 #ifdef USE_FADE
822 // sbyte index;
823 word interrupted;
824 if (graphics_mode == gmMcgaVga) {
825 fade_palette_buffer = make_pal_buffer_fadein(offscreen_surface, 0x6689, /*0*/ 2);
826 is_global_fading = 1;
827 do {
828 interrupted = proc_cutscene_frame(1);
829 if (interrupted == 1) {
830 return 1;
831 }
832 } while (interrupted == 0);
833 is_global_fading = 0;
834 } else {
835 // ...
836 }
837 return 0;
838 #else
839 // stub
840 method_1_blit_rect(onscreen_surface_, offscreen_surface, &screen_rect, &screen_rect, 0);
841 update_screen();
842 // SDL_UpdateRect(onscreen_surface_, 0, 0, 0, 0); // debug
843 return 0;
844 #endif
845 }
846
847 // seg001:112D
fade_out_1()848 int __pascal far fade_out_1() {
849 #ifdef USE_FADE
850 word interrupted;
851 if (graphics_mode == gmMcgaVga) {
852 fade_palette_buffer = make_pal_buffer_fadeout(0x6689, /*0*/ 2);
853 is_global_fading = 1;
854 do {
855 interrupted = proc_cutscene_frame(1);
856 if (interrupted == 1) {
857 return 1;
858 }
859 } while (interrupted == 0);
860 is_global_fading = 0;
861 } else {
862 // ...
863 }
864 #endif
865 // stub
866 return 0;
867 }
868