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. // data:1888
  24. extern const word seqtbl_offsets[];
  25.  
  26. // seg005:000A
  27. void __pascal far seqtbl_offset_char(short seq_index) {
  28.         Char.curr_seq = seqtbl_offsets[seq_index];
  29. }
  30.  
  31. // seg005:001D
  32. void __pascal far seqtbl_offset_opp(int seq_index) {
  33.         Opp.curr_seq = seqtbl_offsets[seq_index];
  34. }
  35.  
  36. // seg005:0030
  37. void __pascal far do_fall() {
  38.         if (is_screaming == 0 && Char.fall_y >= 31) {
  39.                 play_sound(sound_1_falling); // falling
  40.                 is_screaming = 1;
  41.         }
  42.         if ((word)y_land[Char.curr_row + 1] > (word)Char.y) {
  43.                 check_grab();
  44.  
  45.                 #ifdef FIX_GLIDE_THROUGH_WALL
  46.                 if (fix_glide_through_wall) {
  47.                         // Fix for the kid falling through walls after turning around while running (especially when weightless)
  48.                         determine_col();
  49.                         get_tile_at_char();
  50.                         if (curr_tile2 == tiles_20_wall ||
  51.                                         ((curr_tile2 == tiles_12_doortop || curr_tile2 == tiles_7_doortop_with_floor) &&
  52.                                          Char.direction == dir_FF_left)
  53.                         ) {
  54.                                 int delta_x = distance_to_edge_weight();
  55.                                 //printf("delta_x = %d\n", delta_x);
  56.                                 // When falling into a wall or doortop after turning or running, delta_x is likely to be either 8, 11 or 12
  57.                                 // Calling in_wall() here produces the desired fix (no glitching through wall), but only when delta_x >= 10
  58.                                 // The code below "emulates" in_wall() to always get the same effect as if delta_x == 10
  59.                                 // (which distance actually looks/behaves best is a matter of preference)
  60.                                 #define delta_x_reference 10
  61.                                 if (delta_x >= 8) {
  62.                                         delta_x = -5 + delta_x - delta_x_reference;
  63.                                         Char.x = (byte) char_dx_forward(delta_x);
  64.  
  65.                                         Char.fall_x = 0; // not in in_wall(), but we do need to cancel horizontal movement
  66.                                 }
  67.                         }
  68.                 }
  69.                 #endif
  70.  
  71.         } else {
  72.  
  73.                 #ifdef FIX_JUMP_THROUGH_WALL_ABOVE_GATE
  74.                 if (fix_jump_through_wall_above_gate) {
  75.                         // At this point, Char.curr_col has not yet been updated since check_bumped()
  76.                         // Basically, Char.curr_col is still set to the column of the wall itself (even though the kid
  77.                         // may have 'bumped' against the wall, with Char.x being offset)
  78.  
  79.                         // To prevent in_wall() from being called we need to update Char.curr_col here.
  80.                         // (in_wall() only makes things worse, because it tries to 'eject' the kid from the wall the wrong way.
  81.                         // For this reason, the kid can end up behind a closed gate below, like is possible in Level 7)
  82.  
  83.                         // The fix is calling determine_col() here.
  84.  
  85.                         // One caveat: the kid can also land on the rightmost edge of a closed gate tile, when doing a running jump
  86.                         // to the left from two floors up. This 'trick' can be used in original PoP, but is 'fixed' by this change.
  87.                         // To still allow this trick to be possible, we can check that we not jumping into a gate tile.
  88.                         // (By the way, strangely enough, in unmodified PoP the trick even works with a tapestry + floor tile...)
  89.  
  90.                         if (get_tile_at_char() != tiles_4_gate)
  91.                                 determine_col();
  92.                 }
  93.                 #endif
  94.  
  95.                 if (get_tile_at_char() == tiles_20_wall) {
  96.                         in_wall();
  97.                 }
  98.                 #ifdef FIX_DROP_THROUGH_TAPESTRY
  99.                 else if (fix_drop_through_tapestry && get_tile_at_char() == tiles_12_doortop && Char.direction == dir_FF_left) {
  100.                         if (distance_to_edge_weight() >= 8) // only intervene if the kid is actually IN FRONT of the tapestry
  101.                                 in_wall();
  102.                 }
  103.                 #endif
  104.  
  105.                 if (tile_is_floor(curr_tile2)) {
  106.                         land();
  107.                 } else {
  108.                         inc_curr_row();
  109.                 }
  110.         }
  111. }
  112.  
  113. // seg005:0090
  114. void __pascal far land() {
  115.         word seq_id;
  116.         is_screaming = 0;
  117.         Char.y = y_land[Char.curr_row + 1];
  118.         if (get_tile_at_char() != tiles_2_spike) {
  119.  
  120.  
  121.                 if (! tile_is_floor(get_tile_infrontof_char()) &&
  122.                         distance_to_edge_weight() < 3
  123.                 ) {
  124.                         Char.x = char_dx_forward(-3);
  125.                 }
  126.  
  127.                 #ifdef FIX_LAND_AGAINST_GATE_OR_TAPESTRY
  128.                 else if (fix_land_against_gate_or_tapestry) {
  129.                         // A closed gate right in front of the landing spot should not behave like an open floor tile, but like a wall
  130.                         // Similar for a tapestry tile (with floor)
  131.                         get_tile_infrontof_char();
  132.                         if (Char.direction == dir_FF_left && (
  133.                                                         (curr_tile2 == tiles_4_gate && can_bump_into_gate()) ||
  134.                                                         (curr_tile2 == tiles_7_doortop_with_floor))
  135.                                         && distance_to_edge_weight() < 3
  136.                         ) {
  137.                                 Char.x = char_dx_forward(-3);
  138.                         }
  139.                 }
  140.                 #endif
  141.                 start_chompers();
  142.         } else {
  143.                 // fell on spikes
  144.                 goto loc_5EE6;
  145.         }
  146.         if (Char.alive < 0) {
  147.                 // alive
  148.                 if ((distance_to_edge_weight() >= 12 &&
  149.                         get_tile_behind_char() == tiles_2_spike) ||
  150.                         get_tile_at_char() == tiles_2_spike
  151.                 ) {
  152.                         // fell on spikes
  153.                         loc_5EE6:
  154.                         if (is_spike_harmful()) {
  155.                                 spiked();
  156.                                 return;
  157.                         }
  158.                         #ifdef FIX_SAFE_LANDING_ON_SPIKES
  159.                         else if (fix_safe_landing_on_spikes && curr_room_modif[curr_tilepos] == 0) {
  160.                                 // spikes ARE dangerous, just not out yet.
  161.                                 spiked();
  162.                                 return;
  163.                         }
  164.                         #endif // FIX_SAFE_LANDING_ON_SPIKES
  165.                 }
  166.                 {
  167.                         if (Char.fall_y < 22) {
  168.                                 // fell 1 row
  169.                                 loc_5EFD:
  170.                                 if (Char.charid >= charid_2_guard || Char.sword == sword_2_drawn) {
  171.                                         Char.sword = sword_2_drawn;
  172.                                         seq_id = seq_63_guard_stand_active; // stand active after landing
  173.                                 } else {
  174.                                         seq_id = seq_17_soft_land; // crouch (soft land)
  175.                                 }
  176.                                 if (Char.charid == charid_0_kid) {
  177.                                         play_sound(sound_17_soft_land); // soft land (crouch)
  178.                                         is_guard_notice = 1;
  179.                                 }
  180.                         } else if (Char.fall_y < 33) {
  181.                                 // fell 2 rows
  182.                                 if (Char.charid == charid_1_shadow) goto loc_5EFD;
  183.                                 if (Char.charid == charid_2_guard) goto loc_5F6C;
  184.                                 // kid (or skeleton (bug!))
  185.                                 if (! take_hp(1)) {
  186.                                         // still alive
  187.                                         play_sound(sound_16_medium_land); // medium land
  188.                                         is_guard_notice = 1;
  189.                                         seq_id = seq_20_medium_land; // medium land (lose 1 HP, crouch)
  190.                                 } else {
  191.                                         // dead (this was the last HP)
  192.                                         goto loc_5F75;
  193.                                 }
  194.                         } else {
  195.                                 // fell 3 or more rows
  196.                                 goto loc_5F6C;
  197.                         }
  198.                 }
  199.         } else {
  200.                 // dead
  201.                 loc_5F6C:
  202.                 take_hp(100);
  203.                 loc_5F75:
  204.                 play_sound(sound_0_fell_to_death); // prince crashing into the floor
  205.                 seq_id = seq_22_crushed; // dead (after falling)
  206.         }
  207.         seqtbl_offset_char(seq_id);
  208.         play_seq();
  209.         Char.fall_y = 0;
  210. }
  211.  
  212. // seg005:01B7
  213. void __pascal far spiked() {
  214.         // If someone falls into spikes, those spikes become harmless (to others).
  215.         curr_room_modif[curr_tilepos] = 0xFF;
  216.         Char.y = y_land[Char.curr_row + 1];
  217.         Char.x = x_bump[tile_col + 5] + 10;
  218.         Char.x = char_dx_forward(8);
  219.         Char.fall_y = 0;
  220.         play_sound(sound_48_spiked); // something spiked
  221.         take_hp(100);
  222.         seqtbl_offset_char(seq_51_spiked); // spiked
  223.         play_seq();
  224. }
  225.  
  226. // seg005:0213
  227. void __pascal far control() {
  228.         short char_frame;
  229.         short char_action;
  230.         char_frame = Char.frame;
  231.         if (Char.alive >= 0) {
  232.                 if (char_frame == frame_15_stand || // stand
  233.                         char_frame == frame_166_stand_inactive || // stand
  234.                         char_frame == frame_158_stand_with_sword || // stand with sword
  235.                         char_frame == frame_171_stand_with_sword // stand with sword
  236.                 ) {
  237.                         seqtbl_offset_char(seq_71_dying); // dying (not stabbed)
  238.                 }
  239.         } else {
  240.                 char_action = Char.action;
  241.                 if (char_action == actions_5_bumped ||
  242.                         char_action == actions_4_in_freefall
  243.                 ) {
  244.                         release_arrows();
  245.                 } else if (Char.sword == sword_2_drawn) {
  246.                         control_with_sword();
  247.                 } else if (Char.charid >= charid_2_guard) {
  248.                         control_guard_inactive();
  249.                 } else if (char_frame == frame_15_stand || // standing
  250.                         (char_frame>= frame_50_turn && char_frame<53) // end of turning
  251.                 ) {
  252.                         control_standing();
  253.                 } else if (char_frame == frame_48_turn) { // a frame in turning
  254.                         control_turning();
  255.                 } else if (char_frame < 4) { // start run
  256.                         control_startrun();
  257.                 } else if (char_frame >= frame_67_start_jump_up_1 && char_frame < frame_70_jumphang) { // start jump up
  258.                         control_jumpup();
  259.                 } else if (char_frame < 15) { // running
  260.                         control_running();
  261.                 } else if (char_frame >= frame_87_hanging_1 && char_frame < 100) { // hanging
  262.                         control_hanging();
  263.                 } else if (char_frame == frame_109_crouch) { // crouching
  264.                         control_crouched();
  265.                 }
  266.  
  267.                 #ifdef ALLOW_CROUCH_AFTER_CLIMBING
  268.                 // When ducking with down+forward, give time to release the forward control (prevents unintended crouch-hops)
  269.                 else if (enable_crouch_after_climbing && Char.curr_seq >= seqtbl_offsets[seq_50_crouch] &&
  270.                                 Char.curr_seq < seqtbl_offsets[seq_49_stand_up_from_crouch]) // while stooping
  271.                         if (control_forward < 1) control_forward = 0;
  272.                 #endif
  273.  
  274.                 #ifdef FIX_MOVE_AFTER_DRINK
  275.                 if (fix_move_after_drink && char_frame >= frame_191_drink && char_frame <= frame_205_drink)
  276.                         release_arrows();
  277.                 #endif
  278.  
  279.                 #ifdef FIX_MOVE_AFTER_SHEATHE
  280.                 if (fix_move_after_sheathe &&
  281.                                 Char.curr_seq >= seqtbl_offsets[seq_92_put_sword_away] &&
  282.                                 Char.curr_seq < seqtbl_offsets[seq_93_put_sword_away_fast]
  283.                 )
  284.                         release_arrows();
  285.                 #endif
  286.         }
  287. }
  288.  
  289. // seg005:02EB
  290. void __pascal far control_crouched() {
  291.         if (need_level1_music != 0 && current_level == 1) {
  292.                 // Special event: music when crouching
  293.                 if (! check_sound_playing()) {
  294.                         if (need_level1_music == 1) {
  295.                                 play_sound(sound_25_presentation); // presentation (level 1 start)
  296.                                 need_level1_music = 2;
  297.                         } else {
  298. #ifdef USE_REPLAY
  299.                                 if (recording) special_move = MOVE_EFFECT_END;
  300.                                 if (!replaying) // during replays, crouch immobilization gets cancelled in do_replay_move()
  301. #endif
  302.                                 need_level1_music = 0;
  303.                         }
  304.                 }
  305.         } else {
  306.                 need_level1_music = 0;
  307.                 if (control_shift2 < 0 && check_get_item()) return;
  308.                 if (control_y != 1) {
  309.                         seqtbl_offset_char(seq_49_stand_up_from_crouch); // stand up from crouch
  310.                 } else {
  311.                         if (control_forward < 0) {
  312.                                 control_forward = 1; // disable automatic repeat
  313.                                 seqtbl_offset_char(seq_79_crouch_hop); // crouch-hop
  314.                         }
  315.                 }
  316.         }
  317. }
  318.  
  319. // seg005:0358
  320. void __pascal far control_standing() {
  321.         short var_2;
  322.         if (control_shift2 < 0 && control_shift < 0 && check_get_item()) {
  323.                 return;
  324.         }
  325.         if (Char.charid != charid_0_kid && control_down < 0 && control_forward < 0) {
  326.                 draw_sword();
  327.                 return;
  328.         } //else
  329.         if (have_sword) {
  330.                 if (offguard != 0 && control_shift >= 0) goto loc_6213;
  331.                 if (can_guard_see_kid >= 2) {
  332.                         var_2 = char_opp_dist();
  333.                         if (var_2 >= -10 && var_2 < 90) {
  334.                                 holding_sword = 1;
  335.                                 if ((word)var_2 < (word)-6) {
  336.                                         if (Opp.charid == charid_1_shadow &&
  337.                                                 (Opp.action == actions_3_in_midair || (Opp.frame >= frame_107_fall_land_1 && Opp.frame < 118))
  338.                                         ) {
  339.                                                 offguard = 0;
  340.                                         } else {
  341.                                                 draw_sword();
  342.                                                 return;
  343.                                         }
  344.                                 } else {
  345.                                         back_pressed();
  346.                                         return;
  347.                                 }
  348.                         }
  349.                 } else {
  350.                         offguard = 0;
  351.                 }
  352.         }
  353.         if (control_shift < 0) {
  354.                 if (control_backward < 0) {
  355.                         back_pressed();
  356.                 } else if (control_up < 0) {
  357.                         up_pressed();
  358.                 } else if (control_down < 0) {
  359.                         down_pressed();
  360.                 } else if (control_x < 0 && control_forward < 0) {
  361.                         safe_step();
  362.                 }
  363.         } else loc_6213: if (control_forward < 0) {
  364.                 if (is_keyboard_mode && control_up < 0) {
  365.                         standing_jump();
  366.                 } else {
  367.                         forward_pressed();
  368.                 }
  369.         } else if (control_backward < 0) {
  370.                 back_pressed();
  371.         } else if (control_up < 0) {
  372.                 if (is_keyboard_mode && control_forward < 0) {
  373.                         standing_jump();
  374.                 } else {
  375.                         up_pressed();
  376.                 }
  377.         } else if (control_down < 0) {
  378.                 down_pressed();
  379.         } else if (control_x < 0) {
  380.                 forward_pressed();
  381.         }
  382. }
  383.  
  384. // seg005:0482
  385. void __pascal far up_pressed() {
  386.         int leveldoor_tilepos = -1;
  387.         if (get_tile_at_char() == tiles_16_level_door_left) leveldoor_tilepos = curr_tilepos;
  388.         else if (get_tile_behind_char() == tiles_16_level_door_left) leveldoor_tilepos = curr_tilepos;
  389.         else if (get_tile_infrontof_char() == tiles_16_level_door_left) leveldoor_tilepos = curr_tilepos;
  390.         if ((leveldoor_tilepos != -1) &&
  391.                 level.start_room != drawn_room &&
  392.                 curr_room_modif[leveldoor_tilepos] >= 42 // this door must be fully open
  393.         ){
  394.                 go_up_leveldoor();
  395.         } else {
  396.                 if (control_x < 0) {
  397.                         standing_jump();
  398.                 } else {
  399.                         check_jump_up();
  400.                 }
  401.         }
  402. }
  403.  
  404. // seg005:04C7
  405. void __pascal far down_pressed() {
  406.         control_down = 1; // disable automatic repeat
  407.         if (! tile_is_floor(get_tile_infrontof_char()) &&
  408.                 distance_to_edge_weight() < 3
  409.         ) {
  410.                 Char.x = char_dx_forward(5);
  411.                 load_fram_det_col();
  412.         } else {
  413.                 if (! tile_is_floor(get_tile_behind_char()) &&
  414.                         distance_to_edge_weight() >= 8
  415.                 ) {
  416.                         through_tile = get_tile_behind_char();
  417.                         get_tile_at_char();
  418.                         if (can_grab() &&
  419.                                 #ifdef ALLOW_CROUCH_AFTER_CLIMBING
  420.                                 (!(enable_crouch_after_climbing && control_forward == -1)) &&
  421.                                 #endif
  422.                                 (Char.direction >= dir_0_right ||
  423.                                 get_tile_at_char() != tiles_4_gate ||
  424.                                 curr_room_modif[curr_tilepos] >> 2 >= 6)
  425.                         ) {
  426.                                 Char.x = char_dx_forward(distance_to_edge_weight() - 9);
  427.                                 seqtbl_offset_char(seq_68_climb_down); // climb down
  428.                         } else {
  429.                                 crouch();
  430.                         }
  431.                 } else {
  432.                         crouch();
  433.                 }
  434.         }
  435. }
  436.  
  437. // seg005:0574
  438. void __pascal far go_up_leveldoor() {
  439.         Char.x = x_bump[tile_col + 5] + 10;
  440.         Char.direction = dir_FF_left; // right
  441.         seqtbl_offset_char(seq_70_go_up_on_level_door); // go up on level door
  442. }
  443.  
  444. // seg005:058F
  445. void __pascal far control_turning() {
  446.         if (control_shift >= 0 && control_x < 0 && control_y >= 0) {
  447.                 seqtbl_offset_char(seq_43_start_run_after_turn); // start run and run (after turning)
  448.         }
  449.  
  450.         // Added:
  451.         // When using a joystick, the kid may sometimes jump/duck/turn unintendedly after turning around.
  452.         // To prevent this: clear the remembered controls, so that if the stick has already moved to another/neutral position,
  453.         // the kid will not jump, duck, or turn again.
  454.         if (is_joyst_mode) {
  455.                 if (control_up < 0 && control_y >= 0) {
  456.                         control_up = 0;
  457.                 }
  458.                 if (control_down < 0 && control_y <= 0) {
  459.                         control_down = 0;
  460.                 }
  461.                 if (control_backward < 0 && control_x == 0) {
  462.                         control_backward = 0;
  463.                 }
  464.         }
  465. }
  466.  
  467. // seg005:05AD
  468. void __pascal far crouch() {
  469.         seqtbl_offset_char(seq_50_crouch); // crouch
  470.         control_down = release_arrows();
  471. }
  472.  
  473. // seg005:05BE
  474. void __pascal far back_pressed() {
  475.         word seq_id;
  476.         control_backward = release_arrows();
  477.         // After turn, Kid will draw sword if ...
  478.         if (have_sword == 0 || // if Kid has sword
  479.                 can_guard_see_kid < 2 || // and can see Guard
  480.                 char_opp_dist() > 0 || // and Guard was behind him
  481.                 distance_to_edge_weight() < 2
  482.         ) {
  483.                 seq_id = seq_5_turn; // turn
  484.         } else {
  485.                 Char.sword = sword_2_drawn;
  486.                 offguard = 0;
  487.                 seq_id = seq_89_turn_draw_sword; // turn and draw sword
  488.         }
  489.         seqtbl_offset_char(seq_id);
  490. }
  491.  
  492. // seg005:060F
  493. void __pascal far forward_pressed() {
  494.         short distance;
  495.         distance = get_edge_distance();
  496.         #ifdef ALLOW_CROUCH_AFTER_CLIMBING
  497.         if (enable_crouch_after_climbing && control_down < 0) {
  498.                 down_pressed();
  499.                 control_forward = 0;
  500.                 return;
  501.         }
  502.         #endif
  503.  
  504.         if (edge_type == 1 && curr_tile2 != tiles_18_chomper && distance < 8) {
  505.                 // If char is near a wall, step instead of run.
  506.                 if (control_forward < 0) {
  507.                         safe_step();
  508.                 }
  509.         } else {
  510.                 seqtbl_offset_char(seq_1_start_run); // start run and run
  511.         }
  512. }
  513.  
  514. // seg005:0649
  515. void __pascal far control_running() {
  516.         if (control_x == 0 && (Char.frame == frame_7_run || Char.frame == frame_11_run)) {
  517.                 control_forward = release_arrows();
  518.                 seqtbl_offset_char(seq_13_stop_run); // stop run
  519.         } else if (control_x > 0) {
  520.                 control_backward = release_arrows();
  521.                 seqtbl_offset_char(seq_6_run_turn); // run-turn
  522.         } else if (control_y < 0 && control_up < 0) {
  523.                 run_jump();
  524.         } else if (control_down < 0) {
  525.                 control_down = 1; // disable automatic repeat
  526.                 seqtbl_offset_char(seq_26_crouch_while_running); // crouch while running
  527.         }
  528. }
  529.  
  530. // seg005:06A8
  531. void __pascal far safe_step() {
  532.         short distance;
  533.         control_shift2 = 1; // disable automatic repeat
  534.         control_forward = 1; // disable automatic repeat
  535.         distance = get_edge_distance();
  536.         if (distance) {
  537.                 Char.repeat = 1;
  538.                 seqtbl_offset_char(distance + 28); // 29..42: safe step to edge
  539.         } else if (edge_type != 1 && Char.repeat != 0) {
  540.                 Char.repeat = 0;
  541.                 seqtbl_offset_char(seq_44_step_on_edge); // step on edge
  542.         } else {
  543.                 seqtbl_offset_char(seq_39_safe_step_11); // unsafe step (off ledge)
  544.         }
  545. }
  546.  
  547. // seg005:06F0
  548. int __pascal far check_get_item() {
  549.         if (get_tile_at_char() == tiles_10_potion ||
  550.                 curr_tile2 == tiles_22_sword
  551.         ) {
  552.                 if (! tile_is_floor(get_tile_behind_char())) {
  553.                         return 0;
  554.                 }
  555.                 Char.x = char_dx_forward(-14);
  556.                 load_fram_det_col();
  557.         }
  558.         if (get_tile_infrontof_char() == tiles_10_potion ||
  559.                 curr_tile2 == tiles_22_sword
  560.         ) {
  561.                 get_item();
  562.                 return 1;
  563.         }
  564.         return 0;
  565. }
  566.  
  567. // seg005:073E
  568. void __pascal far get_item() {
  569.         short distance;
  570.         if (Char.frame != frame_109_crouch) { // crouching
  571.                 distance = get_edge_distance();
  572.                 if (edge_type != 2) {
  573.                         Char.x = char_dx_forward(distance);
  574.                 }
  575.                 if (Char.direction >= dir_0_right) {
  576.                         Char.x = char_dx_forward((curr_tile2 == tiles_10_potion) - 2);
  577.                 }
  578.                 crouch();
  579.         } else if (curr_tile2 == tiles_22_sword) {
  580.                 do_pickup(-1);
  581.                 seqtbl_offset_char(seq_91_get_sword); // get sword
  582.         } else { // potion
  583.                 do_pickup(curr_room_modif[curr_tilepos] >> 3);
  584.                 seqtbl_offset_char(seq_78_drink); // drink
  585. #ifdef USE_COPYPROT
  586.                 if (current_level == 15) {
  587.                         short index;
  588.                         for (index = 0; index < 14; ++index) {
  589.                                 // remove letter on potions level
  590.                                 if (copyprot_room[index] == curr_room &&
  591.                                         copyprot_tile[index] == curr_tilepos
  592.                                 ) {
  593.                                         copyprot_room[index] = 0;
  594.                                         break;
  595.                                 }
  596.                         }
  597.                 }
  598. #endif
  599.         }
  600. }
  601.  
  602. // seg005:07FF
  603. void __pascal far control_startrun() {
  604.         if (control_y < 0 && control_x < 0) {
  605.                 standing_jump();
  606.         }
  607. }
  608.  
  609. // seg005:0812
  610. void __pascal far control_jumpup() {
  611.         if (control_x < 0 || control_forward < 0) {
  612.                 standing_jump();
  613.         }
  614. }
  615.  
  616. // seg005:0825
  617. void __pascal far standing_jump() {
  618.         control_up = control_forward = 1; // disable automatic repeat
  619.         seqtbl_offset_char(seq_3_standing_jump); // standing jump
  620. }
  621.  
  622. // seg005:0836
  623. void __pascal far check_jump_up() {
  624.         control_up = release_arrows();
  625.         through_tile = get_tile_above_char();
  626.         get_tile_front_above_char();
  627.         if (can_grab()) {
  628.                 grab_up_with_floor_behind();
  629.         } else {
  630.                 through_tile = get_tile_behind_above_char();
  631.                 get_tile_above_char();
  632.                 if (can_grab()) {
  633.                         jump_up_or_grab();
  634.                 } else {
  635.                         jump_up();
  636.                 }
  637.         }
  638. }
  639.  
  640. // seg005:087B
  641. void __pascal far jump_up_or_grab() {
  642.         short distance;
  643.         distance = distance_to_edge_weight();
  644.         if (distance < 6) {
  645.                 jump_up();
  646.         } else if (! tile_is_floor(get_tile_behind_char())) {
  647.                 // There is not floor behind char.
  648.                 grab_up_no_floor_behind();
  649.         } else {
  650.                 // There is floor behind char, go back a bit.
  651.                 Char.x = char_dx_forward(distance - 14);
  652.                 load_fram_det_col();
  653.                 grab_up_with_floor_behind();
  654.         }
  655. }
  656.  
  657. // seg005:08C7
  658. void __pascal far grab_up_no_floor_behind() {
  659.         get_tile_above_char();
  660.         Char.x = char_dx_forward(distance_to_edge_weight() - 10);
  661.         seqtbl_offset_char(seq_16_jump_up_and_grab); // jump up and grab (no floor behind)
  662. }
  663.  
  664. // seg005:08E6
  665. void __pascal far jump_up() {
  666.         short distance;
  667.         control_up = release_arrows();
  668.         distance = get_edge_distance();
  669.         if (distance < 4 && edge_type == 1) {
  670.                 Char.x = char_dx_forward(distance - 3);
  671.         }
  672.         #ifdef FIX_JUMP_DISTANCE_AT_EDGE
  673.         // When climbing up two floors, turning around and jumping upward, the kid falls down.
  674.         // This fix makes the workaround of Trick 25 unnecessary.
  675.         if (fix_jump_distance_at_edge && distance == 3 && edge_type == 0) {
  676.                 Char.x = char_dx_forward(-1);
  677.         }
  678.         #endif
  679.         get_tile(Char.room, get_tile_div_mod(back_delta_x(0) + dx_weight() - 6), Char.curr_row - 1);
  680.         if (curr_tile2 != tiles_20_wall && ! tile_is_floor(curr_tile2)) {
  681.                 seqtbl_offset_char(seq_28_jump_up_with_nothing_above); // jump up with nothing above
  682.         } else {
  683.                 seqtbl_offset_char(seq_14_jump_up_into_ceiling); // jump up with wall or floor above
  684.         }
  685. }
  686.  
  687. // seg005:0968
  688. void __pascal far control_hanging() {
  689.         if (Char.alive < 0) {
  690.                 if (grab_timer == 0 && control_y < 0) {
  691.                         can_climb_up();
  692.                 } else if (control_shift < 0) {
  693.                         // hanging against a wall or a doortop
  694.                         if (Char.action != actions_6_hang_straight &&
  695.                                 (get_tile_at_char() == tiles_20_wall ||
  696.                                 (Char.direction == dir_FF_left && ( // facing left
  697.                                         curr_tile2 == tiles_7_doortop_with_floor ||
  698.                                         curr_tile2 == tiles_12_doortop
  699.                                 )))
  700.                         ) {
  701.                                 if (grab_timer == 0) {
  702.                                         play_sound(sound_8_bumped); // touching a wall (hang against wall)
  703.                                 }
  704.                                 seqtbl_offset_char(seq_25_hang_against_wall); // hang against wall (straight)
  705.                         } else {
  706.                                 if (! tile_is_floor(get_tile_above_char())) {
  707.                                         hang_fall();
  708.                                 }
  709.                         }
  710.                 } else {
  711.                         hang_fall();
  712.                 }
  713.         } else {
  714.                 hang_fall();
  715.         }
  716. }
  717.  
  718. // seg005:09DF
  719. void __pascal far can_climb_up() {
  720.         short seq_id;
  721.         seq_id = seq_10_climb_up; // climb up
  722.         control_up = control_shift2 = release_arrows();
  723.         get_tile_above_char();
  724.         if (((curr_tile2 == tiles_13_mirror || curr_tile2 == tiles_18_chomper) &&
  725.                 Char.direction == dir_0_right) ||
  726.                 (curr_tile2 == tiles_4_gate && Char.direction != dir_0_right &&
  727.                 curr_room_modif[curr_tilepos] >> 2 < 6)
  728.         ) {
  729.                 seq_id = seq_73_climb_up_to_closed_gate; // climb up to closed gate and down
  730.         }
  731.         seqtbl_offset_char(seq_id);
  732. }
  733.  
  734. // seg005:0A46
  735. void __pascal far hang_fall() {
  736.         control_down = release_arrows();
  737.         if (! tile_is_floor(get_tile_behind_char()) &&
  738.                 ! tile_is_floor(get_tile_at_char())
  739.         ) {
  740.                 seqtbl_offset_char(seq_23_release_ledge_and_fall); // release ledge and fall
  741.         } else {
  742.                 if (get_tile_at_char() == tiles_20_wall ||
  743.                         (Char.direction < dir_0_right && ( // looking left
  744.                                 curr_tile2 == tiles_7_doortop_with_floor ||
  745.                                 curr_tile2 == tiles_12_doortop
  746.                         ))
  747.                 ) {
  748.                         Char.x = char_dx_forward(-7);
  749.                 }
  750.                 seqtbl_offset_char(seq_11_release_ledge_and_land); // end of climb down
  751.         }
  752. }
  753.  
  754. // seg005:0AA8
  755. void __pascal far grab_up_with_floor_behind() {
  756.         short distance;
  757.         distance = distance_to_edge_weight();
  758.  
  759.         // The global variable edge_type (which we need!) gets set as a side effect of get_edge_distance()
  760.         short edge_distance = get_edge_distance();
  761.         //printf("Distance to edge weight: %d\tedge type: %d\tedge distance: %d\n", distance, edge_type, edge_distance);
  762.  
  763.         #ifdef FIX_EDGE_DISTANCE_CHECK_WHEN_CLIMBING
  764.         // When climbing to a higher floor, the game unnecessarily checks how far away the edge below is;
  765.         // This contributes to sometimes "teleporting" considerable distances when climbing from firm ground
  766.         #define JUMP_STRAIGHT_CONDITION (fix_edge_distance_check_when_climbing)                                         \
  767.                                                                         ? (distance < 4 && edge_type != 1)                                                                      \
  768.                                                                         : (distance < 4 && edge_distance < 4 && edge_type != 1)
  769.         #else
  770.         #define JUMP_STRAIGHT_CONDITION distance < 4 && edge_distance < 4 && edge_type != 1
  771.         #endif
  772.  
  773.         if (JUMP_STRAIGHT_CONDITION) {
  774.                 Char.x = char_dx_forward(distance);
  775.                 seqtbl_offset_char(seq_8_jump_up_and_grab_straight); // jump up and grab (when?)
  776.         } else {
  777.                 Char.x = char_dx_forward(distance - 4);
  778.                 seqtbl_offset_char(seq_24_jump_up_and_grab_forward); // jump up and grab (with floor behind)
  779.         }
  780. }
  781.  
  782. // seg005:0AF7
  783. void __pascal far run_jump() {
  784.         short var_2;
  785.         short xpos;
  786.         short col;
  787.         short var_8;
  788.         if (Char.frame >= frame_7_run) {
  789.                 // Align Kid to edge of floor.
  790.                 xpos = char_dx_forward(4);
  791.                 col = get_tile_div_mod_m7(xpos);
  792.                 for (var_2 = 0; var_2 < 2; ++var_2) {
  793.                         col += dir_front[Char.direction + 1];
  794.                         get_tile(Char.room, col, Char.curr_row);
  795.                         if (curr_tile2 == tiles_2_spike || ! tile_is_floor(curr_tile2)) {
  796.                                 var_8 = distance_to_edge(xpos) + 14 * var_2 - 14;
  797.                                 if ((word)var_8 < (word)-8 || var_8 >= 2) {
  798.                                         if (var_8 < 128) return;
  799.                                         var_8 = -3;
  800.                                 }
  801.                                 Char.x = char_dx_forward(var_8 + 4);
  802.                                 break;
  803.                         }
  804.                 }
  805.                 control_up = release_arrows(); // disable automatic repeat
  806.                 seqtbl_offset_char(seq_4_run_jump); // run-jump
  807.         }
  808. }
  809.  
  810. // sseg005:0BB5
  811. void __pascal far back_with_sword() {
  812.         short frame;
  813.         frame = Char.frame;
  814.         if (frame == frame_158_stand_with_sword || frame == frame_170_stand_with_sword || frame == frame_171_stand_with_sword) {
  815.                 control_backward = 1; // disable automatic repeat
  816.                 seqtbl_offset_char(seq_57_back_with_sword); // back with sword
  817.         }
  818. }
  819.  
  820. // seg005:0BE3
  821. void __pascal far forward_with_sword() {
  822.         short frame;
  823.         frame = Char.frame;
  824.         if (frame == frame_158_stand_with_sword || frame == frame_170_stand_with_sword || frame == frame_171_stand_with_sword) {
  825.                 control_forward = 1; // disable automatic repeat
  826.                 if (Char.charid != charid_0_kid) {
  827.                         seqtbl_offset_char(seq_56_guard_forward_with_sword); // forward with sword (Guard)
  828.                 } else {
  829.                         seqtbl_offset_char(seq_86_forward_with_sword); // forward with sword (Kid)
  830.                 }
  831.         }
  832. }
  833.  
  834. // seg005:0C1D
  835. void __pascal far draw_sword() {
  836.         word seq_id;
  837.         seq_id = seq_55_draw_sword; // draw sword
  838.         control_forward = control_shift2 = release_arrows();
  839. #ifdef FIX_UNINTENDED_SWORD_STRIKE
  840.         if (fix_unintended_sword_strike) {
  841.                 ctrl1_shift2 = 1; // prevent restoring control_shift2 to -1 in rest_ctrl_1()
  842.         }
  843. #endif
  844.         if (Char.charid == charid_0_kid) {
  845.                 play_sound(sound_19_draw_sword); // taking out the sword
  846.                 offguard = 0;
  847.         } else if (Char.charid != charid_1_shadow) {
  848.                 seq_id = seq_90_en_garde; // stand active
  849.         }
  850.         Char.sword = sword_2_drawn;
  851.         seqtbl_offset_char(seq_id);
  852. }
  853.  
  854. // seg005:0C67
  855. void __pascal far control_with_sword() {
  856.         short distance;
  857.         if (Char.action < actions_2_hang_climb) {
  858.                 if (get_tile_at_char() == tiles_11_loose || can_guard_see_kid >= 2) {
  859.                         distance = char_opp_dist();
  860.                         if ((word)distance < (word)90) {
  861.                                 swordfight();
  862.                                 return;
  863.                         } else if (distance < 0) {
  864.                                 if ((word)distance < (word)-4) {
  865.                                         seqtbl_offset_char(seq_60_turn_with_sword); // turn with sword (after switching places)
  866.                                         return;
  867.                                 } else {
  868.                                         swordfight();
  869.                                         return;
  870.                                 }
  871.                         }
  872.                 } /*else*/ {
  873.                         if (Char.charid == charid_0_kid && Char.alive < 0) {
  874.                                 holding_sword = 0;
  875.                         }
  876.                         if (Char.charid < charid_2_guard) {
  877.                                 // frame 171: stand with sword
  878.                                 if (Char.frame == frame_171_stand_with_sword) {
  879.                                         Char.sword = sword_0_sheathed;
  880.                                         seqtbl_offset_char(seq_92_put_sword_away); // put sword away (Guard died)
  881.                                 }
  882.                         } else {
  883.                                 swordfight();
  884.                         }
  885.                 }
  886.         }
  887. }
  888.  
  889. // seg005:0CDB
  890. void __pascal far swordfight() {
  891.         short frame;
  892.         short seq_id;
  893.         short charid;
  894.         frame = Char.frame;
  895.         charid = Char.charid;
  896.         // frame 161: parry
  897.         if (frame == frame_161_parry && control_shift2 >= 0) {
  898.                 seqtbl_offset_char(seq_57_back_with_sword); // back with sword (when parrying)
  899.                 return;
  900.         } else if (control_shift2 < 0) {
  901.                 if (charid == charid_0_kid) {
  902.                         kid_sword_strike = 15;
  903.                 }
  904.                 sword_strike();
  905.                 if (control_shift2 == 1) return;
  906.         }
  907.         if (control_down < 0) {
  908.                 if (frame == frame_158_stand_with_sword || frame == frame_170_stand_with_sword || frame == frame_171_stand_with_sword) {
  909.                         control_down = 1; // disable automatic repeat
  910.                         Char.sword = sword_0_sheathed;
  911.                         if (charid == charid_0_kid) {
  912.                                 offguard = 1;
  913.                                 guard_refrac = 9;
  914.                                 holding_sword = 0;
  915.                                 seq_id = seq_93_put_sword_away_fast; // put sword away fast (down pressed)
  916.                         } else if (charid == charid_1_shadow) {
  917.                                 seq_id = seq_92_put_sword_away; // put sword away
  918.                         } else {
  919.                                 seq_id = seq_87_guard_become_inactive; // stand inactive (when Kid leaves sight)
  920.                         }
  921.                         seqtbl_offset_char(seq_id);
  922.                 }
  923.         } else if (control_up < 0) {
  924.                 parry();
  925.         } else if (control_forward < 0) {
  926.                 forward_with_sword();
  927.         } else if (control_backward < 0) {
  928.                 back_with_sword();
  929.         }
  930. }
  931.  
  932. // seg005:0DB0
  933. void __pascal far sword_strike() {
  934.         short frame;
  935.         short seq_id;
  936.         frame = Char.frame;
  937.         if (frame == frame_157_walk_with_sword || // walk with sword
  938.                 frame == frame_158_stand_with_sword || // stand with sword
  939.                 frame == frame_170_stand_with_sword || // stand with sword
  940.                 frame == frame_171_stand_with_sword || // stand with sword
  941.                 frame == frame_165_walk_with_sword // walk with sword
  942.         ) {
  943.                 if (Char.charid == charid_0_kid) {
  944.                         seq_id = seq_75_strike; // strike with sword (Kid)
  945.                 } else {
  946.                         seq_id = seq_58_guard_strike; // strike with sword (Guard)
  947.                 }
  948.         } else if (frame == frame_150_parry || frame == frame_161_parry) { // parry
  949.                 seq_id = seq_66_strike_after_parry; // strike with sword after parrying
  950.         } else {
  951.                 return;
  952.         }
  953.         control_shift2 = 1; // disable automatic repeat
  954.         seqtbl_offset_char(seq_id);
  955. }
  956.  
  957. // seg005:0E0F
  958. void __pascal far parry() {
  959.         short opp_frame;
  960.         short char_frame;
  961.         short var_6;
  962.         short seq_id;
  963.         short char_charid;
  964.         char_frame = Char.frame;
  965.         opp_frame = Opp.frame;
  966.         char_charid = Char.charid;
  967.         seq_id = seq_62_parry; // defend (parry) with sword
  968.         var_6 = 0;
  969.         if (
  970.                 char_frame == frame_158_stand_with_sword || // stand with sword
  971.                 char_frame == frame_170_stand_with_sword || // stand with sword
  972.                 char_frame == frame_171_stand_with_sword || // stand with sword
  973.                 char_frame == frame_168_back || // back?
  974.                 char_frame == frame_165_walk_with_sword // walk with sword
  975.         ) {
  976.                 if (char_opp_dist() >= 32 && char_charid != charid_0_kid) {
  977.                         back_with_sword();
  978.                         return;
  979.                 } else if (char_charid == charid_0_kid) {
  980.                         if (opp_frame == frame_168_back) return;
  981.                         if (opp_frame != frame_151_strike_1 &&
  982.                                 opp_frame != frame_152_strike_2 &&
  983.                                 opp_frame != frame_162_block_to_strike
  984.                         ) {
  985.                                 if (opp_frame == frame_153_strike_3) { // strike
  986.                                         var_6 = 1;
  987.                                 } else
  988.                                 if (char_charid != charid_0_kid) {
  989.                                         back_with_sword();
  990.                                         return;
  991.                                 }
  992.                         }
  993.                 } else {
  994.                         if (opp_frame != frame_152_strike_2) return;
  995.                 }
  996.         } else {
  997.                 if (char_frame != frame_167_blocked) return;
  998.                 seq_id = seq_61_parry_after_strike; // parry after striking with sword
  999.         }
  1000.         control_up = 1; // disable automatic repeat
  1001.         seqtbl_offset_char(seq_id);
  1002.         if (var_6) {
  1003.                 play_seq();
  1004.         }
  1005. }
  1006.