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. // seg007:0000
  24. void __pascal far process_trobs() {
  25.         word need_delete;
  26.         word index;
  27.         word new_index;
  28.         need_delete = 0;
  29.         if (trobs_count == 0) return;
  30.         for (index = 0; index < trobs_count; ++index) {
  31.                 trob = trobs[index];
  32.                 animate_tile();
  33.                 trobs[index].type = trob.type;
  34.                 if (trob.type < 0) {
  35.                         need_delete = 1;
  36.                 }
  37.         }
  38.         if (need_delete) {
  39.                 for (index = new_index = 0; index < trobs_count; ++index) {
  40.                         if (trobs[index].type >= 0) {
  41.                                 trobs[new_index++] = trobs[index];
  42.                         }
  43.                 }
  44.                 trobs_count = new_index;
  45.         }
  46. }
  47.  
  48. // seg007:00AF
  49. void __pascal far animate_tile() {
  50.         get_room_address(trob.room);
  51.         switch (get_curr_tile(trob.tilepos)) {
  52.                 case tiles_19_torch:
  53.                 case tiles_30_torch_with_debris:
  54.                         animate_torch();
  55.                 break;
  56.                 case tiles_6_closer:
  57.                 case tiles_15_opener:
  58.                         animate_button();
  59.                 break;
  60.                 case tiles_2_spike:
  61.                         animate_spike();
  62.                 break;
  63.                 case tiles_11_loose:
  64.                         animate_loose();
  65.                 break;
  66.                 case tiles_0_empty:
  67.                         animate_empty();
  68.                 break;
  69.                 case tiles_18_chomper:
  70.                         animate_chomper();
  71.                 break;
  72.                 case tiles_4_gate:
  73.                         animate_door();
  74.                 break;
  75.                 case tiles_16_level_door_left:
  76.                         animate_leveldoor();
  77.                 break;
  78.                 case tiles_10_potion:
  79.                         animate_potion();
  80.                 break;
  81.                 case tiles_22_sword:
  82.                         animate_sword();
  83.                 break;
  84.                 default:
  85.                         trob.type = -1;
  86.                 break;
  87.         }
  88.         curr_room_modif[trob.tilepos] = curr_modifier;
  89. }
  90.  
  91. // seg007:0166
  92. short __pascal far is_trob_in_drawn_room() {
  93.         if (trob.room != drawn_room) {
  94.                 trob.type = -1;
  95.                 return 0;
  96.         } else {
  97.                 return 1;
  98.         }
  99. }
  100.  
  101. // seg007:017E
  102. void __pascal far set_redraw_anim_right() {
  103.         set_redraw_anim(get_trob_right_pos_in_drawn_room(), 1);
  104. }
  105.  
  106. // seg007:018C
  107. void __pascal far set_redraw_anim_curr() {
  108.         set_redraw_anim(get_trob_pos_in_drawn_room(), 1);
  109. }
  110.  
  111. // seg007:019A
  112. void __pascal far redraw_at_trob() {
  113.         word tilepos;
  114.         redraw_height = 63;
  115.         tilepos = get_trob_pos_in_drawn_room();
  116.         set_redraw_full(tilepos, 1);
  117.         set_wipe(tilepos, 1);
  118. }
  119.  
  120. // seg007:01C5
  121. void __pascal far redraw_21h() {
  122.         redraw_height = 0x21;
  123.         redraw_tile_height();
  124. }
  125.  
  126. // seg007:01D0
  127. void __pascal far redraw_11h() {
  128.         redraw_height = 0x11;
  129.         redraw_tile_height();
  130. }
  131.  
  132. // seg007:01DB
  133. void __pascal far redraw_20h() {
  134.         redraw_height = 0x20;
  135.         redraw_tile_height();
  136. }
  137.  
  138. // seg007:01E6
  139. void __pascal far draw_trob() {
  140.         word var_2;
  141.         var_2 = get_trob_right_pos_in_drawn_room();
  142.         set_redraw_anim(var_2, 1);
  143.         set_redraw_fore(var_2, 1);
  144.         set_redraw_anim(get_trob_right_above_pos_in_drawn_room(), 1);
  145. }
  146.  
  147. // seg007:0218
  148. void __pascal far redraw_tile_height() {
  149.         short tilepos;
  150.         tilepos = get_trob_pos_in_drawn_room();
  151.         set_redraw_full(tilepos, 1);
  152.         set_wipe(tilepos, 1);
  153.         tilepos = get_trob_right_pos_in_drawn_room();
  154.         set_redraw_full(tilepos, 1);
  155.         set_wipe(tilepos, 1);
  156. }
  157.  
  158. // seg007:0258
  159. short __pascal far get_trob_pos_in_drawn_room() {
  160.         short tilepos;
  161.         tilepos = trob.tilepos;
  162.         if (trob.room == room_A) {
  163.                 if (tilepos >= 20 && tilepos < 30) {
  164.                         // 20..29 -> -1..-10
  165.                         tilepos = 19 - tilepos;
  166.                 } else {
  167.                         tilepos = 30;
  168.                 }
  169.         } else {
  170.                 if (trob.room != drawn_room) {
  171.                         tilepos = 30;
  172.                 }
  173.         }
  174.         return tilepos;
  175. }
  176.  
  177. // seg007:029D
  178. short __pascal far get_trob_right_pos_in_drawn_room() {
  179.         word tilepos;
  180.         tilepos = trob.tilepos;
  181.         if (trob.room == drawn_room) {
  182.                 if (tilepos % 10 != 9) {
  183.                         ++tilepos;
  184.                 } else {
  185.                         tilepos = 30;
  186.                 }
  187.         } else if (trob.room == room_L) {
  188.                 if (tilepos % 10 == 9) {
  189.                         tilepos -= 9;
  190.                 } else {
  191.                         tilepos = 30;
  192.                 }
  193.         } else if (trob.room == room_A) {
  194.                 if (tilepos >= 20 && tilepos < 29) {
  195.                         // 20..28 -> -2..-10
  196.                         tilepos = 18 - tilepos;
  197.                 } else {
  198.                         tilepos = 30;
  199.                 }
  200.         } else if (trob.room == room_AL && tilepos == 29) {
  201.                 tilepos = -1;
  202.         } else {
  203.                 tilepos = 30;
  204.         }
  205.         return tilepos;
  206. }
  207.  
  208. // seg007:032C
  209. short __pascal far get_trob_right_above_pos_in_drawn_room() {
  210.         word tilepos;
  211.         tilepos = trob.tilepos;
  212.         if (trob.room == drawn_room) {
  213.                 if (tilepos % 10 != 9) {
  214.                         if (tilepos < 10) {
  215.                                 // 0..8 -> -2..-10
  216.                                 tilepos = -(tilepos + 2);
  217.                         } else {
  218.                                 tilepos -= 9;
  219.                         }
  220.                 } else {
  221.                         tilepos = 30;
  222.                 }
  223.         } else if (trob.room == room_L) {
  224.                 if (tilepos == 9) {
  225.                         tilepos = -1;
  226.                 } else {
  227.                         if (tilepos % 10 == 9) {
  228.                                 tilepos -= 19;
  229.                         } else {
  230.                                 tilepos = 30;
  231.                         }
  232.                 }
  233.         } else if (trob.room == room_B) {
  234.                 if (tilepos < 9) {
  235.                         tilepos += 21;
  236.                 } else {
  237.                         tilepos = 30;
  238.                 }
  239.         } else if (trob.room == room_BL && tilepos == 9) {
  240.                 tilepos = 20;
  241.         } else {
  242.                 tilepos = 30;
  243.         }
  244.         return tilepos;
  245. }
  246.  
  247. // seg007:03CF
  248. void __pascal far animate_torch() {
  249.         if (is_trob_in_drawn_room()) {
  250.                 curr_modifier = get_torch_frame(curr_modifier);
  251.                 set_redraw_anim_right();
  252.         }
  253. }
  254.  
  255. // seg007:03E9
  256. void __pascal far animate_potion() {
  257.         word type;
  258.         if (trob.type >= 0 && is_trob_in_drawn_room()) {
  259.                 type = curr_modifier & 0xF8;
  260.                 curr_modifier = bubble_next_frame(curr_modifier & 0x07) | type;
  261.                 set_redraw_anim_curr();
  262.         }
  263. }
  264.  
  265. // seg007:0425
  266. void __pascal far animate_sword() {
  267.         if (is_trob_in_drawn_room()) {
  268.                 --curr_modifier;
  269.                 if (curr_modifier == 0) {
  270.                         curr_modifier = (prandom(255) & 0x3F) + 0x28;
  271.                 }
  272.                 set_redraw_anim_curr();
  273.         }
  274. }
  275.  
  276. // seg007:0448
  277. void __pascal far animate_chomper() {
  278.         word blood;
  279.         word frame;
  280.         if (trob.type >= 0) {
  281.                 blood = curr_modifier & 0x80;
  282.                 frame = (curr_modifier & 0x7F) + 1;
  283.                 if (frame > 15) {
  284.                         frame = 1;
  285.                 }
  286.                 curr_modifier = blood | frame;
  287.                 if (frame == 2) {
  288.                         play_sound(sound_47_chomper); // chomper
  289.                 }
  290.                 // If either:
  291.                 // - Kid left this room
  292.                 // - Kid left this row
  293.                 // - Kid died but not in this chomper
  294.                 // and chomper is past frame 6
  295.                 // then stop.
  296.                 if ((trob.room != drawn_room || trob.tilepos / 10 != Kid.curr_row ||
  297.                         (Kid.alive >= 0 && blood == 0)) && (curr_modifier & 0x7F) >= 6
  298.                 ) {
  299.                         trob.type = -1;
  300.                 }
  301.         }
  302.         if ((curr_modifier & 0x7F) < 6) {
  303.                 redraw_at_trob();
  304.         }
  305. }
  306.  
  307. // seg007:04D3
  308. void __pascal far animate_spike() {
  309.         if (trob.type >= 0) {
  310.                 // 0xFF means a disabled spike.
  311.                 if (curr_modifier == 0xFF) return;
  312.                 if (curr_modifier & 0x80) {
  313.                         --curr_modifier;
  314.                         if (curr_modifier & 0x7F) return;
  315.                         curr_modifier = 6;
  316.                 } else {
  317.                         ++curr_modifier;
  318.                         if (curr_modifier == 5) {
  319.                                 curr_modifier = 0x8F;
  320.                         } else if (curr_modifier == 9) {
  321.                                 curr_modifier = 0;
  322.                                 trob.type = -1;
  323.                         }
  324.                 }
  325.         }
  326.         redraw_21h();
  327. }
  328.  
  329. // data:27B2
  330. const byte gate_close_speeds[] = {0, 0, 0, 20, 40, 60, 80, 100, 120};
  331. // data:27C0
  332. const byte door_delta[] = {-1, 4, 4};
  333. // seg007:0522
  334. void __pascal far animate_door() {
  335. /*
  336. Possible values of anim_type:
  337. 0: closing
  338. 1: open
  339. 2: permanent open
  340. 3,4,5,6,7,8: fast closing with speeds 20,40,60,80,100,120 /4 pixel/frame
  341. */
  342.         sbyte anim_type;
  343.         anim_type = trob.type;
  344.         if (anim_type >= 0) {
  345.                 if (anim_type >= 3) {
  346.                         // closing fast
  347.                         if (anim_type < 8) {
  348.                                 ++anim_type;
  349.                                 trob.type = anim_type;
  350.                         }
  351.                         short new_mod = curr_modifier - gate_close_speeds[anim_type];
  352.                         curr_modifier = new_mod;
  353.                         //if ((sbyte)curr_modifier < 0) {
  354.                         if (new_mod < 0) {
  355.                         //if ((curr_modifier -= gate_close_speeds[anim_type]) < 0) {
  356.                                 curr_modifier = 0;
  357.                                 trob.type = -1;
  358.                                 play_sound(sound_6_gate_closing_fast); // gate closing fast
  359.                         }
  360.                 } else {
  361.                         if (curr_modifier != 0xFF) {
  362.                                 // 0xFF means permanently open.
  363.                                 curr_modifier += door_delta[anim_type];
  364.                                 if (anim_type == 0) {
  365.                                         // closing
  366.                                         if (curr_modifier != 0) {
  367.                                                 if (curr_modifier < 188) {
  368.                                                         if ((curr_modifier & 3) == 3) {
  369.                                                                 play_door_sound_if_visible(sound_4_gate_closing); // gate closing
  370.                                                         }
  371.                                                 }
  372.                                         } else {
  373.                                                 gate_stop();
  374.                                         }
  375.                                 } else {
  376.                                         // opening
  377.                                         if (curr_modifier < 188) {
  378.                                                 if ((curr_modifier & 7) == 0) {
  379.                                                         play_sound(sound_5_gate_opening); // gate opening
  380.                                                 }
  381.                                         } else {
  382.                                                 // stop
  383.                                                 if (anim_type < 2) {
  384.                                                         // after regular open
  385.                                                         curr_modifier = 238;
  386.                                                         trob.type = 0; // closing
  387.                                                         play_sound(sound_7_gate_stop); // gate stop (after opening)
  388.                                                 } else {
  389.                                                         // after permanent open
  390.                                                         curr_modifier = 0xFF; // keep open
  391.                                                         gate_stop();
  392.                                                 }
  393.                                         }
  394.                                 }
  395.                         } else {
  396.                                 gate_stop();
  397.                         }
  398.                 }
  399.         }
  400.         draw_trob();
  401. }
  402.  
  403. // seg007:05E3
  404. void __pascal far gate_stop() {
  405.         trob.type = -1;
  406.         play_door_sound_if_visible(sound_7_gate_stop); // gate stop (after closing)
  407. }
  408.  
  409. // data:27B8
  410. const byte leveldoor_close_speeds[] = {0, 5, 17, 99, 0};
  411. // seg007:05F1
  412. void __pascal far animate_leveldoor() {
  413. /*
  414. Possible values of trob_type:
  415. 0: open
  416. 1: open (with button)
  417. 2: open
  418. 3,4,5,6: fast closing with speeds 0,5,17,99 pixel/frame
  419. */
  420.         word trob_type;
  421.         trob_type = trob.type;
  422.         if (trob.type >= 0) {
  423.                 if (trob_type >= 3) {
  424.                         // closing
  425.                         ++trob.type;
  426.                         curr_modifier -= leveldoor_close_speeds[trob.type - 3];
  427.                         if ((sbyte)curr_modifier < 0) {
  428.                                 curr_modifier = 0;
  429.                                 trob.type = -1;
  430.                                 play_sound(sound_14_leveldoor_closing); // level door closing
  431.                         } else {
  432.                                 if (trob.type == 4 &&
  433.                                         (sound_flags & sfDigi)
  434.                                 ) {
  435.                                         sound_interruptible[sound_15_leveldoor_sliding] = 1;
  436.                                         play_sound(sound_15_leveldoor_sliding); // level door sliding (closing)
  437.                                 }
  438.                         }
  439.                 } else {
  440.                         // opening
  441.                         ++curr_modifier;
  442.                         if (curr_modifier >= 43) {
  443.                                 trob.type = -1;
  444. #ifdef FIX_FEATHER_INTERRUPTED_BY_LEVELDOOR
  445.                                 if (!(fix_feather_interrupted_by_leveldoor && is_feather_fall))
  446. #endif
  447.                                 stop_sounds();
  448.                                 if (leveldoor_open == 0 || leveldoor_open == 2) {
  449.                                         leveldoor_open = 1;
  450.                                         if (current_level == 4) {
  451.                                                 // Special event: place mirror
  452.                                                 get_tile(4, 4, 0);
  453.                                                 curr_room_tiles[curr_tilepos] = tiles_13_mirror;
  454.                                         }
  455.                                 }
  456.                         } else {
  457.                                 sound_interruptible[15] = 0;
  458.                                 play_sound(sound_15_leveldoor_sliding); // level door sliding (opening)
  459.                         }
  460.                 }
  461.         }
  462.         set_redraw_anim_right();
  463. }
  464.  
  465. // seg007:06AD
  466. short __pascal far bubble_next_frame(short curr) {
  467.         short next;
  468.         next = curr + 1;
  469.         if (next >= 8) next = 1;
  470.         return next;
  471. }
  472.  
  473. // seg007:06CD
  474. short __pascal far get_torch_frame(short curr) {
  475.         short next;
  476.         next = prandom(255);
  477.         if (next != curr) {
  478.                 if (next < 9) {
  479.                         return next;
  480.                 } else {
  481.                         next = curr;
  482.                 }
  483.         }
  484.         ++next;
  485.         if (next >= 9) next = 0;
  486.         return next;
  487. }
  488.  
  489. // seg007:070A
  490. void __pascal far set_redraw_anim(short tilepos, byte frames) {
  491.         if (tilepos < 30) {
  492.                 if (tilepos < 0) {
  493.                         ++tilepos;
  494.                         redraw_frames_above[-tilepos] = frames;
  495.                         // or simply: ~tilepos
  496.                 } else {
  497.                         redraw_frames_anim[tilepos] = frames;
  498.                 }
  499.         }
  500. }
  501.  
  502. // seg007:0738
  503. void __pascal far set_redraw2(short tilepos, byte frames) {
  504.         if (tilepos < 30) {
  505.                 if (tilepos < 0) {
  506.                         // trying to draw a mob at a negative tilepos, in the range -1 .. -10
  507.                         // used e.g. when the kid is climbing up to the room above
  508.                         // however, loose tiles falling out of the room end up with a negative tilepos {-2 .. -11} !
  509.                         tilepos = (-tilepos) - 1;
  510.                         if (tilepos > 9) tilepos = 9; // prevent array index out of bounds!
  511.                         redraw_frames_above[tilepos] = frames;
  512.                 } else {
  513.                         redraw_frames2[tilepos] = frames;
  514.                 }
  515.         }
  516. }
  517.  
  518. // seg007:0766
  519. void __pascal far set_redraw_floor_overlay(short tilepos, byte frames) {
  520.         if (tilepos < 30) {
  521.                 if (tilepos < 0) {
  522.                         ++tilepos;
  523.                         redraw_frames_above[-tilepos] = frames;
  524.                         // or simply: ~tilepos
  525.                 } else {
  526.                         redraw_frames_floor_overlay[tilepos] = frames;
  527.                 }
  528.         }
  529. }
  530.  
  531. // seg007:0794
  532. void __pascal far set_redraw_full(short tilepos, byte frames) {
  533.         if (tilepos < 30) {
  534.                 if (tilepos < 0) {
  535.                         ++tilepos;
  536.                         redraw_frames_above[-tilepos] = frames;
  537.                         // or simply: ~tilepos
  538.                 } else {
  539.                         redraw_frames_full[tilepos] = frames;
  540.                 }
  541.         }
  542. }
  543.  
  544. // seg007:07C2
  545. void __pascal far set_redraw_fore(short tilepos, byte frames) {
  546.         if (tilepos < 30 && tilepos >= 0) {
  547.                 redraw_frames_fore[tilepos] = frames;
  548.         }
  549. }
  550.  
  551. // seg007:07DF
  552. void __pascal far set_wipe(short tilepos, byte frames) {
  553.         if (tilepos < 30 && tilepos >= 0) {
  554.                 if (wipe_frames[tilepos] != 0) {
  555.                         redraw_height = MAX(wipe_heights[tilepos], redraw_height);
  556.                 }
  557.                 wipe_heights[tilepos] = redraw_height;
  558.                 wipe_frames[tilepos] = frames;
  559.         }
  560. }
  561.  
  562. // seg007:081E
  563. void __pascal far start_anim_torch(short room,short tilepos) {
  564.         curr_room_modif[tilepos] = prandom(8);
  565.         add_trob(room, tilepos, 1);
  566. }
  567.  
  568. // seg007:0847
  569. void __pascal far start_anim_potion(short room,short tilepos) {
  570.         curr_room_modif[tilepos] &= 0xF8;
  571.         curr_room_modif[tilepos] |= prandom(6) + 1;
  572.         add_trob(room, tilepos, 1);
  573. }
  574.  
  575. // seg007:087C
  576. void __pascal far start_anim_sword(short room,short tilepos) {
  577.         curr_room_modif[tilepos] = prandom(0xFF) & 0x1F;
  578.         add_trob(room, tilepos, 1);
  579. }
  580.  
  581. // seg007:08A7
  582. void __pascal far start_anim_chomper(short room,short tilepos, byte modifier) {
  583.         short old_modifier;
  584.         old_modifier = curr_room_modif[tilepos];
  585.         if (old_modifier == 0 || old_modifier >= 6) {
  586.                 curr_room_modif[tilepos] = modifier;
  587.                 add_trob(room, tilepos, 1);
  588.         }
  589. }
  590.  
  591. // seg007:08E3
  592. void __pascal far start_anim_spike(short room,short tilepos) {
  593.         sbyte old_modifier;
  594.         old_modifier = curr_room_modif[tilepos];
  595.         if (old_modifier <= 0) {
  596.                 if (old_modifier == 0) {
  597.                         add_trob(room, tilepos, 1);
  598.                         play_sound(sound_49_spikes); // spikes
  599.                 } else {
  600.                         // 0xFF means a disabled spike.
  601.                         if (old_modifier != (sbyte)0xFF) {
  602.                                 curr_room_modif[tilepos] = 0x8F;
  603.                         }
  604.                 }
  605.         }
  606. }
  607.  
  608. // seg007:092C
  609. short __pascal far trigger_gate(short room,short tilepos,short button_type) {
  610.         byte modifier;
  611.         modifier = curr_room_modif[tilepos];
  612.         if (button_type == tiles_15_opener) {
  613.                 // If the gate is permanently open, don't to anything.
  614.                 if (modifier == 0xFF) return -1;
  615.                 if (modifier >= 188) { // if it's already open
  616.                         curr_room_modif[tilepos] = 238; // keep it open for a while
  617.                         return -1;
  618.                 }
  619.                 curr_room_modif[tilepos] = (modifier + 3) & 0xFC;
  620.                 return 1; // regular open
  621.         } else if (button_type == tiles_14_debris) {
  622.                 // If it's not fully open:
  623.                 if (modifier < 188) return 2; // permanent open
  624.                 curr_room_modif[tilepos] = 0xFF; // keep open
  625.                 return -1;
  626.         } else {
  627.                 if (modifier != 0) {
  628.                         return 3; // close fast
  629.                 } else {
  630.                         // already closed
  631.                         return -1;
  632.                 }
  633.         }
  634. }
  635.  
  636. // seg007:0999
  637. short __pascal far trigger_1(short target_type,short room,short tilepos,short button_type) {
  638.         short result;
  639.         result = -1;
  640.         if (target_type == tiles_4_gate) {
  641.                 result = trigger_gate(room, tilepos, button_type);
  642.         } else if (target_type == tiles_16_level_door_left) {
  643.                 if (curr_room_modif[tilepos] != 0) {
  644.                         result = -1;
  645.                 } else {
  646.                         result = 1;
  647.                 }
  648.         } else if (allow_triggering_any_tile) { //allow_triggering_any_tile hack
  649.                 result = 1;
  650.         }
  651.         return result;
  652. }
  653.  
  654. // seg007:09E5
  655. void __pascal far do_trigger_list(short index,short button_type) {
  656.         word room;
  657.         word tilepos;
  658.         byte target_type;
  659.         sbyte trigger_result;
  660. //      while (doorlink1_ad[index] != -1) { // these can't be equal!
  661.         while (1) {  // Same as the above but just a little faster and no compiler warning.
  662.                 room = get_doorlink_room(index);
  663.                 get_room_address(room);
  664.                 tilepos = get_doorlink_tile(index);
  665.                 target_type = curr_room_tiles[tilepos] & 0x1F;
  666.                 trigger_result = trigger_1(target_type, room, tilepos, button_type);
  667.                 if (trigger_result >= 0) {
  668.                         add_trob(room, tilepos, trigger_result);
  669.                 }
  670.                 if (get_doorlink_next(index++) == 0) break;
  671.         }
  672. }
  673.  
  674. // seg007:0A5A
  675. void __pascal far add_trob(byte room,byte tilepos,sbyte type) {
  676.         short found;
  677.         if (trobs_count >= 30) {
  678.                 show_dialog("Trobs Overflow");
  679.                 return /*0*/; // added
  680.         }
  681.         trob.room = room;
  682.         trob.tilepos = tilepos;
  683.         trob.type = type;
  684.         found = find_trob();
  685.         if (found == -1) {
  686.                 // add new
  687.                 if (trobs_count == 30) return;
  688.                 trobs[trobs_count++] = trob;
  689.         } else {
  690.                 // change existing
  691.                 trobs[found].type = trob.type;
  692.         }
  693. }
  694.  
  695. // seg007:0ACA
  696. short __pascal far find_trob() {
  697.         short index;
  698.         for (index = 0; index < trobs_count; ++index) {
  699.                 if (trobs[index].tilepos == trob.tilepos &&
  700.                         trobs[index].room == trob.room) return index;
  701.         }
  702.         return -1;
  703. }
  704.  
  705. // seg007:0B0A
  706. void __pascal far clear_tile_wipes() {
  707.         memset_near(redraw_frames_full, 0, sizeof(redraw_frames_full));
  708.         memset_near(wipe_frames, 0, sizeof(wipe_frames));
  709.         memset_near(wipe_heights, 0, sizeof(wipe_heights));
  710.         memset_near(redraw_frames_anim, 0, sizeof(redraw_frames_anim));
  711.         memset_near(redraw_frames_fore, 0, sizeof(redraw_frames_fore));
  712.         memset_near(redraw_frames2, 0, sizeof(redraw_frames2));
  713.         memset_near(redraw_frames_floor_overlay, 0, sizeof(redraw_frames_floor_overlay));
  714.         memset_near(tile_object_redraw, 0, sizeof(tile_object_redraw));
  715.         memset_near(redraw_frames_above, 0, sizeof(redraw_frames_above));
  716. }
  717.  
  718. // seg007:0BB6
  719. short __pascal far get_doorlink_timer(short index) {
  720.         return doorlink2_ad[index] & 0x1F;
  721. }
  722.  
  723. // seg007:0BCD
  724. short __pascal far set_doorlink_timer(short index,byte value) {
  725.         doorlink2_ad[index] &= 0xE0;
  726.         doorlink2_ad[index] |= value & 0x1F;
  727.         return doorlink2_ad[index];
  728. }
  729.  
  730. // seg007:0BF2
  731. short __pascal far get_doorlink_tile(short index) {
  732.         return doorlink1_ad[index] & 0x1F;
  733. }
  734.  
  735. // seg007:0C09
  736. short __pascal far get_doorlink_next(short index) {
  737.         return !(doorlink1_ad[index] & 0x80);
  738. }
  739.  
  740. // seg007:0C26
  741. short __pascal far get_doorlink_room(short index) {
  742.         return
  743.                 ((doorlink1_ad[index] & 0x60) >> 5) +
  744.                 ((doorlink2_ad[index] & 0xE0) >> 3);
  745. }
  746.  
  747. // seg007:0C53
  748. void __pascal far trigger_button(int playsound,int button_type,int modifier) {
  749.         sbyte link_timer;
  750.         get_curr_tile(curr_tilepos);
  751.         if (button_type == 0) {
  752.                 // 0 means currently selected
  753.                 button_type = curr_tile;
  754.         }
  755.         if (modifier == -1) {
  756.                 // -1 means currently selected
  757.                 modifier = curr_modifier;
  758.         }
  759.         link_timer = get_doorlink_timer(modifier);
  760.         // is the event jammed?
  761.         if (link_timer != 0x1F) {
  762.                 set_doorlink_timer(modifier, 5);
  763.                 if (link_timer < 2) {
  764.                         add_trob(curr_room, curr_tilepos, 1);
  765.                         redraw_11h();
  766.                         is_guard_notice = 1;
  767.                         if (playsound) {
  768.                                 play_sound(sound_3_button_pressed); // button pressed
  769.                         }
  770.                 }
  771.                 do_trigger_list(modifier, button_type);
  772.         }
  773. }
  774.  
  775. // seg007:0CD9
  776. void __pascal far died_on_button() {
  777.         word button_type;
  778.         word modifier;
  779.         button_type = get_curr_tile(curr_tilepos);
  780.         modifier = curr_modifier;
  781.         if (curr_tile == tiles_15_opener) {
  782.                 curr_room_tiles[curr_tilepos] = tiles_1_floor;
  783.                 curr_room_modif[curr_tilepos] = 0;
  784.                 button_type = tiles_14_debris; // force permanent open
  785.         } else {
  786.                 curr_room_tiles[curr_tilepos] = tiles_5_stuck;
  787.         }
  788.         trigger_button(1, button_type, modifier);
  789. }
  790.  
  791. // seg007:0D3A
  792. void __pascal far animate_button() {
  793.         word var_2;
  794.         if (trob.type >= 0) {
  795.                 set_doorlink_timer(curr_modifier, var_2 = get_doorlink_timer(curr_modifier) - 1);
  796.                 if (var_2 < 2) {
  797.                         trob.type = -1;
  798.                         redraw_11h();
  799.                 }
  800.         }
  801. }
  802.  
  803. // seg007:0D72
  804. void __pascal far start_level_door(short room,short tilepos) {
  805.         curr_room_modif[tilepos] = 43; // start fully open
  806.         add_trob(room, tilepos, 3);
  807. }
  808.  
  809. // seg007:0D93
  810. void __pascal far animate_empty() {
  811.         trob.type = -1;
  812.         redraw_20h();
  813. }
  814.  
  815. // data:2284
  816. const word y_loose_land[] = {2, 65, 128, 191, 254};
  817. // seg007:0D9D
  818. void __pascal far animate_loose() {
  819.         word room;
  820.         word row;
  821.         word tilepos;
  822.         short anim_type;
  823.         anim_type = trob.type;
  824.         if (anim_type >= 0) {
  825.                 ++curr_modifier;
  826.                 if (curr_modifier & 0x80) {
  827.                         // just shaking
  828.                         // don't shake on level 13
  829.                         if (current_level == 13) return;
  830.                         if (curr_modifier >= 0x84) {
  831.                                 curr_modifier = 0;
  832.                                 trob.type = -1;
  833.                         }
  834.                         loose_shake(!curr_modifier);
  835.                 } else {
  836.                         // something is on the floor
  837.                         // should it fall already?
  838.                         if (curr_modifier >= 11) {
  839.                                 curr_modifier = remove_loose(room = trob.room, tilepos = trob.tilepos);
  840.                                 trob.type = -1;
  841.                                 curmob.xh = (tilepos % 10) << 2;
  842.                                 row = tilepos / 10;
  843.                                 curmob.y = y_loose_land[row + 1];
  844.                                 curmob.room = room;
  845.                                 curmob.speed = 0;
  846.                                 curmob.type = 0;
  847.                                 curmob.row = row;
  848.                                 add_mob();
  849.                         } else {
  850.                                 loose_shake(0);
  851.                         }
  852.                 }
  853.         }
  854.         redraw_20h();
  855. }
  856.  
  857. // data:2734
  858. const byte loose_sound[] = {0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0};
  859. // seg007:0E55
  860. void __pascal far loose_shake(int arg_0) {
  861.         word sound_id;
  862.         if (arg_0 || loose_sound[curr_modifier & 0x7F]) {
  863.                 do {
  864.                         // Sounds 20,21,22: loose floor shaking
  865.                         sound_id = prandom(2) + sound_20_loose_shake_1;
  866.                 } while(sound_id == last_loose_sound);
  867.                 if (sound_flags & sfDigi) {
  868.                         last_loose_sound = sound_id;
  869.                         // random sample rate (10500..11500)
  870.                         //sound_pointers[sound_id]->samplerate = prandom(1000) + 10500;
  871.                 }
  872.                 play_sound(sound_id);
  873.         }
  874. }
  875.  
  876. // seg007:0EB8
  877. int __pascal far remove_loose(int room, int tilepos) {
  878.         curr_room_tiles[tilepos] = tiles_0_empty;
  879.         // note: the level type is used to determine the modifier of the empty space left behind
  880.         return tbl_level_type[current_level];
  881. }
  882.  
  883. // seg007:0ED5
  884. void __pascal far make_loose_fall(byte modifier) {
  885.         // is it a "solid" loose floor?
  886.         if ((curr_room_tiles[curr_tilepos] & 0x20) == 0) {
  887.                 if ((sbyte)curr_room_modif[curr_tilepos] <= 0) {
  888.                         curr_room_modif[curr_tilepos] = modifier;
  889.                         add_trob(curr_room, curr_tilepos, 0);
  890.                         redraw_20h();
  891.                 }
  892.         }
  893. }
  894.  
  895. // seg007:0F13
  896. void __pascal far start_chompers() {
  897.         short timing;
  898.         short modifier;
  899.         short tilepos;
  900.         short column;
  901.         timing = 15;
  902.         if ((byte)Char.curr_row < 3) {
  903.                 get_room_address(Char.room);
  904.                 for (column = 0, tilepos = tbl_line[Char.curr_row];
  905.                         column < 10; ++column, ++tilepos
  906.                 ){
  907.                         if (get_curr_tile(tilepos) == tiles_18_chomper) {
  908.                                 modifier = curr_modifier & 0x7F;
  909.                                 if (modifier == 0 || modifier >= 6) {
  910.                                         start_anim_chomper(Char.room, tilepos, timing | (curr_modifier & 0x80));
  911.                                         timing = next_chomper_timing(timing);
  912.                                 }
  913.                         }
  914.                 }
  915.         }
  916. }
  917.  
  918. // seg007:0F9A
  919. int __pascal far next_chomper_timing(byte timing) {
  920.         // 15,12,9,6,13,10,7,14,11,8,repeat
  921.         timing -= 3;
  922.         if (timing < 6) {
  923.                 timing += 10;
  924.         }
  925.         return timing;
  926. }
  927.  
  928. // seg007:0FB4
  929. void __pascal far loose_make_shake() {
  930.         if (curr_room_modif[curr_tilepos] == 0 && current_level != 13) {
  931.                 curr_room_modif[curr_tilepos] = 0x80;
  932.                 add_trob(curr_room, curr_tilepos, 1);
  933.         }
  934. }
  935.  
  936. // seg007:0FE0
  937. void __pascal far do_knock(int room,int tile_row) {
  938.         short tile_col;
  939.         for (tile_col = 0; tile_col < 10; ++tile_col) {
  940.                 if (get_tile(room, tile_col, tile_row) == tiles_11_loose) {
  941.                         loose_make_shake();
  942.                 }
  943.         }
  944. }
  945.  
  946. // seg007:1010
  947. void __pascal far add_mob() {
  948.         if (mobs_count >= 14) {
  949.                 show_dialog("Mobs Overflow");
  950.                 return /*0*/; // added
  951.         }
  952.         mobs[mobs_count++] = curmob;
  953. }
  954.  
  955. // seg007:1041
  956. short __pascal far get_curr_tile(short tilepos) {
  957.         curr_modifier = curr_room_modif[tilepos];
  958.         return curr_tile = curr_room_tiles[tilepos] & 0x1F;
  959. }
  960.  
  961. // data:43DC
  962. word curmob_index;
  963.  
  964. // seg007:1063
  965. void __pascal far do_mobs() {
  966.         short n_mobs;
  967.         short index;
  968.         short new_index;
  969.         n_mobs = mobs_count;
  970.         for (curmob_index = 0; n_mobs > curmob_index; ++curmob_index) {
  971.                 curmob = mobs[curmob_index];
  972.                 move_mob();
  973.                 check_loose_fall_on_kid();
  974.                 mobs[curmob_index] = curmob;
  975.         }
  976.         new_index = 0;
  977.         for (index = 0; index < mobs_count; ++index) {
  978.                 if (mobs[index].speed != -1) {
  979.                         mobs[new_index++] = mobs[index];
  980.                 }
  981.         }
  982.         mobs_count = new_index;
  983. }
  984.  
  985. // seg007:110F
  986. void __pascal far move_mob() {
  987.         if (curmob.type == 0) {
  988.                 move_loose();
  989.         }
  990.         if (curmob.speed <= 0) {
  991.                 ++curmob.speed;
  992.         }
  993. }
  994.  
  995. // data:227A
  996. const short y_something[] = {-1, 62, 125, 188, 25};
  997. // data:594A
  998. word curr_tile_temp;
  999. // seg007:1126
  1000. void __pascal far move_loose() {
  1001.         if (curmob.speed < 0) return;
  1002.         if (curmob.speed < 29) curmob.speed += 3;
  1003.         curmob.y += curmob.speed;
  1004.         if (curmob.room == 0) {
  1005.                 if (curmob.y < 210) {
  1006.                         return;
  1007.                 } else {
  1008.                         curmob.speed = -2;
  1009.                         return;
  1010.                 }
  1011.         }
  1012.         if (curmob.y < 226 && y_something[curmob.row + 1] <= curmob.y) {
  1013.                 // fell into a different row
  1014.                 curr_tile_temp = get_tile(curmob.room, curmob.xh >> 2, curmob.row);
  1015.                 if (curr_tile_temp == tiles_11_loose) {
  1016.                         loose_fall();
  1017.                 }
  1018.                 if (curr_tile_temp == tiles_0_empty ||
  1019.                         curr_tile_temp == tiles_11_loose
  1020.                 ) {
  1021.                         mob_down_a_row();
  1022.                         return;
  1023.                 }
  1024.                 play_sound(sound_2_tile_crashing); // tile crashing
  1025.                 do_knock(curmob.room, curmob.row);
  1026.                 curmob.y = y_something[curmob.row + 1];
  1027.                 curmob.speed = -2;
  1028.                 loose_land();
  1029.         }
  1030. }
  1031.  
  1032. // seg007:11E8
  1033. void __pascal far loose_land() {
  1034.         short button_type;
  1035.         short tiletype;
  1036.         button_type = 0;
  1037.         tiletype = get_tile(curmob.room, curmob.xh >> 2, curmob.row);
  1038.         switch (tiletype) {
  1039.                 case tiles_15_opener:
  1040.                         curr_room_tiles[curr_tilepos] = tiles_14_debris;
  1041.                         button_type = tiles_14_debris;
  1042.                 // fallthrough!
  1043.                 case tiles_6_closer:
  1044.                         trigger_button(1, button_type, -1);
  1045.                         tiletype = get_tile(curmob.room, curmob.xh >> 2, curmob.row);
  1046.                 // fallthrough!
  1047.                 case tiles_1_floor:
  1048.                 case tiles_2_spike:
  1049.                 case tiles_10_potion:
  1050.                 case tiles_19_torch:
  1051.                 case tiles_30_torch_with_debris:
  1052.                         if (tiletype == tiles_19_torch ||
  1053.                                 tiletype == tiles_30_torch_with_debris
  1054.                         ) {
  1055.                                 curr_room_tiles[curr_tilepos] = tiles_30_torch_with_debris;
  1056.                         } else {
  1057.                                 curr_room_tiles[curr_tilepos] = tiles_14_debris;
  1058.                         }
  1059.                         redraw_at_cur_mob();
  1060.                         if (tile_col != 0) {
  1061.                                 set_redraw_full(curr_tilepos - 1, 1);
  1062.                         }
  1063.         }
  1064. }
  1065.  
  1066. // seg007:12CB
  1067. void __pascal far loose_fall() {
  1068.         curr_room_modif[curr_tilepos] = remove_loose(curr_room, curr_tilepos);
  1069.         curmob.speed >>= 1;
  1070.         mobs[curmob_index] = curmob;
  1071.         curmob.y += 6;
  1072.         mob_down_a_row();
  1073.         add_mob();
  1074.         curmob = mobs[curmob_index];
  1075.         redraw_at_cur_mob();
  1076. }
  1077.  
  1078. // seg007:132C
  1079. void __pascal far redraw_at_cur_mob() {
  1080.         if (curmob.room == drawn_room) {
  1081.                 redraw_height = 0x20;
  1082.                 set_redraw_full(curr_tilepos, 1);
  1083.                 set_wipe(curr_tilepos, 1);
  1084.                 // Redraw tile to the right only if it's in the same room.
  1085.                 if ((curr_tilepos % 10) + 1 < 10) { // changed
  1086.                         set_redraw_full(curr_tilepos + 1, 1);
  1087.                         set_wipe(curr_tilepos + 1, 1);
  1088.                 }
  1089.         }
  1090. }
  1091.  
  1092. // seg007:1387
  1093. void __pascal far mob_down_a_row() {
  1094.         ++curmob.row;
  1095.         if (curmob.row >= 3) {
  1096.                 curmob.y -= 192;
  1097.                 curmob.row = 0;
  1098.                 curmob.room = level.roomlinks[curmob.room - 1].down;
  1099.         }
  1100. }
  1101.  
  1102. // seg007:13AE
  1103. void __pascal far draw_mobs() {
  1104.         short index;
  1105.         for (index = 0; index < mobs_count; ++index) {
  1106.                 curmob = mobs[index];
  1107.                 draw_mob();
  1108.         }
  1109. }
  1110.  
  1111. // seg007:13E5
  1112. void __pascal far draw_mob() {
  1113.         short tile_row;
  1114.         short ypos;
  1115.         short top_row;
  1116.         short tilepos;
  1117.         short tile_col;
  1118.         ypos = curmob.y;
  1119.         if (curmob.room == drawn_room) {
  1120.                 if (curmob.y >= 210) return;
  1121.         } else if (curmob.room == room_B) {
  1122.                 if (ABS(ypos) >= 18) return;
  1123.                 curmob.y += 192;
  1124.                 ypos = curmob.y;
  1125.         } else if (curmob.room == room_A) {
  1126.                 if (curmob.y < 174) return;
  1127.                 ypos = curmob.y - 189;
  1128.         } else {
  1129.                 return;
  1130.         }
  1131.         tile_col = curmob.xh >> 2;
  1132.         tile_row = y_to_row_mod4(ypos);
  1133.         obj_tilepos = get_tilepos_nominus(tile_col, tile_row);
  1134.         ++tile_col;
  1135.         tilepos = get_tilepos(tile_col, tile_row);
  1136.         set_redraw2(tilepos, 1);
  1137.         set_redraw_fore(tilepos, 1);
  1138.         top_row = y_to_row_mod4(ypos - 18);
  1139.         if (top_row != tile_row) {
  1140.                 tilepos = get_tilepos(tile_col, top_row);
  1141.                 set_redraw2(tilepos, 1);
  1142.                 set_redraw_fore(tilepos, 1);
  1143.         }
  1144.         add_mob_to_objtable(ypos);
  1145. }
  1146.  
  1147. // seg007:14DE
  1148. void __pascal far add_mob_to_objtable(int ypos) {
  1149.         word index;
  1150.         objtable_type* curr_obj;
  1151.         index = objtable_count++;
  1152.         curr_obj = &objtable[index];
  1153.         curr_obj->obj_type = curmob.type | 0x80;
  1154.         curr_obj->xh = curmob.xh;
  1155.         curr_obj->xl = 0;
  1156.         curr_obj->y = ypos;
  1157.         curr_obj->chtab_id = id_chtab_6_environment;
  1158.         curr_obj->id = 10;
  1159.         curr_obj->clip.top = 0;
  1160.         curr_obj->clip.left = 0;
  1161.         curr_obj->clip.right = 40;
  1162.         mark_obj_tile_redraw(index);
  1163. }
  1164.  
  1165. // seg007:153E
  1166. void __pascal far sub_9A8E() {
  1167.         // This function is not used.
  1168.         method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_top, &rect_top, 0);
  1169. }
  1170.  
  1171. // seg007:1556
  1172. int __pascal far is_spike_harmful() {
  1173.         sbyte modifier;
  1174.         modifier = curr_room_modif[curr_tilepos];
  1175.         if (modifier == 0 || modifier == -1) {
  1176.                 return 0;
  1177.         } else if (modifier < 0) {
  1178.                 return 1;
  1179.         } else if (modifier < 5) {
  1180.                 return 2;
  1181.         } else {
  1182.                 return 0;
  1183.         }
  1184. }
  1185.  
  1186. // seg007:1591
  1187. void __pascal far check_loose_fall_on_kid() {
  1188.         loadkid();
  1189.         if (Char.room == curmob.room &&
  1190.                 Char.curr_col == curmob.xh >> 2 &&
  1191.                 curmob.y < Char.y &&
  1192.                 Char.y - 30 < curmob.y
  1193.         ) {
  1194.                 fell_on_your_head();
  1195.                 savekid();
  1196.         }
  1197. }
  1198.  
  1199. // seg007:15D3
  1200. void __pascal far fell_on_your_head() {
  1201.         short frame;
  1202.         short action;
  1203.         frame = Char.frame;
  1204.         action = Char.action;
  1205.         // loose floors hurt you in frames 5..14 (running) only on level 13
  1206.         if (
  1207.                 (current_level == 13 || (frame < frame_5_start_run || frame >= 15)) &&
  1208.                 (action < actions_2_hang_climb || action == actions_7_turn)
  1209.         ) {
  1210.                 Char.y = y_land[Char.curr_row + 1];
  1211.                 if (take_hp(1)) {
  1212.                         seqtbl_offset_char(seq_22_crushed); // dead (because of loose floor)
  1213.                         if (frame == frame_177_spiked) { // spiked
  1214.                                 Char.x = char_dx_forward(-12);
  1215.                         }
  1216.                 } else {
  1217.                         if (frame != frame_109_crouch) { // crouching
  1218.                                 if (get_tile_behind_char() == 0) {
  1219.                                         Char.x = char_dx_forward(-2);
  1220.                                 }
  1221.                                 seqtbl_offset_char(seq_52_loose_floor_fell_on_kid); // loose floor fell on Kid
  1222.                         }
  1223.                 }
  1224.         }
  1225. }
  1226.  
  1227. // seg007:1669
  1228. void __pascal far play_door_sound_if_visible(int sound_id) {
  1229.         word has_sound;
  1230.         word tilepos;
  1231.         word gate_room;
  1232.         tilepos = trob.tilepos;
  1233.         gate_room = trob.room;
  1234.         has_sound = 0;
  1235.  
  1236. #ifdef FIX_GATE_SOUNDS
  1237.         sbyte has_sound_condition;
  1238.         if (fix_gate_sounds)
  1239.                 has_sound_condition =   (gate_room == room_L && tilepos % 10 == 9) ||
  1240.                                         (gate_room == drawn_room && tilepos % 10 != 9);
  1241.         else
  1242.                 has_sound_condition =  gate_room == room_L ? tilepos % 10 == 9 :
  1243.                                       (gate_room == drawn_room && tilepos % 10 != 9);
  1244.         #define GATE_SOUND_CONDITION has_sound_condition
  1245. #else
  1246.         #define GATE_SOUND_CONDITION gate_room == room_L ? tilepos % 10 == 9 :          \
  1247.                                     (gate_room == drawn_room && tilepos % 10 != 9)
  1248. #endif
  1249.         // Special event: sound of closing gates
  1250.         if ((current_level == 3 && gate_room == 2) || GATE_SOUND_CONDITION) {
  1251.                 has_sound = 1;
  1252.         }
  1253.         if (has_sound) {
  1254.                 play_sound(sound_id);
  1255.         }
  1256. }
  1257.