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