Subversion Repositories Games.Prince of Persia

Rev

Blame | Last modification | View Log | Download | RSS feed

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